Skip to content

Commit 7a2cdf2

Browse files
Move alias-relate to its own module
1 parent 3572d74 commit 7a2cdf2

File tree

2 files changed

+147
-136
lines changed

2 files changed

+147
-136
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
use super::{EvalCtxt, SolverMode};
2+
use rustc_infer::traits::query::NoSolution;
3+
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
4+
use rustc_middle::ty;
5+
6+
/// We may need to invert the alias relation direction if dealing an alias on the RHS.
7+
#[derive(Debug)]
8+
enum Invert {
9+
No,
10+
Yes,
11+
}
12+
13+
impl<'tcx> EvalCtxt<'_, 'tcx> {
14+
#[instrument(level = "debug", skip(self), ret)]
15+
pub(super) fn compute_alias_relate_goal(
16+
&mut self,
17+
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
18+
) -> QueryResult<'tcx> {
19+
let tcx = self.tcx();
20+
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
21+
if lhs.is_infer() || rhs.is_infer() {
22+
bug!(
23+
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
24+
);
25+
}
26+
27+
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
28+
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
29+
30+
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
31+
(Some(alias_lhs), None) => self.assemble_normalizes_to_candidate(
32+
param_env,
33+
alias_lhs,
34+
rhs,
35+
direction,
36+
Invert::No,
37+
),
38+
39+
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
40+
(None, Some(alias_rhs)) => self.assemble_normalizes_to_candidate(
41+
param_env,
42+
alias_rhs,
43+
lhs,
44+
direction,
45+
Invert::Yes,
46+
),
47+
48+
(Some(alias_lhs), Some(alias_rhs)) => {
49+
debug!("both sides are aliases");
50+
51+
let mut candidates = Vec::new();
52+
// LHS normalizes-to RHS
53+
candidates.extend(self.assemble_normalizes_to_candidate(
54+
param_env,
55+
alias_lhs,
56+
rhs,
57+
direction,
58+
Invert::No,
59+
));
60+
// RHS normalizes-to RHS
61+
candidates.extend(self.assemble_normalizes_to_candidate(
62+
param_env,
63+
alias_rhs,
64+
lhs,
65+
direction,
66+
Invert::Yes,
67+
));
68+
// Relate via substs
69+
let subst_relate_response = self
70+
.assemble_subst_relate_candidate(param_env, alias_lhs, alias_rhs, direction);
71+
candidates.extend(subst_relate_response);
72+
debug!(?candidates);
73+
74+
if let Some(merged) = self.try_merge_responses(&candidates) {
75+
Ok(merged)
76+
} else {
77+
// When relating two aliases and we have ambiguity, we prefer
78+
// relating the generic arguments of the aliases over normalizing
79+
// them. This is necessary for inference during typeck.
80+
//
81+
// As this is incomplete, we must not do so during coherence.
82+
match (self.solver_mode(), subst_relate_response) {
83+
(SolverMode::Normal, Ok(response)) => Ok(response),
84+
(SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
85+
self.flounder(&candidates)
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
93+
#[instrument(level = "debug", skip(self), ret)]
94+
fn assemble_normalizes_to_candidate(
95+
&mut self,
96+
param_env: ty::ParamEnv<'tcx>,
97+
alias: ty::AliasTy<'tcx>,
98+
other: ty::Term<'tcx>,
99+
direction: ty::AliasRelationDirection,
100+
invert: Invert,
101+
) -> QueryResult<'tcx> {
102+
self.probe(|ecx| {
103+
let other = match direction {
104+
// This is purely an optimization.
105+
ty::AliasRelationDirection::Equate => other,
106+
107+
ty::AliasRelationDirection::Subtype => {
108+
let fresh = ecx.next_term_infer_of_kind(other);
109+
let (sub, sup) = match invert {
110+
Invert::No => (fresh, other),
111+
Invert::Yes => (other, fresh),
112+
};
113+
ecx.sub(param_env, sub, sup)?;
114+
fresh
115+
}
116+
};
117+
ecx.add_goal(Goal::new(
118+
ecx.tcx(),
119+
param_env,
120+
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
121+
));
122+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
123+
})
124+
}
125+
126+
fn assemble_subst_relate_candidate(
127+
&mut self,
128+
param_env: ty::ParamEnv<'tcx>,
129+
alias_lhs: ty::AliasTy<'tcx>,
130+
alias_rhs: ty::AliasTy<'tcx>,
131+
direction: ty::AliasRelationDirection,
132+
) -> QueryResult<'tcx> {
133+
self.probe(|ecx| {
134+
match direction {
135+
ty::AliasRelationDirection::Equate => {
136+
ecx.eq(param_env, alias_lhs, alias_rhs)?;
137+
}
138+
ty::AliasRelationDirection::Subtype => {
139+
ecx.sub(param_env, alias_lhs, alias_rhs)?;
140+
}
141+
}
142+
143+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
144+
})
145+
}
146+
}

compiler/rustc_trait_selection/src/solve/mod.rs

+1-136
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc_middle::ty::{
2020
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
2121
};
2222

23+
mod alias_relate;
2324
mod assembly;
2425
mod canonicalize;
2526
mod eval_ctxt;
@@ -154,142 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
154155
}
155156
}
156157

