Skip to content

Commit aaee18f

Browse files
authored
Unrolled build for rust-lang#140260
Rollup merge of rust-lang#140260 - compiler-errors:only-global-post-norm, r=lcnr Only prefer param-env candidates if they remain non-global after norm Introduce `CandidateSource::GlobalParamEnv`, and dynamically compute the `CandidateSource` based on whether the predicate contains params *post-normalization*. This code needs some cleanup and documentation. I'm just putting this up for review. cc rust-lang/trait-system-refactor-initiative#179 r? lcnr
2 parents 7e552b4 + 8a21d1b commit aaee18f

File tree

20 files changed

+301
-179
lines changed

20 files changed

+301
-179
lines changed

compiler/rustc_borrowck/src/type_check/opaque_types.rs

-4
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,6 @@ impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'t
266266
where
267267
OP: FnMut(ty::Region<'tcx>),
268268
{
269-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
270-
t.super_visit_with(self);
271-
}
272-
273269
fn visit_region(&mut self, r: ty::Region<'tcx>) {
274270
match r.kind() {
275271
// ignore bound regions, keep visiting

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_hir::def_id::{DefId, LocalDefId};
99
use rustc_hir::{AmbigArg, HirId};
1010
use rustc_middle::bug;
1111
use rustc_middle::ty::{
12-
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
13-
TypeVisitor, Upcast,
12+
self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
13+
TypeVisitableExt, TypeVisitor, Upcast,
1414
};
1515
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
1616
use rustc_trait_selection::traits;
@@ -996,7 +996,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> {
996996
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
997997
type Result = ControlFlow<ErrorGuaranteed>;
998998

999-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
999+
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
10001000
&mut self,
10011001
binder: &ty::Binder<'tcx, T>,
10021002
) -> Self::Result {

compiler/rustc_infer/src/infer/outlives/for_liveness.rs

-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for FreeRegionsVisitor<'tcx, OP>
2424
where
2525
OP: FnMut(ty::Region<'tcx>),
2626
{
27-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
28-
t.super_visit_with(self);
29-
}
30-
3127
fn visit_region(&mut self, r: ty::Region<'tcx>) {
3228
match r.kind() {
3329
// ignore bound regions, keep visiting

compiler/rustc_lint/src/impl_trait_overcaptures.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use rustc_middle::ty::relate::{
1515
Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
1616
};
1717
use rustc_middle::ty::{
18-
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
18+
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
19+
TypeVisitor,
1920
};
2021
use rustc_middle::{bug, span_bug};
2122
use rustc_session::lint::FutureIncompatibilityReason;
@@ -209,7 +210,7 @@ where
209210
VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>,
210211
OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
211212
{
212-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
213+
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
213214
// When we get into a binder, we need to add its own bound vars to the scope.
214215
let mut added = vec![];
215216
for arg in t.bound_vars() {

compiler/rustc_middle/src/ty/print/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2934,7 +2934,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
29342934

29352935
fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
29362936
where
2937-
T: TypeVisitable<TyCtxt<'tcx>>,
2937+
T: TypeFoldable<TyCtxt<'tcx>>,
29382938
{
29392939
struct RegionNameCollector<'tcx> {
29402940
used_region_names: FxHashSet<Symbol>,

compiler/rustc_middle/src/ty/visit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl<'tcx> TyCtxt<'tcx> {
6666
{
6767
type Result = ControlFlow<()>;
6868

69-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
69+
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
7070
&mut self,
7171
t: &Binder<'tcx, T>,
7272
) -> Self::Result {
@@ -168,7 +168,7 @@ impl LateBoundRegionsCollector {
168168
}
169169

170170
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
171-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
171+
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
172172
self.current_index.shift_in(1);
173173
t.super_visit_with(self);
174174
self.current_index.shift_out(1);

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

+153-23
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@
22
33
pub(super) mod structural_traits;
44

5+
use std::ops::ControlFlow;
6+
57
use derive_where::derive_where;
68
use rustc_type_ir::inherent::*;
79
use rustc_type_ir::lang_items::TraitSolverLangItem;
810
use rustc_type_ir::{
9-
self as ty, Interner, TypeFoldable, TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
11+
self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _,
12+
TypeVisitor, TypingMode, Upcast as _, elaborate,
1013
};
1114
use tracing::{debug, instrument};
1215

13-
use super::has_only_region_constraints;
1416
use super::trait_goals::TraitGoalProvenVia;
17+
use super::{has_only_region_constraints, inspect};
1518
use crate::delegate::SolverDelegate;
1619
use crate::solve::inspect::ProbeKind;
1720
use crate::solve::{
1821
BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
19-
MaybeCause, NoSolution, QueryResult,
22+
MaybeCause, NoSolution, ParamEnvSource, QueryResult,
2023
};
2124

2225
enum AliasBoundKind {
@@ -49,18 +52,6 @@ where
4952

5053
fn trait_def_id(self, cx: I) -> I::DefId;
5154

52-
/// Try equating an assumption predicate against a goal's predicate. If it
53-
/// holds, then execute the `then` callback, which should do any additional
54-
/// work, then produce a response (typically by executing
55-
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
56-
fn probe_and_match_goal_against_assumption(
57-
ecx: &mut EvalCtxt<'_, D>,
58-
source: CandidateSource<I>,
59-
goal: Goal<I, Self>,
60-
assumption: I::Clause,
61-
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
62-
) -> Result<Candidate<I>, NoSolution>;
63-
6455
/// Consider a clause, which consists of a "assumption" and some "requirements",
6556
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
6657
/// goal by equating it with the assumption.
@@ -119,6 +110,67 @@ where
119110
alias_ty: ty::AliasTy<I>,
120111
) -> Vec<Candidate<I>>;
121112

113+
fn probe_and_consider_param_env_candidate(
114+
ecx: &mut EvalCtxt<'_, D>,
115+
goal: Goal<I, Self>,
116+
assumption: I::Clause,
117+
) -> Result<Candidate<I>, NoSolution> {
118+
Self::fast_reject_assumption(ecx, goal, assumption)?;
119+
120+
ecx.probe(|candidate: &Result<Candidate<I>, NoSolution>| match candidate {
121+
Ok(candidate) => inspect::ProbeKind::TraitCandidate {
122+
source: candidate.source,
123+
result: Ok(candidate.result),
124+
},
125+
Err(NoSolution) => inspect::ProbeKind::TraitCandidate {
126+
source: CandidateSource::ParamEnv(ParamEnvSource::Global),
127+
result: Err(NoSolution),
128+
},
129+
})
130+
.enter(|ecx| {
131+
Self::match_assumption(ecx, goal, assumption)?;
132+
let source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
133+
Ok(Candidate {
134+
source,
135+
result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?,
136+
})
137+
})
138+
}
139+
140+
/// Try equating an assumption predicate against a goal's predicate. If it
141+
/// holds, then execute the `then` callback, which should do any additional
142+
/// work, then produce a response (typically by executing
143+
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
144+
fn probe_and_match_goal_against_assumption(
145+
ecx: &mut EvalCtxt<'_, D>,
146+
source: CandidateSource<I>,
147+
goal: Goal<I, Self>,
148+
assumption: I::Clause,
149+
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
150+
) -> Result<Candidate<I>, NoSolution> {
151+
Self::fast_reject_assumption(ecx, goal, assumption)?;
152+
153+
ecx.probe_trait_candidate(source).enter(|ecx| {
154+
Self::match_assumption(ecx, goal, assumption)?;
155+
then(ecx)
156+
})
157+
}
158+
159+
/// Try to reject the assumption based off of simple heuristics, such as [`ty::ClauseKind`]
160+
/// and `DefId`.
161+
fn fast_reject_assumption(
162+
ecx: &mut EvalCtxt<'_, D>,
163+
goal: Goal<I, Self>,
164+
assumption: I::Clause,
165+
) -> Result<(), NoSolution>;
166+
167+
/// Relate the goal and assumption.
168+
fn match_assumption(
169+
ecx: &mut EvalCtxt<'_, D>,
170+
goal: Goal<I, Self>,
171+
assumption: I::Clause,
172+
) -> Result<(), NoSolution>;
173+
122174
fn consider_impl_candidate(
123175
ecx: &mut EvalCtxt<'_, D>,
124176
goal: Goal<I, Self>,
@@ -500,14 +552,8 @@ where
500552
goal: Goal<I, G>,
501553
candidates: &mut Vec<Candidate<I>>,
502554
) {
503-
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
504-
candidates.extend(G::probe_and_consider_implied_clause(
505-
self,
506-
CandidateSource::ParamEnv(i),
507-
goal,
508-
assumption,
509-
[],
510-
));
555+
for assumption in goal.param_env.caller_bounds().iter() {
556+
candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
511557
}
512558
}
513559

@@ -943,4 +989,88 @@ where
943989
}
944990
}
945991
}
992+
993+
/// Compute whether a param-env assumption is global or non-global after normalizing it.
994+
///
995+
/// This is necessary because, for example, given:
996+
///
997+
/// ```ignore,rust
998+
/// where
999+
/// T: Trait<Assoc = u32>,
1000+
/// i32: From<T::Assoc>,
1001+
/// ```
1002+
///
1003+
/// The `i32: From<T::Assoc>` bound is non-global before normalization, but is global after.
1004+
/// Since the old trait solver normalized param-envs eagerly, we want to emulate this
1005+
/// behavior lazily.
1006+
fn characterize_param_env_assumption(
1007+
&mut self,
1008+
param_env: I::ParamEnv,
1009+
assumption: I::Clause,
1010+
) -> Result<CandidateSource<I>, NoSolution> {
1011+
// FIXME: This should be fixed, but it also requires changing the behavior
1012+
// in the old solver which is currently relied on.
1013+
if assumption.has_bound_vars() {
1014+
return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1015+
}
1016+
1017+
match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) {
1018+
ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1019+
ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1020+
ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1021+
}
1022+
}
1023+
}
1024+
1025+
struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
1026+
ecx: &'a mut EvalCtxt<'b, D>,
1027+
param_env: I::ParamEnv,
1028+
}
1029+
1030+
impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
1031+
where
1032+
D: SolverDelegate<Interner = I>,
1033+
I: Interner,
1034+
{
1035+
type Result = ControlFlow<Result<(), NoSolution>>;
1036+
1037+
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
1038+
self.ecx.enter_forall(t.clone(), |ecx, v| {
1039+
v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env })
1040+
})
1041+
}
1042+
1043+
fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
1044+
let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
1045+
return ControlFlow::Break(Err(NoSolution));
1046+
};
1047+
1048+
if let ty::Placeholder(_) = ty.kind() {
1049+
ControlFlow::Break(Ok(()))
1050+
} else {
1051+
ty.super_visit_with(self)
1052+
}
1053+
}
1054+
1055+
fn visit_const(&mut self, ct: I::Const) -> Self::Result {
1056+
let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
1057+
return ControlFlow::Break(Err(NoSolution));
1058+
};
1059+
1060+
if let ty::ConstKind::Placeholder(_) = ct.kind() {
1061+
ControlFlow::Break(Ok(()))
1062+
} else {
1063+
ct.super_visit_with(self)
1064+
}
1065+
}
1066+
1067+
fn visit_region(&mut self, r: I::Region) -> Self::Result {
1068+
match self.ecx.eager_resolve_region(r).kind() {
1069+
ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()),
1070+
ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())),
1071+
ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => {
1072+
unreachable!()
1073+
}
1074+
}
1075+
}
9461076
}

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+22-23
Original file line numberDiff line numberDiff line change
@@ -36,39 +36,38 @@ where
3636
self.def_id()
3737
}
3838

