Skip to content

Commit 4bd33fd

Browse files
authored
Rollup merge of #102472 - lcnr:static-in-eval, r=jackh726
stop special-casing `'static` in evaluation fixes #102360 I have no idea whether this actually removed all places where `'static` matters. Without canonicalization it's very easy to accidentally rely on `'static` again. Blocked on changing the `order_dependent_trait_objects` future-compat lint to a hard error r? `@nikomatsakis`
2 parents 0883848 + 73c79cd commit 4bd33fd

File tree

7 files changed

+151
-102
lines changed

7 files changed

+151
-102
lines changed

Diff for: compiler/rustc_infer/src/infer/freshen.rs

+3-14
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
4343
const_freshen_count: u32,
4444
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
4545
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
46-
keep_static: bool,
4746
}
4847

4948
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
50-
pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
49+
pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
5150
TypeFreshener {
5251
infcx,
5352
ty_freshen_count: 0,
5453
const_freshen_count: 0,
5554
ty_freshen_map: Default::default(),
5655
const_freshen_map: Default::default(),
57-
keep_static,
5856
}
5957
}
6058

@@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
121119
| ty::ReFree(_)
122120
| ty::ReVar(_)
123121
| ty::RePlaceholder(..)
122+
| ty::ReStatic
124123
| ty::ReError(_)
125-
| ty::ReErased => {
126-
// replace all free regions with 'erased
127-
self.interner().lifetimes.re_erased
128-
}
129-
ty::ReStatic => {
130-
if self.keep_static {
131-
r
132-
} else {
133-
self.interner().lifetimes.re_erased
134-
}
135-
}
124+
| ty::ReErased => self.interner().lifetimes.re_erased,
136125
}
137126
}
138127

Diff for: compiler/rustc_infer/src/infer/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -713,12 +713,7 @@ impl<'tcx> InferCtxt<'tcx> {
713713
}
714714

715715
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
716-
freshen::TypeFreshener::new(self, false)
717-
}
718-
719-
/// Like `freshener`, but does not replace `'static` regions.
720-
pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
721-
freshen::TypeFreshener::new(self, true)
716+
freshen::TypeFreshener::new(self)
722717
}
723718

724719
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {

Diff for: compiler/rustc_trait_selection/src/traits/select/mod.rs

+86-78
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
211211
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
212212
SelectionContext {
213213
infcx,
214-
freshener: infcx.freshener_keep_static(),
214+
freshener: infcx.freshener(),
215215
intercrate_ambiguity_causes: None,
216216
query_mode: TraitQueryMode::Standard,
217217
}
@@ -770,14 +770,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
770770
}
771771

772772
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => {
773-
// A global type with no late-bound regions can only
774-
// contain the "'static" lifetime (any other lifetime
775-
// would either be late-bound or local), so it is guaranteed
776-
// to outlive any other lifetime
777-
if pred.0.is_global() && !pred.0.has_late_bound_vars() {
778-
Ok(EvaluatedToOk)
779-
} else {
773+
// A global type with no free lifetimes or generic parameters
774+
// outlives anything.
775+
if pred.0.has_free_regions()
776+
|| pred.0.has_late_bound_regions()
777+
|| pred.0.has_non_region_infer()
778+
|| pred.0.has_non_region_infer()
779+
{
780780
Ok(EvaluatedToOkModuloRegions)
781+
} else {
782+
Ok(EvaluatedToOk)
781783
}
782784
}
783785

@@ -1825,6 +1827,12 @@ enum DropVictim {
18251827
No,
18261828
}
18271829

1830+
impl DropVictim {
1831+
fn drop_if(should_drop: bool) -> DropVictim {
1832+
if should_drop { DropVictim::Yes } else { DropVictim::No }
1833+
}
1834+
}
1835+
18281836
/// ## Winnowing
18291837
///
18301838
/// Winnowing is the process of attempting to resolve ambiguity by
@@ -1890,11 +1898,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18901898
// or the current one if tied (they should both evaluate to the same answer). This is
18911899
// probably best characterized as a "hack", since we might prefer to just do our
18921900
// best to *not* create essentially duplicate candidates in the first place.
1893-
if other.bound_vars().len() <= victim.bound_vars().len() {
1894-
DropVictim::Yes
1895-
} else {
1896-
DropVictim::No
1897-
}
1901+
DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
18981902
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
18991903
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
19001904
&& other.skip_binder().polarity == victim.skip_binder().polarity
@@ -1924,17 +1928,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19241928
| ObjectCandidate(_)
19251929
| ProjectionCandidate(..),
19261930
) => {
1927-
if is_global(other_cand) {
1928-
DropVictim::No
1929-
} else {
1930-
// We have a where clause so don't go around looking
1931-
// for impls. Arbitrarily give param candidates priority
1932-
// over projection and object candidates.
1933-
//
1934-
// Global bounds from the where clause should be ignored
1935-
// here (see issue #50825).
1936-
DropVictim::Yes
1937-
}
1931+
// We have a where clause so don't go around looking
1932+
// for impls. Arbitrarily give param candidates priority
1933+
// over projection and object candidates.
1934+
//
1935+
// Global bounds from the where clause should be ignored
1936+
// here (see issue #50825).
1937+
DropVictim::drop_if(!is_global(other_cand))
19381938
}
19391939
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
19401940
// Prefer these to a global where-clause bound
@@ -1956,18 +1956,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19561956
) => {
19571957
// Prefer these to a global where-clause bound
19581958
// (see issue #50825).
1959-
if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() {
1960-
DropVictim::Yes
1961-
} else {
1962-
DropVictim::No
1963-
}
1959+
DropVictim::drop_if(
1960+
is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(),
1961+
)
19641962
}
19651963

