Skip to content

Commit 5d9141c

Browse files
committed
fix better_any breakage by making the solver more unsound
1 parent bbd3a5a commit 5d9141c

File tree

2 files changed

+75
-2
lines changed

2 files changed

+75
-2
lines changed

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ use rustc_type_ir::{
99
self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
1010
Upcast as _, elaborate,
1111
};
12-
use tracing::{instrument, trace};
12+
use tracing::{debug, instrument, trace};
1313

1414
use crate::delegate::SolverDelegate;
1515
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
1616
use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
1717
use crate::solve::inspect::ProbeKind;
1818
use crate::solve::{
1919
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
20-
NoSolution, ParamEnvSource, QueryResult,
20+
NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
2121
};
2222

2323
impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
@@ -1253,6 +1253,45 @@ where
12531253
D: SolverDelegate<Interner = I>,
12541254
I: Interner,
12551255
{
1256+
/// FIXME(#57893): For backwards compatability with the old trait solver implementation,
1257+
/// we need to handle overlap between builtin and user-written impls for trait objects.
1258+
///
1259+
/// This overlap is unsound in general and something which we intend to fix separately.
1260+
/// To avoid blocking the stabilization of the trait solver, we add this hack to avoid
1261+
/// breakage in cases which are *mostly fine*™. Importantly, this preference is strictly
1262+
/// weaker than the old behavior.
1263+
///
1264+
/// We only prefer builtin over user-written impls if there are no inference constraints.
1265+
/// Importantly, we also only prefer the builtin impls for trait goals, and not during
1266+
/// normalization. This means the only case where this special-case results in exploitable
1267+
/// unsoundness should be lifetime dependent user-written impls.
1268+
pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1269+
match self.typing_mode() {
1270+
TypingMode::Coherence => return,
1271+
TypingMode::Analysis { .. }
1272+
| TypingMode::Borrowck { .. }
1273+
| TypingMode::PostBorrowckAnalysis { .. }
1274+
| TypingMode::PostAnalysis => {}
1275+
}
1276+
1277+
if candidates
1278+
.iter()
1279+
.find(|c| {
1280+
matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1281+
})
1282+
.is_some_and(|c| has_only_region_constraints(c.result))
1283+
{
1284+
candidates.retain(|c| {
1285+
if matches!(c.source, CandidateSource::Impl(_)) {
1286+
debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1287+
false
1288+
} else {
1289+
true
1290+
}
1291+
});
1292+
}
1293+
}
1294+
12561295
#[instrument(level = "debug", skip(self), ret)]
12571296
pub(super) fn merge_trait_candidates(
12581297
&mut self,
@@ -1313,6 +1352,7 @@ where
13131352
}
13141353

13151354
self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1355+
self.unsound_prefer_builtin_dyn_impl(&mut candidates);
13161356

13171357
// If there are *only* global where bounds, then make sure to return that this
13181358
// is still reported as being proven-via the param-env so that rigid projections
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@[next] compile-flags: -Znext-solver
4+
//@ ignore-compare-mode-next-solver (explicit revisions)
5+
6+
// A regression test for trait-system-refactor-initiative#183. While
7+
// this concrete instance is likely not practically unsound, the general
8+
// pattern is, see #57893.
9+
10+
use std::any::TypeId;
11+
12+
unsafe trait TidAble<'a>: Tid<'a> {}
13+
trait TidExt<'a>: Tid<'a> {
14+
fn downcast_box(self: Box<Self>) {
15+
loop {}
16+
}
17+
}
18+
19+
impl<'a, X: ?Sized + Tid<'a>> TidExt<'a> for X {}
20+
21+
unsafe trait Tid<'a>: 'a {}
22+
23+
unsafe impl<'a, T: ?Sized + TidAble<'a>> Tid<'a> for T {}
24+
25+
impl<'a> dyn Tid<'a> + 'a {
26+
fn downcast_any_box(self: Box<Self>) {
27+
self.downcast_box();
28+
}
29+
}
30+
31+
unsafe impl<'a> TidAble<'a> for dyn Tid<'a> + 'a {}
32+
33+
fn main() {}

0 commit comments

Comments
 (0)