Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4e510da

Browse files
authoredSep 28, 2024
Rollup merge of #130866 - compiler-errors:dyn-instantiate-binder, r=lcnr
Allow instantiating object trait binder when upcasting This PR fixes two bugs (that probably need an FCP). ### We use equality rather than subtyping for upcasting dyn conversions This code should be valid: ```rust #![feature(trait_upcasting)] trait Foo: for<'h> Bar<'h> {} trait Bar<'a> {} fn foo(x: &dyn Foo) { let y: &dyn Bar<'static> = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:7:32 | 7 | let y: &dyn Bar<'static> = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> Bar<'h>` found existential trait ref `Bar<'_>` ``` And so should this: ```rust #![feature(trait_upcasting)] fn foo(x: &dyn for<'h> Fn(&'h ())) { let y: &dyn FnOnce(&'static ()) = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:4:39 | 4 | let y: &dyn FnOnce(&'static ()) = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> FnOnce<(&'h (),)>` found existential trait ref `FnOnce<(&(),)>` ``` Specifically, both of these fail because we use *equality* when comparing the supertrait to the *target* of the unsize goal. For the first example, since our supertrait is `for<'h> Bar<'h>` but our target is `Bar<'static>`, there's a higher-ranked type mismatch even though we *should* be able to instantiate that supertrait binder when upcasting. Similarly for the second example. ### New solver uses equality rather than subtyping for no-op (i.e. non-upcasting) dyn conversions This code should be valid in the new solver, like it is with the old solver: ```rust // -Znext-solver fn foo<'a>(x: &mut for<'h> dyn Fn(&'h ())) { let _: &mut dyn Fn(&'a ()) = x; } ``` But instead: ``` error: lifetime may not live long enough --> <source>:2:11 | 1 | fn foo<'a>(x: &mut dyn for<'h> Fn(&'h ())) { | -- lifetime `'a` defined here 2 | let _: &mut dyn Fn(&'a ()) = x; | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` | = note: requirement occurs because of a mutable reference to `dyn Fn(&())` ``` Specifically, this fails because we try to coerce `&mut dyn for<'h> Fn(&'h ())` to `&mut dyn Fn(&'a ())`, which registers an `dyn for<'h> Fn(&'h ()): dyn Fn(&'a ())` goal. This fails because the new solver uses *equating* rather than *subtyping* in `Unsize` goals. This is *mostly* not a problem... You may wonder why the same code passes on the new solver for immutable references: ``` // -Znext-solver fn foo<'a>(x: &dyn Fn(&())) { let _: &dyn Fn(&'a ()) = x; // works } ``` That's because in this case, we first try to coerce via `Unsize`, but due to the leak check the goal fails. Then, later in coercion, we fall back to a simple subtyping operation, which *does* work. Since `&T` is covariant over `T`, but `&mut T` is invariant, that's where the discrepancy between these two examples crops up. --- r? lcnr or reassign :D
2 parents 6e9db86 + d753aba commit 4e510da

File tree

10 files changed

+228
-201
lines changed

10 files changed

+228
-201
lines changed
 

‎compiler/rustc_infer/src/infer/at.rs

Lines changed: 54 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,7 @@ impl<'tcx> InferCtxt<'tcx> {
9292
}
9393

9494
pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
95-
fn to_trace(
96-
cause: &ObligationCause<'tcx>,
97-
a_is_expected: bool,
98-
a: Self,
99-
b: Self,
100-
) -> TypeTrace<'tcx>;
95+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
10196
}
10297

