Skip to content

Commit c0dcb18

Browse files
authored
Rollup merge of rust-lang#124532 - lcnr:elaborate-coherence, r=compiler-errors
elaborate obligations in coherence The following test currently does not pass coherence: ```rust trait Super {} trait Sub<T>: Super {} trait Overlap<T> {} impl<T, U: Sub<T>> Overlap<T> for U {} impl<T> Overlap<T> for () {} fn main() {} ``` We check whether `(): Sub<?t>` holds. This stalls with ambiguity as downstream crates may add an impl for `(): Sub<Local>`. However, its super trait bound `(): Super` cannot be implemented downstream, so this one is known not to hold. By elaborating the bounds in the implicit negative overlap check, this now compiles. This is necessary to prevent breakage from enabling `-Znext-solver=coherence` (rust-lang#121848), see tests/ui/coherence/super-traits/super-trait-knowable-2.rs for more details. r? ``@compiler-errors``
2 parents 8384ed3 + 03d9e84 commit c0dcb18

24 files changed

+230
-390
lines changed

compiler/rustc_middle/src/traits/select.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,18 @@ pub enum SelectionCandidate<'tcx> {
121121
/// Implementation of transmutability trait.
122122
TransmutabilityCandidate,
123123

124-
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
124+
/// A candidate from the `ParamEnv`.
125+
ParamCandidate {
126+
/// The actual `where`-bound, e.g. `T: Trait`.
127+
predicate: ty::PolyTraitPredicate<'tcx>,
128+
/// `true` if the where-bound has no bound vars and does
129+
/// not refer to any parameters or inference variables.
130+
///
131+
/// We prefer all other candidates over global where-bounds.
132+
/// Notably, global where-bounds do not shadow impls.
133+
is_global: bool,
134+
},
135+
125136
ImplCandidate(DefId),
126137
AutoImplCandidate,
127138

compiler/rustc_trait_selection/src/traits/coherence.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,12 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
359359
) -> IntersectionHasImpossibleObligations<'tcx> {
360360
let infcx = selcx.infcx;
361361

