Skip to content

Commit 23e69c0

Browse files
committed
eagerly instantiate binders to avoid relying on sub
1 parent e927184 commit 23e69c0

Some content is hidden

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

46 files changed

+312
-435
lines changed

compiler/rustc_middle/src/traits/mod.rs

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

623+
// FIXME(@lcnr): The `Binder` here should be unnecessary. Just use `TraitRef` instead.
623624
#[derive(Clone, Debug, TypeVisitable)]
624625
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
625626
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
@@ -3430,6 +3430,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
34303430
err
34313431
}
34323432

3433+
// FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
3434+
// instead of using a `Binder`.
34333435
fn report_type_parameter_mismatch_error(
34343436
&self,
34353437
obligation: &PredicateObligation<'tcx>,

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

+6-11
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
150150
_ => return,
151151
}
152152

153-
let result = self
154-
.infcx
155-
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
153+
let result = self.match_projection_obligation_against_definition_bounds(obligation);
156154

157155
candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
158156
}
@@ -708,14 +706,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
708706
let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref)
709707
.enumerate()
710708
.filter(|&(_, upcast_trait_ref)| {
711-
self.infcx.probe(|_| {
712-
self.match_normalize_trait_ref(
713-
obligation,
714-
upcast_trait_ref,
715-
placeholder_trait_predicate.trait_ref,
716-
)
717-
.is_ok()
718-
})
709+
self.matches_trait_ref(
710+
obligation,
711+
placeholder_trait_predicate.trait_ref,
712+
upcast_trait_ref,
713+
)
719714
})
720715
.map(|(idx, _)| ObjectCandidate(idx));
721716

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