19661964
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
19671965
| (ObjectCandidate(i), ObjectCandidate(j)) => {
19681966
// Arbitrarily pick the lower numbered candidate for backwards
19691967
// compatibility reasons. Don't let this affect inference.
1970-
if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No }
1968+
DropVictim::drop_if(i < j && !needs_infer)
19711969
}
19721970
(ObjectCandidate(_), ProjectionCandidate(..))
19731971
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@@ -2018,55 +2016,65 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20182016
}
20192017
}
20202018

2021-
if other.evaluation.must_apply_considering_regions() {
2022-
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
2023-
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
2024-
// Subtle: If the predicate we are evaluating has inference
2025-
// variables, do *not* allow discarding candidates due to
2026-
// marker trait impls.
2027-
//
2028-
// Without this restriction, we could end up accidentally
2029-
// constraining inference variables based on an arbitrarily
2030-
// chosen trait impl.
2031-
//
2032-
// Imagine we have the following code:
2033-
//
2034-
// ```rust
2035-
// #[marker] trait MyTrait {}
2036-
// impl MyTrait for u8 {}
2037-
// impl MyTrait for bool {}
2038-
// ```
2039-
//
2040-
// And we are evaluating the predicate `<_#0t as MyTrait>`.
2041-
//
2042-
// During selection, we will end up with one candidate for each
2043-
// impl of `MyTrait`. If we were to discard one impl in favor
2044-
// of the other, we would be left with one candidate, causing
2045-
// us to "successfully" select the predicate, unifying
2046-
// _#0t with (for example) `u8`.
2047-
//
2048-
// However, we have no reason to believe that this unification
2049-
// is correct - we've essentially just picked an arbitrary
2050-
// *possibility* for _#0t, and required that this be the *only*
2051-
// possibility.
2052-
//
2053-
// Eventually, we will either:
2054-
// 1) Unify all inference variables in the predicate through
2055-
// some other means (e.g. type-checking of a function). We will
2056-
// then be in a position to drop marker trait candidates
2057-
// without constraining inference variables (since there are
2058-
// none left to constrain)
2059-
// 2) Be left with some unconstrained inference variables. We
2060-
// will then correctly report an inference error, since the
2061-
// existence of multiple marker trait impls tells us nothing
2062-
// about which one should actually apply.
2063-
if needs_infer { DropVictim::No } else { DropVictim::Yes }
2064-
}
2065-
Some(_) => DropVictim::Yes,
2066-
None => DropVictim::No,
2019+
match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
2020+
// For #33140 the impl headers must be exactly equal, the trait must not have
2021+
// any associated items and there are no where-clauses.
2022+
//
2023+
// We can just arbitrarily drop one of the impls.
2024+
Some(ty::ImplOverlapKind::Issue33140) => {
2025+
assert_eq!(other.evaluation, victim.evaluation);
2026+
DropVictim::Yes
20672027
}
2068-
} else {
2069-
DropVictim::No
2028+
// For candidates which already reference errors it doesn't really
2029+
// matter what we do 🤷
2030+
Some(ty::ImplOverlapKind::Permitted { marker: false }) => {
2031+
DropVictim::drop_if(other.evaluation.must_apply_considering_regions())
2032+
}
2033+
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
2034+
// Subtle: If the predicate we are evaluating has inference
2035+
// variables, do *not* allow discarding candidates due to
2036+
// marker trait impls.
2037+
//
2038+
// Without this restriction, we could end up accidentally
2039+
// constraining inference variables based on an arbitrarily
2040+
// chosen trait impl.
2041+
//
2042+
// Imagine we have the following code:
2043+
//
2044+
// ```rust
2045+
// #[marker] trait MyTrait {}
2046+
// impl MyTrait for u8 {}
2047+
// impl MyTrait for bool {}
2048+
// ```
2049+
//
2050+
// And we are evaluating the predicate `<_#0t as MyTrait>`.
2051+
//
2052+
// During selection, we will end up with one candidate for each
2053+
// impl of `MyTrait`. If we were to discard one impl in favor
2054+
// of the other, we would be left with one candidate, causing
2055+
// us to "successfully" select the predicate, unifying
2056+
// _#0t with (for example) `u8`.
2057+
//
2058+
// However, we have no reason to believe that this unification
2059+
// is correct - we've essentially just picked an arbitrary
2060+
// *possibility* for _#0t, and required that this be the *only*
2061+
// possibility.
2062+
//
2063+
// Eventually, we will either:
2064+
// 1) Unify all inference variables in the predicate through
2065+
// some other means (e.g. type-checking of a function). We will
2066+
// then be in a position to drop marker trait candidates
2067+
// without constraining inference variables (since there are
2068+
// none left to constrain)
2069+
// 2) Be left with some unconstrained inference variables. We
2070+
// will then correctly report an inference error, since the
2071+
// existence of multiple marker trait impls tells us nothing
2072+
// about which one should actually apply.
2073+
DropVictim::drop_if(
2074+
!needs_infer && other.evaluation.must_apply_considering_regions(),
2075+
)
2076+
}
2077+
None => DropVictim::No,
20702078
}
20712079
}
20722080

