Skip to content

Commit 1f774d7

Browse files
Only prefer param-env candidates if they remain non-global after norm
1 parent df13f7c commit 1f774d7

8 files changed

Lines changed: 268 additions & 145 deletions

File tree

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

Lines changed: 141 additions & 23 deletions
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-
selfas ty,Interner,TypeFoldable,TypeVisitableExtas _,TypingMode,Upcastas _, elaborate,
11+
selfas ty,Interner,TypeFoldable,TypeSuperVisitable,TypeVisitable,TypeVisitableExtas _,
12+
TypeVisitor,TypingMode,Upcastas _, elaborate,
1013
};
1114
use tracing::{debug, instrument};
1215

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

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

5053
fntrait_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-
fnprobe_and_match_goal_against_assumption(
57-
ecx:&mutEvalCtxt<'_,D>,
58-
source:CandidateSource<I>,
59-
goal:Goal<I,Self>,
60-
assumption:I::Clause,
61-
then:implFnOnce(&mutEvalCtxt<'_,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+
fnprobe_and_consider_param_env_candidate(
114+
ecx:&mutEvalCtxt<'_,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::BuiltinImpl(BuiltinImplSource::Misc),
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+
fnprobe_and_match_goal_against_assumption(
145+
ecx:&mutEvalCtxt<'_,D>,
146+
source:CandidateSource<I>,
147+
goal:Goal<I,Self>,
148+
assumption:I::Clause,
149+
then:implFnOnce(&mutEvalCtxt<'_,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 [`I::DefId`].
161+
fnfast_reject_assumption(
162+
ecx:&mutEvalCtxt<'_,D>,
163+
goal:Goal<I,Self>,
164+
assumption:I::Clause,
165+
) -> Result<(),NoSolution>;
166+
167+
/// Relate the goal and assumption.
168+
fnmatch_assumption(
169+
ecx:&mutEvalCtxt<'_,D>,
170+
goal:Goal<I,Self>,
171+
assumption:I::Clause,
172+
) -> Result<(),NoSolution>;
173+
122174
fnconsider_impl_candidate(
123175
ecx:&mutEvalCtxt<'_,D>,
124176
goal:Goal<I,Self>,
@@ -500,14 +552,8 @@ where
500552
goal:Goal<I,G>,
501553
candidates:&mutVec<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,76 @@ where
943989
}
944990
}
945991
}
992+
993+
fncharacterize_param_env_assumption(
994+
&mutself,
995+
param_env:I::ParamEnv,
996+
assumption:I::Clause,
997+
) -> Result<CandidateSource<I>,NoSolution>{
998+
// FIXME:
999+
if assumption.has_bound_vars(){
1000+
returnOk(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
1001+
}
1002+
1003+
match assumption.visit_with(&mutFindParamInClause{ecx:self, param_env }){
1004+
ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
1005+
ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
1006+
ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
1007+
}
1008+
}
1009+
}
1010+
1011+
structFindParamInClause<'a,'b,D:SolverDelegate<Interner = I>,I:Interner>{
1012+
ecx:&'amutEvalCtxt<'b,D>,
1013+
param_env:I::ParamEnv,
1014+
}
1015+
1016+
impl<D,I>TypeVisitor<I>forFindParamInClause<'_,'_,D,I>
1017+
where
1018+
D:SolverDelegate<Interner = I>,
1019+
I:Interner,
1020+
{
1021+
typeResult = ControlFlow<Result<(),NoSolution>>;
1022+
1023+
fnvisit_binder<T:TypeFoldable<I>>(&mutself,t:&ty::Binder<I,T>) -> Self::Result{
1024+
self.ecx.enter_forall(t.clone(), |ecx, v| {
1025+
v.visit_with(&mutFindParamInClause{ ecx,param_env:self.param_env})
1026+
})
1027+
}
1028+
1029+
fnvisit_ty(&mutself,ty:I::Ty) -> Self::Result{
1030+
letOk(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty)else{
1031+
returnControlFlow::Break(Err(NoSolution));
1032+
};
1033+
let ty = self.ecx.eager_resolve(ty);
1034+
1035+
iflet ty::Placeholder(_) = ty.kind(){
1036+
ControlFlow::Break(Ok(()))
1037+
}else{
1038+
ty.super_visit_with(self)
1039+
}
1040+
}
1041+
1042+
fnvisit_const(&mutself,ct:I::Const) -> Self::Result{
1043+
letOk(ct) = self.ecx.structurally_normalize_const(self.param_env, ct)else{
1044+
returnControlFlow::Break(Err(NoSolution));
1045+
};
1046+
let ct = self.ecx.eager_resolve(ct);
1047+
1048+
iflet ty::ConstKind::Placeholder(_) = ct.kind(){
1049+
ControlFlow::Break(Ok(()))
1050+
}else{
1051+
ct.super_visit_with(self)
1052+
}
1053+
}
1054+
1055+
fnvisit_region(&mutself,r:I::Region) -> Self::Result{
1056+
match r.kind(){
1057+
ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()),
1058+
ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())),
1059+
ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => {
1060+
unreachable!()
1061+
}
1062+
}
1063+
}
9461064
}

