Skip to content

Commit 0d45ef8

Browse files
committed
refactor winnowing
1 parent 1a58c9e commit 0d45ef8

File tree

12 files changed

+113
-378
lines changed

12 files changed

+113
-378
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/select/candidate_assembly.rs

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

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

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

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

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

59-
ParamCandidate(param) => {
59+
ParamCandidate { predicate, is_global: _ } => {
6060
let obligations =
61-
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
61+
self.confirm_param_candidate(obligation, predicate.map_bound(|t| t.trait_ref));
6262
ImplSource::Param(obligations)
6363
}
6464

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

+44-143
Original file line numberDiff line numberDiff line change
@@ -1575,7 +1575,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15751575
return false;
15761576
}
15771577
match result {
1578-
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
1578+
Ok(Some(SelectionCandidate::ParamCandidate { predicate, .. })) => {
1579+
!predicate.has_infer()
1580+
}
15791581
_ => true,
15801582
}
15811583
}
@@ -1827,31 +1829,35 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18271829
return DropVictim::Yes;
18281830
}
18291831

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

1854-
(ParamCandidate(other), ParamCandidate(victim)) => {
1849+
// Global bounds from the where clause should be ignored
1850+
// here (see issue #50825).
1851+
(ParamCandidate { is_global: true, .. }, ParamCandidate { is_global: true, .. }) => {
1852+
DropVictim::No
1853+
}
1854+
(_, ParamCandidate { is_global: true, .. }) => DropVictim::Yes,
1855+
(ParamCandidate { is_global: true, .. }, _) => DropVictim::No,
1856+
1857+
(
1858+
ParamCandidate { is_global: false, predicate: other },
1859+
ParamCandidate { is_global: false, predicate: victim },
1860+
) => {
18551861
let same_except_bound_vars = other.skip_binder().trait_ref
18561862
== victim.skip_binder().trait_ref
18571863
&& other.skip_binder().polarity == victim.skip_binder().polarity
@@ -1868,63 +1874,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18681874
}
18691875
}
18701876

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

19291880
(ProjectionCandidate(i), ProjectionCandidate(j))
19301881
| (ObjectCandidate(i), ObjectCandidate(j)) => {
@@ -1937,44 +1888,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19371888
bug!("Have both object and projection candidate")
19381889
}
19391890

1940-
// Arbitrarily give projection and object candidates priority.
1941-
(
1942-
ObjectCandidate(_) | ProjectionCandidate(_),
1943-
ImplCandidate(..)
1944-
| AutoImplCandidate
1945-
| ClosureCandidate { .. }
1946-
| AsyncClosureCandidate
1947-
| AsyncFnKindHelperCandidate
1948-
| CoroutineCandidate
1949-
| FutureCandidate
1950-
| IteratorCandidate
1951-
| AsyncIteratorCandidate
1952-
| FnPointerCandidate { .. }
1953-
| BuiltinObjectCandidate
1954-
| BuiltinUnsizeCandidate
1955-
| TraitUpcastingUnsizeCandidate(_)
1956-
| BuiltinCandidate { .. }
1957-
| TraitAliasCandidate,
1958-
) => DropVictim::Yes,
1891+
// Arbitrarily give projection candidates priority.
1892+
(ProjectionCandidate(_), _) => DropVictim::Yes,
1893+
(_, ProjectionCandidate(_)) => DropVictim::No,
19591894

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

19791904
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
19801905
// See if we can toss out `victim` based on specialization.
@@ -2054,49 +1979,25 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20541979
}
20551980
}
20561981

2057-
(AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => {
2058-
DropVictim::No
2059-
}
2060-
2061-
(AutoImplCandidate, _) | (_, AutoImplCandidate) => {
2062-
bug!(
2063-
"default implementations shouldn't be recorded \
2064-
when there are other global candidates: {:?} {:?}",
2065-
other,
2066-
victim
2067-
);
2068-
}
2069-
2070-
// Everything else is ambiguous
1982+
// Treat all non-trivial builtin impls and user-defined impls the same way.
20711983
(
20721984
ImplCandidate(_)
2073-
| ClosureCandidate { .. }
2074-
| AsyncClosureCandidate
2075-
| AsyncFnKindHelperCandidate
2076-
| CoroutineCandidate
2077-
| FutureCandidate
2078-
| IteratorCandidate
2079-
| AsyncIteratorCandidate
2080-
| FnPointerCandidate { .. }
2081-
| BuiltinObjectCandidate
2082-
| BuiltinUnsizeCandidate
2083-
| TraitUpcastingUnsizeCandidate(_)
1985+
| AutoImplCandidate
20841986
| BuiltinCandidate { has_nested: true }
2085-
| TraitAliasCandidate,
2086-
ImplCandidate(_)
2087-
| ClosureCandidate { .. }
20881987
| AsyncClosureCandidate
20891988
| AsyncFnKindHelperCandidate
20901989
| CoroutineCandidate
20911990
| FutureCandidate
20921991
| IteratorCandidate
20931992
| AsyncIteratorCandidate
20941993
| FnPointerCandidate { .. }
2095-
| BuiltinObjectCandidate
1994+
| ClosureCandidate { .. }
1995+
| TraitAliasCandidate
20961996
| BuiltinUnsizeCandidate
20971997
| TraitUpcastingUnsizeCandidate(_)
2098-
| BuiltinCandidate { has_nested: true }
2099-
| TraitAliasCandidate,
1998+
| TransmutabilityCandidate
1999+
| BuiltinObjectCandidate,
2000+
_,
21002001
) => DropVictim::No,
21012002
}
21022003
}

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -4062,7 +4062,6 @@ ui/traits/issue-6128.rs
40624062
ui/traits/issue-6334.rs
40634063
ui/traits/issue-65284-suggest-generic-trait-bound.rs
40644064
ui/traits/issue-65673.rs
4065-
ui/traits/issue-66768.rs
40664065
ui/traits/issue-68295.rs
40674066
ui/traits/issue-7013.rs
40684067
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/lifetimes/issue-34979.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ impl<'a, T> Foo for &'a T {}
33

44
struct Ctx<'a>(&'a ())
55
where
6-
&'a (): Foo, //~ ERROR: type annotations needed
7-
&'static (): Foo;
6+
&'a (): Foo,
7+
&'static (): Foo; //~ ERROR: mismatched types
88

99
fn main() {}

tests/ui/lifetimes/issue-34979.stderr

+12-14
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo`
2-
--> $DIR/issue-34979.rs:6:13
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-34979.rs:7:18
33
|
4-
LL | &'a (): Foo,
5-
| ^^^
4+
LL | &'static (): Foo;
5+
| ^^^ lifetime mismatch
66
|
7-
note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
8-
--> $DIR/issue-34979.rs:2:1
7+
= note: expected trait `<&'static () as Foo>`
8+
found trait `<&'a () as Foo>`
9+
note: the lifetime `'a` as defined here...
10+
--> $DIR/issue-34979.rs:4:12
911
|
10-
LL | impl<'a, T> Foo for &'a T {}
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12-
...
13-
LL | &'a (): Foo,
14-
| ^^^
15-
LL | &'static (): Foo;
16-
| ^^^
12+
LL | struct Ctx<'a>(&'a ())
13+
| ^^
14+
= note: ...does not necessarily outlive the static lifetime
1715

1816
error: aborting due to 1 previous error
1917

20-
For more information about this error, try `rustc --explain E0283`.
18+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)