39-
fn probe_and_match_goal_against_assumption(
39+
fn fast_reject_assumption(
4040
ecx: &mut EvalCtxt<'_, D>,
41-
source: rustc_type_ir::solve::CandidateSource<I>,
4241
goal: Goal<I, Self>,
43-
assumption: <I as Interner>::Clause,
44-
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
45-
) -> Result<Candidate<I>, NoSolution> {
42+
assumption: I::Clause,
43+
) -> Result<(), NoSolution> {
4644
if let Some(host_clause) = assumption.as_host_effect_clause() {
4745
if host_clause.def_id() == goal.predicate.def_id()
4846
&& host_clause.constness().satisfies(goal.predicate.constness)
4947
{
50-
if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
48+
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
5149
goal.predicate.trait_ref.args,
5250
host_clause.skip_binder().trait_ref.args,
5351
) {
54-
return Err(NoSolution);
52+
return Ok(());
5553
}
56-
57-
ecx.probe_trait_candidate(source).enter(|ecx| {
58-
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
59-
ecx.eq(
60-
goal.param_env,
61-
goal.predicate.trait_ref,
62-
assumption_trait_pred.trait_ref,
63-
)?;
64-
then(ecx)
65-
})
66-
} else {
67-
Err(NoSolution)
6854
}
69-
} else {
70-
Err(NoSolution)
7155
}
56+
57+
Err(NoSolution)
58+
}
59+
60+
fn match_assumption(
61+
ecx: &mut EvalCtxt<'_, D>,
62+
goal: Goal<I, Self>,
63+
assumption: I::Clause,
64+
) -> Result<(), NoSolution> {
65+
let host_clause = assumption.as_host_effect_clause().unwrap();
66+
67+
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
68+
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
69+
70+
Ok(())
7271
}
7372

7473
/// Register additional assumptions for aliases corresponding to `~const` item bounds.
@@ -124,7 +123,7 @@ where
124123
fn consider_impl_candidate(
125124
ecx: &mut EvalCtxt<'_, D>,
126125
goal: Goal<I, Self>,
127-
impl_def_id: <I as Interner>::DefId,
126+
impl_def_id: I::DefId,
128127
) -> Result<Candidate<I>, NoSolution> {
129128
let cx = ecx.cx();
130129

@@ -178,7 +177,7 @@ where
178177

179178
fn consider_error_guaranteed_candidate(
180179
ecx: &mut EvalCtxt<'_, D>,
181-
_guar: <I as Interner>::ErrorGuaranteed,
180+
_guar: I::ErrorGuaranteed,
182181
) -> Result<Candidate<I>, NoSolution> {
183182
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
184183
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))

0 commit comments

Comments
 (0)