Skip to content

Commit 75d9ed7

Browse files
committed
Make mir borrowck's use of opaque types independent of the typeck query's result
1 parent b9b0a5e commit 75d9ed7

20 files changed

+162
-261
lines changed

compiler/rustc_data_structures/src/vec_map.rs

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ where
7070
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
7171
self.into_iter()
7272
}
73+
74+
pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) {
75+
self.0.retain(f)
76+
}
7377
}
7478

7579
impl<K, V> Default for VecMap<K, V> {

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

+62-87
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_middle::mir::*;
2626
use rustc_middle::ty::adjustment::PointerCast;
2727
use rustc_middle::ty::cast::CastTy;
2828
use rustc_middle::ty::fold::TypeFoldable;
29-
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
29+
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
3030
use rustc_middle::ty::{
3131
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
3232
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
@@ -60,7 +60,6 @@ use crate::borrow_check::{
6060
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
6161
},
6262
region_infer::{ClosureRegionRequirementsExt, TypeTest},
63-
renumber,
6463
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
6564
universal_regions::{DefiningTy, UniversalRegions},
6665
Upvar,
@@ -180,7 +179,66 @@ pub(crate) fn type_check<'mir, 'tcx>(
180179
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
181180

182181
translate_outlives_facts(&mut cx);
183-
cx.opaque_type_values
182+
let mut opaque_type_values = cx.opaque_type_values;
183+
184+
for (_, revealed_ty) in &mut opaque_type_values {
185+
// FIXME(oli-obk): Instead of looping, implement a visitor like
186+
// FullTypeResolver. We can't use FullTypeResolver here, as that will
187+
// resolve lifetimes lexically, which it can't because we didn't do old
188+
// borrowck stuff. We want to use MIR borrowck information instead.
189+
190+
while revealed_ty.has_infer_types_or_consts() {
191+
let prev = *revealed_ty;
192+
trace!(prev=?prev.kind());
193+
let type_resolved = infcx.shallow_resolve(prev);
194+
trace!(type_resolved=?type_resolved.kind());
195+
if prev == type_resolved {
196+
infcx.tcx.sess.delay_span_bug(
197+
body.span,
198+
&format!("could not resolve {:#?}", type_resolved.kind()),
199+
);
200+
*revealed_ty = infcx.tcx.ty_error();
201+
break;
202+
}
203+
*revealed_ty = type_resolved;
204+
}
205+
}
206+
207+
opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
208+
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
209+
*def_id == opaque_type_key.def_id
210+
} else {
211+
false
212+
};
213+
214+
if concrete_is_opaque {
215+
// We're using an opaque `impl Trait` type without
216+
// 'revealing' it. For example, code like this:
217+
//
218+
// type Foo = impl Debug;
219+
// fn foo1() -> Foo { ... }
220+
// fn foo2() -> Foo { foo1() }
221+
//
222+
// In `foo2`, we're not revealing the type of `Foo` - we're
223+
// just treating it as the opaque type.
224+
//
225+
// When this occurs, we do *not* want to try to equate
226+
// the concrete type with the underlying defining type
227+
// of the opaque type - this will always fail, since
228+
// the defining type of an opaque type is always
229+
// some other type (e.g. not itself)
230+
// Essentially, none of the normal obligations apply here -
231+
// we're just passing around some unknown opaque type,
232+
// without actually looking at the underlying type it
233+
// gets 'revealed' into
234+
debug!(
235+
"eq_opaque_type_and_type: non-defining use of {:?}",
236+
opaque_type_key.def_id,
237+
);
238+
}
239+
!concrete_is_opaque
240+
});
241+
opaque_type_values
184242
},
185243
);
186244

@@ -1240,13 +1298,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12401298
}
12411299

12421300
let infcx = self.infcx;
1243-
let tcx = infcx.tcx;
12441301
let param_env = self.param_env;
12451302
let body = self.body;
12461303
let mir_def_id = body.source.def_id().expect_local();
12471304

