Skip to content

Commit fd27e87

Browse files
committed
Auto merge of #119849 - lcnr:eagerly-instantiate-binders, r=compiler-errors
more eagerly instantiate binders The old solver sometimes incorrectly used `sub`, change it to explicitly instantiate binders and use `eq` instead. While doing so I also moved the instantiation before the normalize calls. This caused some observable changes, will explain these inline. This PR therefore requires a crater run and an FCP. r? types
2 parents 30f74ff + c8f0f17 commit fd27e87

File tree

56 files changed

+513
-397
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+513
-397
lines changed

compiler/rustc_middle/src/traits/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ pub enum SelectionError<'tcx> {
618618
OpaqueTypeAutoTraitLeakageUnknown(DefId),
619619
}
620620

621+
// FIXME(@lcnr): The `Binder` here should be unnecessary. Just use `TraitRef` instead.
621622
#[derive(Clone, Debug, TypeVisitable)]
622623
pub struct SignatureMismatchData<'tcx> {
623624
pub found_trait_ref: ty::PolyTraitRef<'tcx>,

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3409,6 +3409,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
34093409
self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
34103410
}
34113411

3412+
// FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
3413+
// instead of using a `Binder`.
34123414
fn report_signature_mismatch_error(
34133415
&self,
34143416
obligation: &PredicateObligation<'tcx>,

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
165165
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
166166
let placeholder_trait_predicate =
167167
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
168-
debug!(?placeholder_trait_predicate);
169168

170169
// The bounds returned by `item_bounds` may contain duplicates after
171170
// normalization, so try to deduplicate when possible to avoid
@@ -184,8 +183,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
184183
selcx.infcx.probe(|_| {
185184
match selcx.match_normalize_trait_ref(
186185
obligation,
187-
bound.to_poly_trait_ref(),
188186
placeholder_trait_predicate.trait_ref,
187+
bound.to_poly_trait_ref(),
189188
) {
190189
Ok(None) => {
191190
candidates.vec.push(ProjectionCandidate(idx));
@@ -881,8 +880,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
881880
self.infcx.probe(|_| {
882881
self.match_normalize_trait_ref(
883882
obligation,
884-
upcast_trait_ref,
885883
placeholder_trait_predicate.trait_ref,
884+
upcast_trait_ref,
886885
)
887886
.is_ok()
888887
})

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

+24-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use rustc_ast::Mutability;
1010
use rustc_data_structures::stack::ensure_sufficient_stack;
1111
use rustc_hir::lang_items::LangItem;
12-
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
12+
use rustc_infer::infer::HigherRankedType;
1313
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
1414
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
1515
use rustc_middle::ty::{
@@ -161,8 +161,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
161161
let placeholder_trait_predicate =
162162
self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref;
163163
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
164-
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
165-
166164
let candidate_predicate = self
167165
.for_each_item_bound(
168166
placeholder_self_ty,
@@ -182,6 +180,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
182180
.expect("projection candidate is not a trait predicate")
183181
.map_bound(|t| t.trait_ref);
184182

183+
let candidate = self.infcx.instantiate_binder_with_fresh_vars(
184+
obligation.cause.span,
185+
HigherRankedType,
186+
candidate,
187+
);
185188
let mut obligations = Vec::new();
186189
let candidate = normalize_with_depth_to(
187190
self,
@@ -195,7 +198,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
195198
obligations.extend(
196199
self.infcx
197200
.at(&obligation.cause, obligation.param_env)
198-
.sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
201+
.eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
199202
.map(|InferOk { obligations, .. }| obligations)
200203
.map_err(|_| Unimplemented)?,
201204
);
@@ -499,7 +502,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
499502

500503
let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
501504
let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
502-
let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
503505
let ty::Dynamic(data, ..) = *self_ty.kind() else {
504506
span_bug!(obligation.cause.span, "object candidate with non-object");
505507
};
@@ -520,19 +522,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
520522
let unnormalized_upcast_trait_ref =
521523
supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
522524

525+
let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
526+
obligation.cause.span,
527+
HigherRankedType,
528+
unnormalized_upcast_trait_ref,
529+
);
523530
let upcast_trait_ref = normalize_with_depth_to(
524531
self,
525532
obligation.param_env,
526533
obligation.cause.clone(),
527534
obligation.recursion_depth + 1,
528-
unnormalized_upcast_trait_ref,
535+
upcast_trait_ref,
529536
&mut nested,
530537
);
531538

532539
nested.extend(
533540
self.infcx
534541
.at(&obligation.cause, obligation.param_env)
535-
.sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
542+
.eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
536543
.map(|InferOk { obligations, .. }| obligations)
537544
.map_err(|_| Unimplemented)?,
538545
);
@@ -1021,7 +1028,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10211028
obligation: &PolyTraitObligation<'tcx>,
10221029
self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
10231030
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
1024-
let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
1031+
let obligation_trait_ref =
1032+
self.infcx.enter_forall_and_leak_universe(obligation.predicate.to_poly_trait_ref());
1033+
let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
1034+
obligation.cause.span,
1035+
HigherRankedType,
1036+
self_ty_trait_ref,
1037+
);
10251038
// Normalize the obligation and expected trait refs together, because why not
10261039
let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
10271040
ensure_sufficient_stack(|| {
@@ -1037,15 +1050,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10371050
// needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
10381051
self.infcx
10391052
.at(&obligation.cause, obligation.param_env)
1040-
.sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
1053+
.eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
10411054
.map(|InferOk { mut obligations, .. }| {
10421055
obligations.extend(nested);
10431056
obligations
10441057
})
10451058
.map_err(|terr| {
10461059
SignatureMismatch(Box::new(SignatureMismatchData {
1047-
expected_trait_ref: obligation_trait_ref,
1048-
found_trait_ref: expected_trait_ref,
1060+
expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
1061+
found_trait_ref: ty::Binder::dummy(expected_trait_ref),
10491062
terr,
10501063
}))
10511064
})

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

+20-9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
3333
use rustc_hir as hir;
3434
use rustc_hir::def_id::DefId;
3535
use rustc_infer::infer::BoundRegionConversionTime;
36+
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
3637
use rustc_infer::infer::DefineOpaqueTypes;
3738
use rustc_infer::traits::TraitObligation;
3839
use rustc_middle::dep_graph::dep_kinds;
@@ -42,7 +43,7 @@ use rustc_middle::ty::_match::MatchAgainstFreshVars;
4243
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
4344
use rustc_middle::ty::relate::TypeRelation;
4445
use rustc_middle::ty::GenericArgsRef;
45-
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
46+
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate};
4647
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
4748
use rustc_span::symbol::sym;
4849
use rustc_span::Symbol;
@@ -1651,15 +1652,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16511652
fn match_normalize_trait_ref(
16521653
&mut self,
16531654
obligation: &PolyTraitObligation<'tcx>,
1654-
trait_bound: ty::PolyTraitRef<'tcx>,
16551655
placeholder_trait_ref: ty::TraitRef<'tcx>,
1656-
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
1656+
trait_bound: ty::PolyTraitRef<'tcx>,
1657+
) -> Result<Option<ty::TraitRef<'tcx>>, ()> {
16571658
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
16581659
if placeholder_trait_ref.def_id != trait_bound.def_id() {
16591660
// Avoid unnecessary normalization
16601661
return Err(());
16611662
}
16621663

1664+
let trait_bound = self.infcx.instantiate_binder_with_fresh_vars(
1665+
obligation.cause.span,
1666+
HigherRankedType,
1667+
trait_bound,
1668+
);
16631669
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
16641670
normalize_with_depth(
16651671
self,
@@ -1671,7 +1677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16711677
});
16721678
self.infcx
16731679
.at(&obligation.cause, obligation.param_env)
1674-
.sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
1680+
.eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound)
16751681
.map(|InferOk { obligations: _, value: () }| {
16761682
// This method is called within a probe, so we can't have
16771683
// inference variables and placeholders escape.
@@ -1683,7 +1689,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16831689
})
16841690
.map_err(|_| ())
16851691
}
1686-
16871692
fn where_clause_may_apply<'o>(
16881693
&mut self,
16891694
stack: &TraitObligationStack<'o, 'tcx>,
@@ -1733,7 +1738,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17331738
let is_match = self
17341739
.infcx
17351740
.at(&obligation.cause, obligation.param_env)
1736-
.sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
1741+
.eq(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
17371742
.is_ok_and(|InferOk { obligations, value: () }| {
17381743
self.evaluate_predicates_recursively(
17391744
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -2533,7 +2538,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25332538
nested.extend(
25342539
self.infcx
25352540
.at(&obligation.cause, obligation.param_env)
2536-
.sup(
2541+
.eq(
25372542
DefineOpaqueTypes::No,
25382543
upcast_principal.map_bound(|trait_ref| {
25392544
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
@@ -2571,7 +2576,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25712576
nested.extend(
25722577
self.infcx
25732578
.at(&obligation.cause, obligation.param_env)
2574-
.sup(DefineOpaqueTypes::No, source_projection, target_projection)
2579+
.eq(DefineOpaqueTypes::No, source_projection, target_projection)
25752580
.map_err(|_| SelectionError::Unimplemented)?
25762581
.into_obligations(),
25772582
);
@@ -2615,9 +2620,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
26152620
obligation: &PolyTraitObligation<'tcx>,
26162621
poly_trait_ref: ty::PolyTraitRef<'tcx>,
26172622
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
2623+
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
2624+
let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
2625+
obligation.cause.span,
2626+
HigherRankedType,
2627+
poly_trait_ref,
2628+
);
26182629
self.infcx
26192630
.at(&obligation.cause, obligation.param_env)
2620-
.sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
2631+
.eq(DefineOpaqueTypes::No, predicate.trait_ref, trait_ref)
26212632
.map(|InferOk { obligations, .. }| obligations)
26222633
.map_err(|_| ())
26232634
}

compiler/rustc_trait_selection/src/traits/vtable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ fn vtable_entries<'tcx>(
320320
}
321321

322322
/// Find slot base for trait methods within vtable entries of another trait
323+
// FIXME(@lcnr): This isn't a query, so why does it take a tuple as its argument.
323324
pub(super) fn vtable_trait_first_method_offset<'tcx>(
324325
tcx: TyCtxt<'tcx>,
325326
key: (

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,6 @@
11071107
"ui/generic-associated-types/issue-92954.rs",
11081108
"ui/generic-associated-types/issue-93141.rs",
11091109
"ui/generic-associated-types/issue-93262.rs",
1110-
"ui/generic-associated-types/issue-93340.rs",
11111110
"ui/generic-associated-types/issue-93341.rs",
11121111
"ui/generic-associated-types/issue-93342.rs",
11131112
"ui/generic-associated-types/issue-93874.rs",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ check-pass
2+
3+
// We try to prove `T::Rigid: Into<?0>` and have 2 candidates from where-clauses:
4+
//
5+
// - `Into<String>`
6+
// - `Into<<T::Rigid as Elaborate>::Assoc>`
7+
//
8+
// This causes ambiguity unless we normalize the alias in the second candidate
9+
// to detect that they actually result in the same constraints.
10+
trait Trait {
11+
type Rigid: Elaborate<Assoc = String> + Into<String>;
12+
}
13+
14+
trait Elaborate: Into<Self::Assoc> {
15+
type Assoc;
16+
}
17+
18+
fn impls<T: Into<U>, U>(_: T) {}
19+
20+
fn test<P: Trait>(rigid: P::Rigid) {
21+
impls(rigid);
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// We try to prove `for<'b> T::Rigid: Bound<'b, ?0>` and have 2 candidates from where-clauses:
2+
//
3+
// - `for<'a> Bound<'a, String>`
4+
// - `for<'a> Bound<'a, <T::Rigid as Elaborate>::Assoc>`
5+
//
6+
// This causes ambiguity unless we normalize the alias in the second candidate
7+
// to detect that they actually result in the same constraints. We currently
8+
// fail to detect that the constraints from these bounds are equal and error
9+
// with ambiguity.
10+
trait Bound<'a, U> {}
11+
12+
trait Trait {
13+
type Rigid: Elaborate<Assoc = String> + for<'a> Bound<'a, String>;
14+
}
15+
16+
trait Elaborate: for<'a> Bound<'a, Self::Assoc> {
17+
type Assoc;
18+
}
19+
20+
fn impls<T: for<'b> Bound<'b, U>, U>(_: T) {}
21+
22+
fn test<P: Trait>(rigid: P::Rigid) {
23+
impls(rigid);
24+
//~^ ERROR type annotations needed
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/dedup-normalized-2-higher-ranked.rs:23:5
3+
|
4+
LL | impls(rigid);
5+
| ^^^^^ cannot infer type of the type parameter `U` declared on the function `impls`
6+
|
7+
= note: cannot satisfy `for<'b> <P as Trait>::Rigid: Bound<'b, _>`
8+
note: required by a bound in `impls`
9+
--> $DIR/dedup-normalized-2-higher-ranked.rs:20:13
10+
|
11+
LL | fn impls<T: for<'b> Bound<'b, U>, U>(_: T) {}
12+
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls`
13+
help: consider specifying the generic arguments
14+
|
15+
LL | impls::<<P as Trait>::Rigid, U>(rigid);
16+
| ++++++++++++++++++++++++++
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0283`.

tests/ui/async-await/return-type-notation/issue-110963-early.stderr

+8-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | #![feature(return_type_notation)]
77
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10-
error[E0308]: mismatched types
10+
error: implementation of `Send` is not general enough
1111
--> $DIR/issue-110963-early.rs:14:5
1212
|
1313
LL | / spawn(async move {
@@ -16,17 +16,12 @@ LL | | if !hc.check().await {
1616
LL | | log_health_check_failure().await;
1717
LL | | }
1818
LL | | });
19-
| |______^ one type is more general than the other
19+
| |______^ implementation of `Send` is not general enough
2020
|
21-
= note: expected trait `Send`
22-
found trait `for<'a> Send`
23-
note: the lifetime requirement is introduced here
24-
--> $DIR/issue-110963-early.rs:34:17
25-
|
26-
LL | F: Future + Send + 'static,
27-
| ^^^^
21+
= note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`...
22+
= note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2`
2823

29-
error[E0308]: mismatched types
24+
error: implementation of `Send` is not general enough
3025
--> $DIR/issue-110963-early.rs:14:5
3126
|
3227
LL | / spawn(async move {
@@ -35,17 +30,11 @@ LL | | if !hc.check().await {
3530
LL | | log_health_check_failure().await;
3631
LL | | }
3732
LL | | });
38-
| |______^ one type is more general than the other
39-
|
40-
= note: expected trait `Send`
41-
found trait `for<'a> Send`
42-
note: the lifetime requirement is introduced here
43-
--> $DIR/issue-110963-early.rs:34:17
33+
| |______^ implementation of `Send` is not general enough
4434
|
45-
LL | F: Future + Send + 'static,
46-
| ^^^^
35+
= note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`...
36+
= note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2`
4737
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
4838

4939
error: aborting due to 2 previous errors; 1 warning emitted
5040

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

0 commit comments

Comments
 (0)