lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
- hir::TyImplTraitExistential(
- hir::ItemId {
- id: exist_ty_id.node_id
- },
- DefId::local(exist_ty_def_index),
- lifetimes,
- )
+ let path = P(hir::Path {
+ span: exist_ty_span,
+ def: Def::Existential(DefId::local(exist_ty_def_index)),
+ segments: hir_vec![hir::PathSegment {
+ infer_types: false,
+ ident: Ident::new(keywords::Invalid.name(), exist_ty_span),
+ args: Some(P(hir::GenericArgs {
+ parenthesized: false,
+ bindings: HirVec::new(),
+ args: lifetimes,
+ }))
+ }],
+ });
+ hir::TyPath(hir::QPath::Resolved(None, path))
})
}
exist_ty_id: NodeId,
parent_index: DefIndex,
bounds: &hir::GenericBounds,
- ) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
+ ) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
// This visitor walks over impl trait bounds and creates defs for all lifetimes which
// appear in the bounds, excluding lifetimes that are created within the bounds.
// e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>`
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: HashSet<hir::LifetimeName>,
- output_lifetimes: Vec<hir::Lifetime>,
+ output_lifetimes: Vec<hir::GenericArg>,
output_lifetime_params: Vec<hir::GenericParam>,
}
&& !self.already_defined_lifetimes.contains(&name) {
self.already_defined_lifetimes.insert(name);
- self.output_lifetimes.push(hir::Lifetime {
+ self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime {
id: self.context.next_id().node_id,
span: lifetime.span,
name,
- });
+ }));
// We need to manually create the ids here, because the
// definitions will go into the explicit `existential type`
};
self.with(scope, |_, this| this.visit_ty(&mt.ty));
}
- hir::TyImplTraitExistential(item_id, _, ref lifetimes) => {
- // Resolve the lifetimes that are applied to the existential type.
- // These are resolved in the current scope.
- // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
- // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
- // ^ ^this gets resolved in the current scope
- for lifetime in lifetimes {
- self.visit_lifetime(lifetime);
-
- // Check for predicates like `impl for<'a> SomeTrait<impl OtherTrait<'a>>`
- // and ban them. Type variables instantiated inside binders aren't
- // well-supported at the moment, so this doesn't work.
- // In the future, this should be fixed and this error should be removed.
- let def = self.map.defs.get(&lifetime.id).cloned();
- if let Some(Region::LateBound(_, def_id, _)) = def {
- if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
- // Ensure that the parent of the def is an item, not HRTB
- let parent_id = self.tcx.hir.get_parent_node(node_id);
- let parent_impl_id = hir::ImplItemId { node_id: parent_id };
- let parent_trait_id = hir::TraitItemId { node_id: parent_id };
- let krate = self.tcx.hir.forest.krate();
- if !(krate.items.contains_key(&parent_id)
- || krate.impl_items.contains_key(&parent_impl_id)
- || krate.trait_items.contains_key(&parent_trait_id))
- {
- span_err!(
- self.tcx.sess,
- lifetime.span,
- E0657,
- "`impl Trait` can only capture lifetimes \
- bound at the fn or impl level"
- );
- self.uninsert_lifetime_on_error(lifetime, def.unwrap());
+ hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
+ if let Def::Existential(exist_ty_did) = path.def {
+ assert!(exist_ty_did.is_local());
+ // Resolve the lifetimes that are applied to the existential type.
+ // These are resolved in the current scope.
+ // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+ // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
+ // ^ ^this gets resolved in the current scope
+ for lifetime in &path.segments[0].args.as_ref().unwrap().args {
+ if let hir::GenericArg::Lifetime(lifetime) = lifetime {
+ self.visit_lifetime(lifetime);
+
+ // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
+ // and ban them. Type variables instantiated inside binders aren't
+ // well-supported at the moment, so this doesn't work.
+ // In the future, this should be fixed and this error should be removed.
+ let def = self.map.defs.get(&lifetime.id).cloned();
+ if let Some(Region::LateBound(_, def_id, _)) = def {
+ if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ // Ensure that the parent of the def is an item, not HRTB
+ let parent_id = self.tcx.hir.get_parent_node(node_id);
+ let parent_impl_id = hir::ImplItemId { node_id: parent_id };
+ let parent_trait_id = hir::TraitItemId { node_id: parent_id };
+ let krate = self.tcx.hir.forest.krate();
+ if !(krate.items.contains_key(&parent_id)
+ || krate.impl_items.contains_key(&parent_impl_id)
+ || krate.trait_items.contains_key(&parent_trait_id))
+ {
+ span_err!(
+ self.tcx.sess,
+ lifetime.span,
+ E0657,
+ "`impl Trait` can only capture lifetimes \
+ bound at the fn or impl level"
+ );
+ self.uninsert_lifetime_on_error(lifetime, def.unwrap());
+ }
+ }
}
}
}
- }
- // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
- // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
- // `abstract type MyAnonTy<'b>: MyTrait<'b>;`
- // ^ ^ this gets resolved in the scope of
- // the exist_ty generics
- let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node {
- hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => (
- generics,
- bounds,
- ),
- ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
- };
+ let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap();
+
+ // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
+ // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
+ // `abstract type MyAnonTy<'b>: MyTrait<'b>;`
+ // ^ ^ this gets resolved in the scope of
+ // the exist_ty generics
+ let (generics, bounds) = match self.tcx.hir.expect_item(id).node {
+ hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => (
+ generics,
+ bounds,
+ ),
+ ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
+ };
- // We want to start our early-bound indices at the end of the parent scope,
- // not including any parent `impl Trait`s.
- let mut index = self.next_early_index_for_abstract_type();
- debug!("visit_ty: index = {}", index);
+ // We want to start our early-bound indices at the end of the parent scope,
+ // not including any parent `impl Trait`s.
+ let mut index = self.next_early_index_for_abstract_type();
+ debug!("visit_ty: index = {}", index);
- let mut elision = None;
- let mut lifetimes = FxHashMap();
- let mut type_count = 0;
- for param in &generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m);
- if let hir::ParamName::Plain(param_name) = name {
- if param_name.name == keywords::UnderscoreLifetime.name() {
- // Pick the elided lifetime "definition" if one exists
- // and use it to make an elision scope.
- elision = Some(reg);
+ let mut elision = None;
+ let mut lifetimes = FxHashMap();
+ let mut type_count = 0;
+ for param in &generics.params {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m);
+ if let hir::ParamName::Plain(param_name) = name {
+ if param_name.name == keywords::UnderscoreLifetime.name() {
+ // Pick the elided lifetime "definition" if one exists
+ // and use it to make an elision scope.
+ elision = Some(reg);
+ } else {
+ lifetimes.insert(name, reg);
+ }
} else {
lifetimes.insert(name, reg);
}
- } else {
- lifetimes.insert(name, reg);
}
- }
- GenericParamKind::Type { .. } => {
- type_count += 1;
+ GenericParamKind::Type { .. } => {
+ type_count += 1;
+ }
}
}
- }
- let next_early_index = index + type_count;
+ let next_early_index = index + type_count;
- if let Some(elision_region) = elision {
- let scope = Scope::Elision {
- elide: Elide::Exact(elision_region),
- s: self.scope,
- };
- self.with(scope, |_old_scope, this| {
+ if let Some(elision_region) = elision {
+ let scope = Scope::Elision {
+ elide: Elide::Exact(elision_region),
+ s: self.scope,
+ };
+ self.with(scope, |_old_scope, this| {
+ let scope = Scope::Binder {
+ lifetimes,
+ next_early_index,
+ s: this.scope,
+ track_lifetime_uses: true,
+ abstract_type_parent: false,
+ };
+ this.with(scope, |_old_scope, this| {
+ this.visit_generics(generics);
+ for bound in bounds {
+ this.visit_param_bound(bound);
+ }
+ });
+ });
+ } else {
let scope = Scope::Binder {
lifetimes,
next_early_index,
- s: this.scope,
+ s: self.scope,
track_lifetime_uses: true,
abstract_type_parent: false,
};
- this.with(scope, |_old_scope, this| {
+ self.with(scope, |_old_scope, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
}
});
- });
+ }
} else {
- let scope = Scope::Binder {
- lifetimes,
- next_early_index,
- s: self.scope,
- track_lifetime_uses: true,
- abstract_type_parent: false,
- };
- self.with(scope, |_old_scope, this| {
- this.visit_generics(generics);
- for bound in bounds {
- this.visit_param_bound(bound);
- }
- });
+ intravisit::walk_ty(self, ty)
}
}
_ => intravisit::walk_ty(self, ty),
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemGlobalAsm(..) => {}
- // Checked by visit_ty
- hir::ItemExistential(..) => {}
+ hir::ItemExistential(..) => {
+ if item_level.is_some() {
+ // Reach the (potentially private) type and the API being exposed
+ self.reach(item.id).ty().predicates();
+ }
+ }
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
module_id = self.tcx.hir.get_parent_node(module_id);
}
}
-
- fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyImplTraitExistential(item_id, _, _) = ty.node {
- if self.get(item_id.id).is_some() {
- // Reach the (potentially private) type and the API being exposed
- self.reach(item_id.id).ty().predicates();
- }
- }
-
- intravisit::walk_ty(self, ty);
- }
}
impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
hir::ItemUse(..) => {}
// No subitems
hir::ItemGlobalAsm(..) => {}
- // Checked in visit_ty
- hir::ItemExistential(..) => {}
+ hir::ItemExistential(..) => {
+ // Check the traits being exposed, as they're separate,
+ // e.g. `impl Iterator<Item=T>` has two predicates,
+ // `X: Iterator` and `<X as Iterator>::Item == T`,
+ // where `X` is the `impl Iterator<Item=T>` itself,
+ // stored in `predicates_of`, not in the `Ty` itself.
+
+ self.check(item.id, self.inner_visibility).predicates();
+ }
// Subitems of these items have inherited publicity
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemTy(..) => {
// handled in `visit_item` above
}
- fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyImplTraitExistential(ref exist_item, _, _) = ty.node {
- // Check the traits being exposed, as they're separate,
- // e.g. `impl Iterator<Item=T>` has two predicates,
- // `X: Iterator` and `<X as Iterator>::Item == T`,
- // where `X` is the `impl Iterator<Item=T>` itself,
- // stored in `predicates_of`, not in the `Ty` itself.
-
- self.check(exist_item.id, self.inner_visibility).predicates();
- }
-
- intravisit::walk_ty(self, ty);
- }
-
// Don't recurse into expressions in array sizes or const initializers
fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
// Don't recurse into patterns in function arguments