362+
// Elaborate obligations in case the current obligation is unknowable,
363+
// but its super trait bound is not. See #124532 for more details.
364+
let obligations = util::elaborate(infcx.tcx, obligations.iter().cloned());
362365
if infcx.next_trait_solver() {
363366
let ocx = ObligationCtxt::new(infcx);
364-
ocx.register_obligations(obligations.iter().cloned());
367+
ocx.register_obligations(obligations);
365368
let errors_and_ambiguities = ocx.select_all_or_error();
366369
// We only care about the obligations that are *definitely* true errors.
367370
// Ambiguities do not prove the disjointness of two impls.
@@ -388,7 +391,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
388391
for obligation in obligations {
389392
// We use `evaluate_root_obligation` to correctly track intercrate
390393
// ambiguity clauses.
391-
let evaluation_result = selcx.evaluate_root_obligation(obligation);
394+
let evaluation_result = selcx.evaluate_root_obligation(&obligation);
392395

393396
match evaluation_result {
394397
Ok(result) => {

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
252252
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
253253

254254
// Keep only those bounds which may apply, and propagate overflow if it occurs.
255-
for bound in matching_bounds {
256-
if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity {
255+
for predicate in matching_bounds {
256+
if predicate.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity
257+
{
257258
continue;
258259
}
259260

260261
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
261262
// polarity here.
262-
let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
263+
let wc = self.where_clause_may_apply(stack, predicate.map_bound(|t| t.trait_ref))?;
263264
if wc.may_apply() {
264-
candidates.vec.push(ParamCandidate(bound));
265+
let is_global = predicate.is_global() && !predicate.has_bound_vars();
266+
candidates.vec.push(ParamCandidate { predicate, is_global });
265267
}
266268
}
267269

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
5757
ImplSource::Builtin(BuiltinImplSource::Misc, data)
5858
}
5959

60-
ParamCandidate(param) => {
60+
ParamCandidate { predicate, is_global: _ } => {
6161
let obligations =
62-
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
62+
self.confirm_param_candidate(obligation, predicate.map_bound(|t| t.trait_ref));
6363
ImplSource::Param(obligations)
6464
}
6565

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

+44-148
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15771577
return false;
15781578
}
15791579
match result {
1580-
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
1580+
Ok(Some(SelectionCandidate::ParamCandidate { predicate, .. })) => {
1581+
!predicate.has_infer()
1582+
}
15811583
_ => true,
15821584
}
15831585
}
@@ -1829,31 +1831,35 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18291831
return DropVictim::Yes;
18301832
}
18311833

1832-
// Check if a bound would previously have been removed when normalizing
1833-
// the param_env so that it can be given the lowest priority. See
1834-
// #50825 for the motivation for this.
1835-
let is_global =
1836-
|cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
1837-
1838-
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
1839-
// `DiscriminantKindCandidate`, `ConstDestructCandidate`
1840-
// to anything else.
1841-
//
1842-
// This is a fix for #53123 and prevents winnowing from accidentally extending the
1843-
// lifetime of a variable.
18441834
match (&other.candidate, &victim.candidate) {
1845-
// FIXME(@jswrenn): this should probably be more sophisticated
1846-
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
1847-
1848-
// (*)
1835+
// Prefer `BuiltinCandidate { has_nested: false }`, `ConstDestructCandidate`
1836+
// to anything else.
1837+
//
1838+
// This is a fix for #53123 and prevents winnowing from accidentally extending the
1839+
// lifetime of a variable.
1840+
(
1841+
BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_),
1842+
BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_),
1843+
) => bug!("two trivial builtin candidates: {other:?} {victim:?}"),
18491844
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => {
18501845
DropVictim::Yes
18511846
}
18521847
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
18531848
DropVictim::No
18541849
}
18551850

1856-
(ParamCandidate(other), ParamCandidate(victim)) => {
1851+
// Global bounds from the where clause should be ignored
1852+
// here (see issue #50825).
1853+
(ParamCandidate { is_global: true, .. }, ParamCandidate { is_global: true, .. }) => {
1854+
DropVictim::No
1855+
}
1856+
(_, ParamCandidate { is_global: true, .. }) => DropVictim::Yes,
1857+
(ParamCandidate { is_global: true, .. }, _) => DropVictim::No,
1858+
1859+
(
1860+
ParamCandidate { is_global: false, predicate: other },
1861+
ParamCandidate { is_global: false, predicate: victim },
1862+
) => {
18571863
let same_except_bound_vars = other.skip_binder().trait_ref
18581864
== victim.skip_binder().trait_ref
18591865
&& other.skip_binder().polarity == victim.skip_binder().polarity
@@ -1870,68 +1876,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18701876
}
18711877
}
18721878

1873-
// Drop otherwise equivalent non-const fn pointer candidates
1874-
(FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
1875-
DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
1876-
}
1877-
1878-
(
1879-
ParamCandidate(ref other_cand),
1880-
ImplCandidate(..)
1881-
| AutoImplCandidate
1882-
| ClosureCandidate { .. }
1883-
| AsyncClosureCandidate
1884-
| AsyncFnKindHelperCandidate
1885-
| CoroutineCandidate
1886-
| FutureCandidate
1887-
| IteratorCandidate
1888-
| AsyncIteratorCandidate
1889-
| FnPointerCandidate { .. }
1890-
| BuiltinObjectCandidate
1891-
| BuiltinUnsizeCandidate
1892-
| TraitUpcastingUnsizeCandidate(_)
1893-
| BuiltinCandidate { .. }
1894-
| TraitAliasCandidate
1895-
| ObjectCandidate(_)
1896-
| ProjectionCandidate(_),
1897-
) => {
1898-
// We have a where clause so don't go around looking
1899-
// for impls. Arbitrarily give param candidates priority
1900-
// over projection and object candidates.
1901-
//
1902-
// Global bounds from the where clause should be ignored
1903-
// here (see issue #50825).
1904-
DropVictim::drop_if(!is_global(other_cand))
1905-
}
1906-
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
1907-
// Prefer these to a global where-clause bound
1908-
// (see issue #50825).
1909-
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
1910-
}
1911-
(
1912-
ImplCandidate(_)
1913-
| AutoImplCandidate
1914-
| ClosureCandidate { .. }
1915-
| AsyncClosureCandidate
1916-
| AsyncFnKindHelperCandidate
1917-
| CoroutineCandidate
1918-
| FutureCandidate
1919-
| IteratorCandidate
1920-
| AsyncIteratorCandidate
1921-
| FnPointerCandidate { .. }
1922-
| BuiltinObjectCandidate
1923-
| BuiltinUnsizeCandidate
1924-
| TraitUpcastingUnsizeCandidate(_)
1925-
| BuiltinCandidate { has_nested: true }
1926-
| TraitAliasCandidate,
1927-
ParamCandidate(ref victim_cand),
1928-
) => {
1929-
// Prefer these to a global where-clause bound
1930-
// (see issue #50825).
1931-
DropVictim::drop_if(
1932-
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
1933-
)
1934-
}
1879+
(ParamCandidate { is_global: false, .. }, _) => DropVictim::Yes,
1880+
(_, ParamCandidate { is_global: false, .. }) => DropVictim::No,
19351881

