Skip to content

Commit f55ac69

Browse files
authored
Auto merge of #35091 - eddyb:impl-trait, r=nikomatsakis
Implement `impl Trait` in return type position by anonymization. This is the first step towards implementing `impl Trait` (cc #34511). `impl Trait` types are only allowed in function and inherent method return types, and capture all named lifetime and type parameters, being invariant over them. No lifetimes that are not explicitly named lifetime parameters are allowed to escape from the function body. The exposed traits are only those listed explicitly, i.e. `Foo` and `Clone` in `impl Foo + Clone`, with the exception of "auto traits" (like `Send` or `Sync`) which "leak" the actual contents. The implementation strategy is anonymization, i.e.: ```rust fn foo<T>(xs: Vec<T>) -> impl Iterator<Item=impl FnOnce() -> T> { xs.into_iter().map(|x| || x) } // is represented as: type A</*invariant over*/ T> where A<T>: Iterator<Item=B<T>>; type B</*invariant over*/ T> where B<T>: FnOnce() -> T; fn foo<T>(xs: Vec<T>) -> A<T> { xs.into_iter().map(|x| || x): $0 where $0: Iterator<Item=$1>, $1: FnOnce() -> T } ``` `$0` and `$1` are resolved (to `iter::Map<vec::Iter<T>, closure>` and the closure, respectively) and assigned to `A` and `B`, after checking the body of `foo`. `A` and `B` are *never* resolved for user-facing type equality (typeck), but always for the low-level representation and specialization (trans). The "auto traits" exception is implemented by collecting bounds like `impl Trait: Send` that have failed for the obscure `impl Trait` type (i.e. `A` or `B` above), pretending they succeeded within the function and trying them again after type-checking the whole crate, by replacing `impl Trait` with the real type. While passing around values which have explicit lifetime parameters (of the function with `-> impl Trait`) in their type *should* work, regionck appears to as#ference variables in *way* too many cases, and never properly resolving them to either explicit lifetime parameters, or `'static`. We might not be able to handle lifetime parameters in `impl Trait` without changes to lifetime inference, but type parameters can have arbitrary lifetimes in them from the caller, so most type-generic usecases (or not generic at all) should not run into this problem. cc @rust-lang/lang
2 parents 68d9284 + 23f0494 commit f55ac69

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2788
-532
lines changed

Diff for: src/librustc/hir/fold.rs

+3
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
375375
TyPolyTraitRef(bounds) => {
376376
TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
377377
}
378+
TyImplTrait(bounds) => {
379+
TyImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
380+
}
378381
},
379382
span: fld.new_span(span),
380383
}

Diff for: src/librustc/hir/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
427427
TyPolyTraitRef(ref bounds) => {
428428
walk_list!(visitor, visit_ty_param_bound, bounds);
429429
}
430+
TyImplTrait(ref bounds) => {
431+
walk_list!(visitor, visit_ty_param_bound, bounds);
432+
}
430433
TyTypeof(ref expression) => {
431434
visitor.visit_expr(expression)
432435
}

Diff for: src/librustc/hir/lowering.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,10 @@ impl<'a> LoweringContext<'a> {
293293
hir::TyTypeof(self.lower_expr(expr))
294294
}
295295
PolyTraitRef(ref bounds) => {
296-
let bounds = bounds.iter().map(|b| self.lower_ty_param_bound(b)).collect();
297-
hir::TyPolyTraitRef(bounds)
296+
hir::TyPolyTraitRef(self.lower_bounds(bounds))
297+
}
298+
ImplTrait(ref bounds) => {
299+
hir::TyImplTrait(self.lower_bounds(bounds))
298300
}
299301
Mac(_) => panic!("TyMac should have been expanded by now."),
300302
},

Diff for: src/librustc/hir/map/collector.rs

+8
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
194194
});
195195
}
196196

197+
fn visit_ty(&mut self, ty: &'ast Ty) {
198+
self.insert(ty.id, NodeTy(ty));
199+
200+
self.with_parent(ty.id, |this| {
201+
intravisit::walk_ty(this, ty);
202+
});
203+
}
204+
197205
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
198206
b: &'ast Block, s: Span, id: NodeId) {
199207
assert_eq!(self.parent_node, id);

Diff for: src/librustc/hir/map/def_collector.rs

+6
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
268268
if let TyKind::FixedLengthVec(_, ref length) = ty.node {
269269
self.visit_ast_const_integer(length);
270270
}
271+
if let TyKind::ImplTrait(..) = ty.node {
272+
self.create_def(ty.id, DefPathData::ImplTrait);
273+
}
271274
visit::walk_ty(self, ty);
272275
}
273276