+25-10
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, SelectionOutputTypeParameterMismatch};
1515
use rustc_middle::ty::{
@@ -152,7 +152,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
152152
let placeholder_trait_predicate =
153153
self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref;
154154
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
155-
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
156155
let (def_id, args) = match *placeholder_self_ty.kind() {
157156
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
158157
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
@@ -167,6 +166,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
167166
.as_trait_clause()
168167
.expect("projection candidate is not a trait predicate")
169168
.map_bound(|t| t.trait_ref);
169+
let candidate = self.infcx.instantiate_binder_with_fresh_vars(
170+
obligation.cause.span,
171+
HigherRankedType,
172+
candidate,
173+
);
170174
let mut obligations = Vec::new();
171175
let candidate = normalize_with_depth_to(
172176
self,
@@ -180,7 +184,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
180184
obligations.extend(self.infcx.commit_if_ok(|_| {
181185
self.infcx
182186
.at(&obligation.cause, obligation.param_env)
183-
.sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
187+
.eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
184188
.map(|InferOk { obligations, .. }| obligations)
185189
.map_err(|_| Unimplemented)
186190
})?);
@@ -486,7 +490,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
486490

487491
let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
488492
let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
489-
let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
490493
let ty::Dynamic(data, ..) = *self_ty.kind() else {
491494
span_bug!(obligation.cause.span, "object candidate with non-object");
492495
};
@@ -507,19 +510,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
507510
let unnormalized_upcast_trait_ref =
508511
supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
509512

513+
let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
514+
obligation.cause.span,
515+
HigherRankedType,
516+
unnormalized_upcast_trait_ref,
517+
);
510518
let upcast_trait_ref = normalize_with_depth_to(
511519
self,
512520
obligation.param_env,
513521
obligation.cause.clone(),
514522
obligation.recursion_depth + 1,
515-
unnormalized_upcast_trait_ref,
523+
upcast_trait_ref,
516524
&mut nested,
517525
);
518526

519527
nested.extend(self.infcx.commit_if_ok(|_| {
520528
self.infcx
521529
.at(&obligation.cause, obligation.param_env)
522-
.sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
530+
.eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
523531
.map(|InferOk { obligations, .. }| obligations)
524532
.map_err(|_| Unimplemented)
525533
})?);
@@ -900,7 +908,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
900908
obligation: &PolyTraitObligation<'tcx>,
901909
self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
902910
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
903-
let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
911+
let obligation_trait_ref = self
912+
.infcx
913+
.instantiate_binder_with_placeholders(obligation.predicate.to_poly_trait_ref());
914+
let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
915+
obligation.cause.span,
916+
HigherRankedType,
917+
self_ty_trait_ref,
918+
);
904919
// Normalize the obligation and expected trait refs together, because why not
905920
let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
906921
ensure_sufficient_stack(|| {
@@ -916,15 +931,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
916931
// needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
917932
self.infcx
918933
.at(&obligation.cause, obligation.param_env)
919-
.sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
934+
.eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
920935
.map(|InferOk { mut obligations, .. }| {
921936
obligations.extend(nested);
922937
obligations
923938
})
924939
.map_err(|terr| {
925940
OutputTypeParameterMismatch(Box::new(SelectionOutputTypeParameterMismatch {
926-
expected_trait_ref: obligation_trait_ref,
927-
found_trait_ref: expected_trait_ref,
941+
expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
942+
found_trait_ref: ty::Binder::dummy(expected_trait_ref),
928943
terr,
929944
}))
930945
})

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

+42-53
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use rustc_errors::Diagnostic;
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;
@@ -43,7 +44,7 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
4344
use rustc_middle::ty::fold::BottomUpFolder;
4445
use rustc_middle::ty::relate::TypeRelation;
4546
use rustc_middle::ty::GenericArgsRef;
46-
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
47+
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPredicate};
4748
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
4849
use rustc_span::symbol::sym;
4950
use rustc_span::Symbol;
@@ -1627,33 +1628,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16271628
};
16281629
let bounds = tcx.item_bounds(def_id).instantiate(tcx, args);
16291630

1630-
// The bounds returned by `item_bounds` may contain duplicates after
1631-
// normalization, so try to deduplicate when possible to avoid
1632-
// unnecessary ambiguity.
1633-
let mut distinct_normalized_bounds = FxHashSet::default();
1634-
16351631
bounds
16361632
.iter()
16371633
.enumerate()
16381634
.filter_map(|(idx, bound)| {
16391635
let bound_predicate = bound.kind();
16401636
if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() {
16411637
let bound = bound_predicate.rebind(pred.trait_ref);
1642-
if self.infcx.probe(|_| {
1643-
match self.match_normalize_trait_ref(
1644-
obligation,
1645-
bound,
1646-
placeholder_trait_predicate.trait_ref,
1647-
) {
1648-
Ok(None) => true,
1649-
Ok(Some(normalized_trait))
1650-
if distinct_normalized_bounds.insert(normalized_trait) =>
1651-
{
1652-
true
1653-
}
1654-
_ => false,
1655-
}
1656-
}) {
1638+
if self.matches_trait_ref(
1639+
obligation,
1640+
placeholder_trait_predicate.trait_ref,
1641+
bound,
1642+
) {
16571643
return Some(idx);
16581644
}
16591645
}
@@ -1662,43 +1648,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16621648
.collect()
16631649
}
16641650

1665-
/// Equates the trait in `obligation` with trait bound. If the two traits
1666-
/// can be equated and the normalized trait bound doesn't contain inference
1667-
/// variables or placeholders, the normalized bound is returned.
1668-
fn match_normalize_trait_ref(
1651+
/// Equates the trait in `obligation` with trait bound and returns
1652+
/// true if the two traits can be equated.
1653+
fn matches_trait_ref(
16691654
&mut self,
16701655
obligation: &PolyTraitObligation<'tcx>,
1671-
trait_bound: ty::PolyTraitRef<'tcx>,
16721656
placeholder_trait_ref: ty::TraitRef<'tcx>,
1673-
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
1657+
trait_bound: ty::PolyTraitRef<'tcx>,
1658+
) -> bool {
16741659
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
16751660
if placeholder_trait_ref.def_id != trait_bound.def_id() {
16761661
// Avoid unnecessary normalization
1677-
return Err(());
1662+
return false;
16781663
}
16791664

1680-
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
1681-
project::normalize_with_depth(
1682-
self,
1683-
obligation.param_env,
1684-
obligation.cause.clone(),
1685-
obligation.recursion_depth + 1,
1665+
self.infcx.probe(|_| {
1666+
let trait_bound = self.infcx.instantiate_binder_with_fresh_vars(
1667+
obligation.cause.span,
1668+
HigherRankedType,
16861669
trait_bound,
1687-
)
1688-
});
1689-
self.infcx
1690-
.at(&obligation.cause, obligation.param_env)
1691-
.sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
1692-
.map(|InferOk { obligations: _, value: () }| {
1693-
// This method is called within a probe, so we can't have
1694-
// inference variables and placeholders escape.
1695-
if !trait_bound.has_infer() && !trait_bound.has_placeholders() {
1696-
Some(trait_bound)
1697-
} else {
1698-
None
1699-
}
1700-
})
1701-
.map_err(|_| ())
1670+
);
1671+
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
1672+
project::normalize_with_depth(
1673+
self,
1674+
obligation.param_env,
1675+
obligation.cause.clone(),
1676+
obligation.recursion_depth + 1,
1677+
trait_bound,
1678+
)
1679+
});
1680+
self.infcx
1681+
.at(&obligation.cause, obligation.param_env)
1682+
.eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound)
1683+
.is_ok()
1684+
})
17021685
}
17031686

