Skip to content

Commit d488de8

Browse files
committed
Auto merge of #87587 - oli-obk:lazy_tait, r=spastorino
Various refactorings of the TAIT infrastructure Before this PR we used to store the opaque type knowledge outside the `InferCtxt`, so it got recomputed on every opaque type instantiation. I also removed a feature gate check that makes no sense in the planned lazy TAIT resolution scheme Each commit passes all tests, so this PR is best reviewed commit by commit. r? `@spastorino`
2 parents 47b41b7 + 93c4aa8 commit d488de8

33 files changed

+339
-482
lines changed

compiler/rustc_infer/src/infer/mod.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ pub use self::RegionVariableOrigin::*;
44
pub use self::SubregionOrigin::*;
55
pub use self::ValuePairs::*;
66

7+
use self::opaque_types::OpaqueTypeMap;
78
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
89

910
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
1011

12+
use hir::def_id::CRATE_DEF_ID;
1113
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1214
use rustc_data_structures::sync::Lrc;
1315
use rustc_data_structures::undo_log::Rollback;
@@ -59,6 +61,7 @@ pub mod lattice;
5961
mod lexical_region_resolve;
6062
mod lub;
6163
pub mod nll_relate;
64+
pub mod opaque_types;
6265
pub mod outlives;
6366
pub mod region_constraints;
6467
pub mod resolve;
@@ -191,6 +194,19 @@ pub struct InferCtxtInner<'tcx> {
191194
region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
192195

193196
undo_log: InferCtxtUndoLogs<'tcx>,
197+
198+
// Opaque types found in explicit return types and their
199+
// associated fresh inference variable. Writeback resolves these
200+
// variables to get the concrete type, which can be used to
201+
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
202+
pub opaque_types: OpaqueTypeMap<'tcx>,
203+
204+
/// A map from inference variables created from opaque
205+
/// type instantiations (`ty::Infer`) to the actual opaque
206+
/// type (`ty::Opaque`). Used during fallback to map unconstrained
207+
/// opaque type inference variables to their corresponding
208+
/// opaque type.
209+
pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
194210
}
195211

196212
impl<'tcx> InferCtxtInner<'tcx> {
@@ -204,6 +220,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
204220
float_unification_storage: ut::UnificationTableStorage::new(),
205221
region_constraint_storage: Some(RegionConstraintStorage::new()),
206222
region_obligations: vec![],
223+
opaque_types: Default::default(),
224+
opaque_types_vars: Default::default(),
207225
}
208226
}
209227

@@ -273,6 +291,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
273291
pub struct InferCtxt<'a, 'tcx> {
274292
pub tcx: TyCtxt<'tcx>,
275293

294+
/// The `DefId` of the item in whose context we are performing inference or typeck.
295+
/// It is used to check whether an opaque type use is a defining use.
296+
pub defining_use_anchor: LocalDefId,
297+
276298
/// During type-checking/inference of a body, `in_progress_typeck_results`
277299
/// contains a reference to the typeck results being built up, which are
278300
/// used for reading closure kinds/signatures as they are inferred,
@@ -531,6 +553,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
531553
pub struct InferCtxtBuilder<'tcx> {
532554
tcx: TyCtxt<'tcx>,
533555
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
556+
defining_use_anchor: LocalDefId,
534557
}
535558

536559
pub trait TyCtxtInferExt<'tcx> {
@@ -539,15 +562,31 @@ pub trait TyCtxtInferExt<'tcx> {
539562

540563
impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
541564
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
542-
InferCtxtBuilder { tcx: self, fresh_typeck_results: None }
565+
InferCtxtBuilder {
566+
tcx: self,
567+
defining_use_anchor: CRATE_DEF_ID,
568+
fresh_typeck_results: None,
569+
}
543570
}
544571
}
545572

546573
impl<'tcx> InferCtxtBuilder<'tcx> {
547574
/// Used only by `rustc_typeck` during body type-checking/inference,
548575
/// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
576+
/// Will also change the scope for opaque type defining use checks to the given owner.
549577
pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
550578
self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
579+
self.with_opaque_type_inference(table_owner)
580+
}
581+
582+
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
583+
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
584+
///
585+
/// It is only meant to be called in two places, for typeck
586+
/// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
587+
/// in mir borrowck.
588+
pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
589+
self.defining_use_anchor = defining_use_anchor;
551590
self
552591
}
553592

@@ -575,10 +614,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
575614
}
576615

