Check uses of Self in impls in the compiler rather than during expansion

Closes #23909
This commit is contained in:
Nick Cameron 2015-04-03 17:13:52 +13:00
parent 5e30f05a05
commit dc8a8e9beb
11 changed files with 336 additions and 229 deletions

View File

@ -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) }

View File

@ -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<ast::DefId>, // 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"),
}
}

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()) {
// `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...

View File

@ -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<T, F>(&mut self, self_type: &Ty, f: F) -> T where
F: FnOnce(&mut Resolver) -> T,
fn with_current_self_type<T, F>(&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<DefId>) -> 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<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,
generics: &Generics,
opt_trait_reference: &Option<TraitRef>,
self_type: &Ty,
item_id: NodeId,
impl_items: &[P<ImplItem>]) {
// 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(_) => {}
}
}
});
});
});
});

View File

@ -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(..) |

View File

@ -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<ty::PolyTraitRef<'tcx>, 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<Ty<'tcx>>,
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<Ty<'tcx>>,
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 <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() {
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<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;
// 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);
}

View File

@ -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;

View File

@ -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

View File

@ -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<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> {
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<ast::Block>,
/// 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<P<ast::Ty>>,
}
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<ast::Item>) -> SmallVector<P<ast::Item>> {
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<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 {
new_span(self.cx, span)
}

View File

@ -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 <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;
}
impl Foo for Bar {
type Baz = 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

@ -22,6 +22,17 @@ impl Foo {
fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> 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<X> {
}
trait Bar<X> {
type Qux;
fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
fn dummy(&self, x: X) { }
}
impl Bar<isize> for Box<Baz<isize>> {
type Qux = i32;
fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
let _: Self::Qux = 42;
let _: <Self as Bar<isize>>::Qux = 42;
box Baz { f: 42 }
}
}
@ -43,6 +60,6 @@ impl Bar<isize> for Box<Baz<isize>> {
fn main() {
let _: Foo = Foo::foo(Foo, &Foo, box Foo);
let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
&box Baz { f: 42 },
box box Baz { f: 42 });
&box Baz { f: 42 },
box box Baz { f: 42 });
}