17041687
fn where_clause_may_apply<'o>(
@@ -1750,7 +1733,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17501733
let is_match = self
17511734
.infcx
17521735
.at(&obligation.cause, obligation.param_env)
1753-
.sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
1736+
.eq(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
17541737
.is_ok_and(|InferOk { obligations, value: () }| {
17551738
self.evaluate_predicates_recursively(
17561739
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -2532,7 +2515,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25322515
nested.extend(
25332516
self.infcx
25342517
.at(&obligation.cause, obligation.param_env)
2535-
.sup(
2518+
.eq(
25362519
DefineOpaqueTypes::No,
25372520
upcast_principal.map_bound(|trait_ref| {
25382521
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
@@ -2570,7 +2553,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
25702553
nested.extend(
25712554
self.infcx
25722555
.at(&obligation.cause, obligation.param_env)
2573-
.sup(DefineOpaqueTypes::No, source_projection, target_projection)
2556+
.eq(DefineOpaqueTypes::No, source_projection, target_projection)
25742557
.map_err(|_| SelectionError::Unimplemented)?
25752558
.into_obligations(),
25762559
);
@@ -2614,9 +2597,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
26142597
obligation: &PolyTraitObligation<'tcx>,
26152598
poly_trait_ref: ty::PolyTraitRef<'tcx>,
26162599
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
2600+
let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
2601+
let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
2602+
obligation.cause.span,
2603+
HigherRankedType,
2604+
poly_trait_ref,
2605+
);
26172606
self.infcx
26182607
.at(&obligation.cause, obligation.param_env)
2619-
.sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
2608+
.eq(DefineOpaqueTypes::No, predicate.trait_ref, trait_ref)
26202609
.map(|InferOk { obligations, .. }| obligations)
26212610
.map_err(|_| ())
26222611
}

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: (

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`.

tests/ui/closures/multiple-fn-bounds.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | foo(move |x| v);
77
| expected due to this
88
|
99
= note: expected closure signature `fn(_) -> _`
10-
found closure signature `for<'a> fn(&'a _) -> _`
10+
found closure signature `fn(&_) -> _`
1111
note: closure inferred to have a different signature due to this bound
1212
--> $DIR/multiple-fn-bounds.rs:1:11
1313
|

0 commit comments

Comments
 (0)