577616
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
578-
let InferCtxtBuilder { tcx, ref fresh_typeck_results } = *self;
617+
let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
579618
let in_progress_typeck_results = fresh_typeck_results.as_ref();
580619
f(InferCtxt {
581620
tcx,
621+
defining_use_anchor,
582622
in_progress_typeck_results,
583623
inner: RefCell::new(InferCtxtInner::new()),
584624
lexical_region_resolutions: RefCell::new(None),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use rustc_data_structures::vec_map::VecMap;
2+
use rustc_hir as hir;
3+
use rustc_middle::ty::{OpaqueTypeKey, Ty};
4+
use rustc_span::Span;
5+
6+
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
7+
8+
/// Information about the opaque types whose values we
9+
/// are inferring in this function (these are the `impl Trait` that
10+
/// appear in the return type).
11+
#[derive(Copy, Clone, Debug)]
12+
pub struct OpaqueTypeDecl<'tcx> {
13+
/// The opaque type (`ty::Opaque`) for this declaration.
14+
pub opaque_type: Ty<'tcx>,
15+
16+
/// The span of this particular definition of the opaque type. So
17+
/// for example:
18+
///
19+
/// ```ignore (incomplete snippet)
20+
/// type Foo = impl Baz;
21+
/// fn bar() -> Foo {
22+
/// // ^^^ This is the span we are looking for!
23+
/// }
24+
/// ```
25+
///
26+
/// In cases where the fn returns `(impl Trait, impl Trait)` or
27+
/// other such combinations, the result is currently
28+
/// over-approximated, but better than nothing.
29+
pub definition_span: Span,
30+
31+
/// The type variable that represents the value of the opaque type
32+
/// that we require. In other words, after we compile this function,
33+
/// we will be created a constraint like:
34+
///
35+
/// Foo<'a, T> = ?C
36+
///
37+
/// where `?C` is the value of this type variable. =) It may
38+
/// naturally refer to the type and lifetime parameters in scope
39+
/// in this function, though ultimately it should only reference
40+
/// those that are arguments to `Foo` in the constraint above. (In
41+
/// other words, `?C` should not include `'b`, even though it's a
42+
/// lifetime parameter on `foo`.)
43+
pub concrete_ty: Ty<'tcx>,
44+
45+
/// The origin of the opaque type.
46+
pub origin: hir::OpaqueTyOrigin,
47+
}

compiler/rustc_mir/src/borrow_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ fn mir_borrowck<'tcx>(
105105
let (input_body, promoted) = tcx.mir_promoted(def);
106106
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
107107

108-
let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
108+
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
109109
let input_body: &Body<'_> = &input_body.borrow();
110110
let promoted: &IndexVec<_, _> = &promoted.borrow();
111111
do_mir_borrowck(&infcx, input_body, promoted)

compiler/rustc_mir/src/borrow_check/type_check/mod.rs

+74-90
Original file line numberDiff line numberDiff line change
@@ -179,54 +179,55 @@ pub(crate) fn type_check<'mir, 'tcx>(
179179
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
180180

181181
translate_outlives_facts(&mut cx);
182-
let mut opaque_type_values = cx.opaque_type_values;
183-
184-
for (_, revealed_ty) in &mut opaque_type_values {
185-
*revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty);
186-
if revealed_ty.has_infer_types_or_consts() {
187-
infcx.tcx.sess.delay_span_bug(
188-
body.span,
189-
&format!("could not resolve {:#?}", revealed_ty.kind()),
190-
);
191-
*revealed_ty = infcx.tcx.ty_error();
192-
}
193-
}
194-
195-
opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
196-
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
197-
*def_id == opaque_type_key.def_id
198-
} else {
199-
false
200-
};
182+
let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
201183

202-
if concrete_is_opaque {
203-
// We're using an opaque `impl Trait` type without
204-
// 'revealing' it. For example, code like this:
205-
//
206-
// type Foo = impl Debug;
207-
// fn foo1() -> Foo { ... }
208-
// fn foo2() -> Foo { foo1() }
209-
//
210-
// In `foo2`, we're not revealing the type of `Foo` - we're
211-
// just treating it as the opaque type.
212-
//
213-
// When this occurs, we do *not* want to try to equate
214-
// the concrete type with the underlying defining type
215-
// of the opaque type - this will always fail, since
216-
// the defining type of an opaque type is always
217-
// some other type (e.g. not itself)
218-
// Essentially, none of the normal obligations apply here -
219-
// we're just passing around some unknown opaque type,
220-
// without actually looking at the underlying type it
221-
// gets 'revealed' into
222-
debug!(
223-
"eq_opaque_type_and_type: non-defining use of {:?}",
224-
opaque_type_key.def_id,
225-
);
226-
}
227-
!concrete_is_opaque
228-
});
229184
opaque_type_values
185+
.into_iter()
186+
.filter_map(|(opaque_type_key, decl)| {
187+
let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
188+
if revealed_ty.has_infer_types_or_consts() {
189+
infcx.tcx.sess.delay_span_bug(
190+
body.span,
191+
&format!("could not resolve {:#?}", revealed_ty.kind()),
192+
);
193+
revealed_ty = infcx.tcx.ty_error();
194+
}
195+
let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() {
196+
*def_id == opaque_type_key.def_id
197+
} else {
198+
false
199+
};
200+
201+
if concrete_is_opaque {
202+
// We're using an opaque `impl Trait` type without
203+
// 'revealing' it. For example, code like this:
204+
//
205+
// type Foo = impl Debug;
206+
// fn foo1() -> Foo { ... }
207+
// fn foo2() -> Foo { foo1() }
208+
//
209+
// In `foo2`, we're not revealing the type of `Foo` - we're
210+
// just treating it as the opaque type.
211+
//
212+
// When this occurs, we do *not* want to try to equate
213+
// the concrete type with the underlying defining type
214+
// of the opaque type - this will always fail, since
215+
// the defining type of an opaque type is always
216+
// some other type (e.g. not itself)
217+
// Essentially, none of the normal obligations apply here -
218+
// we're just passing around some unknown opaque type,
219+
// without actually looking at the underlying type it
220+
// gets 'revealed' into
221+
debug!(
222+
"eq_opaque_type_and_type: non-defining use of {:?}",
223+
opaque_type_key.def_id,
224+
);
225+
None
226+
} else {
227+
Some((opaque_type_key, revealed_ty))
228+
}
229+
})
230+
.collect()
230231
},
231232
);
232233

