Skip to content

Commit 2a2bbd4

Browse files
compiler-errorslcnr
authored andcommitted
w
1 parent 8b46d01 commit 2a2bbd4

File tree

8 files changed

+242
-56
lines changed

8 files changed

+242
-56
lines changed

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

+130-12
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@
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

16+
use super::inspect;
1317
use super::trait_goals::TraitGoalProvenVia;
1418
use crate::delegate::SolverDelegate;
19+
use crate::resolve::EagerResolver;
1520
use crate::solve::inspect::ProbeKind;
1621
use crate::solve::{
1722
BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
@@ -118,6 +123,38 @@ where
118123
alias_ty: ty::AliasTy<I>,
119124
) -> Vec<Candidate<I>>;
120125

126+
fn probe_and_consider_param_env_candidate(
127+
ecx: &mut EvalCtxt<'_, D>,
128+
goal: Goal<I, Self>,
129+
assumption: I::Clause,
130+
idx: usize,
131+
) -> Result<Candidate<I>, NoSolution> {
132+
ecx.probe(|candidate: &Result<Candidate<I>, NoSolution>| match candidate {
133+
Ok(candidate) => inspect::ProbeKind::TraitCandidate {
134+
source: candidate.source,
135+
result: Ok(candidate.result),
136+
},
137+
Err(NoSolution) => inspect::ProbeKind::TraitCandidate {
138+
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
139+
result: Err(NoSolution),
140+
},
141+
})
142+
.enter(|ecx| {
143+
Self::match_param_env_candidate(ecx, goal, assumption)?;
144+
let source = ecx.characterize(goal.param_env, assumption, idx)?;
145+
Ok(Candidate {
146+
source,
147+
result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?,
148+
})
149+
})
150+
}
151+
152+
fn match_param_env_candidate(
153+
ecx: &mut EvalCtxt<'_, D>,
154+
goal: Goal<I, Self>,
155+
assumption: I::Clause,
156+
) -> Result<(), NoSolution>;
157+
121158
fn consider_impl_candidate(
122159
ecx: &mut EvalCtxt<'_, D>,
123160
goal: Goal<I, Self>,
@@ -508,13 +545,7 @@ where
508545
candidates: &mut Vec<Candidate<I>>,
509546
) {
510547
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
511-
candidates.extend(G::probe_and_consider_implied_clause(
512-
self,
513-
CandidateSource::ParamEnv(i),
514-
goal,
515-
assumption,
516-
[],
517-
));
548+
candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption, i));
518549
}
519550
}
520551

@@ -831,11 +862,20 @@ where
831862
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
832863
let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
833864
.iter()
834-
.any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
835-
{
865+
.any(|c| {
866+
matches!(
867+
c.source,
868+
CandidateSource::ParamEnv(_) | CandidateSource::GlobalParamEnv(_)
869+
)
870+
}) {
836871
candidates_from_env_and_bounds
837872
.into_iter()
838-
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
873+
.filter(|c| {
874+
matches!(
875+
c.source,
876+
CandidateSource::ParamEnv(_) | CandidateSource::GlobalParamEnv(_)
877+
)
878+
})
839879
.map(|c| c.result)
840880
.collect()
841881
} else {
@@ -864,7 +904,12 @@ where
864904
// (for example, and ideally only) when proving item bounds for an impl.
865905
let candidates_from_env: Vec<_> = candidates
866906
.iter()
867-
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
907+
.filter(|c| {
908+
matches!(
909+
c.source,
910+
CandidateSource::ParamEnv(_) | CandidateSource::GlobalParamEnv(_)
911+
)
912+
})
868913
.map(|c| c.result)
869914
.collect();
870915
if let Some(response) = self.try_merge_responses(&candidates_from_env) {
@@ -880,4 +925,77 @@ where
880925
}
881926
}
882927
}
928+
929+
fn characterize(
930+
&mut self,
931+
param_env: I::ParamEnv,
932+
assumption: I::Clause,
933+
idx: usize,
934+
) -> Result<CandidateSource<I>, NoSolution> {
935+
// FIXME:
936+
if assumption.has_bound_vars() {
937+
return Ok(CandidateSource::ParamEnv(idx));
938+
}
939+
940+
match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) {
941+
ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
942+
ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(idx)),
943+
ControlFlow::Continue(()) => Ok(CandidateSource::GlobalParamEnv(idx)),
944+
}
945+
}
946+
}
947+
948+
struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
949+
ecx: &'a mut EvalCtxt<'b, D>,
950+
param_env: I::ParamEnv,
951+
}
952+
953+
impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
954+
where
955+
D: SolverDelegate<Interner = I>,
956+
I: Interner,
957+
{
958+
type Result = ControlFlow<Result<(), NoSolution>>;
959+
960+
fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
961+
self.ecx.enter_forall(t.clone(), |ecx, v| {
962+
v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env })
963+
})
964+
}
965+
966+
fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
967+
let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
968+
return ControlFlow::Break(Err(NoSolution));
969+
};
970+
let ty = ty.fold_with(&mut EagerResolver::new(self.ecx.delegate));
971+
972+
if let ty::Placeholder(_) = ty.kind() {
973+
ControlFlow::Break(Ok(()))
974+
} else {
975+
ty.super_visit_with(self)
976+
}
977+
}
978+
979+
fn visit_const(&mut self, ct: I::Const) -> Self::Result {
980+
let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
981+
return ControlFlow::Break(Err(NoSolution));
982+
};
983+
let ct = ct.fold_with(&mut EagerResolver::new(self.ecx.delegate));
984+
985+
if let ty::ConstKind::Placeholder(_) = ct.kind() {
986+
ControlFlow::Break(Ok(()))
987+
} else {
988+
ct.super_visit_with(self)
989+
}
990+
}
991+
992+
fn visit_region(&mut self, r: I::Region) -> Self::Result {
993+
match r.kind() {
994+
ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()),
995+
ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())),
996+
ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => {
997+
unreachable!()
998+
}
999+
}
1000+
}
8831001
}

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ where
4040
ecx: &mut EvalCtxt<'_, D>,
4141
source: rustc_type_ir::solve::CandidateSource<I>,
4242
goal: Goal<I, Self>,
43-
assumption: <I as Interner>::Clause,
43+
assumption: I::Clause,
4444
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
4545
) -> Result<Candidate<I>, NoSolution> {
4646
if let Some(host_clause) = assumption.as_host_effect_clause() {
@@ -71,6 +71,32 @@ where
7171
}
7272
}
7373

