Skip to content

Commit 93afb1a

Browse files
committed
connect NLL type checker to the impl trait code
We now add the suitable `impl Trait` constraints.
1 parent da63aaa commit 93afb1a

File tree

14 files changed

+339
-38
lines changed

14 files changed

+339
-38
lines changed

src/librustc/infer/anon_types/mod.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
9393
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
9494
/// info about the `impl Iterator<..>` type and `?1` to info about
9595
/// the `impl Debug` type.
96+
///
97+
/// # Parameters
98+
///
99+
/// - `parent_def_id` -- we will only instantiate anonymous types
100+
/// with this parent. This is typically the def-id of the function
101+
/// in whose return type anon types are being instantiated.
102+
/// - `body_id` -- the body-id with which the resulting obligations should
103+
/// be associated
104+
/// - `param_env` -- the in-scope parameter environment to be used for
105+
/// obligations
106+
/// - `value` -- the value within which we are instantiating anon types
96107
pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
97108
&self,
109+
parent_def_id: DefId,
98110
body_id: ast::NodeId,
99111
param_env: ty::ParamEnv<'tcx>,
100112
value: &T,
101113
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
102114
debug!(
103-
"instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
115+
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})",
104116
value,
117+
parent_def_id,
105118
body_id,
106119
param_env,
107120
);
108121
let mut instantiator = Instantiator {
109122
infcx: self,
123+
parent_def_id,
110124
body_id,
111125
param_env,
112126
anon_types: DefIdMap(),
@@ -480,6 +494,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
480494

481495
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
482496
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
497+
parent_def_id: DefId,
483498
body_id: ast::NodeId,
484499
param_env: ty::ParamEnv<'tcx>,
485500
anon_types: AnonTypeMap<'tcx>,
@@ -489,11 +504,33 @@ struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
489504
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
490505
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
491506
debug!("instantiate_anon_types_in_map(value={:?})", value);
507+
let tcx = self.infcx.tcx;
492508
value.fold_with(&mut BottomUpFolder {
493-
tcx: self.infcx.tcx,
494-
fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
495-
self.fold_anon_ty(ty, def_id, substs)
496-
} else {
509+
tcx,
510+
fldop: |ty| {
511+
if let ty::TyAnon(def_id, substs) = ty.sty {
512+
// Check that this is `impl Trait` type is declared by
513+
// `parent_def_id`. During the first phase of type-check, this
514+
// is true, but during NLL type-check, we sometimes encounter
515+
// `impl Trait` types in e.g. inferred closure signatures that
516+
// are not 'local' to the current function and hence which
517+
// ought not to be instantiated.
518+
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
519+
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
520+
let anon_parent_def_id = tcx.hir.local_def_id(anon_parent_node_id);
521+
if self.parent_def_id == anon_parent_def_id {
522+
return self.fold_anon_ty(ty, def_id, substs);
523+
}
524+
525+
debug!("instantiate_anon_types_in_map: \
526+
encountered anon with wrong parent \
527+
def_id={:?} \
528+
anon_parent_def_id={:?}",
529+
def_id,
530+
anon_parent_def_id);
531+
}
532+
}
533+
497534
ty
498535
},
499536
})