10398
impl<'a, 'tcx> At<'a, 'tcx> {
@@ -116,7 +111,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
116111
{
117112
let mut fields = CombineFields::new(
118113
self.infcx,
119-
ToTrace::to_trace(self.cause, true, expected, actual),
114+
ToTrace::to_trace(self.cause, expected, actual),
120115
self.param_env,
121116
define_opaque_types,
122117
);
@@ -136,7 +131,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
136131
{
137132
let mut fields = CombineFields::new(
138133
self.infcx,
139-
ToTrace::to_trace(self.cause, true, expected, actual),
134+
ToTrace::to_trace(self.cause, expected, actual),
140135
self.param_env,
141136
define_opaque_types,
142137
);
@@ -154,12 +149,26 @@ impl<'a, 'tcx> At<'a, 'tcx> {
154149
where
155150
T: ToTrace<'tcx>,
156151
{
157-
let mut fields = CombineFields::new(
158-
self.infcx,
159-
ToTrace::to_trace(self.cause, true, expected, actual),
160-
self.param_env,
152+
self.eq_trace(
161153
define_opaque_types,
162-
);
154+
ToTrace::to_trace(self.cause, expected, actual),
155+
expected,
156+
actual,
157+
)
158+
}
159+
160+
/// Makes `expected == actual`.
161+
pub fn eq_trace<T>(
162+
self,
163+
define_opaque_types: DefineOpaqueTypes,
164+
trace: TypeTrace<'tcx>,
165+
expected: T,
166+
actual: T,
167+
) -> InferResult<'tcx, ()>
168+
where
169+
T: Relate<TyCtxt<'tcx>>,
170+
{
171+
let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types);
163172
fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?;
164173
Ok(InferOk {
165174
value: (),
@@ -192,7 +201,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
192201
assert!(self.infcx.next_trait_solver());
193202
let mut fields = CombineFields::new(
194203
self.infcx,
195-
ToTrace::to_trace(self.cause, true, expected, actual),
204+
ToTrace::to_trace(self.cause, expected, actual),
196205
self.param_env,
197206
DefineOpaqueTypes::Yes,
198207
);
@@ -284,7 +293,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
284293
{
285294
let mut fields = CombineFields::new(
286295
self.infcx,
287-
ToTrace::to_trace(self.cause, true, expected, actual),
296+
ToTrace::to_trace(self.cause, expected, actual),
288297
self.param_env,
289298
define_opaque_types,
290299
);
@@ -306,7 +315,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
306315
{
307316
let mut fields = CombineFields::new(
308317
self.infcx,
309-
ToTrace::to_trace(self.cause, true, expected, actual),
318+
ToTrace::to_trace(self.cause, expected, actual),
310319
self.param_env,
311320
define_opaque_types,
312321
);
@@ -316,18 +325,13 @@ impl<'a, 'tcx> At<'a, 'tcx> {
316325
}
317326

318327
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
319-
fn to_trace(
320-
cause: &ObligationCause<'tcx>,
321-
a_is_expected: bool,
322-
a: Self,
323-
b: Self,
324-
) -> TypeTrace<'tcx> {
328+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
325329
match (a, b) {
326330
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
327-
ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
331+
ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
328332
}
329333
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
330-
ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
334+
ToTrace::to_trace(cause, ty_a, ty_b)
331335
}
332336
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
333337
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@@ -338,65 +342,45 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
338342
}
339343

340344
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
341-
fn to_trace(
342-
cause: &ObligationCause<'tcx>,
343-
a_is_expected: bool,
344-
a: Self,
345-
b: Self,
346-
) -> TypeTrace<'tcx> {
345+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
347346
TypeTrace {
348347
cause: cause.clone(),
349-
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
348+
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
350349
}
351350
}
352351
}
353352

354353
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
355-
fn to_trace(
356-
cause: &ObligationCause<'tcx>,
357-
a_is_expected: bool,
358-
a: Self,
359-
b: Self,
360-
) -> TypeTrace<'tcx> {
354+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
361355
TypeTrace {
362356
cause: cause.clone(),
363-
values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)),
357+
values: ValuePairs::Regions(ExpectedFound::new(true, a, b)),
364358
}
365359
}
366360
}
367361

368362
impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
369-
fn to_trace(
370-
cause: &ObligationCause<'tcx>,
371-
a_is_expected: bool,
372-
a: Self,
373-
b: Self,
374-
) -> TypeTrace<'tcx> {
363+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
375364
TypeTrace {
376365
cause: cause.clone(),
377-
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
366+
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
378367
}
379368
}
380369
}
381370

