Skip to content

Commit

Permalink
Rollup merge of #51979 - oli-obk:lowering_cleanups4, r=nikomatsakis
Browse files Browse the repository at this point in the history
Get rid of `TyImplTraitExistential`

cc @eddyb

r? @nikomatsakis
  • Loading branch information
Mark-Simulacrum authored Jul 2, 2018
2 parents 55caead + 75a6fde commit 4dcaf90
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 177 deletions.
7 changes: 0 additions & 7 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,13 +607,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
}
visitor.visit_lifetime(lifetime);
}
TyImplTraitExistential(_, def_id, ref lifetimes) => {
// we are not recursing into the `existential` item, because it is already being visited
// as part of the surrounding module. The `NodeId` just exists so we don't have to look
// it up everywhere else in the compiler
visitor.visit_def_mention(Def::Existential(def_id));
walk_list!(visitor, visit_lifetime, lifetimes);
}
TyTypeof(ref expression) => {
visitor.visit_anon_const(expression)
}
Expand Down
29 changes: 18 additions & 11 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,13 +1307,20 @@ impl<'a> LoweringContext<'a> {
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))
})
}

Expand All @@ -1322,7 +1329,7 @@ impl<'a> LoweringContext<'a> {
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>`
Expand All @@ -1333,7 +1340,7 @@ impl<'a> LoweringContext<'a> {
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>,
}

Expand Down Expand Up @@ -1417,11 +1424,11 @@ impl<'a> LoweringContext<'a> {
&& !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`
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1692,18 +1692,6 @@ pub enum Ty_ {
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
/// An existentially quantified (there exists a type satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
///
/// The `Item` is the generated
/// `existential type Foo<'a, 'b>: MyTrait<'a, 'b>;`.
///
/// The `HirVec<Lifetime>` is the list of lifetimes applied as parameters
/// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`.
/// This list is only a list of lifetimes and not type parameters
/// because all in-scope type parameters are captured by `impl Trait`,
/// so they are resolved directly through the parent `Generics`.
TyImplTraitExistential(ItemId, DefId, HirVec<Lifetime>),
/// Unused for now
TyTypeof(AnonConst),
/// TyInfer means the type should be inferred instead of it having been
Expand Down
9 changes: 0 additions & 9 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,15 +420,6 @@ impl<'a> State<'a> {
self.print_lifetime(lifetime)?;
}
}
hir::TyImplTraitExistential(hir_id, _def_id, ref _lifetimes) => {
match self.ann.try_fetch_item(hir_id.id).map(|it| &it.node) {
None => self.word_space("impl {{Trait}}")?,
Some(&hir::ItemExistential(ref exist_ty)) => {
self.print_bounds("impl", &exist_ty.bounds)?;
},
other => bug!("impl Trait pointed to {:#?}", other),
}
}
hir::TyArray(ref ty, ref length) => {
self.s.word("[")?;
self.print_type(&ty)?;
Expand Down
1 change: 0 additions & 1 deletion src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,6 @@ impl_stable_hash_for!(enum hir::Ty_ {
TyTup(ts),
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
TyImplTraitExistential(existty, def_id, lifetimes),
TyTypeof(body_id),
TyErr,
TyInfer
Expand Down
191 changes: 100 additions & 91 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,122 +625,131 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
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, &param);
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, &param);
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),
Expand Down
Loading

0 comments on commit 4dcaf90

Please sign in to comment.