@@ -865,7 +866,6 @@ struct TypeChecker<'a, 'tcx> {
865866
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
866867
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
867868
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
868-
opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
869869
}
870870

871871
struct BorrowCheckContext<'a, 'tcx> {
@@ -1025,7 +1025,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10251025
borrowck_context,
10261026
reported_errors: Default::default(),
10271027
universal_region_relations,
1028-
opaque_type_values: VecMap::default(),
10291028
};
10301029
checker.check_user_type_annotations();
10311030
checker
@@ -1289,10 +1288,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12891288
let body = self.body;
12901289
let mir_def_id = body.source.def_id().expect_local();
12911290

1292-
let mut opaque_type_values = VecMap::new();
1293-
12941291
debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
1295-
let opaque_type_map = self.fully_perform_op(
1292+
self.fully_perform_op(
12961293
locations,
12971294
category,
12981295
CustomTypeOp::new(
@@ -1307,20 +1304,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13071304
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
13081305
// (Note that the key of the map is both the def-id of `Foo` along with
13091306
// any generic parameters.)
1310-
let (output_ty, opaque_type_map) =
1311-
obligations.add(infcx.instantiate_opaque_types(
1312-
mir_def_id,
1313-
dummy_body_id,
1314-
param_env,
1315-
anon_ty,
1316-
locations.span(body),
1317-
));
1307+
let output_ty = obligations.add(infcx.instantiate_opaque_types(
1308+
dummy_body_id,
1309+
param_env,
1310+
anon_ty,
1311+
locations.span(body),
1312+
));
13181313
debug!(
13191314
"eq_opaque_type_and_type: \
13201315
instantiated output_ty={:?} \
1321-
opaque_type_map={:#?} \
13221316
revealed_ty={:?}",
1323-
output_ty, opaque_type_map, revealed_ty
1317+
output_ty, revealed_ty
13241318
);
13251319

13261320
// Make sure that the inferred types are well-formed. I'm
@@ -1338,48 +1332,38 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13381332
.eq(output_ty, revealed_ty)?,
13391333
);
13401334

1341-
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
1342-
opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
1343-
}
1344-
13451335
debug!("eq_opaque_type_and_type: equated");
13461336

1347-
Ok(InferOk {
1348-
value: Some(opaque_type_map),
1349-
obligations: obligations.into_vec(),
1350-
})
1337+
Ok(InferOk { value: (), obligations: obligations.into_vec() })
13511338
},
13521339
|| "input_output".to_string(),
13531340
),
13541341
)?;
13551342

1356-
self.opaque_type_values.extend(opaque_type_values);
1357-
13581343
let universal_region_relations = self.universal_region_relations;
13591344

13601345
// Finally, if we instantiated the anon types successfully, we
13611346
// have to solve any bounds (e.g., `-> impl Iterator` needs to
13621347
// prove that `T: Iterator` where `T` is the type we
13631348
// instantiated it with).
1364-
if let Some(opaque_type_map) = opaque_type_map {
1365-
for (opaque_type_key, opaque_decl) in opaque_type_map {
1366-
self.fully_perform_op(
1367-
locations,
1368-
ConstraintCategory::OpaqueType,
1369-
CustomTypeOp::new(
1370-
|infcx| {
1371-
infcx.constrain_opaque_type(
1372-
opaque_type_key,
1373-
&opaque_decl,
1374-
GenerateMemberConstraints::IfNoStaticBound,
1375-
universal_region_relations,
1376-
);
1377-
Ok(InferOk { value: (), obligations: vec![] })
1378-
},
1379-
|| "opaque_type_map".to_string(),
1380-
),
1381-
)?;
1382-
}
1349+
let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
1350+
for (opaque_type_key, opaque_decl) in opaque_type_map {
1351+
self.fully_perform_op(
1352+
locations,
1353+
ConstraintCategory::OpaqueType,
1354+
CustomTypeOp::new(
1355+
|infcx| {
1356+
infcx.constrain_opaque_type(
1357+
opaque_type_key,
1358+
&opaque_decl,
1359+
GenerateMemberConstraints::IfNoStaticBound,
1360+
universal_region_relations,
1361+
);
1362+
Ok(InferOk { value: (), obligations: vec![] })
1363+
},
1364+
|| "opaque_type_map".to_string(),
1365+
),
1366+
)?;
13831367
}
13841368
Ok(())
13851369
}

0 commit comments

Comments
 (0)