Auto merge of #23998 - nrc:impl-self, r=nikomatsakis

Closes #23909

r? @nikomatsakis (or anyone else, really)
This commit is contained in:
bors
2015-04-08 09:58:05 +00:00
15 changed files with 396 additions and 250 deletions

View File

@@ -457,7 +457,11 @@ impl tr for def::Def {
def::DefMethod(did, p) => { def::DefMethod(did, p) => {
def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) 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::DefMod(did) => { def::DefMod(did.tr(dcx)) }
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }

View File

@@ -22,7 +22,8 @@ use std::cell::RefCell;
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def { pub enum Def {
DefFn(ast::DefId, bool /* is_ctor */), DefFn(ast::DefId, bool /* is_ctor */),
DefSelfTy(/* trait id */ ast::NodeId), DefSelfTy(Option<ast::DefId>, // trait id
Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id)
DefMod(ast::DefId), DefMod(ast::DefId),
DefForeignMod(ast::DefId), DefForeignMod(ast::DefId),
DefStatic(ast::DefId, bool /* is_mutbl */), DefStatic(ast::DefId, bool /* is_mutbl */),
@@ -139,18 +140,19 @@ impl Def {
DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id, _) | DefConst(id) => { DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
id id
} }
DefLocal(id) | DefLocal(id) |
DefSelfTy(id) |
DefUpvar(id, _) | DefUpvar(id, _) |
DefRegion(id) | DefRegion(id) |
DefLabel(id) => { DefLabel(id) |
DefSelfTy(_, Some((_, id))) => {
local_def(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"),
} }
} }

View File

@@ -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()) { let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
// `int` etc. (None doesn't seem to occur.) // `int` etc. (None doesn't seem to occur.)
None | Some(def::DefPrimTy(..)) => return false, None | Some(def::DefPrimTy(..)) => return false,
Some(def) => def.def_id() Some(def) => def.def_id(),
}; };
// A path can only be private if: // A path can only be private if:
// it's in this crate... // it's in this crate...

View File

