diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b6061f39233..998ce0cac47 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -457,7 +457,11 @@ impl tr for def::Def { def::DefMethod(did, p) => { def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) } - def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) } + def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), + impl_ids.map(|(nid1, nid2)| { + (dcx.tr_id(nid1), + dcx.tr_id(nid2)) + })) } def::DefMod(did) => { def::DefMod(did.tr(dcx)) } def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 6707a4d3fd7..f0b35908854 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -22,7 +22,8 @@ use std::cell::RefCell; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), - DefSelfTy(/* trait id */ ast::NodeId), + DefSelfTy(Option, // trait id + Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id) DefMod(ast::DefId), DefForeignMod(ast::DefId), DefStatic(ast::DefId, bool /* is_mutbl */), @@ -139,18 +140,19 @@ impl Def { DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | - DefMethod(id, _) | DefConst(id) => { + DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> { id } DefLocal(id) | - DefSelfTy(id) | DefUpvar(id, _) | DefRegion(id) | - DefLabel(id) => { + DefLabel(id) | + DefSelfTy(_, Some((_, id))) => { local_def(id) } - DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy") + DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"), + DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"), } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 44ab0962813..060b086ff01 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) { // `int` etc. (None doesn't seem to occur.) None | Some(def::DefPrimTy(..)) => return false, - Some(def) => def.def_id() + Some(def) => def.def_id(), }; // A path can only be private if: // it's in this crate... diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 045320e4fa4..002e5cc5e82 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1689,7 +1689,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } - DefTyParam(..) | DefSelfTy(_) => { + DefTyParam(..) | DefSelfTy(..) => { for rib in ribs { match rib.kind { NormalRibKind | MethodRibKind | ClosureRibKind(..) => { @@ -1797,63 +1797,57 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } ItemDefaultImpl(_, ref trait_ref) => { - self.with_optional_trait_ref(Some(trait_ref), |_| {}); + self.with_optional_trait_ref(Some(trait_ref), |_, _| {}); } - ItemImpl(_, _, + ItemImpl(_, + _, ref generics, - ref implemented_traits, + ref opt_trait_ref, ref self_type, ref impl_items) => { self.resolve_implementation(generics, - implemented_traits, + opt_trait_ref, &**self_type, + item.id, &impl_items[..]); } ItemTrait(_, ref generics, ref bounds, ref trait_items) => { self.check_if_primitive_type_name(name, item.span); - // Create a new rib for the self type. - let mut self_type_rib = Rib::new(ItemRibKind); + self.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| { + // Create a new rib for the trait-wide type parameters. + this.with_type_parameter_rib(HasTypeParameters(generics, + TypeSpace, + NormalRibKind), + |this| { + this.visit_generics(generics); + visit::walk_ty_param_bounds_helper(this, bounds); - // plain insert (no renaming, types are not currently hygienic....) - let name = special_names::type_self; - self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id))); - self.type_ribs.push(self_type_rib); + for trait_item in trait_items { + // Create a new rib for the trait_item-specific type + // parameters. + // + // FIXME #4951: Do we need a node ID here? - // Create a new rib for the trait-wide type parameters. - self.with_type_parameter_rib(HasTypeParameters(generics, - TypeSpace, - NormalRibKind), - |this| { - this.visit_generics(generics); - visit::walk_ty_param_bounds_helper(this, bounds); - - for trait_item in trait_items { - // Create a new rib for the trait_item-specific type - // parameters. - // - // FIXME #4951: Do we need a node ID here? - - let type_parameters = match trait_item.node { - ast::MethodTraitItem(ref sig, _) => { - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind) - } - ast::TypeTraitItem(..) => { - this.check_if_primitive_type_name(trait_item.ident.name, - trait_item.span); - NoTypeParameters - } - }; - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_trait_item(this, trait_item) - }); - } + let type_parameters = match trait_item.node { + ast::MethodTraitItem(ref sig, _) => { + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind) + } + ast::TypeTraitItem(..) => { + this.check_if_primitive_type_name(trait_item.ident.name, + trait_item.span); + NoTypeParameters + } + }; + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_trait_item(this, trait_item) + }); + } + }); }); - - self.type_ribs.pop(); } ItemMod(_) | ItemForeignMod(_) => { @@ -2030,8 +2024,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { visit::walk_generics(self, generics); } - fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T where - F: FnOnce(&mut Resolver) -> T, + fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T + where F: FnOnce(&mut Resolver) -> T { // Handle nested impls (inside fn bodies) let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); @@ -2044,29 +2038,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { opt_trait_ref: Option<&TraitRef>, f: F) -> T - where F: FnOnce(&mut Resolver) -> T, + where F: FnOnce(&mut Resolver, Option) -> T { let mut new_val = None; + let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) { - Ok(path_res) => { - self.record_def(trait_ref.ref_id, path_res); - new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); - } - Err(_) => { /* error was already reported */ } + if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id, + &trait_ref.path, 0) { + assert!(path_res.depth == 0); + self.record_def(trait_ref.ref_id, path_res); + new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); + new_id = Some(path_res.base_def.def_id()); } visit::walk_trait_ref(self, trait_ref); } let original_trait_ref = replace(&mut self.current_trait_ref, new_val); - let result = f(self); + let result = f(self, new_id); self.current_trait_ref = original_trait_ref; result } + fn with_self_rib(&mut self, self_def: Def, f: F) + where F: FnOnce(&mut Resolver) + { + let mut self_type_rib = Rib::new(NormalRibKind); + + // plain insert (no renaming, types are not currently hygienic....) + let name = special_names::type_self; + self_type_rib.bindings.insert(name, DlDef(self_def)); + self.type_ribs.push(self_type_rib); + f(self); + self.type_ribs.pop(); + } + fn resolve_implementation(&mut self, generics: &Generics, opt_trait_reference: &Option, self_type: &Ty, + item_id: NodeId, impl_items: &[P]) { // If applicable, create a rib for the type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, @@ -2077,40 +2086,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { this.visit_generics(generics); // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| { + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { // Resolve the self type. this.visit_ty(self_type); - this.with_current_self_type(self_type, |this| { - for impl_item in impl_items { - match impl_item.node { - MethodImplItem(ref sig, _) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); + this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| { + this.with_current_self_type(self_type, |this| { + for impl_item in impl_items { + match impl_item.node { + MethodImplItem(ref sig, _) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); - // We also need a new scope for the method- - // specific type parameters. - let type_parameters = - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind); - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_impl_item(this, impl_item); - }); - } - TypeImplItem(ref ty) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); + // We also need a new scope for the method- + // specific type parameters. + let type_parameters = + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_impl_item(this, impl_item); + }); + } + TypeImplItem(ref ty) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); - this.visit_ty(ty); + this.visit_ty(ty); + } + ast::MacImplItem(_) => {} } - ast::MacImplItem(_) => {} } - } + }); }); }); }); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 26fcf947e4f..691276a8eb1 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -248,7 +248,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefFn(..) => Some(recorder::FnRef), - def::DefSelfTy(_) | + def::DefSelfTy(..) | def::DefRegion(_) | def::DefLabel(_) | def::DefTyParam(..) | diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 939142cff1c..1e7e27762f6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,7 +56,7 @@ use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, Ty}; -use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, +use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::ppaux::{self, Repr, UserString}; @@ -1041,6 +1041,65 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, type_str, trait_str, name); } +// Search for a bound on a type parameter which includes the associated item +// given by assoc_name. We assume that ty_path_def is the def for such a type +// parameter (which might be `Self`). This function will fail if there are no +// suitable bounds or there is any ambiguity. +fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, + ty_path_def: def::Def, + assoc_name: ast::Name, + span: Span) + -> Result, ErrorReported> +{ + let tcx = this.tcx(); + + let ty_param_node_id = ty_path_def.local_node_id(); + + let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { + Ok(v) => v, + Err(ErrorReported) => { + return Err(ErrorReported); + } + }; + + // Ensure the super predicates and stop if we encountered an error. + if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { + return Err(ErrorReported); + } + + // Check that there is exactly one way to find an associated type with the + // correct name. + let mut suitable_bounds: Vec<_> = + traits::transitive_bounds(tcx, &bounds) + .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) + .collect(); + + let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; + if suitable_bounds.len() == 0 { + span_err!(tcx.sess, span, E0220, + "associated type `{}` not found for type parameter `{}`", + token::get_name(assoc_name), + token::get_name(ty_param_name)); + return Err(ErrorReported); + } + + if suitable_bounds.len() > 1 { + span_err!(tcx.sess, span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", + token::get_name(assoc_name), + token::get_name(ty_param_name)); + + for suitable_bound in &suitable_bounds { + span_note!(tcx.sess, span, + "associated type `{}` could derive from `{}`", + token::get_name(ty_param_name), + suitable_bound.user_string(tcx)); + } + } + + Ok(suitable_bounds.pop().unwrap().clone()) +} + // Create a type from a a path to an associated type. // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C // and item_segment is the path segment for D. We return a type and a def for @@ -1061,11 +1120,44 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); - // Check that the path prefix given by ty/ty_path_def is a type parameter/Self. - match (&ty.sty, ty_path_def) { + // Find the type of the associated item, and the trait where the associated + // item is declared. + let (ty, trait_did) = match (&ty.sty, ty_path_def) { + (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { + // `Self` in an impl of a trait - we have a concrete self type and a + // trait reference. + match tcx.map.expect_item(impl_id).node { + ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { + let trait_segment = &trait_ref.path.segments.last().unwrap(); + let trait_ref = ast_path_to_mono_trait_ref(this, + &ExplicitRscope, + span, + PathParamMode::Explicit, + trait_did, + Some(ty), + trait_segment); + + let ty = this.projected_ty(span, trait_ref, assoc_name); + (ty, trait_did) + } + _ => unreachable!() + } + } (&ty::ty_param(_), def::DefTyParam(..)) | - (&ty::ty_param(_), def::DefSelfTy(_)) => {} + (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => { + // A type parameter or Self, we need to find the associated item from + // a bound. + let bound = match find_bound_for_assoc_item(this, ty_path_def, assoc_name, span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + }; + let trait_did = bound.0.def_id; + let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); + + (ty, trait_did) + } _ => { + println!("{:?} {:?}", ty.sty, ty_path_def); report_ambiguous_associated_type(tcx, span, &ty.user_string(tcx), @@ -1073,61 +1165,12 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, &token::get_name(assoc_name)); return (tcx.types.err, ty_path_def); } - } - - let ty_param_node_id = ty_path_def.local_node_id(); - let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; - - let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { - Ok(v) => v, - Err(ErrorReported) => { - return (tcx.types.err, ty_path_def); - } }; - // Ensure the super predicates and stop if we encountered an error. - if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { - return (this.tcx().types.err, ty_path_def); - } - - // Check that there is exactly one way to find an associated type with the - // correct name. - let mut suitable_bounds: Vec<_> = - traits::transitive_bounds(tcx, &bounds) - .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) - .collect(); - - if suitable_bounds.len() == 0 { - span_err!(tcx.sess, span, E0220, - "associated type `{}` not found for type parameter `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); - return (this.tcx().types.err, ty_path_def); - } - - if suitable_bounds.len() > 1 { - span_err!(tcx.sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); - - for suitable_bound in &suitable_bounds { - span_note!(this.tcx().sess, span, - "associated type `{}` could derive from `{}`", - token::get_name(ty_param_name), - suitable_bound.user_string(this.tcx())); - } - } - - let suitable_bound = suitable_bounds.pop().unwrap().clone(); - let trait_did = suitable_bound.0.def_id; - - let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name); - let item_did = if trait_did.krate == ast::LOCAL_CRATE { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. - match this.tcx().map.expect_item(trait_did.node).node { + match tcx.map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { let item = trait_items.iter() .find(|i| i.ident.name == assoc_name) @@ -1137,7 +1180,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } else { - let trait_items = ty::trait_items(this.tcx(), trait_did); + let trait_items = ty::trait_items(tcx, trait_did); let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; @@ -1173,14 +1216,13 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); - let trait_ref = - ast_path_to_mono_trait_ref(this, - rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment); + let trait_ref = ast_path_to_mono_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); @@ -1220,20 +1262,20 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } -// Note that both base_segments and assoc_segments may be empty, although not at -// the same time. -pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - def: &def::Def, - opt_self_ty: Option>, - base_segments: &[ast::PathSegment], - assoc_segments: &[ast::PathSegment]) - -> Ty<'tcx> { +// Check the base def in a PathResolution and convert it to a Ty. If there are +// associated types in the PathResolution, these will need to be seperately +// resolved. +fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment]) + -> Ty<'tcx> { let tcx = this.tcx(); - let base_ty = match *def { + match *def { def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details @@ -1257,18 +1299,28 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, } def::DefTy(did, _) | def::DefStruct(did) => { check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); - ast_path_to_ty(this, rscope, span, - param_mode, did, + ast_path_to_ty(this, + rscope, + span, + param_mode, + did, base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_param(tcx, space, index, name) } - def::DefSelfTy(_) => { - // N.b.: resolve guarantees that the this type only appears in a - // trait, which we rely upon in various places when creating - // substs. + def::DefSelfTy(_, Some((_, self_ty_id))) => { + // Self in impl (we know the concrete type). + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); + if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) { + ty + } else { + tcx.sess.span_bug(span, "self type has not been fully resolved") + } + } + def::DefSelfTy(Some(_), None) => { + // Self in trait. check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_self_type(tcx) } @@ -1288,6 +1340,9 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // FIXME(#22519) This part of the resolution logic should be // avoided entirely for that form, once we stop needed a Def // for `associated_path_def_to_ty`. + // Fixing this will also let use resolve ::Foo the same way we + // resolve Self::Foo, at the moment we can't resolve the former because + // we don't have the trait information around, which is just sad. if !base_segments.is_empty() { span_err!(tcx.sess, @@ -1308,11 +1363,29 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, "found value name used as a type: {:?}", *def); return this.tcx().types.err; } - }; + } +} - // If any associated type segments remain, attempt to resolve them. - let mut ty = base_ty; +// Note that both base_segments and assoc_segments may be empty, although not at +// the same time. +pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment], + assoc_segments: &[ast::PathSegment]) + -> Ty<'tcx> { + let mut ty = base_def_to_ty(this, + rscope, + span, + param_mode, + def, + opt_self_ty, + base_segments); let mut def = *def; + // If any associated type segments remain, attempt to resolve them. for segment in assoc_segments { if ty.sty == ty::ty_err { break; @@ -1996,7 +2069,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, check_type_argument_count(tcx, b.trait_ref.path.span, parameters.types().len(), 0, 0); } - if parameters.lifetimes().len() > 0{ + if parameters.lifetimes().len() > 0 { report_lifetime_number_error(tcx, b.trait_ref.path.span, parameters.lifetimes().len(), 0); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 156fbfede9c..ce1227608cf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3341,11 +3341,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def = path_res.base_def; if path_res.depth == 0 { - let (scheme, predicates) = - type_scheme_and_predicates_for_def(fcx, expr.span, def); - instantiate_path(fcx, &path.segments, - scheme, &predicates, - opt_self_ty, def, expr.span, id); + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, + expr.span, + def); + instantiate_path(fcx, + &path.segments, + scheme, + &predicates, + opt_self_ty, + def, + expr.span, + id); } else { let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8f1b8bf1092..f38ebf111fd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -547,14 +547,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, if let ast::TyPath(None, _) = ast_ty.node { let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap(); match path_res.base_def { - def::DefSelfTy(node_id) => - path_res.depth == 0 && node_id == param_id, - - def::DefTyParam(_, _, def_id, _) => - path_res.depth == 0 && def_id == local_def(param_id), - - _ => - false, + def::DefSelfTy(Some(def_id), None) => { + path_res.depth == 0 && def_id.node == param_id + } + def::DefTyParam(_, _, def_id, _) => { + path_res.depth == 0 && def_id == local_def(param_id) + } + _ => { + false + } } } else { false diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 94abc0b34bc..b71c23b29e3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -14,7 +14,6 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}; use ast::{StmtExpr, StmtSemi}; use ast::TokenTree; use ast; -use ast_util::path_to_ident; use ext::mtwt; use ext::build::AstBuilder; use attr; @@ -34,30 +33,6 @@ use visit; use visit::Visitor; use std_inject; -pub fn expand_type(t: P, - fld: &mut MacroExpander, - impl_ty: Option>) - -> P { - debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty); - let t = match (t.node.clone(), impl_ty) { - // Expand uses of `Self` in impls to the concrete type. - (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => { - let path_as_ident = path_to_ident(path); - // Note unhygenic comparison here. I think this is correct, since - // even though `Self` is almost just a type parameter, the treatment - // for this expansion is as if it were a keyword. - if path_as_ident.is_some() && - path_as_ident.unwrap().name == token::special_idents::type_self.name { - impl_ty.clone() - } else { - t - } - } - _ => t - }; - fold::noop_fold_ty(t, fld) -} - pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the @@ -1354,13 +1329,11 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, /// A tree-folder that performs macro expansion pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - // The type of the impl currently being expanded. - current_impl_type: Option>, } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> { - MacroExpander { cx: cx, current_impl_type: None } + MacroExpander { cx: cx } } } @@ -1374,14 +1347,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_item(&mut self, item: P) -> SmallVector> { - let prev_type = self.current_impl_type.clone(); - if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node { - self.current_impl_type = Some(ty.clone()); - } - - let result = expand_item(item, self); - self.current_impl_type = prev_type; - result + expand_item(item, self) } fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ { @@ -1410,11 +1376,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { .into_iter().map(|i| i.expect_impl_item()).collect() } - fn fold_ty(&mut self, t: P) -> P { - let impl_type = self.current_impl_type.clone(); - expand_type(t, self, impl_type) - } - fn new_span(&mut self, span: Span) -> Span { new_span(self.cx, span) } diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs new file mode 100644 index 00000000000..ec913aa844d --- /dev/null +++ b/src/test/compile-fail/self-impl.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that unsupported uses of `Self` in impls don't crash + +struct Bar; + +trait Foo { + type Baz; +} + +impl Foo for Bar { + type Baz = bool; +} + +impl Bar { + fn f() { + let _: ::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + let _: Self::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + } +} + +fn main() {} diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs index c32773aa88c..746ddc9892a 100644 --- a/src/test/run-pass/self-impl.rs +++ b/src/test/run-pass/self-impl.rs @@ -22,6 +22,17 @@ impl Foo { fn foo(_x: Self, _y: &Self, _z: Box) -> Self { Foo } + + fn baz() { + // Test that Self cannot be shadowed. + type Foo = i32; + // There is no empty method on i32. + Self::empty(); + + let _: Self = Foo; + } + + fn empty() {} } // Test uses when implementing a trait and with a type parameter. @@ -30,12 +41,18 @@ pub struct Baz { } trait Bar { + type Qux; + fn bar(x: Self, y: &Self, z: Box) -> Self; fn dummy(&self, x: X) { } } impl Bar for Box> { + type Qux = i32; + fn bar(_x: Self, _y: &Self, _z: Box) -> Self { + let _: Self::Qux = 42; + let _: >::Qux = 42; box Baz { f: 42 } } } @@ -43,6 +60,6 @@ impl Bar for Box> { fn main() { let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Box> = Bar::bar(box Baz { f: 42 }, - &box Baz { f: 42 }, - box box Baz { f: 42 }); + &box Baz { f: 42 }, + box box Baz { f: 42 }); }