Diff for: tests/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
// check-pass
1+
// known-bug: #89515
2+
//
3+
// The trait solver cannot deal with ambiguous marker trait impls
4+
// if there are lifetimes involved. As we must not special-case any
5+
// regions this does not work, even with 'static
26
#![feature(marker_trait_attr)]
37

48
#[marker]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
2+
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:17
3+
|
4+
LL | impl Marker for &'static () {}
5+
| ^^^^^^^^^^^
6+
|
7+
note: multiple `impl`s satisfying `&'static (): Marker` found
8+
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
9+
|
10+
LL | impl Marker for &'static () {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl Marker for &'static () {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error[E0283]: type annotations needed: cannot satisfy `&'static (): Marker`
16+
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:12:17
17+
|
18+
LL | impl Marker for &'static () {}
19+
| ^^^^^^^^^^^
20+
|
21+
note: multiple `impl`s satisfying `&'static (): Marker` found
22+
--> $DIR/overlap-marker-trait-with-static-lifetime.rs:11:1
23+
|
24+
LL | impl Marker for &'static () {}
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
LL | impl Marker for &'static () {}
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
29+
error: aborting due to 2 previous errors
30+
31+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
// check-pass
1+
// known-bug: #109481
2+
//
3+
// While the `T: Copy` is always applicable when checking
4+
// that the impl `impl<T: Copy> F for T {}` is well formed,
5+
// the old trait solver can only approximate this by checking
6+
// that there are no inference variables in the obligation and
7+
// no region constraints in the evaluation result.
8+
//
9+
// Because of this we end up with ambiguity here.
210
#![feature(marker_trait_attr)]
311

412
#[marker]
513
pub trait F {}
6-
impl<T> F for T where T: Copy {}
7-
impl<T> F for T where T: 'static {}
14+
impl<T: Copy> F for T {}
15+
impl<T: 'static> F for T {}
816

917
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0310]: the parameter type `T` may not live long enough
2+
--> $DIR/overlapping-impl-1-modulo-regions.rs:14:21
3+
|
4+
LL | impl<T: Copy> F for T {}
5+
| ^ ...so that the type `T` will meet its required lifetime bounds
6+
|
7+
help: consider adding an explicit lifetime bound...
8+
|
9+
LL | impl<T: Copy + 'static> F for T {}
10+
| +++++++++
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0310`.

0 commit comments

Comments
 (0)