mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 12:13:43 +00:00
Check uses of Self
in impls in the compiler rather than during expansion
Closes #23909
This commit is contained in:
parent
5e30f05a05
commit
dc8a8e9beb
@ -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) }
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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...
|
||||
|
@ -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(_) => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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(..) |
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
32
src/test/compile-fail/self-impl.rs
Normal file
32
src/test/compile-fail/self-impl.rs
Normal 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() {}
|
@ -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 });
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user