Skip to content

Commit 20371b9

Browse files
committed
Immediately register new opaque types in the global list.
Previously each opaque type instantiation would create new inference vars, even for the same opaque type/substs combination. Now there is a global map in InferCtxt that gets filled whenever we encounter an opaque type.
1 parent 816b9fc commit 20371b9

File tree

9 files changed

+107
-119
lines changed

9 files changed

+107
-119
lines changed

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

Lines changed: 58 additions & 68 deletions
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-
}
182+
let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
194183

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-
};
201-
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,18 @@ 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+
mir_def_id,
1309+
dummy_body_id,
1310+
param_env,
1311+
anon_ty,
1312+
locations.span(body),
1313+
));
13181314
debug!(
13191315
"eq_opaque_type_and_type: \
13201316
instantiated output_ty={:?} \
1321-
opaque_type_map={:#?} \
13221317
revealed_ty={:?}",
1323-
output_ty, opaque_type_map, revealed_ty
1318+
output_ty, revealed_ty
13241319
);
13251320

13261321
// Make sure that the inferred types are well-formed. I'm
@@ -1338,26 +1333,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13381333
.eq(output_ty, revealed_ty)?,
13391334
);
13401335

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-
13451336
debug!("eq_opaque_type_and_type: equated");
13461337

1347-
Ok(InferOk { value: opaque_type_map, obligations: obligations.into_vec() })
1338+
Ok(InferOk { value: (), obligations: obligations.into_vec() })
13481339
},
13491340
|| "input_output".to_string(),
13501341
),
13511342
)?;
13521343

1353-
self.opaque_type_values.extend(opaque_type_values);
1354-
13551344
let universal_region_relations = self.universal_region_relations;
13561345

13571346
// Finally, if we instantiated the anon types successfully, we
13581347
// have to solve any bounds (e.g., `-> impl Iterator` needs to
13591348
// prove that `T: Iterator` where `T` is the type we
13601349
// instantiated it with).
1350+
let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
13611351
for (opaque_type_key, opaque_decl) in opaque_type_map {
13621352
self.fully_perform_op(
13631353
locations,

compiler/rustc_trait_selection/src/opaque_types.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hir as hir;
66
use rustc_hir::def_id::{DefId, LocalDefId};
77
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
88
use rustc_infer::infer::free_regions::FreeRegionRelations;
9-
use rustc_infer::infer::opaque_types::{OpaqueTypeDecl, OpaqueTypeMap};
9+
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
1010
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1111
use rustc_infer::infer::{self, InferCtxt, InferOk};
1212
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
@@ -37,7 +37,7 @@ pub trait InferCtxtExt<'tcx> {
3737
param_env: ty::ParamEnv<'tcx>,
3838
value: T,
3939
value_span: Span,
40-
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>;
40+
) -> InferOk<'tcx, T>;
4141

4242
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
4343

@@ -99,7 +99,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
9999
param_env: ty::ParamEnv<'tcx>,
100100
value: T,
101101
value_span: Span,
102-
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
102+
) -> InferOk<'tcx, T> {
103103
debug!(
104104
"instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
105105
param_env={:?}, value_span={:?})",
@@ -111,11 +111,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
111111
body_id,
112112
param_env,
113113
value_span,
114-
opaque_types: Default::default(),
115114
obligations: vec![],
116115
};
117116
let value = instantiator.instantiate_opaque_types_in_map(value);
118-
InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations }
117+
InferOk { value, obligations: instantiator.obligations }
119118
}
120119

121120
/// Given the map `opaque_types` containing the opaque
@@ -862,7 +861,6 @@ struct Instantiator<'a, 'tcx> {
862861
body_id: hir::HirId,
863862
param_env: ty::ParamEnv<'tcx>,
864863
value_span: Span,
865-
opaque_types: OpaqueTypeMap<'tcx>,
866864
obligations: Vec<PredicateObligation<'tcx>>,
867865
}
868866

@@ -972,7 +970,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
972970

973971
// Use the same type variable if the exact same opaque type appears more
974972
// than once in the return type (e.g., if it's passed to a type alias).
975-
if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) {
973+
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
976974
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
977975
return opaque_defn.concrete_ty;
978976
}
@@ -994,10 +992,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
994992
// Foo, impl Bar)`.
995993
let definition_span = self.value_span;
996994