@@ -428,6 +431,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
428431
if let hir::TyFixedLengthVec(_, ref length) = ty.node {
429432
self.visit_hir_const_integer(length);
430433
}
434+
if let hir::TyImplTrait(..) = ty.node {
435+
self.create_def(ty.id, DefPathData::ImplTrait);
436+
}
431437
intravisit::walk_ty(self, ty);
432438
}
433439

Diff for: src/librustc/hir/map/definitions.rs

+6
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ pub enum DefPathData {
215215
Initializer,
216216
/// Pattern binding
217217
Binding(InternedString),
218+
/// An `impl Trait` type node.
219+
ImplTrait
218220
}
219221

220222
impl Definitions {
@@ -369,6 +371,10 @@ impl DefPathData {
369371
Initializer => {
370372
InternedString::new("{{initializer}}")
371373
}
374+
375+
ImplTrait => {
376+
InternedString::new("{{impl-Trait}}")
377+
}
372378
}
373379
}
374380

Diff for: src/librustc/hir/map/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub enum Node<'ast> {
5050
NodeVariant(&'ast Variant),
5151
NodeExpr(&'ast Expr),
5252
NodeStmt(&'ast Stmt),
53+
NodeTy(&'ast Ty),
5354
NodeLocal(&'ast Pat),
5455
NodePat(&'ast Pat),
5556
NodeBlock(&'ast Block),
@@ -76,6 +77,7 @@ pub enum MapEntry<'ast> {
7677
EntryVariant(NodeId, &'ast Variant),
7778
EntryExpr(NodeId, &'ast Expr),
7879
EntryStmt(NodeId, &'ast Stmt),
80+
EntryTy(NodeId, &'ast Ty),
7981
EntryLocal(NodeId, &'ast Pat),
8082
EntryPat(NodeId, &'ast Pat),
8183
EntryBlock(NodeId, &'ast Block),
@@ -104,6 +106,7 @@ impl<'ast> MapEntry<'ast> {
104106
NodeVariant(n) => EntryVariant(p, n),
105107
NodeExpr(n) => EntryExpr(p, n),
106108
NodeStmt(n) => EntryStmt(p, n),
109+
NodeTy(n) => EntryTy(p, n),
107110
NodeLocal(n) => EntryLocal(p, n),
108111
NodePat(n) => EntryPat(p, n),
109112
NodeBlock(n) => EntryBlock(p, n),
@@ -122,6 +125,7 @@ impl<'ast> MapEntry<'ast> {
122125
EntryVariant(id, _) => id,
123126
EntryExpr(id, _) => id,
124127
EntryStmt(id, _) => id,
128+
EntryTy(id, _) => id,
125129
EntryLocal(id, _) => id,
126130
EntryPat(id, _) => id,
127131
EntryBlock(id, _) => id,
@@ -144,6 +148,7 @@ impl<'ast> MapEntry<'ast> {
144148
EntryVariant(_, n) => NodeVariant(n),
145149
EntryExpr(_, n) => NodeExpr(n),
146150
EntryStmt(_, n) => NodeStmt(n),
151+
EntryTy(_, n) => NodeTy(n),
147152
EntryLocal(_, n) => NodeLocal(n),
148153
EntryPat(_, n) => NodePat(n),
149154
EntryBlock(_, n) => NodeBlock(n),
@@ -257,6 +262,7 @@ impl<'ast> Map<'ast> {
257262
EntryVariant(p, _) |
258263
EntryExpr(p, _) |
259264
EntryStmt(p, _) |
265+
EntryTy(p, _) |
260266
EntryLocal(p, _) |
261267
EntryPat(p, _) |
262268
EntryBlock(p, _) |
@@ -297,6 +303,7 @@ impl<'ast> Map<'ast> {
297303
EntryVariant(p, _) |
298304
EntryExpr(p, _) |
299305
EntryStmt(p, _) |
306+
EntryTy(p, _) |
300307
EntryLocal(p, _) |
301308
EntryPat(p, _) |
302309
EntryBlock(p, _) |
@@ -680,6 +687,7 @@ impl<'ast> Map<'ast> {
680687
Some(NodeVariant(variant)) => variant.span,
681688
Some(NodeExpr(expr)) => expr.span,
682689
Some(NodeStmt(stmt)) => stmt.span,
690+
Some(NodeTy(ty)) => ty.span,
683691
Some(NodeLocal(pat)) => pat.span,
684692
Some(NodePat(pat)) => pat.span,
685693
Some(NodeBlock(block)) => block.span,
@@ -971,6 +979,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
971979
NodeVariant(a) => self.print_variant(&a),
972980
NodeExpr(a) => self.print_expr(&a),
973981
NodeStmt(a) => self.print_stmt(&a),
982+
NodeTy(a) => self.print_type(&a),
974983
NodePat(a) => self.print_pat(&a),
975984
NodeBlock(a) => self.print_block(&a),
976985
NodeLifetime(a) => self.print_lifetime(&a),
@@ -1059,6 +1068,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
10591068
Some(NodeStmt(ref stmt)) => {
10601069
format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
10611070
}
1071+
Some(NodeTy(ref ty)) => {
1072+
format!("type {}{}", pprust::ty_to_string(&ty), id_str)
1073+
}
10621074
Some(NodeLocal(ref pat)) => {
10631075
format!("local {}{}", pprust::pat_to_string(&pat), id_str)
10641076
}

Diff for: src/librustc/hir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,8 @@ pub enum Ty_ {
11321132
TyObjectSum(P<Ty>, TyParamBounds),
11331133
/// A type like `for<'a> Foo<&'a Bar>`
11341134
TyPolyTraitRef(TyParamBounds),
1135+
/// An `impl TraitA+TraitB` type.
1136+
TyImplTrait(TyParamBounds),
11351137
/// Unused for now
11361138
TyTypeof(P<Expr>),
11371139
/// TyInfer means the type should be inferred instead of it having been

Diff for: src/librustc/hir/print.rs

+3
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,9 @@ impl<'a> State<'a> {
536536
hir::TyPolyTraitRef(ref bounds) => {
537537
self.print_bounds("", &bounds[..])?;
538538
}
539+
hir::TyImplTrait(ref bounds) => {
540+
self.print_bounds("impl ", &bounds[..])?;
541+
}
539542
hir::TyFixedLengthVec(ref ty, ref v) => {
540543
word(&mut self.s, "[")?;
541544
self.print_type(&ty)?;

Diff for: src/librustc/infer/freshen.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
170170
ty::TyClosure(..) |
171171
ty::TyTuple(..) |
172172
ty::TyProjection(..) |
173-
ty::TyParam(..) => {
173+
ty::TyParam(..) |
174+
ty::TyAnon(..) => {
174175
t.super_fold_with(self)
175176
}
176177
}

Diff for: src/librustc/infer/mod.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use ty::{self, Ty, TyCtxt};
3434
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
3535
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
3636
use ty::relate::{Relate, RelateResult, TypeRelation};
37-
use traits::{self, PredicateObligations, ProjectionMode};
37+
use traits::{self, PredicateObligations, Reveal};
3838
use rustc_data_structures::unify::{self, UnificationTable};
3939
use std::cell::{Cell, RefCell, Ref, RefMut};
4040
use std::fmt;
@@ -147,8 +147,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
147147

148148
// Sadly, the behavior of projection varies a bit depending on the
149149
// stage of compilation. The specifics are given in the
150-
// documentation for `ProjectionMode`.
151-
projection_mode: ProjectionMode,
150+
// documentation for `Reveal`.
151+
projection_mode: Reveal,
152152

153153
// When an error occurs, we want to avoid reporting "derived"
154154
// errors that are due to this original failure. Normally, we
@@ -459,15 +459,15 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
459459
arenas: ty::CtxtArenas<'tcx>,
460460
tables: Option<RefCell<ty::Tables<'tcx>>>,
461461
param_env: Option<ty::ParameterEnvironment<'gcx>>,
462-
projection_mode: ProjectionMode,
462+
projection_mode: Reveal,
463463
normalize: bool
464464
}
465465

466466
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
467467
pub fn infer_ctxt(self,
468468
tables: Option<ty::Tables<'tcx>>,
469469
param_env: Option<ty::ParameterEnvironment<'gcx>>,
470-
projection_mode: ProjectionMode)
470+
projection_mode: Reveal)
471471
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
472472
InferCtxtBuilder {
473473
global_tcx: self,
@@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
479479
}
480480
}
481481

482-
pub fn normalizing_infer_ctxt(self, projection_mode: ProjectionMode)
482+
pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
483483
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
484484
InferCtxtBuilder {
485485
global_tcx: self,
@@ -509,7 +509,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
509509
projection_cache: RefCell::new(traits::ProjectionCache::new()),
510510
reported_trait_errors: RefCell::new(FnvHashSet()),
511511
normalize: false,
512-
projection_mode: ProjectionMode::AnyFinal,
512+
projection_mode: Reveal::NotSpecializable,
513513
tainted_by_errors_flag: Cell::new(false),
514514
err_count_on_creation: self.sess.err_count(),
515515
obligations_in_snapshot: Cell::new(false),
@@ -641,7 +641,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
641641
return value;
642642
}
643643

644-
self.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
644+
self.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
645645
value.trans_normalize(&infcx)
646646
})
647647
}
@@ -659,7 +659,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
659659
return value;
660660
}
661661

662-
self.infer_ctxt(None, Some(env.clone()), ProjectionMode::Any).enter(|infcx| {
662+
self.infer_ctxt(None, Some(env.clone()), Reveal::All).enter(|infcx| {
663663
value.trans_normalize(&infcx)
664664
})
665665
}
@@ -736,7 +736,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
736736
Ok(self.tcx.erase_regions(&result))
737737
}
738738

739-
pub fn projection_mode(&self) -> ProjectionMode {
739+
pub fn projection_mode(&self) -> Reveal {
740740
self.projection_mode
741741
}
742742

Diff for: src/librustc/middle/intrinsicck.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use dep_graph::DepNode;
1212
use hir::def::Def;
1313
use hir::def_id::DefId;
1414
use infer::InferCtxt;
15-
use traits::ProjectionMode;
15+
use traits::Reveal;
1616
use ty::{self, Ty, TyCtxt};
1717
use ty::layout::{LayoutError, Pointer, SizeSkeleton};
1818

@@ -36,7 +36,7 @@ struct ItemVisitor<'a, 'tcx: 'a> {
3636
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
3737
fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
3838
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
39-
self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
39+
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
4040
let mut visitor = ExprVisitor {
4141
infcx: &infcx
4242
};
@@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
114114
impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
115115
// const, static and N in [T; N].
116116
fn visit_expr(&mut self, expr: &hir::Expr) {
117-
self.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
117+
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
118118
let mut visitor = ExprVisitor {
119119
infcx: &infcx
120120
};
@@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
144144
span_bug!(s, "intrinsicck: closure outside of function")
145145
}
146146
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
147-
self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
147+
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
148148
let mut visitor = ExprVisitor {
149149
infcx: &infcx
150150
};

Diff for: src/librustc/middle/liveness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ use dep_graph::DepNode;
113113
use hir::def::*;
114114
use hir::pat_util;
115115
use ty::{self, TyCtxt, ParameterEnvironment};
116-
use traits::{self, ProjectionMode};
116+
use traits::{self, Reveal};
117117
use ty::subst::Subst;
118118
use lint;
119119
use util::nodemap::NodeMap;
@@ -1484,7 +1484,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
14841484
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
14851485
let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
14861486
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
1487-
ProjectionMode::Any).enter(|infcx| {
1487+
Reveal::All).enter(|infcx| {
14881488
let cause = traits::ObligationCause::dummy();
14891489
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
14901490
});

Diff for: src/librustc/middle/resolve_lifetime.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
832832
constrained_by_input.visit_ty(&arg.ty);
833833
}
834834

835-
let mut appears_in_output = AllCollector { regions: FnvHashSet() };
835+
let mut appears_in_output = AllCollector {
836+
regions: FnvHashSet(),
837+
impl_trait: false
838+
};
836839
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
837840

838841
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}",
@@ -842,7 +845,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
842845
//
843846
// Subtle point: because we disallow nested bindings, we can just
844847
// ignore binders here and scrape up all names we see.
845-
let mut appears_in_where_clause = AllCollector { regions: FnvHashSet() };
848+
let mut appears_in_where_clause = AllCollector {
849+
regions: FnvHashSet(),
850+
impl_trait: false
851+
};
846852
for ty_param in generics.ty_params.iter() {
847853
walk_list!(&mut appears_in_where_clause,
848854
visit_ty_param_bound,
@@ -864,12 +870,16 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
864870
// Late bound regions are those that:
865871
// - appear in the inputs
866872
// - do not appear in the where-clauses
873+
// - are not implicitly captured by `impl Trait`
867874
for lifetime in &generics.lifetimes {
868875
let name = lifetime.lifetime.name;
869876

870877
// appears in the where clauses? early-bound.
871878
if appears_in_where_clause.regions.contains(&name) { continue; }
872879

880+
// any `impl Trait` in the return type? early-bound.
881+
if appears_in_output.impl_trait { continue; }
882+
873883
// does not appear in the inputs, but appears in the return
874884
// type? eventually this will be early-bound, but for now we
875885
// just mark it so we can issue warnings.
@@ -932,12 +942,20 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
932942

933943
struct AllCollector {
934944
regions: FnvHashSet<ast::Name>,
945+
impl_trait: bool
935946
}
936947

937948
impl<'v> Visitor<'v> for AllCollector {
938949
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
939950
self.regions.insert(lifetime_ref.name);
940951
}
952+
953+
fn visit_ty(&mut self, ty: &hir::Ty) {
954+
if let hir::TyImplTrait(_) = ty.node {
955+
self.impl_trait = true;
956+
}
957+
intravisit::walk_ty(self, ty);
958+
}
941959
}
942960
}
943961

0 commit comments

Comments
 (0)