Skip to content

Commit d92e594

Browse files
committed
typeck: record impl Trait concrete resolutions.
1 parent 1ef7ddf commit d92e594

File tree

10 files changed

+1224
-96
lines changed

10 files changed

+1224
-96
lines changed

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);

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
}

src/librustc_metadata/encoder.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,20 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
13901390
intravisit::walk_foreign_item(self, ni);
13911391
encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
13921392
}
1393+
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
1394+
intravisit::walk_ty(self, ty);
1395+
1396+
if let hir::TyImplTrait(_) = ty.node {
1397+
let rbml_w = &mut *self.rbml_w_for_visit_item;
1398+
let def_id = self.ecx.tcx.map.local_def_id(ty.id);
1399+
let _task = self.index.record(def_id, rbml_w);
1400+
rbml_w.start_tag(tag_items_data_item);
1401+
encode_def_id_and_key(self.ecx, rbml_w, def_id);
1402+
encode_family(rbml_w, 'y');
1403+
encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
1404+
rbml_w.end_tag();
1405+
}
1406+
}
13931407
}
13941408

13951409
fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,

src/librustc_typeck/astconv.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -1763,25 +1763,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
17631763

17641764
// Create the anonymized type.
17651765
let def_id = tcx.map.local_def_id(ast_ty.id);
1766-
let substs = if let Some(anon_scope) = rscope.anon_type_scope() {
1767-
anon_scope.fresh_substs(tcx)
1766+
if let Some(anon_scope) = rscope.anon_type_scope() {
1767+
let substs = anon_scope.fresh_substs(tcx);
1768+
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
1769+
1770+
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
1771+
let bounds = compute_bounds(self, ty, bounds,
1772+
SizedByDefault::Yes,
1773+
Some(anon_scope),
1774+
ast_ty.span);
1775+
let predicates = bounds.predicates(tcx, ty);
1776+
let predicates = tcx.lift_to_global(&predicates).unwrap();
1777+
tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
1778+
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
1779+
});
1780+
1781+
ty
17681782
} else {
17691783
span_err!(tcx.sess, ast_ty.span, E0562,
17701784
"`impl Trait` not allowed outside of function \
17711785
and inherent method return types");
1772-
tcx.mk_substs(Substs::empty())
1773-
};
1774-
let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
1775-
1776-
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
1777-
let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, ast_ty.span);
1778-
let predicates = tcx.lift_to_global(&bounds.predicates(tcx, ty)).unwrap();
1779-
let predicates = ty::GenericPredicates {
1780-
predicates: VecPerParamSpace::new(vec![], vec![], predicates)
1781-
};
1782-
tcx.predicates.borrow_mut().insert(def_id, predicates);
1783-
1784-
ty
1786+
tcx.types.err
1787+
}
17851788
}
17861789
hir::TyPath(ref maybe_qself, ref path) => {
17871790
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);

src/librustc_typeck/check/mod.rs

+60-22
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
9696
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
9797
use rustc::ty::{MethodCall, MethodCallee};
9898
use rustc::ty::adjustment;
99-
use rustc::ty::fold::TypeFoldable;
99+
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
100100
use rustc::ty::util::{Representability, IntTypeExt};
101101
use require_c_abi_if_variadic;
102102
use rscope::{ElisionFailureInfo, RegionScope};
@@ -172,6 +172,12 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
172172
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'gcx, 'tcx>>>>,
173173

174174
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
175+
176+
// Anonymized types found in explicit return types and their
177+
// associated fresh inference variable. Writeback resolves these
178+
// variables to get the concrete type, which can be used to
179+
// deanonymize TyAnon, after typeck is done with all functions.
180+
anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
175181
}
176182

