Skip to content

Commit 2a1ea44

Browse files
committed
Nest the impl Trait existential item inside the return type
1 parent f55129d commit 2a1ea44

File tree

10 files changed

+144
-173
lines changed

10 files changed

+144
-173
lines changed

src/librustc/hir/intravisit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
603603
TyKind::Path(ref qpath) => {
604604
visitor.visit_qpath(qpath, typ.hir_id, typ.span);
605605
}
606+
TyKind::Def(item_id, ref lifetimes) => {
607+
visitor.visit_nested_item(item_id);
608+
walk_list!(visitor, visit_generic_arg, lifetimes);
609+
}
606610
TyKind::Array(ref ty, ref length) => {
607611
visitor.visit_ty(ty);
608612
visitor.visit_anon_const(length)

src/librustc/hir/lowering.rs

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,20 +1352,7 @@ impl<'a> LoweringContext<'a> {
13521352
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
13531353

13541354
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
1355-
let path = P(hir::Path {
1356-
span: exist_ty_span,
1357-
def: Def::Existential(DefId::local(exist_ty_def_index)),
1358-
segments: hir_vec![hir::PathSegment {
1359-
infer_types: false,
1360-
ident: Ident::new(keywords::Invalid.name(), exist_ty_span),
1361-
args: Some(P(hir::GenericArgs {
1362-
parenthesized: false,
1363-
bindings: HirVec::new(),
1364-
args: lifetimes,
1365-
}))
1366-
}],
1367-
});
1368-
hir::TyKind::Path(hir::QPath::Resolved(None, path))
1355+
hir::TyKind::Def(hir::ItemId { id: exist_ty_id.node_id }, lifetimes)
13691356
})
13701357
}
13711358

@@ -3207,23 +3194,6 @@ impl<'a> LoweringContext<'a> {
32073194
}
32083195
}
32093196