382371
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
383-
fn to_trace(
384-
cause: &ObligationCause<'tcx>,
385-
a_is_expected: bool,
386-
a: Self,
387-
b: Self,
388-
) -> TypeTrace<'tcx> {
372+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
389373
TypeTrace {
390374
cause: cause.clone(),
391375
values: match (a.unpack(), b.unpack()) {
392376
(GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
393-
ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b))
377+
ValuePairs::Regions(ExpectedFound::new(true, a, b))
394378
}
395379
(GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
396-
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
380+
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
397381
}
398382
(GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
399-
ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
383+
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
400384
}
401385

402386
(
@@ -419,72 +403,47 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
419403
}
420404

421405
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
422-
fn to_trace(
423-
cause: &ObligationCause<'tcx>,
424-
a_is_expected: bool,
425-
a: Self,
426-
b: Self,
427-
) -> TypeTrace<'tcx> {
406+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
428407
TypeTrace {
429408
cause: cause.clone(),
430-
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)),
409+
values: ValuePairs::Terms(ExpectedFound::new(true, a, b)),
431410
}
432411
}
433412
}
434413

435414
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
436-
fn to_trace(
437-
cause: &ObligationCause<'tcx>,
438-
a_is_expected: bool,
439-
a: Self,
440-
b: Self,
441-
) -> TypeTrace<'tcx> {
415+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
442416
TypeTrace {
443417
cause: cause.clone(),
444-
values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
418+
values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)),
445419
}
446420
}
447421
}
448422

449423
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
450-
fn to_trace(
451-
cause: &ObligationCause<'tcx>,
452-
a_is_expected: bool,
453-
a: Self,
454-
b: Self,
455-
) -> TypeTrace<'tcx> {
424+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
456425
TypeTrace {
457426
cause: cause.clone(),
458-
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
427+
values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())),
459428
}
460429
}
461430
}
462431

463432
impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
464-
fn to_trace(
465-
cause: &ObligationCause<'tcx>,
466-
a_is_expected: bool,
467-
a: Self,
468-
b: Self,
469-
) -> TypeTrace<'tcx> {
433+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
470434
TypeTrace {
471435
cause: cause.clone(),
472-
values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)),
436+
values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)),
473437
}
474438
}
475439
}
476440

477441
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
478-
fn to_trace(
479-
cause: &ObligationCause<'tcx>,
480-
a_is_expected: bool,
481-
a: Self,
482-
b: Self,
483-
) -> TypeTrace<'tcx> {
442+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
484443
TypeTrace {
485444
cause: cause.clone(),
486445
values: ValuePairs::PolySigs(ExpectedFound::new(
487-
a_is_expected,
446+
true,
488447
ty::Binder::dummy(a),
489448
ty::Binder::dummy(b),
490449
)),
@@ -493,43 +452,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
493452
}
494453

495454
impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
496-
fn to_trace(
497-
cause: &ObligationCause<'tcx>,
498-
a_is_expected: bool,
499-
a: Self,
500-
b: Self,
501-
) -> TypeTrace<'tcx> {
455+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
502456
TypeTrace {
503457
cause: cause.clone(),
504-
values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)),
458+
values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)),
505459
}
506460
}
507461
}
508462

509463
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
510-
fn to_trace(
511-
cause: &ObligationCause<'tcx>,
512-
a_is_expected: bool,
513-
a: Self,
514-
b: Self,
515-
) -> TypeTrace<'tcx> {
464+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
516465
TypeTrace {
517466
cause: cause.clone(),
518-
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
467+
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)),
519468
}
520469
}
521470
}
522471

523472
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
524-
fn to_trace(
525-
cause: &ObligationCause<'tcx>,
526-
a_is_expected: bool,
527-
a: Self,
528-
b: Self,
529-
) -> TypeTrace<'tcx> {
473+
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
530474
TypeTrace {
531475
cause: cause.clone(),
532-
values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
476+
values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)),
533477
}
534478
}
535479
}

‎compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,10 @@ where
448448
}
449449
}
450450
} else {
451-
self.delegate.enter_forall(kind, |kind| {
452-
let goal = goal.with(self.cx(), ty::Binder::dummy(kind));
453-
self.add_goal(GoalSource::InstantiateHigherRanked, goal);
454-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
451+
self.enter_forall(kind, |ecx, kind| {
452+
let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
453+
ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
454+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
455455
})
456456
}
457457
}
@@ -840,12 +840,14 @@ where
840840
self.delegate.instantiate_binder_with_infer(value)
841841
}
842842

