Skip to content

Commit a08eb7a

Browse files
committed
Auto merge of rust-lang#141128 - compiler-errors:fast-path, r=<try>
Fast path for processing some obligations in the new solver r? lcnr
2 parents b0e9259 + 9e31dcb commit a08eb7a

File tree

7 files changed

+104
-9
lines changed

7 files changed

+104
-9
lines changed

compiler/rustc_next_trait_solver/src/delegate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
1717
where
1818
V: TypeFoldable<Self::Interner>;
1919

20+
fn compute_goal_fast_path(
21+
&self,
22+
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
23+
span: <Self::Interner as Interner>::Span,
24+
) -> Option<()>;
25+
2026
fn fresh_var_for_kind_with_span(
2127
&self,
2228
arg: <Self::Interner as Interner>::GenericArg,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use std::iter;
1313

1414
use rustc_index::IndexVec;
15+
use rustc_type_ir::data_structures::HashSet;
1516
use rustc_type_ir::inherent::*;
1617
use rustc_type_ir::relate::solver_relating::RelateExt;
1718
use rustc_type_ir::{
@@ -158,10 +159,12 @@ where
158159
self.compute_external_query_constraints(certainty, normalization_nested_goals);
159160
let (var_values, mut external_constraints) = (self.var_values, external_constraints)
160161
.fold_with(&mut EagerResolver::new(self.delegate));
161-
// Remove any trivial region constraints once we've resolved regions
162-
external_constraints
163-
.region_constraints
164-
.retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1));
162+
163+
// Remove any trivial or duplicated region constraints once we've resolved regions
164+
let mut unique = HashSet::default();
165+
external_constraints.region_constraints.retain(|outlives| {
166+
outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives)
167+
});
165168

166169
let canonical = Canonicalizer::canonicalize_response(
167170
self.delegate,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,11 @@ where
603603
// If this loop did not result in any progress, what's our final certainty.
604604
let mut unchanged_certainty = Some(Certainty::Yes);
605605
for (source, goal) in mem::take(&mut self.nested_goals) {
606+
if let Some(()) = self.delegate.compute_goal_fast_path(goal, self.origin_span) {
607+
unchanged_certainty = None;
608+
continue;
609+
}
610+
606611
// We treat normalizes-to goals specially here. In each iteration we take the
607612
// RHS of the projection, replace it with a fresh inference variable, and only
608613
// after evaluating that goal do we equate the fresh inference variable with the

compiler/rustc_trait_selection/src/solve/delegate.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
66
use rustc_infer::infer::canonical::{
77
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
88
};
9-
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
9+
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
1010
use rustc_infer::traits::solve::Goal;
1111
use rustc_middle::traits::query::NoSolution;
1212
use rustc_middle::traits::solve::Certainty;
1313
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode};
1414
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
1515

16-
use crate::traits::{EvaluateConstErr, specialization_graph};
16+
use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph};
1717

1818
#[repr(transparent)]
1919
pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -55,6 +55,37 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
5555
(SolverDelegate(infcx), value, vars)
5656
}
5757

58+
fn compute_goal_fast_path(
59+
&self,
60+
goal: Goal<'tcx, ty::Predicate<'tcx>>,
61+
span: Span,
62+
) -> Option<()> {
63+
let pred = goal.predicate.kind();
64+
match pred.no_bound_vars()? {
65+
ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
66+
Some(())
67+
}
68+
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
69+
self.0.sub_regions(
70+
SubregionOrigin::RelateRegionParamBound(span, None),
71+
outlives.1,
72+
outlives.0,
73+
);
74+
Some(())
75+
}
76+
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
77+
self.0.register_region_obligation_with_cause(
78+
outlives.0,
79+
outlives.1,
80+
&ObligationCause::dummy_with_span(span),
81+
);
82+
83+
Some(())
84+
}
85+
_ => None,
86+
}
87+
}
88+
5889
fn fresh_var_for_kind_with_span(
5990
&self,
6091
arg: ty::GenericArg<'tcx>,

compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_infer::traits::{
1212
use rustc_middle::ty::{
1313
self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
1414
};
15+
use rustc_next_trait_solver::delegate::SolverDelegate as _;
1516
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
1617
use rustc_span::Span;
1718
use tracing::instrument;
@@ -172,7 +173,13 @@ where
172173
}
173174

174175
let goal = obligation.as_goal();
175-
let result = <&SolverDelegate<'tcx>>::from(infcx)
176+
let delegate = <&SolverDelegate<'tcx>>::from(infcx);
177+
if let Some(()) = delegate.compute_goal_fast_path(goal, obligation.cause.span) {
178+
has_changed = true;
179+
continue;
180+
}
181+
182+
let result = delegate
176183
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
177184
.0;
178185
self.inspect_evaluated_obligation(infcx, &obligation, &result);

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,9 +701,15 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause
701701
let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate);
702702
ocx.register_obligation(obligation);
703703
}
704-
let errors = ocx.select_all_or_error();
705704

706-
if !errors.is_empty() {
705+
// Use `select_where_possible` to only return impossible for true errors,
706+
// and not ambiguities or overflows. Since the new trait solver forces
707+
// some currently undetected overlap between `dyn Trait: Trait` built-in
708+
// vs user-written impls to AMBIGUOUS, this may return ambiguity even
709+
// with no infer vars. There may also be ways to encounter ambiguity due
710+
// to post-mono overflow.
711+
let true_errors = ocx.select_where_possible();
712+
if !true_errors.is_empty() {
707713
return true;
708714
}
709715

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// In this example below, we have two overlapping candidates for `dyn Q: Q`.
2+
// Specifically, the user written impl for `<dyn Q as Mirror>::Assoc` and the
3+
// built-in impl for object types. Since they differ by their region responses,
4+
// the goal is ambiguous. This affects codegen since impossible obligations
5+
// for method dispatch will lead to a segfault, since we end up emitting dummy
6+
// call vtable offsets due to <https://github.com/rust-lang/rust/pull/136311>.
7+
8+
// Test for <https://github.com/rust-lang/rust/issues/141119>.
9+
10+
//@ run-pass
11+
12+
trait Mirror {
13+
type Assoc: ?Sized;
14+
}
15+
impl<T: ?Sized> Mirror for T {
16+
type Assoc = T;
17+
}
18+
19+
trait Q: 'static {
20+
fn q(&self);
21+
}
22+
23+
impl Q for i32 {
24+
fn q(&self) { println!("i32"); }
25+
}
26+
27+
impl Q for <dyn Q as Mirror>::Assoc where Self: 'static {
28+
fn q(&self) { println!("dyn Q"); }
29+
}
30+
31+
fn foo<T: Q + ?Sized>(t: &T) {
32+
t.q();
33+
}
34+
35+
fn main() {
36+
foo(&1 as &dyn Q);
37+
}

0 commit comments

Comments
 (0)