src/librustc/util/ppaux.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -865,13 +865,17 @@ impl fmt::Debug for ty::RegionVid {
865865
define_print! {
866866
() ty::InferTy, (self, f, cx) {
867867
display {
868-
match *self {
869-
ty::TyVar(_) => write!(f, "_"),
870-
ty::IntVar(_) => write!(f, "{}", "{integer}"),
871-
ty::FloatVar(_) => write!(f, "{}", "{float}"),
872-
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
873-
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
874-
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
868+
if cx.is_verbose {
869+
print!(f, cx, print_debug(self))
870+
} else {
871+
match *self {
872+
ty::TyVar(_) => write!(f, "_"),
873+
ty::IntVar(_) => write!(f, "{}", "{integer}"),
874+
ty::FloatVar(_) => write!(f, "{}", "{float}"),
875+
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
876+
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
877+
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
878+
}
875879
}
876880
}
877881
debug {

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,12 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
7777
Option<ClosureRegionRequirements<'gcx>>,
7878
) {
7979
// Run the MIR type-checker.
80-
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
8180
let liveness = &LivenessResults::compute(mir);
8281
let constraint_sets = &type_check::type_check(
8382
infcx,
84-
mir_node_id,
8583
param_env,
8684
mir,
85+
def_id,
8786
&universal_regions,
8887
&liveness,
8988
flow_inits,

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
246246
.map(|origin| RegionDefinition::new(origin))
247247
.collect();
248248

249+
let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.nll_dump_cause);
250+
249251
let mut result = Self {
250252
definitions,
251253
elements: elements.clone(),
252254
liveness_constraints: RegionValues::new(
253255
elements,
254256
num_region_variables,
255-
TrackCauses(true),
257+
TrackCauses(nll_dump_cause),
256258
),
257259
inferred_values: None,
258260
constraints: Vec::new(),

src/librustc_mir/borrow_check/nll/renumber.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,44 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
1616

1717
/// Replaces all free regions appearing in the MIR with fresh
1818
/// inference variables, returning the number of variables created.
19-
pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
19+
pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, '_, 'tcx>, mir: &mut Mir<'tcx>) {
2020
debug!("renumber_mir()");
2121
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
2222

2323
let mut visitor = NLLVisitor { infcx };
2424
visitor.visit_mir(mir);
2525
}
2626

27+
/// Replaces all regions appearing in `value` with fresh inference
28+
/// variables.
29+
pub fn renumber_regions<'tcx, T>(
30+
infcx: &InferCtxt<'_, '_, 'tcx>,
31+
ty_context: TyContext,
32+
value: &T,
33+
) -> T
34+
where
35+
T: TypeFoldable<'tcx>,
36+
{
37+
debug!("renumber_regions(value={:?})", value);
38+
39+
infcx
40+
.tcx
41+
.fold_regions(value, &mut false, |_region, _depth| {
42+
let origin = NLLRegionVariableOrigin::Inferred(ty_context);
43+
infcx.next_nll_region_var(origin)
44+
})
45+
}
46+
2747
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
2848
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
2949
}
3050

3151
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
32-
/// Replaces all regions appearing in `value` with fresh inference
33-
/// variables. This is what we do for almost the entire MIR, with
34-
/// the exception of the declared types of our arguments.
3552
fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
3653
where
3754
T: TypeFoldable<'tcx>,
3855
{
39-
debug!("renumber_regions(value={:?})", value);
40-
41-
self.infcx
42-
.tcx
43-
.fold_regions(value, &mut false, |_region, _depth| {
44-
let origin = NLLRegionVariableOrigin::Inferred(ty_context);
45-
self.infcx.next_nll_region_var(origin)
46-
})
56+
renumber_regions(self.infcx, ty_context, value)
4757
}
4858
}
4959

src/librustc_mir/borrow_check/nll/type_check/input_output.rs

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@
1717
//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and
1818
//! contain revealed `impl Trait` values).
1919
20+
use borrow_check::nll::renumber;
2021
use borrow_check::nll::universal_regions::UniversalRegions;
22+
use rustc::hir::def_id::DefId;
23+
use rustc::infer::InferOk;
2124
use rustc::ty::Ty;
25+
use rustc::ty::subst::Subst;
2226
use rustc::mir::*;
27+
use rustc::mir::visit::TyContext;
28+
use rustc::traits::PredicateObligations;
2329

2430
use rustc_data_structures::indexed_vec::Idx;
2531

@@ -29,13 +35,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
2935
pub(super) fn equate_inputs_and_outputs(
3036
&mut self,
3137
mir: &Mir<'tcx>,
38+
mir_def_id: DefId,
3239
universal_regions: &UniversalRegions<'tcx>,
3340
) {
41+
let tcx = self.infcx.tcx;
42+
3443
let &UniversalRegions {
3544
unnormalized_output_ty,
3645
unnormalized_input_tys,
3746
..
3847
} = universal_regions;
48+
let infcx = self.infcx;
3949

4050
let start_position = Location {
4151
block: START_BLOCK,
@@ -52,10 +62,88 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
5262

5363
// Return types are a bit more complex. They may contain existential `impl Trait`
5464
// types.
55-
65+
debug!(
66+
"equate_inputs_and_outputs: unnormalized_output_ty={:?}",
67+
unnormalized_output_ty
68+
);
5669
let output_ty = self.normalize(&unnormalized_output_ty, start_position);
70+
debug!(
71+
"equate_inputs_and_outputs: normalized output_ty={:?}",
72+
output_ty
73+
);
5774
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
58-
self.equate_normalized_input_or_output(start_position, output_ty, mir_output_ty);
75+
let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
76+
let mut obligations = ObligationAccumulator::default();
77+
78+
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
79+
mir_def_id,
80+
cx.body_id,
81+
cx.param_env,
82+
&output_ty,
83+
));
84+
debug!(
85+
"equate_inputs_and_outputs: instantiated output_ty={:?}",
86+
output_ty
87+
);
88+
debug!(
89+
"equate_inputs_and_outputs: anon_type_map={:#?}",
90+
anon_type_map
91+
);
92+
93+
debug!(
94+
"equate_inputs_and_outputs: mir_output_ty={:?}",
95+
mir_output_ty
96+
);
97+
obligations.add(infcx
98+
.at(&cx.misc(cx.last_span), cx.param_env)
99+
.eq(output_ty, mir_output_ty)?);
100+
101+
for (&anon_def_id, anon_decl) in &anon_type_map {
102+
let anon_defn_ty = tcx.type_of(anon_def_id);
103+
let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
104+
let anon_defn_ty = renumber::renumber_regions(
105+
cx.infcx,
106+
TyContext::Location(start_position),
107+
&anon_defn_ty,
108+
);
109+
debug!(
110+
"equate_inputs_and_outputs: concrete_ty={:?}",
111+
anon_decl.concrete_ty
112+
);
113+
debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
114+
obligations.add(infcx
115+
.at(&cx.misc(cx.last_span), cx.param_env)
116+
.eq(anon_decl.concrete_ty, anon_defn_ty)?);
117+
}
118+
119+
debug!("equate_inputs_and_outputs: equated");
120+
121+
Ok(InferOk {
122+
value: Some(anon_type_map),
123+
obligations: obligations.into_vec(),
124+
})
125+
}).unwrap_or_else(|terr| {
126+
span_mirbug!(
127+
self,
128+
start_position,
129+
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
130+
output_ty,
131+
mir_output_ty,
132+
terr
133+
);
134+
None
135+
});
136+
137+
// Finally
138+
if let Some(anon_type_map) = anon_type_map {
139+
self.fully_perform_op(start_position.at_self(), |_cx| {
140+
infcx.constrain_anon_types(&anon_type_map, universal_regions);
141+
Ok(InferOk {
142+
value: (),
143+
obligations: vec![],
144+
})
145+
}).unwrap();
146+
}
59147
}
60148