1248-
// the "concrete opaque types" maps
1249-
let concrete_opaque_types = &tcx.typeck(mir_def_id).concrete_opaque_types;
12501305
let mut opaque_type_values = VecMap::new();
12511306

12521307
debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
@@ -1296,88 +1351,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12961351
.eq(output_ty, revealed_ty)?,
12971352
);
12981353

1299-
// For each opaque type `Foo<T>` inferred by this value, we want to equate
1300-
// the inference variable `?T` with the revealed type that was computed
1301-
// earlier by type check.
13021354
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
1303-
let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
1304-
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
1305-
*def_id == opaque_type_key.def_id
1306-
} else {
1307-
false
1308-
};
1309-
1310-
// The revealed type computed by the earlier phase of type check.
1311-
// In our example, this would be `(U, u32)`. Note that this references
1312-
// the type parameter `U` from the definition of `Foo`.
1313-
let concrete_ty = match concrete_opaque_types
1314-
.get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
1315-
{
1316-
None => {
1317-
if !concrete_is_opaque {
1318-
tcx.sess.delay_span_bug(
1319-
body.span,
1320-
&format!(
1321-
"Non-defining use of {:?} with revealed type",
1322-
opaque_type_key.def_id,
1323-
),
1324-
);
1325-
}
1326-
continue;
1327-
}
1328-
Some(concrete_ty) => concrete_ty,
1329-
};
1330-
debug!("concrete_ty = {:?}", concrete_ty);
1331-
1332-
// Apply the substitution, in this case `[U -> T]`, so that the
1333-
// concrete type becomes `Foo<(T, u32)>`
1334-
let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
1335-
1336-
// "Renumber" this, meaning that we replace all the regions
1337-
// with fresh inference variables. Not relevant to our example.
1338-
let renumbered_opaque_defn_ty =
1339-
renumber::renumber_regions(infcx, subst_opaque_defn_ty);
1340-
1341-
debug!(
1342-
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
1343-
concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
1344-
);
1345-
1346-
if !concrete_is_opaque {
1347-
// Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`,
1348-
// in our example) with the renumbered version that we took from
1349-
// the type check results (`Foo<(T, u32)>`).
1350-
obligations.add(
1351-
infcx
1352-
.at(&ObligationCause::dummy(), param_env)
1353-
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
1354-
);
1355-
opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty);
1356-
} else {
1357-
// We're using an opaque `impl Trait` type without
1358-
// 'revealing' it. For example, code like this:
1359-
//
1360-
// type Foo = impl Debug;
1361-
// fn foo1() -> Foo { ... }
1362-
// fn foo2() -> Foo { foo1() }
1363-
//
1364-
// In `foo2`, we're not revealing the type of `Foo` - we're
1365-
// just treating it as the opaque type.
1366-
//
1367-
// When this occurs, we do *not* want to try to equate
1368-
// the concrete type with the underlying defining type
1369-
// of the opaque type - this will always fail, since
1370-
// the defining type of an opaque type is always
1371-
// some other type (e.g. not itself)
1372-
// Essentially, none of the normal obligations apply here -
1373-
// we're just passing around some unknown opaque type,
1374-
// without actually looking at the underlying type it
1375-
// gets 'revealed' into
1376-
debug!(
1377-
"eq_opaque_type_and_type: non-defining use of {:?}",
1378-
opaque_type_key.def_id,
1379-
);
1380-
}
1355+
opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
13811356
}
13821357

13831358
debug!("eq_opaque_type_and_type: equated");

