Rollup merge of #135766 - lcnr:candidate-assembly-3, r=compiler-errors
handle global trait bounds defining assoc types
This also fixes the compare-mode for
- tests/ui/coherence/coherent-due-to-fulfill.rs
- tests/ui/codegen/mono-impossible-2.rs
- tests/ui/trivial-bounds/trivial-bounds-inconsistent-projection.rs
- tests/ui/nll/issue-61320-normalize.rs
I first considered the alternative to always prefer where-bounds during normalization, regardless of how the trait goal has been proven by changing `fn merge_candidates` instead. ecda83b30f/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs (L785)
This approach is more restrictive than behavior of the old solver to avoid mismatches between trait and normalization goals. This may be breaking in case the where-bound adds unnecessary region constraints and we currently don't ever try to normalize an associated type. I would like to detect these cases and change the approach to exactly match the old solver if required. I want to minimize cases where attempting to normalize in more places causes code to break.
r? `@compiler-errors`
This commit is contained in:
commit
dafc861aa3
4 changed files with 49 additions and 22 deletions
|
@ -4260,7 +4260,6 @@ dependencies = [
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
"rustc_type_ir",
|
"rustc_type_ir",
|
||||||
"rustc_type_ir_macros",
|
"rustc_type_ir_macros",
|
||||||
"smallvec",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true }
|
||||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||||
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
||||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||||
smallvec = "1.8.1"
|
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
# tidy-alphabetical-end
|
# tidy-alphabetical-end
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||||
use rustc_type_ir::solve::CanonicalResponse;
|
use rustc_type_ir::solve::CanonicalResponse;
|
||||||
use rustc_type_ir::visit::TypeVisitableExt as _;
|
use rustc_type_ir::visit::TypeVisitableExt as _;
|
||||||
use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
|
use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
|
||||||
use smallvec::SmallVec;
|
|
||||||
use tracing::{instrument, trace};
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use crate::delegate::SolverDelegate;
|
use crate::delegate::SolverDelegate;
|
||||||
|
@ -1199,33 +1198,42 @@ where
|
||||||
// nested requirements, over all others. This is a fix for #53123 and
|
// nested requirements, over all others. This is a fix for #53123 and
|
||||||
// prevents where-bounds from accidentally extending the lifetime of a
|
// prevents where-bounds from accidentally extending the lifetime of a
|
||||||
// variable.
|
// variable.
|
||||||
if candidates
|
let mut trivial_builtin_impls = candidates.iter().filter(|c| {
|
||||||
.iter()
|
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
|
||||||
.any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)))
|
});
|
||||||
{
|
if let Some(candidate) = trivial_builtin_impls.next() {
|
||||||
let trivial_builtin_impls: SmallVec<[_; 1]> = candidates
|
|
||||||
.iter()
|
|
||||||
.filter(|c| {
|
|
||||||
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
|
|
||||||
})
|
|
||||||
.map(|c| c.result)
|
|
||||||
.collect();
|
|
||||||
// There should only ever be a single trivial builtin candidate
|
// There should only ever be a single trivial builtin candidate
|
||||||
// as they would otherwise overlap.
|
// as they would otherwise overlap.
|
||||||
assert_eq!(trivial_builtin_impls.len(), 1);
|
assert!(trivial_builtin_impls.next().is_none());
|
||||||
return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) {
|
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
|
||||||
Ok((response, Some(TraitGoalProvenVia::Misc)))
|
|
||||||
} else {
|
|
||||||
Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are non-global where-bounds, prefer where-bounds
|
// If there are non-global where-bounds, prefer where-bounds
|
||||||
// (including global ones) over everything else.
|
// (including global ones) over everything else.
|
||||||
let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
|
let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
|
||||||
CandidateSource::ParamEnv(idx) => {
|
CandidateSource::ParamEnv(idx) => {
|
||||||
let where_bound = goal.param_env.caller_bounds().get(idx);
|
let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
|
||||||
where_bound.has_bound_vars() || !where_bound.is_global()
|
let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
|
||||||
|
unreachable!("expected trait-bound: {where_bound:?}");
|
||||||
|
};
|
||||||
|
|
||||||
|
if trait_pred.has_bound_vars() || !trait_pred.is_global() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't consider a trait-bound global if it has a projection bound.
|
||||||
|
//
|
||||||
|
// See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
|
||||||
|
// for an example where this is necessary.
|
||||||
|
for p in goal.param_env.caller_bounds().iter() {
|
||||||
|
if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
|
||||||
|
if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
//@ compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// `(): Trait` is a global where-bound with a projection bound.
|
||||||
|
// This previously resulted in ambiguity as we considered both
|
||||||
|
// the impl and the where-bound while normalizing.
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl Trait for () {
|
||||||
|
type Assoc = &'static ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<'a>(x: <() as Trait>::Assoc)
|
||||||
|
where
|
||||||
|
(): Trait<Assoc = &'a ()>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue