Skip to content

Commit b1035d7

Browse files
Rollup merge of #135498 - compiler-errors:dyn-upcasting-completeness, r=lcnr
Prefer lower `TraitUpcasting` candidates in selection Fixes #135463. The underlying cause is this ambiguity, but it's more clear (and manifests as a coercion error, rather than a MIR validation error) when it's written the way I did in the UI test. Sorry this is cursed r? lcnr
2 parents b1d047b + bf545ce commit b1035d7

File tree

6 files changed

+54
-6
lines changed

6 files changed

+54
-6
lines changed

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -741,12 +741,14 @@ where
741741
a_data.principal(),
742742
));
743743
} else if let Some(a_principal) = a_data.principal() {
744-
for new_a_principal in
745-
elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1)
744+
for (idx, new_a_principal) in
745+
elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
746+
.enumerate()
747+
.skip(1)
746748
{
747749
responses.extend(self.consider_builtin_upcast_to_principal(
748750
goal,
749-
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
751+
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
750752
a_data,
751753
a_region,
752754
b_data,

compiler/rustc_trait_selection/src/solve/select.rs

+4
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
117117
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)),
118118
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)),
119119
) => a >= b,
120+
(
121+
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(a)),
122+
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(b)),
123+
) => a >= b,
120124
// Prefer dyn candidates over non-dyn candidates. This is necessary to
121125
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
122126
(

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10901090
)?
10911091
.expect("did not expect ambiguity during confirmation");
10921092

1093-
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting, nested))
1093+
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting(idx), nested))
10941094
}
10951095

10961096
fn confirm_builtin_unsize_candidate(

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

+12
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18951895
Some(None) => {}
18961896
None => return None,
18971897
}
1898+
// Same for upcasting.
1899+
let upcast_bound = candidates
1900+
.iter()
1901+
.filter_map(|c| {
1902+
if let TraitUpcastingUnsizeCandidate(i) = c.candidate { Some(i) } else { None }
1903+
})
1904+
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
1905+
match upcast_bound {
1906+
Some(Some(index)) => return Some(TraitUpcastingUnsizeCandidate(index)),
1907+
Some(None) => {}
1908+
None => return None,
1909+
}
18981910

18991911
// Finally, handle overlapping user-written impls.
19001912
let impls = candidates.iter().filter_map(|c| {

compiler/rustc_type_ir/src/solve/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ pub enum BuiltinImplSource {
177177
/// A built-in implementation of `Upcast` for trait objects to other trait objects.
178178
///
179179
/// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only
180-
/// use it to detect when upcasting traits in hir typeck.
181-
TraitUpcasting,
180+
/// use it to detect when upcasting traits in hir typeck. The index is only used
181+
/// for winnowing.
182+
TraitUpcasting(usize),
182183
/// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
183184
///
184185
/// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
6+
// Ensure we don't have ambiguity when upcasting to two supertraits
7+
// that are identical modulo normalization.
8+
9+
#![feature(trait_upcasting)]
10+
11+
trait Supertrait<T> {
12+
fn method(&self) {}
13+
}
14+
impl<T> Supertrait<T> for () {}
15+
16+
trait Identity {
17+
type Selff;
18+
}
19+
impl<Selff> Identity for Selff {
20+
type Selff = Selff;
21+
}
22+
trait Trait<P>: Supertrait<()> + Supertrait<<P as Identity>::Selff> {}
23+
24+
impl<P> Trait<P> for () {}
25+
26+
fn main() {
27+
let x: &dyn Trait<()> = &();
28+
let x: &dyn Supertrait<()> = x;
29+
}

0 commit comments

Comments
 (0)