Skip to content

Commit

Permalink
hir: lower ImplicitSelf to resolved Self TyQPath's.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Dec 28, 2016
1 parent 0807104 commit 6ebb6fd
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 183 deletions.
27 changes: 13 additions & 14 deletions src/librustc/hir/lowering.rs
Expand Up @@ -259,7 +259,7 @@ impl<'a> LoweringContext<'a> {
P(hir::Ty {
id: t.id,
node: match t.node {
TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
TyKind::Infer => hir::TyInfer,
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
TyKind::Rptr(ref region, ref mt) => {
Expand All @@ -283,6 +283,16 @@ impl<'a> LoweringContext<'a> {
TyKind::Path(ref qself, ref path) => {
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
}
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
def: self.expect_full_def(t.id),
segments: hir_vec![hir::PathSegment {
name: keywords::SelfType.name(),
parameters: hir::PathParameters::none()
}],
span: t.span,
})))
}
TyKind::ObjectSum(ref ty, ref bounds) => {
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
Expand Down Expand Up @@ -976,7 +986,7 @@ impl<'a> LoweringContext<'a> {
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
has_self: sig.decl.get_self().is_some(),
has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
Expand Down Expand Up @@ -1051,24 +1061,13 @@ impl<'a> LoweringContext<'a> {
}

fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
let hir_sig = hir::MethodSig {
hir::MethodSig {
generics: self.lower_generics(&sig.generics),
abi: sig.abi,
unsafety: self.lower_unsafety(sig.unsafety),
constness: self.lower_constness(sig.constness),
decl: self.lower_fn_decl(&sig.decl),
};
// Check for `self: _` and `self: &_`
if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
match hir_sig.decl.get_self().map(|eself| eself.node) {
Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
"the type placeholder `_` is not allowed within types on item signatures");
}
_ => {}
}
}
hir_sig
}

fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
Expand Down
38 changes: 3 additions & 35 deletions src/librustc/hir/mod.rs
Expand Up @@ -35,8 +35,8 @@ use hir::def_id::DefId;
use util::nodemap::{NodeMap, FxHashSet};
use rustc_data_structures::fnv::FnvHashMap;

use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, respan, Spanned};
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
Expand Down Expand Up @@ -1234,37 +1234,8 @@ pub struct Arg {
pub id: NodeId,
}

/// Alternative representation for `Arg`s describing `self` parameter of methods.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum SelfKind {
/// `self`, `mut self`
Value(Mutability),
/// `&'lt self`, `&'lt mut self`
Region(Option<Lifetime>, Mutability),
/// `self: TYPE`, `mut self: TYPE`
Explicit(P<Ty>, Mutability),
}

pub type ExplicitSelf = Spanned<SelfKind>;

impl Arg {
pub fn to_self(&self) -> Option<ExplicitSelf> {
if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
if name.node == keywords::SelfValue.name() {
return match self.ty.node {
TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
}
_ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
SelfKind::Explicit(self.ty.clone(), mutbl)))
}
}
}
None
}