997-
self.opaque_types.insert(
998-
OpaqueTypeKey { def_id, substs },
999-
OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
1000-
);
995+
{
996+
let mut infcx = self.infcx.inner.borrow_mut();
997+
infcx.opaque_types.insert(
998+
OpaqueTypeKey { def_id, substs },
999+
OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
1000+
);
1001+
infcx.opaque_types_vars.insert(ty_var, ty);
1002+
}
1003+
10011004
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
10021005
self.compute_opaque_type_obligations(opaque_type_key, span);
10031006

compiler/rustc_typeck/src/check/_match.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
598598
{
599599
let impl_trait_ret_ty =
600600
self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span);
601-
let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
602-
for o in impl_trait_ret_ty.obligations {
601+
assert!(
602+
impl_trait_ret_ty.obligations.is_empty(),
603+
"we should never get new obligations here"
604+
);
605+
let obligations = self.fulfillment_cx.borrow().pending_obligations();
606+
let mut suggest_box = !obligations.is_empty();
607+
for o in obligations {
603608
match o.predicate.kind().skip_binder() {
604609
ty::PredicateKind::Trait(t, constness) => {
605610
let pred = ty::PredicateKind::Trait(

compiler/rustc_typeck/src/check/check.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,10 +650,11 @@ fn check_opaque_meets_bounds<'tcx>(
650650

651651
let misc_cause = traits::ObligationCause::misc(span, hir_id);
652652

653-
let (_, opaque_type_map) = inh.register_infer_ok_obligations(
653+
let _ = inh.register_infer_ok_obligations(
654654
infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
655655
);
656656

657+
let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
657658
for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
658659
match infcx
659660
.at(&misc_cause, param_env)

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -374,23 +374,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
374374
parent_def_id, value
375375
);
376376

377-
let (value, opaque_type_map) =
378-
self.register_infer_ok_obligations(self.instantiate_opaque_types(
379-
parent_def_id,
380-
self.body_id,
381-
self.param_env,
382-
value,
383-
value_span,
384-
));
385-
386-
let mut infcx = self.infcx.inner.borrow_mut();
387-
388-
for (ty, decl) in opaque_type_map {
389-
let _ = infcx.opaque_types.insert(ty, decl);
390-
let _ = infcx.opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
391-
}
392-
393-
value
377+
self.register_infer_ok_obligations(self.instantiate_opaque_types(
378+
parent_def_id,
379+
self.body_id,
380+
self.param_env,
381+
value,
382+
value_span,
383+
))
394384
}
395385

396386
/// Convenience method which tracks extra diagnostic information for normalization

src/test/ui/type-alias-impl-trait/issue-63279.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
#![feature(type_alias_impl_trait)]
44

5-
type Closure = impl FnOnce(); //~ ERROR: type mismatch resolving
5+
type Closure = impl FnOnce();
66

77
fn c() -> Closure {
8-
|| -> Closure { || () }
8+
|| -> Closure { || () } //~ ERROR: mismatched types
99
}
1010

1111
fn main() {}
Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as FnOnce<()>>::Output == ()`
2-
--> $DIR/issue-63279.rs:5:16
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-63279.rs:8:5
33
|
44
LL | type Closure = impl FnOnce();
5-
| ^^^^^^^^^^^^^ expected `()`, found opaque type
5+
| ------------- the found opaque type
6+
...
7+
LL | || -> Closure { || () }
8+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
69
|
7-
= note: expected unit type `()`
8-
found opaque type `impl FnOnce<()>`
10+
= note: expected type `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
11+
found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]`
12+
= note: no two closures, even if identical, have the same type
13+
= help: consider boxing your closure and/or using it as a trait object
914

1015
error: aborting due to previous error
1116

12-
For more information about this error, try `rustc --explain E0271`.
17+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/type-alias-impl-trait/issue-74280.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ type Test = impl Copy;
66

77
fn test() -> Test {
88
let y = || -> Test { () };
9-
//~^ ERROR: concrete type differs from previous defining opaque type use
10-
7
9+
7 //~ ERROR mismatched types
1110
}
1211

1312
fn main() {}
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/issue-74280.rs:8:13
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-74280.rs:9:5
33
|
4-
LL | let y = || -> Test { () };
5-
| ^^^^^^^^^^^^^^^^^ expected `i32`, got `()`
6-
|
7-
note: previous use here
8-
--> $DIR/issue-74280.rs:7:1
9-
|
10-
LL | fn test() -> Test {
11-
| ^^^^^^^^^^^^^^^^^
4+
LL | 7
5+
| ^ expected `()`, found integer
126

137
error: aborting due to previous error
148

9+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)