843+
/// `enter_forall`, but takes `&mut self` and passes it back through the
844+
/// callback since it can't be aliased during the call.
843845
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
844-
&self,
846+
&mut self,
845847
value: ty::Binder<I, T>,
846-
f: impl FnOnce(T) -> U,
848+
f: impl FnOnce(&mut Self, T) -> U,
847849
) -> U {
848-
self.delegate.enter_forall(value, f)
850+
self.delegate.enter_forall(value, |value| f(self, value))
849851
}
850852

851853
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,13 @@ where
895895
source_projection.item_def_id() == target_projection.item_def_id()
896896
&& ecx
897897
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
898-
.enter(|ecx| -> Result<(), NoSolution> {
899-
ecx.eq(param_env, source_projection, target_projection)?;
900-
let _ = ecx.try_evaluate_added_goals()?;
901-
Ok(())
898+
.enter(|ecx| -> Result<_, NoSolution> {
899+
ecx.enter_forall(target_projection, |ecx, target_projection| {
900+
let source_projection =
901+
ecx.instantiate_binder_with_infer(source_projection);
902+
ecx.eq(param_env, source_projection, target_projection)?;
903+
ecx.try_evaluate_added_goals()
904+
})
902905
})
903906
.is_ok()
904907
};
@@ -909,11 +912,14 @@ where
909912
// Check that a's supertrait (upcast_principal) is compatible
910913
// with the target (b_ty).
911914
ty::ExistentialPredicate::Trait(target_principal) => {
912-
ecx.eq(
913-
param_env,
914-
upcast_principal.unwrap(),
915-
bound.rebind(target_principal),
916-
)?;
915+
let source_principal = upcast_principal.unwrap();
916+
let target_principal = bound.rebind(target_principal);
917+
ecx.enter_forall(target_principal, |ecx, target_principal| {
918+
let source_principal =
919+
ecx.instantiate_binder_with_infer(source_principal);
920+
ecx.eq(param_env, source_principal, target_principal)?;
921+
ecx.try_evaluate_added_goals()
922+
})?;
917923
}
918924
// Check that b_ty's projection is satisfied by exactly one of
919925
// a_ty's projections. First, we look through the list to see if
@@ -934,7 +940,12 @@ where
934940
Certainty::AMBIGUOUS,
935941
);
936942
}
937-
ecx.eq(param_env, source_projection, target_projection)?;
943+
ecx.enter_forall(target_projection, |ecx, target_projection| {
944+
let source_projection =
945+
ecx.instantiate_binder_with_infer(source_projection);
946+
ecx.eq(param_env, source_projection, target_projection)?;
947+
ecx.try_evaluate_added_goals()
948+
})?;
938949
}
939950
// Check that b_ty's auto traits are present in a_ty's bounds.
940951
ty::ExistentialPredicate::AutoTrait(def_id) => {
@@ -1187,17 +1198,15 @@ where
11871198
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
11881199
) -> Result<Candidate<I>, NoSolution> {
11891200
self.probe_trait_candidate(source).enter(|ecx| {
1190-
ecx.add_goals(
1191-
GoalSource::ImplWhereBound,
1192-
constituent_tys(ecx, goal.predicate.self_ty())?
1193-
.into_iter()
1194-
.map(|ty| {
1195-
ecx.enter_forall(ty, |ty| {
1196-
goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
1197-
})
1201+
let goals = constituent_tys(ecx, goal.predicate.self_ty())?
1202+
.into_iter()
1203+
.map(|ty| {
1204+
ecx.enter_forall(ty, |ecx, ty| {
1205+
goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))
11981206
})
1199-
.collect::<Vec<_>>(),
1200-
);
1207+
})
1208+
.collect::<Vec<_>>();
1209+
ecx.add_goals(GoalSource::ImplWhereBound, goals);
12011210
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
12021211
})
12031212
}

