Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

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)