74+
fn match_param_env_candidate(
75+
ecx: &mut EvalCtxt<'_, D>,
76+
goal: Goal<I, Self>,
77+
assumption: I::Clause,
78+
) -> Result<(), NoSolution> {
79+
if let Some(host_clause) = assumption.as_host_effect_clause() {
80+
if host_clause.def_id() == goal.predicate.def_id()
81+
&& host_clause.constness().satisfies(goal.predicate.constness)
82+
{
83+
if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
84+
goal.predicate.trait_ref.args,
85+
host_clause.skip_binder().trait_ref.args,
86+
) {
87+
return Err(NoSolution);
88+
}
89+
90+
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
91+
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)
92+
} else {
93+
Err(NoSolution)
94+
}
95+
} else {
96+
Err(NoSolution)
97+
}
98+
}
99+
74100
/// Register additional assumptions for aliases corresponding to `~const` item bounds.
75101
///
76102
/// Unlike item bounds, they are not simply implied by the well-formedness of the alias.
@@ -124,7 +150,7 @@ where
124150
fn consider_impl_candidate(
125151
ecx: &mut EvalCtxt<'_, D>,
126152
goal: Goal<I, Self>,
127-
impl_def_id: <I as Interner>::DefId,
153+
impl_def_id: I::DefId,
128154
) -> Result<Candidate<I>, NoSolution> {
129155
let cx = ecx.cx();
130156

@@ -178,7 +204,7 @@ where
178204

179205
fn consider_error_guaranteed_candidate(
180206
ecx: &mut EvalCtxt<'_, D>,
181-
_guar: <I as Interner>::ErrorGuaranteed,
207+
_guar: I::ErrorGuaranteed,
182208
) -> Result<Candidate<I>, NoSolution> {
183209
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
184210
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ where
8888
/// If some `InferCtxt` method is missing, please first think defensively about
8989
/// the method's compatibility with this solver, or if an existing one does
9090
/// the job already.
91-
delegate: &'a D,
91+
pub delegate: &'a D,
9292

9393
/// The variable info for the `var_values`, only used to make an ambiguous response
9494
/// with no constraints.

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

+41
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,47 @@ where
148148
}
149149
}
150150

151+
fn match_param_env_candidate(
152+
ecx: &mut EvalCtxt<'_, D>,
153+
goal: Goal<I, Self>,
154+
assumption: I::Clause,
155+
) -> Result<(), NoSolution> {
156+
if let Some(projection_pred) = assumption.as_projection_clause() {
157+
if projection_pred.item_def_id() == goal.predicate.def_id() {
158+
let cx = ecx.cx();
159+
if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
160+
goal.predicate.alias.args,
161+
projection_pred.skip_binder().projection_term.args,
162+
) {
163+
return Err(NoSolution);
164+
}
165+
let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred);
166+
ecx.eq(
167+
goal.param_env,
168+
goal.predicate.alias,
169+
assumption_projection_pred.projection_term,
170+
)?;
171+
172+
ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term);
173+
174+
// Add GAT where clauses from the trait's definition
175+
// FIXME: We don't need these, since these are the type's own WF obligations.
176+
ecx.add_goals(
177+
GoalSource::AliasWellFormed,
178+
cx.own_predicates_of(goal.predicate.def_id())
179+
.iter_instantiated(cx, goal.predicate.alias.args)
180+
.map(|pred| goal.with(cx, pred)),
181+
);
182+
183+
Ok(())
184+
} else {
185+
Err(NoSolution)
186+
}
187+
} else {
188+
Err(NoSolution)
189+
}
190+
}
191+
151192
fn consider_additional_alias_assumptions(
152193
_ecx: &mut EvalCtxt<'_, D>,
153194
_goal: Goal<I, Self>,

0 commit comments

Comments
 (0)