19361882
(ProjectionCandidate(i), ProjectionCandidate(j))
19371883
| (ObjectCandidate(i), ObjectCandidate(j)) => {
@@ -1944,44 +1890,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19441890
bug!("Have both object and projection candidate")
19451891
}
19461892

1947-
// Arbitrarily give projection and object candidates priority.
1948-
(
1949-
ObjectCandidate(_) | ProjectionCandidate(_),
1950-
ImplCandidate(..)
1951-
| AutoImplCandidate
1952-
| ClosureCandidate { .. }
1953-
| AsyncClosureCandidate
1954-
| AsyncFnKindHelperCandidate
1955-
| CoroutineCandidate
1956-
| FutureCandidate
1957-
| IteratorCandidate
1958-
| AsyncIteratorCandidate
1959-
| FnPointerCandidate { .. }
1960-
| BuiltinObjectCandidate
1961-
| BuiltinUnsizeCandidate
1962-
| TraitUpcastingUnsizeCandidate(_)
1963-
| BuiltinCandidate { .. }
1964-
| TraitAliasCandidate,
1965-
) => DropVictim::Yes,
1893+
// Arbitrarily give projection candidates priority.
1894+
(ProjectionCandidate(_), _) => DropVictim::Yes,
1895+
(_, ProjectionCandidate(_)) => DropVictim::No,
19661896

1967-
(
1968-
ImplCandidate(..)
1969-
| AutoImplCandidate
1970-
| ClosureCandidate { .. }
1971-
| AsyncClosureCandidate
1972-
| AsyncFnKindHelperCandidate
1973-
| CoroutineCandidate
1974-
| FutureCandidate
1975-
| IteratorCandidate
1976-
| AsyncIteratorCandidate
1977-
| FnPointerCandidate { .. }
1978-
| BuiltinObjectCandidate
1979-
| BuiltinUnsizeCandidate
1980-
| TraitUpcastingUnsizeCandidate(_)
1981-
| BuiltinCandidate { .. }
1982-
| TraitAliasCandidate,
1983-
ObjectCandidate(_) | ProjectionCandidate(_),
1984-
) => DropVictim::No,
1897+
// Need to prioritize builtin trait object impls as
1898+
// `<dyn Any as Any>::type_id` should use the vtable method
1899+
// and not the method provided by the user-defined impl
1900+
// `impl<T: ?Sized> Any for T { .. }`.
1901+
//
1902+
// cc #57893
1903+
(ObjectCandidate(_), _) => DropVictim::Yes,
1904+
(_, ObjectCandidate(_)) => DropVictim::No,
19851905

19861906
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
19871907
// See if we can toss out `victim` based on specialization.
@@ -2061,49 +1981,25 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20611981
}
20621982
}
20631983

