Skip to content

Commit 7e439ab

Browse files
committed
Make HR trait object conversions a coercion
1 parent 3e53337 commit 7e439ab

14 files changed

Lines changed: 116 additions & 200 deletions

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,57 +1055,99 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10551055
(&ty::Dynamic(data_a, r_a), &ty::Dynamic(data_b, r_b)) => {
10561056
// See `assemble_candidates_for_unsizing` for more info.
10571057
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
1058-
let existential_predicates = if data_b.principal().is_some() {
1059-
tcx.mk_poly_existential_predicates_from_iter(
1060-
data_a
1061-
.principal()
1062-
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
1063-
.into_iter()
1064-
.chain(
1065-
data_a
1066-
.projection_bounds()
1067-
.map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
1058+
if let Some(hr_target_principal) = data_b.principal() {
1059+
let hr_source_principal = data_a.principal().unwrap_or_else(|| {
1060+
span_bug!(obligation.cause.span, "unsizing to an object with no principal")
1061+
});
1062+
let mut obligations = self
1063+
.infcx
1064+
.enter_forall(hr_target_principal, |target_principal| {
1065+
let source_principal = self.infcx.instantiate_binder_with_fresh_vars(
1066+
obligation.cause.span,
1067+
BoundRegionConversionTime::HigherRankedType,
1068+
hr_source_principal,
1069+
);
1070+
self.infcx.at(&obligation.cause, obligation.param_env).eq(
1071+
DefineOpaqueTypes::Yes,
1072+
target_principal,
1073+
source_principal,
10681074
)
1069-
.chain(
1070-
data_b
1071-
.auto_traits()
1072-
.map(ty::ExistentialPredicate::AutoTrait)
1073-
.map(ty::Binder::dummy),
1074-
),
1075-
)
1075+
})
1076+
.map_err(|_| SelectionError::Unimplemented)?
1077+
.into_obligations();
1078+
1079+
debug_assert_eq!(
1080+
data_a.projection_bounds().count(),
1081+
data_b.projection_bounds().count(),
1082+
"source and target object types have a different number of projection bounds",
1083+
);
1084+
for (hr_source_projection, hr_target_projection) in
1085+
data_a.projection_bounds().zip(data_b.projection_bounds())
1086+
{
1087+
obligations.extend(
1088+
self.infcx
1089+
.enter_forall(hr_target_projection, |target_projection| {
1090+
let source_projection =
1091+
self.infcx.instantiate_binder_with_fresh_vars(
1092+
obligation.cause.span,
1093+
BoundRegionConversionTime::HigherRankedType,
1094+
hr_source_projection,
1095+
);
1096+
self.infcx.at(&obligation.cause, obligation.param_env).eq(
1097+
DefineOpaqueTypes::Yes,
1098+
target_projection,
1099+
source_projection,
1100+
)
1101+
})
1102+
.map_err(|_| SelectionError::Unimplemented)?
1103+
.into_obligations(),
1104+
);
1105+
}
1106+
1107+
// Register one obligation for 'a: 'b.
1108+
let outlives = ty::OutlivesPredicate(r_a, r_b);
1109+
obligations.push(Obligation::with_depth(
1110+
tcx,
1111+
obligation.cause.clone(),
1112+
obligation.recursion_depth + 1,
1113+
obligation.param_env,
1114+
obligation.predicate.rebind(outlives),
1115+
));
1116+
1117+
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
10761118
} else {
10771119
// If we're unsizing to a dyn type that has no principal, then drop
10781120
// the principal and projections from the type. We use the auto traits
10791121
// from the RHS type since as we noted that we've checked for auto
10801122
// trait compatibility during unsizing.
1081-
tcx.mk_poly_existential_predicates_from_iter(
1123+
let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(
10821124
data_b
10831125
.auto_traits()
10841126
.map(ty::ExistentialPredicate::AutoTrait)
10851127
.map(ty::Binder::dummy),
1086-
)
1087-
};
1088-
let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b);
1089-
1090-
// Require that the traits involved in this upcast are **equal**;
1091-
// only the **lifetime bound** is changed.
1092-
let InferOk { mut obligations, .. } = self
1093-
.infcx
1094-
.at(&obligation.cause, obligation.param_env)
1095-
.sup(DefineOpaqueTypes::Yes, target, source_trait)
1096-
.map_err(|_| SelectionError::Unimplemented)?;
1097-
1098-
// Register one obligation for 'a: 'b.
1099-
let outlives = ty::OutlivesPredicate(r_a, r_b);
1100-
obligations.push(Obligation::with_depth(
1101-
tcx,
1102-
obligation.cause.clone(),
1103-
obligation.recursion_depth + 1,
1104-
obligation.param_env,
1105-
obligation.predicate.rebind(outlives),
1106-
));
1128+
);
1129+
let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b);
1130+
1131+
// Require that the traits involved in this upcast are **equal**;
1132+
// only the **lifetime bound** is changed.
1133+
let InferOk { mut obligations, .. } = self
1134+
.infcx
1135+
.at(&obligation.cause, obligation.param_env)
1136+
.sup(DefineOpaqueTypes::Yes, target, source_trait)
1137+
.map_err(|_| SelectionError::Unimplemented)?;
1138+
1139+
// Register one obligation for 'a: 'b.
1140+
let outlives = ty::OutlivesPredicate(r_a, r_b);
1141+
obligations.push(Obligation::with_depth(
1142+
tcx,
1143+
obligation.cause.clone(),
1144+
obligation.recursion_depth + 1,
1145+
obligation.param_env,
1146+
obligation.predicate.rebind(outlives),
1147+
));
11071148

1108-
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
1149+
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
1150+
}
11091151
}
11101152