pub fn is_self(&self) -> bool {
fn is_self(&self) -> bool {
if let PatKind::Binding(_, _, name, _) = self.pat.node {
name.node == keywords::SelfValue.name()
} else {
Expand All @@ -1282,9 +1253,6 @@ pub struct FnDecl {
}

impl FnDecl {
pub fn get_self(&self) -> Option<ExplicitSelf> {
self.inputs.get(0).and_then(Arg::to_self)
}
pub fn has_self(&self) -> bool {
self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
}
Expand Down
45 changes: 10 additions & 35 deletions src/librustc/hir/print.rs
Expand Up @@ -25,7 +25,7 @@ use syntax_pos::{self, BytePos};
use errors;

use hir;
use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
use hir::{Crate, PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};

use std::io::{self, Write, Read};

Expand Down Expand Up @@ -1954,27 +1954,6 @@ impl<'a> State<'a> {
self.end() // close enclosing cbox
}

fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
match explicit_self.node {
SelfKind::Value(m) => {
self.print_mutability(m)?;
word(&mut self.s, "self")
}
SelfKind::Region(ref lt, m) => {
word(&mut self.s, "&")?;
self.print_opt_lifetime(lt)?;
self.print_mutability(m)?;
word(&mut self.s, "self")
}
SelfKind::Explicit(ref typ, m) => {
self.print_mutability(m)?;
word(&mut self.s, "self")?;
self.word_space(":")?;
self.print_type(&typ)
}
}
}

pub fn print_fn(&mut self,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
Expand Down Expand Up @@ -2185,21 +2164,17 @@ impl<'a> State<'a> {
match input.ty.node {
hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
_ => {
if let Some(eself) = input.to_self() {
self.print_explicit_self(&eself)?;
let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
name.node == keywords::Invalid.name()
} else {
let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
name.node == keywords::Invalid.name()
} else {
false
};
if !invalid {
self.print_pat(&input.pat)?;
word(&mut self.s, ":")?;
space(&mut self.s)?;
}
self.print_type(&input.ty)?;
false
};
if !invalid {
self.print_pat(&input.pat)?;
word(&mut self.s, ":")?;
space(&mut self.s)?;
}
self.print_type(&input.ty)?;
}
}
self.end()
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/mod.rs
Expand Up @@ -2127,7 +2127,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {

let (kind, has_self, has_value) = match trait_item.node {
hir::MethodTraitItem(ref sig, ref body) => {
(AssociatedKind::Method, sig.decl.get_self().is_some(),
(AssociatedKind::Method, sig.decl.has_self(),
body.is_some())
}
hir::ConstTraitItem(_, ref value) => {
Expand Down
12 changes: 12 additions & 0 deletions src/librustc_resolve/lib.rs
Expand Up @@ -571,6 +571,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
fn visit_ty(&mut self, ty: &'tcx Ty) {
if let TyKind::Path(ref qself, ref path) = ty.node {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
} else if let TyKind::ImplicitSelf = ty.node {
let self_ty = keywords::SelfType.ident();
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
}
visit::walk_ty(self, ty);
}
Expand Down Expand Up @@ -741,6 +746,13 @@ impl<'a> LexicalScopeBinding<'a> {
_ => None,
}
}

fn def(self) -> Def {
match self {
LexicalScopeBinding::Item(binding) => binding.def(),
LexicalScopeBinding::Def(def) => def,
}
}
}

#[derive(Clone)]
Expand Down
73 changes: 23 additions & 50 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -50,7 +50,7 @@

use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use hir::{self, SelfKind};
use hir;
use hir::def::Def;
use hir::def_id::DefId;
use hir::print as pprust;
Expand Down Expand Up @@ -1743,36 +1743,33 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
// declaration are bound to that function type.
let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);

// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
(Some(untransformed_self_ty), Some(explicit_self)) => {
let self_type = self.determine_self_type(&rb, untransformed_self_ty,
&explicit_self);
(Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
}
_ => (None, None),
};
let input_tys: Vec<Ty> =
decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();

// HACK(eddyb) replace the fake self type in the AST with the actual type.
let arg_params = if self_ty.is_some() {
&decl.inputs[1..]
} else {
&decl.inputs[..]
let has_self = decl.has_self();
let explicit_self = match (opt_untransformed_self_ty, has_self) {
(Some(untransformed_self_ty), true) => {
Some(ExplicitSelf::determine(untransformed_self_ty, input_tys[0]))
}
_ => None
};
let arg_tys: Vec<Ty> =
arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();

// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
let implied_output_region = match explicit_self {
// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),

// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
_ => {
self.find_implied_output_region(&arg_tys,
let arg_params = &decl.inputs[has_self as usize..];
let arg_tys = &input_tys[has_self as usize..];

self.find_implied_output_region(arg_tys,
arg_params.iter()
.map(|a| pprust::pat_to_string(&a.pat)))

Expand All @@ -1793,37 +1790,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
unsafety: unsafety,
abi: abi,
sig: ty::Binder(self.tcx().mk_fn_sig(
self_ty.into_iter().chain(arg_tys),
input_tys.into_iter(),
output_ty,
decl.variadic
)),
})
}

fn determine_self_type<'a>(&self,
rscope: &RegionScope,
untransformed_self_ty: Ty<'tcx>,
explicit_self: &hir::ExplicitSelf)
-> Ty<'tcx>
{
match explicit_self.node {
SelfKind::Value(..) => untransformed_self_ty,
SelfKind::Region(ref lifetime, mutability) => {
let region =
self.opt_ast_region_to_region(
rscope,
explicit_self.span,
lifetime);
self.tcx().mk_ref(region,
ty::TypeAndMut {
ty: untransformed_self_ty,
mutbl: mutability
})
}
SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
}
}

pub fn ty_of_closure(&self,
unsafety: hir::Unsafety,
decl: &hir::FnDecl,
Expand Down
40 changes: 13 additions & 27 deletions src/librustc_typeck/check/compare_method.rs
Expand Up @@ -8,14 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir;
use rustc::hir::{self, ImplItemKind, TraitItem_};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
use rustc::ty;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
use rustc::util::common::ErrorReported;

use syntax::ast;
Expand Down Expand Up @@ -456,31 +455,18 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
_ => bug!("{:?} is not a MethodTraitItem", trait_m),
};

impl_m_iter.zip(trait_m_iter)
.find(|&(ref impl_arg, ref trait_arg)| {
match (&impl_arg.ty.node, &trait_arg.ty.node) {
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
impl_mt.mutbl != trait_mt.mutbl
}
_ => false,
}
})
.map(|(ref impl_arg, ref trait_arg)| {
match (impl_arg.to_self(), trait_arg.to_self()) {
(Some(impl_self), Some(trait_self)) => {
(impl_self.span, Some(trait_self.span))
}
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
_ => {
bug!("impl and trait fns have different first args, impl: \
{:?}, trait: {:?}",
impl_arg,
trait_arg)
}
}
})
.unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
match (&impl_arg.ty.node, &trait_arg.ty.node) {
(&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
(&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
impl_mt.mutbl != trait_mt.mutbl
}
_ => false,
}
}).map(|(ref impl_arg, ref trait_arg)| {
(impl_arg.ty.span, Some(trait_arg.ty.span))
})
.unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
} else {
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
Expand Down

0 comments on commit 6ebb6fd

Please sign in to comment.