src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ impl Bar for AssocNoCopy {
2929
impl Thing for AssocNoCopy {
3030
type Out = Box<dyn Bar<Assoc: Copy>>;
3131
//~^ ERROR the trait bound `String: Copy` is not satisfied
32-
//~| ERROR the trait bound `String: Copy` is not satisfied
3332

3433
fn func() -> Self::Out {
3534
Box::new(AssocNoCopy)

src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
44
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
55
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
66

7-
error[E0277]: the trait bound `String: Copy` is not satisfied
8-
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
9-
|
10-
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
11-
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
12-
13-
error: aborting due to 2 previous errors
7+
error: aborting due to previous error
148

159
For more information about this error, try `rustc --explain E0277`.

src/test/ui/impl-trait/auto-trait-leak.rs

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ fn main() {
1212
fn cycle1() -> impl Clone {
1313
//~^ ERROR cycle detected
1414
send(cycle2().clone());
15-
//~^ ERROR cannot be sent between threads safely
1615

1716
Rc::new(Cell::new(5))
1817
}

src/test/ui/impl-trait/auto-trait-leak.stderr

+9-25
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone {
3636
| ^^^^^^^^^^^^^^^^^^^^^^^^^
3737
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
3838
note: ...which requires computing type of `cycle2::{opaque#0}`...
39-
--> $DIR/auto-trait-leak.rs:20:16
39+
--> $DIR/auto-trait-leak.rs:19:16
4040
|
4141
LL | fn cycle2() -> impl Clone {
4242
| ^^^^^^^^^^
4343
note: ...which requires borrow-checking `cycle2`...
44-
--> $DIR/auto-trait-leak.rs:20:1
44+
--> $DIR/auto-trait-leak.rs:19:1
4545
|
4646
LL | fn cycle2() -> impl Clone {
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4848
note: ...which requires processing `cycle2`...
49-
--> $DIR/auto-trait-leak.rs:20:1
49+
--> $DIR/auto-trait-leak.rs:19:1
5050
|
5151
LL | fn cycle2() -> impl Clone {
5252
| ^^^^^^^^^^^^^^^^^^^^^^^^^
5353
note: ...which requires processing MIR for `cycle2`...
54-
--> $DIR/auto-trait-leak.rs:20:1
54+
--> $DIR/auto-trait-leak.rs:19:1
5555
|
5656
LL | fn cycle2() -> impl Clone {
5757
| ^^^^^^^^^^^^^^^^^^^^^^^^^
5858
note: ...which requires unsafety-checking `cycle2`...
59-
--> $DIR/auto-trait-leak.rs:20:1
59+
--> $DIR/auto-trait-leak.rs:19:1
6060
|
6161
LL | fn cycle2() -> impl Clone {
6262
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6363
note: ...which requires building MIR for `cycle2`...
64-
--> $DIR/auto-trait-leak.rs:20:1
64+
--> $DIR/auto-trait-leak.rs:19:1
6565
|
6666
LL | fn cycle2() -> impl Clone {
6767
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6868
note: ...which requires type-checking `cycle2`...
69-
--> $DIR/auto-trait-leak.rs:20:1
69+
--> $DIR/auto-trait-leak.rs:19:1
7070
|
7171
LL | fn cycle2() -> impl Clone {
7272
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,22 +84,6 @@ LL | | Rc::new(String::from("foo"))
8484
LL | | }
8585
| |_^
8686

87-
error[E0277]: `Rc<String>` cannot be sent between threads safely
88-
--> $DIR/auto-trait-leak.rs:14:5
89-
|
90-
LL | fn send<T: Send>(_: T) {}
91-
| ---- required by this bound in `send`
92-
...
93-
LL | send(cycle2().clone());
94-
| ^^^^ `Rc<String>` cannot be sent between threads safely
95-
...
96-
LL | fn cycle2() -> impl Clone {
97-
| ---------- within this `impl Clone`
98-
|
99-
= help: within `impl Clone`, the trait `Send` is not implemented for `Rc<String>`
100-
= note: required because it appears within the type `impl Clone`
101-
102-
error: aborting due to 2 previous errors
87+
error: aborting due to previous error
10388

104-
Some errors have detailed explanations: E0277, E0391.
105-
For more information about an error, try `rustc --explain E0277`.
89+
For more information about this error, try `rustc --explain E0391`.

src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr

+1-10
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,7 @@ LL | type WrongGeneric<T> = impl 'static;
3636
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
3737
| - help: consider adding an explicit lifetime bound...: `T: 'static`
3838

39-
error[E0310]: the parameter type `T` may not live long enough
40-
--> $DIR/generic_type_does_not_live_long_enough.rs:12:24
41-
|
42-
LL | type WrongGeneric<T> = impl 'static;
43-
| ^^^^^^^^^^^^
44-
|
45-
= help: consider adding an explicit lifetime bound `T: 'static`...
46-
= note: ...so that the type `T` will meet its required lifetime bounds
47-
48-
error: aborting due to 4 previous errors; 1 warning emitted
39+
error: aborting due to 3 previous errors; 1 warning emitted
4940

5041
Some errors have detailed explanations: E0308, E0310.
5142
For more information about an error, try `rustc --explain E0308`.

src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr

+1-10
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,7 @@ LL | type WrongGeneric<T> = impl 'static;
2727
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
2828
| - help: consider adding an explicit lifetime bound...: `T: 'static`
2929

30-
error[E0310]: the parameter type `T` may not live long enough
31-
--> $DIR/generic_type_does_not_live_long_enough.rs:12:24
32-
|
33-
LL | type WrongGeneric<T> = impl 'static;
34-
| ^^^^^^^^^^^^
35-
|
36-
= help: consider adding an explicit lifetime bound `T: 'static`...
37-
= note: ...so that the type `T` will meet its required lifetime bounds
38-
39-
error: aborting due to 4 previous errors
30+
error: aborting due to 3 previous errors
4031

4132
Some errors have detailed explanations: E0308, E0310.
4233
For more information about an error, try `rustc --explain E0308`.

src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ fn main() {
1111

1212
type WrongGeneric<T> = impl 'static;
1313
//~^ ERROR the parameter type `T` may not live long enough
14-
//~| ERROR the parameter type `T` may not live long enough
1514
//~| ERROR: at least one trait must be specified
1615

1716
fn wrong_generic<T>(t: T) -> WrongGeneric<T> {

src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr

+1-48
Original file line numberDiff line numberDiff line change
@@ -16,52 +16,5 @@ LL | type Bar = impl Baz<Self, Self>;
1616
= note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
1717
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
1818

19-
error[E0308]: mismatched types
20-
--> $DIR/issue-57611-trait-alias.rs:20:16
21-
|
22-
LL | type Bar = impl Baz<Self, Self>;
23-
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
24-
|
25-
= note: expected type `for<'r> Fn<(&'r X,)>`
26-
found type `Fn<(&'<empty> X,)>`
27-
note: this closure does not fulfill the lifetime requirements
28-
--> $DIR/issue-57611-trait-alias.rs:28:9
29-
|
30-
LL | |x| x
31-
| ^^^^^
32-
33-
error: implementation of `FnOnce` is not general enough
34-
--> $DIR/issue-57611-trait-alias.rs:20:16
35-
|
36-
LL | type Bar = impl Baz<Self, Self>;
37-
| ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
38-
|
39-
= note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
40-
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
41-
42-
error[E0308]: mismatched types
43-
--> $DIR/issue-57611-trait-alias.rs:20:16
44-
|
45-
LL | type Bar = impl Baz<Self, Self>;
46-
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
47-
|
48-
= note: expected type `for<'r> Fn<(&'r X,)>`
49-
found type `Fn<(&'<empty> X,)>`
50-
note: this closure does not fulfill the lifetime requirements
51-
--> $DIR/issue-57611-trait-alias.rs:28:9
52-
|
53-
LL | |x| x
54-
| ^^^^^
55-
56-
error: implementation of `FnOnce` is not general enough
57-
--> $DIR/issue-57611-trait-alias.rs:20:16
58-
|
59-
LL | type Bar = impl Baz<Self, Self>;
60-
| ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
61-
|
62-
= note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
63-
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
64-
65-
error: aborting due to 5 previous errors; 1 warning emitted
19+
error: aborting due to previous error; 1 warning emitted
6620

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

0 commit comments

Comments
 (0)