‎compiler/rustc_next_trait_solver/src/solve/effect_goals.rs‎

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,39 +36,40 @@ where
3636
self.def_id()
3737
}
3838

39-
fnprobe_and_match_goal_against_assumption(
39+
fnfast_reject_assumption(
4040
ecx:&mutEvalCtxt<'_,D>,
41-
source: rustc_type_ir::solve::CandidateSource<I>,
4241
goal:Goal<I,Self>,
43-
assumption: <IasInterner>::Clause,
44-
then:implFnOnce(&mutEvalCtxt<'_,D>) -> QueryResult<I>,
45-
) -> Result<Candidate<I>,NoSolution>{
42+
assumption:I::Clause,
43+
) -> Result<(),NoSolution>{
4644
ifletSome(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+
ifDeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
5149
goal.predicate.trait_ref.args,
5250
host_clause.skip_binder().trait_ref.args,
5351
){
54-
returnErr(NoSolution);
52+
returnOk(());
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+
fnmatch_assumption(
61+
ecx:&mutEvalCtxt<'_,D>,
62+
goal:Goal<I,Self>,
63+
assumption:I::Clause,
64+
) -> Result<(),NoSolution>{
65+
letSome(host_clause) = assumption.as_host_effect_clause()else{
66+
panic!("fast_reject_assumption should have avoided this");
67+
};
68+
69+
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
70+
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
71+
72+
Ok(())
7273
}
7374

7475
/// Register additional assumptions for aliases corresponding to `~const` item bounds.
@@ -124,7 +125,7 @@ where
124125
fnconsider_impl_candidate(
125126
ecx:&mutEvalCtxt<'_,D>,
126127
goal:Goal<I,Self>,
127-
impl_def_id:<IasInterner>::DefId,
128+
impl_def_id:I::DefId,
128129
) -> Result<Candidate<I>,NoSolution>{
129130
let cx = ecx.cx();
130131

@@ -178,7 +179,7 @@ where
178179

179180
fnconsider_error_guaranteed_candidate(
180181
ecx:&mutEvalCtxt<'_,D>,
181-
_guar:<IasInterner>::ErrorGuaranteed,
182+
_guar:I::ErrorGuaranteed,
182183
) -> Result<Candidate<I>,NoSolution>{
183184
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
184185
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use tracing::{debug, instrument, trace};
1919
usesuper::has_only_region_constraints;
2020
usecrate::coherence;
2121
usecrate::delegate::SolverDelegate;
22+
usecrate::resolve::EagerResolver;
2223
usecrate::solve::inspect::{self,ProofTreeBuilder};
2324
usecrate::solve::search_graph::SearchGraph;
2425
usecrate::solve::{
@@ -1000,6 +1001,13 @@ where
10001001
self.delegate.resolve_vars_if_possible(value)
10011002
}
10021003

1004+
pub(super)fneager_resolve<T>(&self,value:T) -> T
1005+
where
1006+
T:TypeFoldable<I>,
1007+
{
1008+
value.fold_with(&mutEagerResolver::new(self.delegate))
1009+
}
1010+
10031011
pub(super)fnfresh_args_for_item(&mutself,def_id:I::DefId) -> I::GenericArgs{
10041012
let args = self.delegate.fresh_args_for_item(def_id);
10051013
for arg in args.iter(){

‎compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs‎

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -106,50 +106,50 @@ where
106106
self.trait_def_id(cx)
107107
}
108108

109-
fnprobe_and_match_goal_against_assumption(
109+
fnfast_reject_assumption(
110110
ecx:&mutEvalCtxt<'_,D>,
111-
source:CandidateSource<I>,
112111
goal:Goal<I,Self>,
113112
assumption:I::Clause,
114-
then:implFnOnce(&mutEvalCtxt<'_,D>) -> QueryResult<I>,
115-
) -> Result<Candidate<I>,NoSolution>{
113+
) -> Result<(),NoSolution>{
116114
ifletSome(projection_pred) = assumption.as_projection_clause(){
117115
if projection_pred.item_def_id() == goal.predicate.def_id(){
118-
let cx = ecx.cx();
119-
if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
116+
ifDeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
120117
goal.predicate.alias.args,
121118
projection_pred.skip_binder().projection_term.args,
122119
){
123-
returnErr(NoSolution);
120+
returnOk(());
124121
}
125-
ecx.probe_trait_candidate(source).enter(|ecx| {
126-
let assumption_projection_pred =
127-
ecx.instantiate_binder_with_infer(projection_pred);
128-
ecx.eq(
129-
goal.param_env,
130-
goal.predicate.alias,
131-
assumption_projection_pred.projection_term,
132-
)?;
133-
134-
ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term);
135-
136-
// Add GAT where clauses from the trait's definition
137-
// FIXME: We don't need these, since these are the type's own WF obligations.
138-
ecx.add_goals(
139-
GoalSource::AliasWellFormed,
140-
cx.own_predicates_of(goal.predicate.def_id())
141-
.iter_instantiated(cx, goal.predicate.alias.args)
142-
.map(|pred| goal.with(cx, pred)),
143-
);
144-
145-
then(ecx)
146-
})
147-
}else{
148-
Err(NoSolution)
149122
}
150-
}else{
151-
Err(NoSolution)
152123
}
124+
125+
Err(NoSolution)
126+
}
127+
128+
fnmatch_assumption(
129+
ecx:&mutEvalCtxt<'_,D>,
130+
goal:Goal<I,Self>,
131+
assumption:I::Clause,
132+
) -> Result<(),NoSolution>{
133+
letSome(projection_pred) = assumption.as_projection_clause()else{
134+
panic!("fast_reject_assumption should have avoided this");
135+
};
136+
137+
let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred);
138+
ecx.eq(goal.param_env, goal.predicate.alias, assumption_projection_pred.projection_term)?;
139+
140+
ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term);
141+
142+
// Add GAT where clauses from the trait's definition
143+
// FIXME: We don't need these, since these are the type's own WF obligations.
144+
let cx = ecx.cx();
145+
ecx.add_goals(
146+
GoalSource::AliasWellFormed,
147+
cx.own_predicates_of(goal.predicate.def_id())
148+
.iter_instantiated(cx, goal.predicate.alias.args)
149+
.map(|pred| goal.with(cx, pred)),
150+
);
151+
152+
Ok(())
153153
}
154154

155155
fnconsider_additional_alias_assumptions(

0 commit comments

Comments
 (0)