157-
#[instrument(level = "debug", skip(self), ret)]
158-
fn compute_alias_relate_goal(
159-
&mut self,
160-
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
161-
) -> QueryResult<'tcx> {
162-
let tcx = self.tcx();
163-
// We may need to invert the alias relation direction if dealing an alias on the RHS.
164-
#[derive(Debug)]
165-
enum Invert {
166-
No,
167-
Yes,
168-
}
169-
let evaluate_normalizes_to =
170-
|ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
171-
let span = tracing::span!(
172-
tracing::Level::DEBUG,
173-
"compute_alias_relate_goal(evaluate_normalizes_to)",
174-
?alias,
175-
?other,
176-
?direction,
177-
?invert
178-
);
179-
let _enter = span.enter();
180-
let result = ecx.probe(|ecx| {
181-
let other = match direction {
182-
// This is purely an optimization.
183-
ty::AliasRelationDirection::Equate => other,
184-
185-
ty::AliasRelationDirection::Subtype => {
186-
let fresh = ecx.next_term_infer_of_kind(other);
187-
let (sub, sup) = match invert {
188-
Invert::No => (fresh, other),
189-
Invert::Yes => (other, fresh),
190-
};
191-
ecx.sub(goal.param_env, sub, sup)?;
192-
fresh
193-
}
194-
};
195-
ecx.add_goal(goal.with(
196-
tcx,
197-
ty::Binder::dummy(ty::ProjectionPredicate {
198-
projection_ty: alias,
199-
term: other,
200-
}),
201-
));
202-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
203-
});
204-
debug!(?result);
205-
result
206-
};
207-
208-
let (lhs, rhs, direction) = goal.predicate;
209-
210-
if lhs.is_infer() || rhs.is_infer() {
211-
bug!(
212-
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
213-
);
214-
}
215-
216-
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
217-
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
218-
219-
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
220-
(Some(alias_lhs), None) => {
221-
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
222-
}
223-
224-
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
225-
(None, Some(alias_rhs)) => {
226-
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
227-
}
228-
229-
(Some(alias_lhs), Some(alias_rhs)) => {
230-
debug!("both sides are aliases");
231-
232-
let mut candidates = Vec::new();
233-
// LHS normalizes-to RHS
234-
candidates.extend(evaluate_normalizes_to(
235-
self,
236-
alias_lhs,
237-
rhs,
238-
direction,
239-
Invert::No,
240-
));
241-
// RHS normalizes-to RHS
242-
candidates.extend(evaluate_normalizes_to(
243-
self,
244-
alias_rhs,
245-
lhs,
246-
direction,
247-
Invert::Yes,
248-
));
249-
// Relate via substs
250-
let subst_relate_response = self.probe(|ecx| {
251-
let span = tracing::span!(
252-
tracing::Level::DEBUG,
253-
"compute_alias_relate_goal(relate_via_substs)",
254-
?alias_lhs,
255-
?alias_rhs,
256-
?direction
257-
);
258-
let _enter = span.enter();
259-
260-
match direction {
261-
ty::AliasRelationDirection::Equate => {
262-
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
263-
}
264-
ty::AliasRelationDirection::Subtype => {
265-
ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
266-
}
267-
}
268-
269-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
270-
});
271-
candidates.extend(subst_relate_response);
272-
debug!(?candidates);
273-
274-
if let Some(merged) = self.try_merge_responses(&candidates) {
275-
Ok(merged)
276-
} else {
277-
// When relating two aliases and we have ambiguity, we prefer
278-
// relating the generic arguments of the aliases over normalizing
279-
// them. This is necessary for inference during typeck.
280-
//
281-
// As this is incomplete, we must not do so during coherence.
282-
match (self.solver_mode(), subst_relate_response) {
283-
(SolverMode::Normal, Ok(response)) => Ok(response),
284-
(SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
285-
self.flounder(&candidates)
286-
}
287-
}
288-
}
289-
}
290-
}
291-
}
292-
293158
#[instrument(level = "debug", skip(self), ret)]
294159
fn compute_const_arg_has_type_goal(
295160
&mut self,

0 commit comments

Comments
 (0)