3210-
/// Lowers `impl Trait` items for a function and appends them to the list
3211-
fn lower_fn_impl_trait_ids(
3212-
&mut self,
3213-
decl: &FnDecl,
3214-
header: &FnHeader,
3215-
ids: &mut SmallVec<[hir::ItemId; 1]>,
3216-
) {
3217-
if let Some(id) = header.asyncness.opt_return_id() {
3218-
ids.push(hir::ItemId { id });
3219-
}
3220-
let mut visitor = ImplTraitTypeIdVisitor { ids };
3221-
match decl.output {
3222-
FunctionRetTy::Default(_) => {},
3223-
FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty),
3224-
}
3225-
}
3226-
32273197
fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
32283198
match i.node {
32293199
ItemKind::Use(ref use_tree) => {
@@ -3232,20 +3202,8 @@ impl<'a> LoweringContext<'a> {
32323202
vec
32333203
}
32343204
ItemKind::MacroDef(..) => SmallVec::new(),
3235-
ItemKind::Fn(ref decl, ref header, ..) => {
3236-
let mut ids = smallvec![hir::ItemId { id: i.id }];
3237-
self.lower_fn_impl_trait_ids(decl, header, &mut ids);
3238-
ids
3239-
},
3240-
ItemKind::Impl(.., None, _, ref items) => {
3241-
let mut ids = smallvec![hir::ItemId { id: i.id }];
3242-
for item in items {
3243-
if let ImplItemKind::Method(ref sig, _) = item.node {
3244-
self.lower_fn_impl_trait_ids(&sig.decl, &sig.header, &mut ids);
3245-
}
3246-
}
3247-
ids
3248-
},
3205+
ItemKind::Fn(..) |
3206+
ItemKind::Impl(.., None, _, _) => smallvec![hir::ItemId { id: i.id }],
32493207
ItemKind::Static(ref ty, ..) => {
32503208
let mut ids = smallvec![hir::ItemId { id: i.id }];
32513209
if self.sess.features_untracked().impl_trait_in_bindings {

src/librustc/hir/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,12 @@ pub enum TyKind {
17231723
///
17241724
/// Type parameters may be stored in each `PathSegment`.
17251725
Path(QPath),
1726+
/// A type definition itself. This is currently only used for the `existential type`
1727+
/// item that `impl Trait` in return position desugars to.
1728+
///
1729+
/// The generic arg list are the lifetimes (and in the future possibly parameters) that are
1730+
/// actually bound on the `impl Trait`.
1731+
Def(ItemId, HirVec<GenericArg>),
17261732
/// A trait object type `Bound1 + Bound2 + Bound3`
17271733
/// where `Bound` is a trait or a lifetime.
17281734
TraitObject(HirVec<PolyTraitRef>, Lifetime),

src/librustc/hir/print.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl<'a> State<'a> {
401401
self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params,
402402
&f.arg_names[..])?;
403403
}
404+
hir::TyKind::Def(..) => {},
404405
hir::TyKind::Path(ref qpath) => {
405406
self.print_qpath(qpath, false)?
406407
}

src/librustc/ich/impls_hir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ impl_stable_hash_for!(enum hir::TyKind {
339339
Never,
340340
Tup(ts),
341341
Path(qpath),
342+
Def(it, lt),
342343
TraitObject(trait_refs, lifetime),
343344
Typeof(body_id),
344345
Err,

src/librustc/middle/resolve_lifetime.rs

Lines changed: 103 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -621,140 +621,135 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
621621
};
622622
self.with(scope, |_, this| this.visit_ty(&mt.ty));
623623
}
624-
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
625-
if let Def::Existential(exist_ty_did) = path.def {
626-
let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap();
627-
628-
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
629-
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
630-
// `abstract type MyAnonTy<'b>: MyTrait<'b>;`
631-
// ^ ^ this gets resolved in the scope of
632-
// the exist_ty generics
633-
let (generics, bounds) = match self.tcx.hir.expect_item(id).node {
634-
// named existential types don't need these hacks
635-
hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => {
636-
intravisit::walk_ty(self, ty);
637-
return;
638-
},
639-
hir::ItemKind::Existential(hir::ExistTy{
640-
ref generics,
641-
ref bounds,
642-
..
643-
}) => (
644-
generics,
645-
bounds,
646-
),
647-
ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
648-
};
624+
hir::TyKind::Def(item_id, ref lifetimes) => {
625+
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
626+
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
627+
// `abstract type MyAnonTy<'b>: MyTrait<'b>;`
628+
// ^ ^ this gets resolved in the scope of
629+
// the exist_ty generics
630+
let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node {
631+
// named existential types are reached via TyKind::Path
632+
// this arm is for `impl Trait` in the types of statics, constants and locals
633+
hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => {
634+
intravisit::walk_ty(self, ty);
635+
return;
636+
},
637+
// RPIT (return position impl trait)
638+
hir::ItemKind::Existential(hir::ExistTy{
639+
ref generics,
640+
ref bounds,
641+
..
642+
}) => (
643+
generics,
644+
bounds,
645+
),
646+
ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
647+
};
648+
649+
// Resolve the lifetimes that are applied to the existential type.
650+
// These are resolved in the current scope.
651+
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
652+
// `fn foo<'a>() -> MyAnonTy<'a> { ... }`
653+
// ^ ^this gets resolved in the current scope
654+
for lifetime in lifetimes {
655+
if let hir::GenericArg::Lifetime(lifetime) = lifetime {
656+
self.visit_lifetime(lifetime);
649657

650-
assert!(exist_ty_did.is_local());
651-
// Resolve the lifetimes that are applied to the existential type.
652-
// These are resolved in the current scope.
653-
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
654-
// `fn foo<'a>() -> MyAnonTy<'a> { ... }`
655-
// ^ ^this gets resolved in the current scope
656-
for lifetime in &path.segments[0].args.as_ref().unwrap().args {
657-
if let hir::GenericArg::Lifetime(lifetime) = lifetime {
658-
self.visit_lifetime(lifetime);
659-
660-
// Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
661-
// and ban them. Type variables instantiated inside binders aren't
662-
// well-supported at the moment, so this doesn't work.
663-
// In the future, this should be fixed and this error should be removed.
664-
let def = self.map.defs.get(&lifetime.id).cloned();
665-
if let Some(Region::LateBound(_, def_id, _)) = def {
666-
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
667-
// Ensure that the parent of the def is an item, not HRTB
668-
let parent_id = self.tcx.hir.get_parent_node(node_id);
669-
let parent_impl_id = hir::ImplItemId { node_id: parent_id };
670-
let parent_trait_id = hir::TraitItemId { node_id: parent_id };
671-
let krate = self.tcx.hir.forest.krate();
672-
if !(krate.items.contains_key(&parent_id)
673-
|| krate.impl_items.contains_key(&parent_impl_id)
674-
|| krate.trait_items.contains_key(&parent_trait_id))
675-
{
676-
span_err!(
677-
self.tcx.sess,
678-
lifetime.span,
679-
E0657,
680-
"`impl Trait` can only capture lifetimes \
681-
bound at the fn or impl level"
682-
);
683-
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
684-
}
658+
// Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
659+
// and ban them. Type variables instantiated inside binders aren't
660+
// well-supported at the moment, so this doesn't work.
661+
// In the future, this should be fixed and this error should be removed.
662+
let def = self.map.defs.get(&lifetime.id).cloned();
663+
if let Some(Region::LateBound(_, def_id, _)) = def {
664+
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
665+
// Ensure that the parent of the def is an item, not HRTB
666+
let parent_id = self.tcx.hir.get_parent_node(node_id);
667+
let parent_impl_id = hir::ImplItemId { node_id: parent_id };
668+
let parent_trait_id = hir::TraitItemId { node_id: parent_id };
669+
let krate = self.tcx.hir.forest.krate();
670+
if !(krate.items.contains_key(&parent_id)
671+
|| krate.impl_items.contains_key(&parent_impl_id)
672+
|| krate.trait_items.contains_key(&parent_trait_id))
673+
{
674+
span_err!(
675+
self.tcx.sess,
676+
lifetime.span,
677+
E0657,
678+
"`impl Trait` can only capture lifetimes \
679+
bound at the fn or impl level"
680+
);
681+
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
685682
}
686683
}
687684
}
688685
}
686+
}
689687

690-
// We want to start our early-bound indices at the end of the parent scope,
691-
// not including any parent `impl Trait`s.
692-
let mut index = self.next_early_index_for_abstract_type();
693-
debug!("visit_ty: index = {}", index);
688+
// We want to start our early-bound indices at the end of the parent scope,
689+
// not including any parent `impl Trait`s.
690+
let mut index = self.next_early_index_for_abstract_type();
691+
debug!("visit_ty: index = {}", index);
694692

695-
let mut elision = None;
696-
let mut lifetimes = FxHashMap();
697-
let mut type_count = 0;
698-
for param in &generics.params {
699-
match param.kind {
700-
GenericParamKind::Lifetime { .. } => {
701-
let (name, reg) = Region::early(&self.tcx.hir, &mut index, &param);
702-
if let hir::ParamName::Plain(param_name) = name {
703-
if param_name.name == keywords::UnderscoreLifetime.name() {
704-
// Pick the elided lifetime "definition" if one exists
705-
// and use it to make an elision scope.
706-
elision = Some(reg);
707-
} else {
708-
lifetimes.insert(name, reg);
709-
}
693+
let mut elision = None;
694+
let mut lifetimes = FxHashMap();
695+
let mut type_count = 0;
696+
for param in &generics.params {
697+
match param.kind {
698+
GenericParamKind::Lifetime { .. } => {
699+
let (name, reg) = Region::early(&self.tcx.hir, &mut index, &param);
700+
if let hir::ParamName::Plain(param_name) = name {
701+
if param_name.name == keywords::UnderscoreLifetime.name() {
702+
// Pick the elided lifetime "definition" if one exists
703+
// and use it to make an elision scope.
704+
elision = Some(reg);
710705
} else {
711706
lifetimes.insert(name, reg);
712707
}
713-
}
714-
GenericParamKind::Type { .. } => {
715-
type_count += 1;
708+
} else {
709+
lifetimes.insert(name, reg);
716710
}
717711
}
712+
GenericParamKind::Type { .. } => {
713+
type_count += 1;
714+
}
718715
}
719-
let next_early_index = index + type_count;
716+
}
717+
let next_early_index = index + type_count;
720718

721-
if let Some(elision_region) = elision {
722-
let scope = Scope::Elision {
723-
elide: Elide::Exact(elision_region),
724-
s: self.scope,
725-
};
726-
self.with(scope, |_old_scope, this| {
727-
let scope = Scope::Binder {
728-
lifetimes,
729-
next_early_index,
730-
s: this.scope,
731-
track_lifetime_uses: true,
732-
abstract_type_parent: false,
733-
};
734-
this.with(scope, |_old_scope, this| {
735-
this.visit_generics(generics);
736-
for bound in bounds {
737-
this.visit_param_bound(bound);
738-
}
739-
});
740-
});
741-
} else {
719+
if let Some(elision_region) = elision {
720+
let scope = Scope::Elision {
721+
elide: Elide::Exact(elision_region),
722+
s: self.scope,
723+
};
724+
self.with(scope, |_old_scope, this| {
742725
let scope = Scope::Binder {
743726
lifetimes,
744727
next_early_index,
745-
s: self.scope,
728+
s: this.scope,
746729
track_lifetime_uses: true,
747730
abstract_type_parent: false,
748731
};
749-
self.with(scope, |_old_scope, this| {
732+
this.with(scope, |_old_scope, this| {
750733
this.visit_generics(generics);
751734
for bound in bounds {
752735
this.visit_param_bound(bound);
753736
}
754737
});
755-
}
738+
});
756739
} else {
757-
intravisit::walk_ty(self, ty)
740+
let scope = Scope::Binder {
741+
lifetimes,
742+
next_early_index,
743+
s: self.scope,
744+
track_lifetime_uses: true,
745+
abstract_type_parent: false,
746+
};
747+
self.with(scope, |_old_scope, this| {
748+
this.visit_generics(generics);
749+
for bound in bounds {
750+
this.visit_param_bound(bound);
751+
}
752+
});
758753
}
759754
}
760755
_ => intravisit::walk_ty(self, ty),

src/librustc_typeck/astconv.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,10 +1338,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
13381338
match path.def {
13391339
Def::Existential(did) => {
13401340
// check for desugared impl trait
1341-
if ty::is_impl_trait_defn(tcx, did).is_some() {
1342-
let lifetimes = &path.segments[0].args.as_ref().unwrap().args;
1343-
return self.impl_trait_ty_to_ty(did, lifetimes);
1344-
}
1341+
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
13451342
let item_segment = path.segments.split_last().unwrap();
13461343
self.prohibit_generics(item_segment.1);
13471344
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
@@ -1462,6 +1459,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
14621459
});
14631460
self.def_to_ty(opt_self_ty, path, false)
14641461
}
1462+
hir::TyKind::Def(item_id, ref lifetimes) => {
1463+
let did = tcx.hir.local_def_id(item_id.id);
1464+
self.impl_trait_ty_to_ty(did, lifetimes)
1465+
},
14651466
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
14661467
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
14671468
let ty = self.ast_ty_to_ty(qself);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// compile-pass
2+
3+
#![deny(warnings)]
4+
5+
#[deprecated]
6+
trait Deprecated {}
7+
8+
#[deprecated]
9+
struct DeprecatedTy;
10+
11+
#[allow(deprecated)]
12+
impl Deprecated for DeprecatedTy {}
13+
14+
#[allow(deprecated)]
15+
fn foo() -> impl Deprecated { DeprecatedTy }
16+
17+
fn main() {
18+
foo();
19+
}

0 commit comments

Comments
 (0)