177183
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -408,6 +414,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
408414
locals: RefCell::new(NodeMap()),
409415
deferred_call_resolutions: RefCell::new(DefIdMap()),
410416
deferred_cast_checks: RefCell::new(Vec::new()),
417+
anon_types: RefCell::new(DefIdMap()),
411418
})
412419
})
413420
}
@@ -631,32 +638,29 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
631638
body: &'gcx hir::Block)
632639
-> FnCtxt<'a, 'gcx, 'tcx>
633640
{
634-
let arg_tys = &fn_sig.inputs;
635-
let ret_ty = fn_sig.output;
641+
let mut fn_sig = fn_sig.clone();
636642

637-
debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
638-
arg_tys,
639-
ret_ty,
640-
fn_id);
643+
debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);
641644

642645
// Create the function context. This is either derived from scratch or,
643646
// in the case of function expressions, based on the outer context.
644-
let fcx = FnCtxt::new(inherited, ret_ty, body.id);
647+
let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
645648
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
646649

647-
if let ty::FnConverging(ret_ty) = ret_ty {
648-
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
649-
}
650-
651-
debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
652-
653-
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
650+
fn_sig.output = match fcx.ret_ty {
651+
ty::FnConverging(orig_ret_ty) => {
652+
fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
653+
ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
654+
}
655+
ty::FnDiverging => ty::FnDiverging
656+
};
657+
fcx.ret_ty = fn_sig.output;
654658

655659
{
656660
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
657661

658662
// Add formal parameters.
659-
for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
663+
for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) {
660664
// The type of the argument must be well-formed.
661665
//
662666
// NB -- this is now checked in wfcheck, but that
@@ -672,21 +676,20 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
672676
});
673677

674678
// Check the pattern.
675-
fcx.check_pat(&input.pat, *arg_ty);
679+
fcx.check_pat(&input.pat, arg_ty);
680+
fcx.write_ty(input.id, arg_ty);
676681
}
677682

678683
visit.visit_block(body);
679684
}
680685

681-
fcx.check_block_with_expected(body, match ret_ty {
686+
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
687+
688+
fcx.check_block_with_expected(body, match fcx.ret_ty {
682689
ty::FnConverging(result_type) => ExpectHasType(result_type),
683690
ty::FnDiverging => NoExpectation
684691
});
685692

686-
for (input, arg) in decl.inputs.iter().zip(arg_tys) {
687-
fcx.write_ty(input.id, arg);
688-
}
689-
690693
fcx
691694
}
692695

@@ -1623,6 +1626,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
16231626
}
16241627
}
16251628

1629+
/// Replace all anonymized types with fresh inference variables
1630+
/// and record them for writeback.
1631+
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
1632+
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
1633+
if let ty::TyAnon(def_id, substs) = ty.sty {
1634+
// Use the same type variable if the exact same TyAnon appears more
1635+
// than once in the return type (e.g. if it's pased to a type alias).
1636+
if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
1637+
return ty_var;
1638+
}
1639+
let ty_var = self.next_ty_var();
1640+
self.anon_types.borrow_mut().insert(def_id, ty_var);
1641+
1642+
let item_predicates = self.tcx.lookup_predicates(def_id);
1643+
let bounds = item_predicates.instantiate(self.tcx, substs);
1644+
1645+
let span = self.tcx.map.def_id_span(def_id, codemap::DUMMY_SP);
1646+
for predicate in bounds.predicates {
1647+
// Change the predicate to refer to the type variable,
1648+
// which will be the concrete type, instead of the TyAnon.
1649+
// This also instantiates nested `impl Trait`.
1650+
let predicate = self.instantiate_anon_types(&predicate);
1651+
1652+
// Require that the predicate holds for the concrete type.
1653+
let cause = traits::ObligationCause::new(span, self.body_id,
1654+
traits::ReturnType);
1655+
self.register_predicate(traits::Obligation::new(cause, predicate));
1656+
}
1657+
1658+
ty_var
1659+
} else {
1660+
ty
1661+
}
1662+
}})
1663+
}
16261664

16271665
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
16281666
where T : TypeFoldable<'tcx>

0 commit comments

Comments
 (0)