‎compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hir::LangItem;
1616
use rustc_hir::def_id::DefId;
1717
use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
1818
use rustc_infer::infer::DefineOpaqueTypes;
19+
use rustc_infer::infer::at::ToTrace;
1920
use rustc_infer::infer::relate::TypeRelation;
2021
use rustc_infer::traits::TraitObligation;
2122
use rustc_middle::bug;
@@ -44,7 +45,7 @@ use super::{
4445
TraitQueryMode, const_evaluatable, project, util, wf,
4546
};
4647
use crate::error_reporting::InferCtxtErrorExt;
47-
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
48+
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
4849
use crate::solve::InferCtxtSelectExt as _;
4950
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
5051
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
@@ -2579,16 +2580,31 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25792580
// Check that a_ty's supertrait (upcast_principal) is compatible
25802581
// with the target (b_ty).
25812582
ty::ExistentialPredicate::Trait(target_principal) => {
2583+
let hr_source_principal = upcast_principal.map_bound(|trait_ref| {
2584+
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
2585+
});
2586+
let hr_target_principal = bound.rebind(target_principal);
2587+
25822588
nested.extend(
25832589
self.infcx
2584-
.at(&obligation.cause, obligation.param_env)
2585-
.eq(
2586-
DefineOpaqueTypes::Yes,
2587-
upcast_principal.map_bound(|trait_ref| {
2588-
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
2589-
}),
2590-
bound.rebind(target_principal),
2591-
)
2590+
.enter_forall(hr_target_principal, |target_principal| {
2591+
let source_principal =
2592+
self.infcx.instantiate_binder_with_fresh_vars(
2593+
obligation.cause.span,
2594+
HigherRankedType,
2595+
hr_source_principal,
2596+
);
2597+
self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
2598+
DefineOpaqueTypes::Yes,
2599+
ToTrace::to_trace(
2600+
&obligation.cause,
2601+
hr_target_principal,
2602+
hr_source_principal,
2603+
),
2604+
target_principal,
2605+
source_principal,
2606+
)
2607+
})
25922608
.map_err(|_| SelectionError::Unimplemented)?
25932609
.into_obligations(),
25942610
);
@@ -2599,28 +2615,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25992615
// return ambiguity. Otherwise, if exactly one matches, equate
26002616
// it with b_ty's projection.
26012617
ty::ExistentialPredicate::Projection(target_projection) => {
2602-
let target_projection = bound.rebind(target_projection);
2618+
let hr_target_projection = bound.rebind(target_projection);
2619+
26032620
let mut matching_projections =
2604-
a_data.projection_bounds().filter(|source_projection| {
2621+
a_data.projection_bounds().filter(|&hr_source_projection| {
26052622
// Eager normalization means that we can just use can_eq
26062623
// here instead of equating and processing obligations.
2607-
source_projection.item_def_id() == target_projection.item_def_id()
2608-
&& self.infcx.can_eq(
2609-
obligation.param_env,
2610-
*source_projection,
2611-
target_projection,
2612-
)
2624+
hr_source_projection.item_def_id() == hr_target_projection.item_def_id()
2625+
&& self.infcx.probe(|_| {
2626+
self.infcx
2627+
.enter_forall(hr_target_projection, |target_projection| {
2628+
let source_projection =
2629+
self.infcx.instantiate_binder_with_fresh_vars(
2630+
obligation.cause.span,
2631+
HigherRankedType,
2632+
hr_source_projection,
2633+
);
2634+
self.infcx
2635+
.at(&obligation.cause, obligation.param_env)
2636+
.eq_trace(
2637+
DefineOpaqueTypes::Yes,
2638+
ToTrace::to_trace(
2639+
&obligation.cause,
2640+
hr_target_projection,
2641+
hr_source_projection,
2642+
),
2643+
target_projection,
2644+
source_projection,
2645+
)
2646+
})
2647+
.is_ok()
2648+
})
26132649
});
2614-
let Some(source_projection) = matching_projections.next() else {
2650+
2651+
let Some(hr_source_projection) = matching_projections.next() else {
26152652
return Err(SelectionError::Unimplemented);
26162653
};
26172654
if matching_projections.next().is_some() {
26182655
return Ok(None);
26192656
}
26202657
nested.extend(
26212658
self.infcx
2622-
.at(&obligation.cause, obligation.param_env)
2623-
.eq(DefineOpaqueTypes::Yes, source_projection, target_projection)
2659+
.enter_forall(hr_target_projection, |target_projection| {
2660+
let source_projection =
2661+
self.infcx.instantiate_binder_with_fresh_vars(
2662+
obligation.cause.span,
2663+
HigherRankedType,
2664+
hr_source_projection,
2665+
);
2666+
self.infcx.at(&obligation.cause, obligation.param_env).eq_trace(
2667+
DefineOpaqueTypes::Yes,
2668+
ToTrace::to_trace(
2669+
&obligation.cause,
2670+
hr_target_projection,
2671+
hr_source_projection,
2672+
),
2673+
target_projection,
2674+
source_projection,
2675+
)
2676+
})
26242677
.map_err(|_| SelectionError::Unimplemented)?
26252678
.into_obligations(),
26262679
);

‎tests/ui/coercion/sub-principals.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
// Verify that the unsize goal can cast a higher-ranked trait goal to
7+
// a non-higer-ranked instantiation.
8+
9+
#![feature(unsize)]
10+
11+
use std::marker::Unsize;
12+
13+
fn test<T: ?Sized, U: ?Sized>()
14+
where
15+
T: Unsize<U>,
16+
{
17+
}
18+
19+
fn main() {
20+
test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn Fn(&'static ()) -> &'static ()>();
21+
22+
trait Foo<'a, 'b> {}
23+
test::<dyn for<'a, 'b> Foo<'a, 'b>, dyn for<'a> Foo<'a, 'a>>();
24+
25+
trait Bar<'a> {}
26+
test::<dyn for<'a> Bar<'a>, dyn Bar<'_>>();
27+
}

‎tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr

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

‎tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
//@ revisions: current next
22
//@ ignore-compare-mode-next-solver (explicit revisions)
33
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
45

56
// We should be able to instantiate a binder during trait upcasting.
67
// This test could be `check-pass`, but we should make sure that we
78
// do so in both trait solvers.
9+
810
#![feature(trait_upcasting)]
9-
#![crate_type = "rlib"]
10-
trait Supertrait<'a, 'b> {}
1111

12+
trait Supertrait<'a, 'b> {}
1213
trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
1314

1415
impl<'a> Supertrait<'a, 'a> for () {}
1516
impl<'a> Subtrait<'a, 'a> for () {}
1617
fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
17-
x //~ ERROR mismatched types
18-
//[current]~^ ERROR mismatched types
18+
x
1919
}
20+
21+
fn main() {}

‎tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ error[E0308]: mismatched types
44
LL | x
55
| ^ one type is more general than the other
66
|
7-
= note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
8-
found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
7+
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
8+
found existential trait ref `for<'a> Supertrait<'a, 'a>`
99

1010
error[E0308]: mismatched types
1111
--> $DIR/higher-ranked-upcasting-ub.rs:22:5
1212
|
1313
LL | x
1414
| ^ one type is more general than the other
1515
|
16-
= note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
17-
found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
16+
= note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
17+
found existential trait ref `for<'a> Supertrait<'a, 'a>`
1818
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1919

2020
error: aborting due to 2 previous errors
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
// Verify that the unsize goal can cast a higher-ranked trait goal to
7+
// a non-higer-ranked instantiation.
8+
9+
#![feature(unsize)]
10+
11+
use std::marker::Unsize;
12+
13+
fn test<T: ?Sized, U: ?Sized>()
14+
where
15+
T: Unsize<U>,
16+
{
17+
}
18+
19+
fn main() {
20+
test::<dyn for<'a> Fn(&'a ()) -> &'a (), dyn FnOnce(&'static ()) -> &'static ()>();
21+
22+
trait Foo: for<'a> Bar<'a> {}
23+
trait Bar<'a> {}
24+
test::<dyn Foo, dyn Bar<'static>>();
25+
test::<dyn Foo, dyn Bar<'_>>();
26+
}

0 commit comments

Comments
 (0)
Please sign in to comment.