Skip to content

Commit dafc861

Browse files
authored
Rollup merge of rust-lang#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. https://github.com/rust-lang/rust/blob/ecda83b30f0f68cf5692855dddc0bc38ee8863fc/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`
2 parents 4496f23 + 09b784f commit dafc861

File tree

4 files changed

+49
-22
lines changed

4 files changed

+49
-22
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4260,7 +4260,6 @@ dependencies = [
42604260
"rustc_serialize",
42614261
"rustc_type_ir",
42624262
"rustc_type_ir_macros",
4263-
"smallvec",
42644263
"tracing",
42654264
]
42664265

compiler/rustc_next_trait_solver/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true }
1313
rustc_serialize = { path = "../rustc_serialize", optional = true }
1414
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
1515
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
16-
smallvec = "1.8.1"
1716
tracing = "0.1"
1817
# tidy-alphabetical-end
1918

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
88
use rustc_type_ir::solve::CanonicalResponse;
99
use rustc_type_ir::visit::TypeVisitableExt as _;
1010
use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
11-
use smallvec::SmallVec;
1211
use tracing::{instrument, trace};
1312

1413
use crate::delegate::SolverDelegate;
@@ -1199,33 +1198,42 @@ where
11991198
// nested requirements, over all others. This is a fix for #53123 and
12001199
// prevents where-bounds from accidentally extending the lifetime of a
12011200
// variable.
1202-
if candidates
1203-
.iter()
1204-
.any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)))
1205-
{
1206-
let trivial_builtin_impls: SmallVec<[_; 1]> = candidates
1207-
.iter()
1208-
.filter(|c| {
1209-
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1210-
})
1211-
.map(|c| c.result)
1212-
.collect();
1201+
let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1202+
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1203+
});
1204+
if let Some(candidate) = trivial_builtin_impls.next() {
12131205
// There should only ever be a single trivial builtin candidate
12141206
// as they would otherwise overlap.
1215-
assert_eq!(trivial_builtin_impls.len(), 1);
1216-
return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) {
1217-
Ok((response, Some(TraitGoalProvenVia::Misc)))
1218-
} else {
1219-
Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None))
1220-
};
1207+
assert!(trivial_builtin_impls.next().is_none());
1208+
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
12211209
}
12221210

12231211
// If there are non-global where-bounds, prefer where-bounds
12241212
// (including global ones) over everything else.
12251213
let has_non_global_where_bounds = candidates.iter().any(|c| match c.source {
12261214
CandidateSource::ParamEnv(idx) => {
1227-
let where_bound = goal.param_env.caller_bounds().get(idx);
1228-
where_bound.has_bound_vars() || !where_bound.is_global()
1215+
let where_bound = goal.param_env.caller_bounds().get(idx).unwrap();
1216+
let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else {
1217+
unreachable!("expected trait-bound: {where_bound:?}");
1218+
};
1219+
1220+
if trait_pred.has_bound_vars() || !trait_pred.is_global() {
1221+
return true;
1222+
}
1223+
1224+
// We don't consider a trait-bound global if it has a projection bound.
1225+
//
1226+
// See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
1227+
// for an example where this is necessary.
1228+
for p in goal.param_env.caller_bounds().iter() {
1229+
if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
1230+
if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
1231+
return true;
1232+
}
1233+
}
1234+
}
1235+
1236+
false
12291237
}
12301238
_ => false,
12311239
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: -Znext-solver
2+
//@ check-pass
3+
4+
// `(): Trait` is a global where-bound with a projection bound.
5+
// This previously resulted in ambiguity as we considered both
6+
// the impl and the where-bound while normalizing.
7+
8+
trait Trait {
9+
type Assoc;
10+
}
11+
impl Trait for () {
12+
type Assoc = &'static ();
13+
}
14+
15+
fn foo<'a>(x: <() as Trait>::Assoc)
16+
where
17+
(): Trait<Assoc = &'a ()>,
18+
{
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)