11111153
// `T` -> `dyn Trait`

tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ error[E0308]: mismatched types
107107
LL | x as _
108108
| ^^^^^^ one type is more general than the other
109109
|
110-
= note: expected trait object `dyn for<'b> Trait<'b>`
111-
found trait object `dyn Trait<'_>`
110+
= note: expected existential trait ref `for<'b> Trait<'b>`
111+
found existential trait ref `Trait<'_>`
112112

113113
error: lifetime may not live long enough
114114
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5

tests/ui/cast/ptr-to-trait-obj-ok.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
//@ known-bug: unknown
2-
31
// Casting pointers to object types has some special rules in order to
42
// ensure VTables stay valid. E.g.
53
// - Cannot introduce new autotraits
64
// - Cannot extend or shrink lifetimes in trait arguments
75
// - Cannot extend the lifetime of the object type
86
//
97
// This test is a mostly miscellaneous set of examples of casts that do
10-
// uphold these rules
8+
// uphold these rules.
9+
//
10+
// FIXME(higher-ranked-coercions): `cast_away_higher_ranked_wrap` below
11+
// regressed when higher-ranked subtyping was removed: casting away a
12+
// higher-ranked principal through a (non-coercion) wrapped raw-pointer cast no
13+
// longer type-checks. This is entangled with the raw-pointer-cast lifetime rules
14+
// of #141402 and is left as a follow-up; the conversion still works for the
15+
// unwrapped case (`cast_away_higher_ranked`) via an unsizing coercion.
1116

1217
trait Trait<'a> {}
1318

@@ -52,6 +57,8 @@ fn cast_inherent_lt_wrap<'a: 'b, 'b>(
5257

5358
fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper<dyn Trait<'a>> {
5459
x as _
60+
//~^ ERROR lifetime may not live long enough
61+
//~| ERROR mismatched types
5562
}
5663

5764
fn unprincipled_wrap<'a: 'b, 'b>(x: *mut (dyn Send + 'a)) -> *mut Wrapper<dyn Sync + 'b> {
Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/ptr-to-trait-obj-ok.rs:25:5
3-
|
4-
LL | fn cast_away_higher_ranked<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut dyn Trait<'a> {
5-
| -- lifetime `'a` defined here
6-
LL | x as _
7-
| ^^^^^^ returning this value requires that `'a` must outlive `'static`
8-
|
9-
= note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
10-
= note: mutable pointers are invariant over their type parameter
11-
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
12-
note: raw pointer casts of trait objects cannot extend lifetimes
13-
--> $DIR/ptr-to-trait-obj-ok.rs:25:5
14-
|
15-
LL | x as _
16-
| ^^^^^^
17-
= note: this was previously accepted by the compiler but was changed recently
18-
= help: see <https://github.com/rust-lang/rust/issues/141402> for more information
19-
20-
error[E0308]: mismatched types
21-
--> $DIR/ptr-to-trait-obj-ok.rs:25:5
22-
|
23-
LL | x as _
24-
| ^^^^^^ one type is more general than the other
25-
|
26-
= note: expected trait object `dyn Trait<'_>`
27-
found trait object `dyn for<'b> Trait<'b>`
28-
29-
error: lifetime may not live long enough
30-
--> $DIR/ptr-to-trait-obj-ok.rs:54:5
2+
--> $DIR/ptr-to-trait-obj-ok.rs:59:5
313
|
324
LL | fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper<dyn Trait<'a>> {
335
| -- lifetime `'a` defined here
@@ -38,22 +10,22 @@ LL | x as _
3810
= note: mutable pointers are invariant over their type parameter
3911
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
4012
note: raw pointer casts of trait objects cannot extend lifetimes
41-
--> $DIR/ptr-to-trait-obj-ok.rs:54:5
13+
--> $DIR/ptr-to-trait-obj-ok.rs:59:5
4214
|
4315
LL | x as _
4416
| ^^^^^^
4517
= note: this was previously accepted by the compiler but was changed recently
4618
= help: see <https://github.com/rust-lang/rust/issues/141402> for more information
4719

4820
error[E0308]: mismatched types
49-
--> $DIR/ptr-to-trait-obj-ok.rs:54:5
21+
--> $DIR/ptr-to-trait-obj-ok.rs:59:5
5022
|
5123
LL | x as _
5224
| ^^^^^^ one type is more general than the other
5325
|
5426
= note: expected trait object `dyn Trait<'_>`
5527
found trait object `dyn for<'b> Trait<'b>`
5628

57-
error: aborting due to 4 previous errors
29+
error: aborting due to 2 previous errors
5830

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

tests/ui/closures/closure-to-fn-pointer-lifetime-error.stderr

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@ error[E0308]: mismatched types
44
LL | foo(bar);
55
| ^^^ one type is more general than the other
66
|
7-
= note: expected trait object `dyn for<'a> Fn(&'a i32)`
8-
found trait object `dyn Fn(&i32)`
7+
= note: expected existential trait ref `for<'a> Fn<(&'a i32,)>`
8+
found existential trait ref `Fn<(&i32,)>`
99

1010
error[E0308]: mismatched types
1111
--> $DIR/closure-to-fn-pointer-lifetime-error.rs:8:9
1212
|
1313
LL | foo(bar);
1414
| ^^^ one type is more general than the other
1515
|
16-
= note: expected trait object `dyn for<'a> Fn(&'a i32)`
17-
found trait object `dyn Fn(&i32)`
18-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
16+
= note: expected existential projection `for<'a> Output = ()`
17+
found existential projection `Output = ()`
1918

2019
error: aborting due to 2 previous errors
2120

tests/ui/codegen/sub-principals-in-codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ known-bug: unknown
1+
//@ build-pass
22

33
// Regression test for an overly aggressive assertion in #130855.
44

tests/ui/codegen/sub-principals-in-codegen.stderr

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/ui/coercion/sub-principals.current.stderr

Lines changed: 0 additions & 50 deletions
This file was deleted.

tests/ui/coercion/sub-principals.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
//@ check-pass
12
//@ revisions: current next
2-
//@[next] check-pass
3-
//@[current] known-bug: unknown
43
//@ ignore-compare-mode-next-solver (explicit revisions)
54
//@[next] compile-flags: -Znext-solver
65

tests/ui/lub-glb/old-lub-glb-object.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//@ known-bug: unknown
21
// Test that we give a note when the old LUB/GLB algorithm would have
32
// succeeded but the new code (which is stricter) gives an error.
43

@@ -8,6 +7,8 @@ fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a
87
let z = match 22 {
98
0 => x,
109
_ => y,
10+
//~^ ERROR mismatched types
11+
//~| ERROR mismatched types
1112
};
1213
}
1314

0 commit comments

Comments
 (0)