@@ -1689,7 +1689,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
} }
DefTyParam(..) | DefSelfTy(_) => { DefTyParam(..) | DefSelfTy(..) => {
for rib in ribs { for rib in ribs {
match rib.kind { match rib.kind {
NormalRibKind | MethodRibKind | ClosureRibKind(..) => { NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
@@ -1797,35 +1797,30 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
ItemDefaultImpl(_, ref trait_ref) => { 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 generics,
ref implemented_traits, ref opt_trait_ref,
ref self_type, ref self_type,
ref impl_items) => { ref impl_items) => {
self.resolve_implementation(generics, self.resolve_implementation(generics,
implemented_traits, opt_trait_ref,
&**self_type, &**self_type,
item.id,
&impl_items[..]); &impl_items[..]);
} }
ItemTrait(_, ref generics, ref bounds, ref trait_items) => { ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
self.check_if_primitive_type_name(name, item.span); 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);
// 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);
// Create a new rib for the trait-wide type parameters. // Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace, TypeSpace,
NormalRibKind), ItemRibKind),
|this| { |this| {
this.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| {
this.visit_generics(generics); this.visit_generics(generics);
visit::walk_ty_param_bounds_helper(this, bounds); visit::walk_ty_param_bounds_helper(this, bounds);
@@ -1852,8 +1847,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}); });
} }
}); });
});
self.type_ribs.pop();
} }
ItemMod(_) | ItemForeignMod(_) => { ItemMod(_) | ItemForeignMod(_) => {
@@ -2030,8 +2024,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
visit::walk_generics(self, generics); visit::walk_generics(self, generics);
} }
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T where fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
F: FnOnce(&mut Resolver) -> T, where F: FnOnce(&mut Resolver) -> T
{ {
// Handle nested impls (inside fn bodies) // Handle nested impls (inside fn bodies)
let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); 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>, opt_trait_ref: Option<&TraitRef>,
f: F) f: F)
-> T -> T
where F: FnOnce(&mut Resolver) -> T, where F: FnOnce(&mut Resolver, Option<DefId>) -> T
{ {
let mut new_val = None; let mut new_val = None;
let mut new_id = None;
if let Some(trait_ref) = opt_trait_ref { if let Some(trait_ref) = opt_trait_ref {
match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) { if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id,
Ok(path_res) => { &trait_ref.path, 0) {
assert!(path_res.depth == 0);
self.record_def(trait_ref.ref_id, path_res); self.record_def(trait_ref.ref_id, path_res);
new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
} new_id = Some(path_res.base_def.def_id());
Err(_) => { /* error was already reported */ }
} }
visit::walk_trait_ref(self, trait_ref); visit::walk_trait_ref(self, trait_ref);
} }
let original_trait_ref = replace(&mut self.current_trait_ref, new_val); 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; self.current_trait_ref = original_trait_ref;
result result
} }
fn with_self_rib<F>(&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, fn resolve_implementation(&mut self,
generics: &Generics, generics: &Generics,
opt_trait_reference: &Option<TraitRef>, opt_trait_reference: &Option<TraitRef>,
self_type: &Ty, self_type: &Ty,
item_id: NodeId,
impl_items: &[P<ImplItem>]) { impl_items: &[P<ImplItem>]) {
// If applicable, create a rib for the type parameters. // If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, self.with_type_parameter_rib(HasTypeParameters(generics,
@@ -2077,10 +2086,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
this.visit_generics(generics); this.visit_generics(generics);
// Resolve the trait reference, if necessary. // 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. // Resolve the self type.
this.visit_ty(self_type); this.visit_ty(self_type);
this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| {
this.with_current_self_type(self_type, |this| { this.with_current_self_type(self_type, |this| {
for impl_item in impl_items { for impl_item in impl_items {
match impl_item.node { match impl_item.node {
@@ -2114,6 +2124,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}); });
}); });
}); });
});
} }
fn check_trait_item(&self, name: Name, span: Span) { fn check_trait_item(&self, name: Name, span: Span) {

View File

@@ -248,7 +248,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
def::DefFn(..) => Some(recorder::FnRef), def::DefFn(..) => Some(recorder::FnRef),
def::DefSelfTy(_) | def::DefSelfTy(..) |
def::DefRegion(_) | def::DefRegion(_) |
def::DefLabel(_) | def::DefLabel(_) |
def::DefTyParam(..) | def::DefTyParam(..) |

View File

@@ -56,7 +56,7 @@ use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::traits; use middle::traits;
use middle::ty::{self, RegionEscape, Ty}; use middle::ty::{self, RegionEscape, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::ppaux::{self, Repr, UserString}; use util::ppaux::{self, Repr, UserString};
@@ -872,24 +872,11 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
} }
} }
if candidates.len() > 1 { let candidate = try!(one_bound_for_assoc_type(tcx,
span_err!(tcx.sess, binding.span, E0217, candidates,
"ambiguous associated type: `{}` defined in multiple supertraits `{}`", &trait_ref.user_string(tcx),
token::get_name(binding.item_name), &token::get_name(binding.item_name),
candidates.user_string(tcx)); binding.span));
return Err(ErrorReported);
}
let candidate = match candidates.pop() {
Some(c) => c,
None => {
span_err!(tcx.sess, binding.span, E0218,
"no associated type `{}` defined in `{}`",
token::get_name(binding.item_name),
trait_ref.user_string(tcx));
return Err(ErrorReported);
}
};
Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+
projection_ty: ty::ProjectionTy { // | projection_ty: ty::ProjectionTy { // |
@@ -1042,6 +1029,81 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt,
type_str, trait_str, name); type_str, trait_str, name);
} }
// Search for a bound on a type parameter which includes the associated item
// given by assoc_name. ty_param_node_id is the node id for the type parameter
// (which might be `Self`, but only if it is the `Self` of a trait, not an
// impl). 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_param_node_id: ast::NodeId,
assoc_name: ast::Name,
span: Span)
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
{
let tcx = this.tcx();
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 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.type_parameter_def(ty_param_node_id).name;
one_bound_for_assoc_type(tcx,
suitable_bounds,
&token::get_name(ty_param_name),
&token::get_name(assoc_name),
span)
}
// Checks that bounds contains exactly one element and reports appropriate
// errors otherwise.
fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>,
bounds: Vec<ty::PolyTraitRef<'tcx>>,
ty_param_name: &str,
assoc_name: &str,
span: Span)
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
{
if bounds.len() == 0 {
span_err!(tcx.sess, span, E0220,
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name);
return Err(ErrorReported);
}
if bounds.len() > 1 {
span_err!(tcx.sess, span, E0221,
"ambiguous associated type `{}` in bounds of `{}`",
assoc_name,
ty_param_name);
for bound in &bounds {
span_note!(tcx.sess, span,
"associated type `{}` could derive from `{}`",
ty_param_name,
bound.user_string(tcx));
}
}
Ok(bounds[0].clone())
}
// Create a type from a a path to an associated type. // 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 // 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 // and item_segment is the path segment for D. We return a type and a def for
@@ -1062,10 +1124,55 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); 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. // Find the type of the associated item, and the trait where the associated
match (&ty.sty, ty_path_def) { // item is declared.
let bound = 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), _, _) => {
if this.ensure_super_predicates(span, trait_did).is_err() {
return (tcx.types.err, ty_path_def);
}
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 candidates: Vec<ty::PolyTraitRef> =
traits::supertraits(tcx, ty::Binder(trait_ref.clone()))
.filter(|r| this.trait_defines_associated_type_named(r.def_id(),
assoc_name))
.collect();
match one_bound_for_assoc_type(tcx,
candidates,
"Self",
&token::get_name(assoc_name),
span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
_ => unreachable!()
}
}
(&ty::ty_param(_), def::DefTyParam(..)) | (&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 ty_param_node_id = ty_path_def.local_node_id();
match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
_ => { _ => {
report_ambiguous_associated_type(tcx, report_ambiguous_associated_type(tcx,
span, span,
@@ -1074,61 +1181,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
&token::get_name(assoc_name)); &token::get_name(assoc_name));
return (tcx.types.err, ty_path_def); 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. let trait_did = bound.0.def_id;
if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
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 { let item_did = if trait_did.krate == ast::LOCAL_CRATE {
// `ty::trait_items` used below requires information generated // `ty::trait_items` used below requires information generated
// by type collection, which may be in progress at this point. // 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) => { ast::ItemTrait(_, _, _, ref trait_items) => {
let item = trait_items.iter() let item = trait_items.iter()
.find(|i| i.ident.name == assoc_name) .find(|i| i.ident.name == assoc_name)
@@ -1138,7 +1199,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
_ => unreachable!() _ => unreachable!()
} }
} else { } 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); let item = trait_items.iter().find(|i| i.name() == assoc_name);
item.expect("missing associated type").def_id() item.expect("missing associated type").def_id()
}; };
@@ -1174,8 +1235,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
let trait_ref = let trait_ref = ast_path_to_mono_trait_ref(this,
ast_path_to_mono_trait_ref(this,
rscope, rscope,
span, span,
param_mode, param_mode,
@@ -1221,20 +1281,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 // Check the base def in a PathResolution and convert it to a Ty. If there are
// the same time. // associated types in the PathResolution, these will need to be seperately
pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // resolved.
fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope, rscope: &RegionScope,
span: Span, span: Span,
param_mode: PathParamMode, param_mode: PathParamMode,
def: &def::Def, def: &def::Def,
opt_self_ty: Option<Ty<'tcx>>, opt_self_ty: Option<Ty<'tcx>>,
base_segments: &[ast::PathSegment], base_segments: &[ast::PathSegment])
assoc_segments: &[ast::PathSegment])
-> Ty<'tcx> { -> Ty<'tcx> {
let tcx = this.tcx(); let tcx = this.tcx();
let base_ty = match *def { match *def {
def::DefTrait(trait_def_id) => { def::DefTrait(trait_def_id) => {
// N.B. this case overlaps somewhat with // N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details // TyObjectSum, see that fn for details
@@ -1258,18 +1318,28 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
} }
def::DefTy(did, _) | def::DefStruct(did) => { def::DefTy(did, _) | def::DefStruct(did) => {
check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
ast_path_to_ty(this, rscope, span, ast_path_to_ty(this,
param_mode, did, rscope,
span,
param_mode,
did,
base_segments.last().unwrap()) base_segments.last().unwrap())
} }
def::DefTyParam(space, index, _, name) => { def::DefTyParam(space, index, _, name) => {
check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, space, index, name) ty::mk_param(tcx, space, index, name)
} }
def::DefSelfTy(_) => { def::DefSelfTy(_, Some((_, self_ty_id))) => {
// N.b.: resolve guarantees that the this type only appears in a // Self in impl (we know the concrete type).
// trait, which we rely upon in various places when creating check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
// substs. 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); check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
ty::mk_self_type(tcx) ty::mk_self_type(tcx)
} }
@@ -1289,6 +1359,9 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
// FIXME(#22519) This part of the resolution logic should be // FIXME(#22519) This part of the resolution logic should be
// avoided entirely for that form, once we stop needed a Def // avoided entirely for that form, once we stop needed a Def
// for `associated_path_def_to_ty`. // for `associated_path_def_to_ty`.
// Fixing this will also let use resolve <Self>::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() { if !base_segments.is_empty() {
span_err!(tcx.sess, span_err!(tcx.sess,
@@ -1309,11 +1382,29 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
"found value name used as a type: {:?}", *def); "found value name used as a type: {:?}", *def);
return this.tcx().types.err; return this.tcx().types.err;
} }
}; }
}
// If any associated type segments remain, attempt to resolve them. // Note that both base_segments and assoc_segments may be empty, although not at
let mut ty = base_ty; // 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<Ty<'tcx>>,
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; let mut def = *def;
// If any associated type segments remain, attempt to resolve them.
for segment in assoc_segments { for segment in assoc_segments {
if ty.sty == ty::ty_err { if ty.sty == ty::ty_err {
break; break;

View File

@@ -3341,11 +3341,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
let def = path_res.base_def; let def = path_res.base_def;
if path_res.depth == 0 { if path_res.depth == 0 {
let (scheme, predicates) = let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
type_scheme_and_predicates_for_def(fcx, expr.span, def); expr.span,
instantiate_path(fcx, &path.segments, def);
scheme, &predicates, instantiate_path(fcx,
opt_self_ty, def, expr.span, id); &path.segments,
scheme,
&predicates,
opt_self_ty,
def,
expr.span,
id);
} else { } else {
let ty_segments = path.segments.init(); let ty_segments = path.segments.init();
let base_ty_end = path.segments.len() - path_res.depth; let base_ty_end = path.segments.len() - path_res.depth;

View File

@@ -547,14 +547,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
if let ast::TyPath(None, _) = ast_ty.node { if let ast::TyPath(None, _) = ast_ty.node {
let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap(); let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
match path_res.base_def { match path_res.base_def {
def::DefSelfTy(node_id) => def::DefSelfTy(Some(def_id), None) => {
path_res.depth == 0 && node_id == param_id, path_res.depth == 0 && def_id.node == param_id
}
def::DefTyParam(_, _, def_id, _) => def::DefTyParam(_, _, def_id, _) => {
path_res.depth == 0 && def_id == local_def(param_id), path_res.depth == 0 && def_id == local_def(param_id)
}
_ => _ => {
false, false
}
} }
} else { } else {
false false

View File

@@ -14,7 +14,6 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi}; use ast::{StmtExpr, StmtSemi};
use ast::TokenTree; use ast::TokenTree;
use ast; use ast;
use ast_util::path_to_ident;
use ext::mtwt; use ext::mtwt;
use ext::build::AstBuilder; use ext::build::AstBuilder;
use attr; use attr;
@@ -34,30 +33,6 @@ use visit;
use visit::Visitor; use visit::Visitor;
use std_inject; use std_inject;
pub fn expand_type(t: P<ast::Ty>,
fld: &mut MacroExpander,
impl_ty: Option<P<ast::Ty>>)
-> P<ast::Ty> {
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<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
e.and_then(|ast::Expr {id, node, span}| match node { e.and_then(|ast::Expr {id, node, span}| match node {
// expr_mac should really be expr_ext or something; it's the // 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<ast::Block>,
/// A tree-folder that performs macro expansion /// A tree-folder that performs macro expansion
pub struct MacroExpander<'a, 'b:'a> { pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>, pub cx: &'a mut ExtCtxt<'b>,
// The type of the impl currently being expanded.
current_impl_type: Option<P<ast::Ty>>,
} }
impl<'a, 'b> MacroExpander<'a, 'b> { impl<'a, 'b> MacroExpander<'a, 'b> {
pub fn new(cx: &'a mut ExtCtxt<'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<ast::Item>) -> SmallVector<P<ast::Item>> { fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
let prev_type = self.current_impl_type.clone(); expand_item(item, self)
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
} }
fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ { 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() .into_iter().map(|i| i.expect_impl_item()).collect()
} }
fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
let impl_type = self.current_impl_type.clone();
expand_type(t, self, impl_type)
}
fn new_span(&mut self, span: Span) -> Span { fn new_span(&mut self, span: Span) -> Span {
new_span(self.cx, span) new_span(self.cx, span)
} }

View File

@@ -0,0 +1,40 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
}
trait SuperFoo {
type SuperBaz;
}
impl Foo for Bar {
type Baz = bool;
}
impl SuperFoo for Bar {
type SuperBaz = bool;
}
impl Bar {
fn f() {
let _: <Self>::Baz = true;
//~^ERROR: ambiguous associated type; specify the type using the syntax `<Bar as Trait>::Baz`
let _: Self::Baz = true;
//~^ERROR: ambiguous associated type; specify the type using the syntax `<Bar as Trait>::Baz`
}
}
fn main() {}

View File

@@ -12,7 +12,7 @@
trait One<A> { fn foo(&self) -> A; } trait One<A> { fn foo(&self) -> A; }
fn foo(_: &One()) //~ ERROR no associated type `Output` defined in `One<()>` fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>`
{} {}
fn main() { } fn main() { }

View File

@@ -14,7 +14,7 @@ trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
fn foo(_: &Three()) fn foo(_: &Three())
//~^ ERROR wrong number of type arguments //~^ ERROR wrong number of type arguments
//~| ERROR no associated type `Output` //~| ERROR associated type `Output` not found
{} {}
fn main() { } fn main() { }

View File

@@ -14,7 +14,7 @@ trait Zero { fn dummy(&self); }
fn foo(_: Zero()) fn foo(_: Zero())
//~^ ERROR wrong number of type arguments //~^ ERROR wrong number of type arguments
//~| ERROR no associated type `Output` defined in `Zero` //~| ERROR associated type `Output` not found for `Zero`
{} {}
fn main() { } fn main() { }

View File

@@ -14,6 +14,6 @@ trait Trait {}
fn f<F:Trait(isize) -> isize>(x: F) {} fn f<F:Trait(isize) -> isize>(x: F) {}
//~^ ERROR wrong number of type arguments: expected 0, found 1 //~^ ERROR wrong number of type arguments: expected 0, found 1
//~| ERROR no associated type `Output` //~| ERROR associated type `Output` not found
fn main() {} fn main() {}

View File

@@ -22,6 +22,17 @@ impl Foo {
fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self { fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
Foo 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. // Test uses when implementing a trait and with a type parameter.
@@ -29,13 +40,31 @@ pub struct Baz<X> {
pub f: X, pub f: X,
} }
trait Bar<X> { trait SuperBar {
fn bar(x: Self, y: &Self, z: Box<Self>) -> Self; type SuperQux;
}
trait Bar<X>: SuperBar {
type Qux;
fn bar(x: Self, y: &Self, z: Box<Self>, _: Self::SuperQux) -> Self;
fn dummy(&self, x: X) { } fn dummy(&self, x: X) { }
} }
impl SuperBar for Box<Baz<isize>> {
type SuperQux = bool;
}
impl Bar<isize> for Box<Baz<isize>> { impl Bar<isize> for Box<Baz<isize>> {
fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self { type Qux = i32;
fn bar(_x: Self, _y: &Self, _z: Box<Self>, _: Self::SuperQux) -> Self {
let _: Self::Qux = 42;
let _: <Self as Bar<isize>>::Qux = 42;
let _: Self::SuperQux = true;
let _: <Self as SuperBar>::SuperQux = true;
box Baz { f: 42 } box Baz { f: 42 }
} }
} }
@@ -44,5 +73,6 @@ fn main() {
let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Foo = Foo::foo(Foo, &Foo, box Foo);
let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 }, let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
&box Baz { f: 42 }, &box Baz { f: 42 },
box box Baz { f: 42 }); box box Baz { f: 42 },
true);
} }