2064-
(AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => {
2065-
DropVictim::No
2066-
}
2067-
2068-
(AutoImplCandidate, _) | (_, AutoImplCandidate) => {
2069-
bug!(
2070-
"default implementations shouldn't be recorded \
2071-
when there are other global candidates: {:?} {:?}",
2072-
other,
2073-
victim
2074-
);
2075-
}
2076-
2077-
// Everything else is ambiguous
1984+
// Treat all non-trivial builtin impls and user-defined impls the same way.
20781985
(
20791986
ImplCandidate(_)
2080-
| ClosureCandidate { .. }
2081-
| AsyncClosureCandidate
2082-
| AsyncFnKindHelperCandidate
2083-
| CoroutineCandidate
2084-
| FutureCandidate
2085-
| IteratorCandidate
2086-
| AsyncIteratorCandidate
2087-
| FnPointerCandidate { .. }
2088-
| BuiltinObjectCandidate
2089-
| BuiltinUnsizeCandidate
2090-
| TraitUpcastingUnsizeCandidate(_)
1987+
| AutoImplCandidate
20911988
| BuiltinCandidate { has_nested: true }
2092-
| TraitAliasCandidate,
2093-
ImplCandidate(_)
2094-
| ClosureCandidate { .. }
20951989
| AsyncClosureCandidate
20961990
| AsyncFnKindHelperCandidate
20971991
| CoroutineCandidate
20981992
| FutureCandidate
20991993
| IteratorCandidate
21001994
| AsyncIteratorCandidate
21011995
| FnPointerCandidate { .. }
2102-
| BuiltinObjectCandidate
1996+
| ClosureCandidate { .. }
1997+
| TraitAliasCandidate
21031998
| BuiltinUnsizeCandidate
21041999
| TraitUpcastingUnsizeCandidate(_)
2105-
| BuiltinCandidate { has_nested: true }
2106-
| TraitAliasCandidate,
2000+
| TransmutabilityCandidate
2001+
| BuiltinObjectCandidate,
2002+
_,
21072003
) => DropVictim::No,
21082004
}
21092005
}

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -4061,7 +4061,6 @@ ui/traits/issue-6128.rs
40614061
ui/traits/issue-6334.rs
40624062
ui/traits/issue-65284-suggest-generic-trait-bound.rs
40634063
ui/traits/issue-65673.rs
4064-
ui/traits/issue-66768.rs
40654064
ui/traits/issue-68295.rs
40664065
ui/traits/issue-7013.rs
40674066
ui/traits/issue-70944.rs

tests/ui/associated-item/issue-105449.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
//@ check-pass
21
//@ compile-flags: -C debug_assertions=yes -Zunstable-options
32

4-
#[allow(dead_code)]
3+
// This is a mutated variant of #66768 which has been removed
4+
// as it no longer tests the original issue.
55
fn problematic_function<Space>()
66
where
77
DefaultAlloc: FinAllok<R1, Space>,
88
{
99
let e = Edge2dElement;
1010
let _ = Into::<Point>::into(e.map_reference_coords());
11+
//~^ ERROR the trait bound `Point: From<(Ure, R1, MStorage)>` is not satisfied
1112
}
1213
impl<N> Allocator<N, R0> for DefaultAlloc {
1314
type Buffer = MStorage;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: the trait bound `Point: From<(Ure, R1, MStorage)>` is not satisfied
2+
--> $DIR/issue-105449.rs:10:33
3+
|
4+
LL | let _ = Into::<Point>::into(e.map_reference_coords());
5+
| ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<(Ure, R1, MStorage)>` is not implemented for `Point`, which is required by `(Ure, R1, MStorage): Into<Point>`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `From<(Ure, Space, <DefaultAlloc as Allocator<Ure, Space>>::Buffer)>` is implemented for `Point`
10+
= help: for that trait implementation, expected `Space`, found `R1`
11+
= note: required for `(Ure, R1, MStorage)` to implement `Into<Point>`
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.

tests/ui/coherence/coherence-overlap-unnormalizable-projection-0.classic.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ LL | | for<'a> <T as WithAssoc<'a>>::Assoc: WhereBound,
1111
LL | impl<T> Trait for Box<T> {}
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
1313
|
14-
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
1514
= note: downstream crates may implement trait `WhereBound` for type `<std::boxed::Box<_> as WithAssoc<'a>>::Assoc`
15+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
1616

1717
error: aborting due to 1 previous error
1818

tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.classic.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ LL | | for<'a> Box<<T as WithAssoc<'a>>::Assoc>: WhereBound,
1111
LL | impl<T> Trait for Box<T> {}
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
1313
|
14-
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
1514
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
15+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
1616

1717
error: aborting due to 1 previous error
1818

tests/ui/coherence/normalize-for-errors.current.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Ite
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)`
99
|
1010
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
11+
= note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions
1112

1213
error: aborting due to 1 previous error
1314

0 commit comments

Comments
 (0)