61149
fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
@@ -73,3 +161,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
73161
}
74162
}
75163
}
164+
165+
#[derive(Debug, Default)]
166+
struct ObligationAccumulator<'tcx> {
167+
obligations: PredicateObligations<'tcx>,
168+
}
169+
170+
impl<'tcx> ObligationAccumulator<'tcx> {
171+
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
172+
let InferOk { value, obligations } = value;
173+
self.obligations.extend(obligations);
174+
value
175+
}
176+
177+
fn into_vec(self) -> PredicateObligations<'tcx> {
178+
self.obligations
179+
}
180+
}

src/librustc_mir/borrow_check/nll/type_check/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use borrow_check::nll::universal_regions::UniversalRegions;
1717
use dataflow::FlowAtLocation;
1818
use dataflow::MaybeInitializedLvals;
1919
use dataflow::move_paths::MoveData;
20+
use rustc::hir::def_id::DefId;
2021
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
2122
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
2223
use rustc::traits::{self, FulfillmentContext};
@@ -77,9 +78,9 @@ mod input_output;
7778
/// # Parameters
7879
///
7980
/// - `infcx` -- inference context to use
80-
/// - `body_id` -- body-id of the MIR being checked
8181
/// - `param_env` -- parameter environment to use for trait solving
8282
/// - `mir` -- MIR to type-check
83+
/// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
8384
/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
8485
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
8586
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
@@ -94,14 +95,15 @@ mod input_output;
9495
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
9596
pub(crate) fn type_check<'gcx, 'tcx>(
9697
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
97-
body_id: ast::NodeId,
9898
param_env: ty::ParamEnv<'gcx>,
9999
mir: &Mir<'tcx>,
100+
mir_def_id: DefId,
100101
universal_regions: &UniversalRegions<'tcx>,
101102
liveness: &LivenessResults,
102103
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
103104
move_data: &MoveData<'tcx>,
104105
) -> MirTypeckRegionConstraints<'tcx> {
106+
let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
105107
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
106108
type_check_internal(
107109
infcx,
@@ -113,7 +115,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
113115
&mut |cx| {
114116
liveness::generate(cx, mir, liveness, flow_inits, move_data);
115117

116-
cx.equate_inputs_and_outputs(mir, universal_regions);
118+
cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
117119
},
118120
)
119121
}

0 commit comments

Comments
 (0)