Skip to content

Commit b4855d8

Browse files
committed
w
1 parent 557ed64 commit b4855d8

File tree

2 files changed

+72
-174
lines changed

2 files changed

+72
-174
lines changed

Diff for: compiler/rustc_trait_selection/src/solve/alias_relate.rs

+52-174
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,11 @@
1111
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
1212
//! may apply, then we can compute the "intersection" of both normalizes-to by
1313
//! performing them together. This is used specifically to resolve ambiguities.
14-
use super::{EvalCtxt, SolverMode};
14+
use super::EvalCtxt;
1515
use rustc_infer::traits::query::NoSolution;
1616
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
1717
use rustc_middle::ty;
1818

19-
/// We may need to invert the alias relation direction if dealing an alias on the RHS.
20-
#[derive(Debug)]
21-
enum Invert {
22-
No,
23-
Yes,
24-
}
25-
2619
impl<'tcx> EvalCtxt<'_, 'tcx> {
2720
#[instrument(level = "debug", skip(self), ret)]
2821
pub(super) fn compute_alias_relate_goal(
@@ -31,187 +24,72 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3124
) -> QueryResult<'tcx> {
3225
let tcx = self.tcx();
3326
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
34-
if lhs.is_infer() || rhs.is_infer() {
35-
bug!(
36-
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
37-
);
38-
}
39-
40-
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
41-
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
4227

43-
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
44-
(Some(alias_lhs), None) => self.assemble_normalizes_to_candidate(
45-
param_env,
46-
alias_lhs,
47-
rhs,
48-
direction,
49-
Invert::No,
50-
),
28+
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
29+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
30+
};
5131

52-
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
53-
(None, Some(alias_rhs)) => self.assemble_normalizes_to_candidate(
54-
param_env,
55-
alias_rhs,
56-
lhs,
57-
direction,
58-
Invert::Yes,
59-
),
32+
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
33+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
34+
};
6035

61-
(Some(alias_lhs), Some(alias_rhs)) => {
62-
debug!("both sides are aliases");
36+
let variance = match direction {
37+
ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
38+
ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
39+
};
6340

64-
let mut candidates = Vec::new();
65-
// LHS normalizes-to RHS
66-
candidates.extend(self.assemble_normalizes_to_candidate(
67-
param_env,
68-
alias_lhs,
69-
rhs,
70-
direction,
71-
Invert::No,
72-
));
73-
// RHS normalizes-to RHS
74-
candidates.extend(self.assemble_normalizes_to_candidate(
75-
param_env,
76-
alias_rhs,
77-
lhs,
78-
direction,
79-
Invert::Yes,
80-
));
81-
// Relate via args
82-
candidates.extend(
83-
self.assemble_subst_relate_candidate(
84-
param_env, alias_lhs, alias_rhs, direction,
85-
),
86-
);
87-
debug!(?candidates);
41+
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
42+
(None, None) => {
43+
self.relate(param_env, lhs, variance, rhs)?;
44+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
45+
}
8846

89-
if let Some(merged) = self.try_merge_responses(&candidates) {
90-
Ok(merged)
47+
(Some(_), None) => {
48+
if rhs.is_infer() {
49+
self.relate(param_env, lhs, variance, rhs)?;
50+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9151
} else {
92-
// When relating two aliases and we have ambiguity, if both
93-
// aliases can be normalized to something, we prefer
94-
// "bidirectionally normalizing" both of them within the same
95-
// candidate.
96-
//
97-
// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/25>.
98-
//
99-
// As this is incomplete, we must not do so during coherence.
100-
match self.solver_mode() {
101-
SolverMode::Normal => {
102-
if let Ok(bidirectional_normalizes_to_response) = self
103-
.assemble_bidirectional_normalizes_to_candidate(
104-
param_env, lhs, rhs, direction,
105-
)
106-
{
107-
Ok(bidirectional_normalizes_to_response)
108-
} else {
109-
self.flounder(&candidates)
110-
}
111-
}
112-
SolverMode::Coherence => self.flounder(&candidates),
113-
}
52+
Err(NoSolution)
11453
}
11554
}
116-
}
117-
}
118-
119-
#[instrument(level = "debug", skip(self), ret)]
120-
fn assemble_normalizes_to_candidate(
121-
&mut self,
122-
param_env: ty::ParamEnv<'tcx>,
123-
alias: ty::AliasTy<'tcx>,
124-
other: ty::Term<'tcx>,
125-
direction: ty::AliasRelationDirection,
126-
invert: Invert,
127-
) -> QueryResult<'tcx> {
128-
self.probe_misc_candidate("normalizes-to").enter(|ecx| {
129-
ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
130-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
131-
})
132-
}
133-
134-
// Computes the normalizes-to branch, with side-effects. This must be performed
135-
// in a probe in order to not taint the evaluation context.
136-
fn normalizes_to_inner(
137-
&mut self,
138-
param_env: ty::ParamEnv<'tcx>,
139-
alias: ty::AliasTy<'tcx>,
140-
other: ty::Term<'tcx>,
141-
direction: ty::AliasRelationDirection,
142-
invert: Invert,
143-
) -> Result<(), NoSolution> {
144-
let other = match direction {
145-
// This is purely an optimization. No need to instantiate a new
146-
// infer var and equate the RHS to it.
147-
ty::AliasRelationDirection::Equate => other,
148-
149-
// Instantiate an infer var and subtype our RHS to it, so that we
150-
// properly represent a subtype relation between the LHS and RHS
151-
// of the goal.
152-
ty::AliasRelationDirection::Subtype => {
153-
let fresh = self.next_term_infer_of_kind(other);
154-
let (sub, sup) = match invert {
155-
Invert::No => (fresh, other),
156-
Invert::Yes => (other, fresh),
157-
};
158-
self.sub(param_env, sub, sup)?;
159-
fresh
55+
(None, Some(_)) => {
56+
if lhs.is_infer() {
57+
self.relate(param_env, lhs, variance, rhs)?;
58+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
59+
} else {
60+
Err(NoSolution)
61+
}
16062
}
161-
};
162-
self.add_goal(Goal::new(
163-
self.tcx(),
164-
param_env,
165-
ty::ProjectionPredicate { projection_ty: alias, term: other },
166-
));
16763

168-
Ok(())
64+
(Some(alias_lhs), Some(alias_rhs)) => {
65+
self.relate(param_env, alias_lhs, variance, alias_rhs)?;
66+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
67+
}
68+
}
16969
}
17070

171-
fn assemble_subst_relate_candidate(
71+
/// Normalize the `term` to equate it later.
72+
fn try_normalize_term(
17273
&mut self,
17374
param_env: ty::ParamEnv<'tcx>,
174-
alias_lhs: ty::AliasTy<'tcx>,
175-
alias_rhs: ty::AliasTy<'tcx>,
176-
direction: ty::AliasRelationDirection,
177-
) -> QueryResult<'tcx> {
178-
self.probe_misc_candidate("args relate").enter(|ecx| {
179-
match direction {
180-
ty::AliasRelationDirection::Equate => {
181-
ecx.eq(param_env, alias_lhs, alias_rhs)?;
182-
}
183-
ty::AliasRelationDirection::Subtype => {
184-
ecx.sub(param_env, alias_lhs, alias_rhs)?;
75+
term: ty::Term<'tcx>,
76+
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
77+
match term.unpack() {
78+
ty::TermKind::Ty(ty) => Ok(self.try_normalize_ty(param_env, ty).map(Into::into)),
79+
ty::TermKind::Const(_) => {
80+
if let Some(alias) = term.to_alias_ty(self.tcx()) {
81+
let term = self.next_term_infer_of_kind(term);
82+
self.add_goal(Goal::new(
83+
self.tcx(),
84+
param_env,
85+
ty::ProjectionPredicate { projection_ty: alias, term },
86+
));
87+
self.try_evaluate_added_goals()?;
88+
Ok(Some(self.resolve_vars_if_possible(term)))
89+
} else {
90+
Ok(Some(term))
18591
}
18692
}
187-
188-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
189-
})
190-
}
191-
192-
fn assemble_bidirectional_normalizes_to_candidate(
193-
&mut self,
194-
param_env: ty::ParamEnv<'tcx>,
195-
lhs: ty::Term<'tcx>,
196-
rhs: ty::Term<'tcx>,
197-
direction: ty::AliasRelationDirection,
198-
) -> QueryResult<'tcx> {
199-
self.probe_misc_candidate("bidir normalizes-to").enter(|ecx| {
200-
ecx.normalizes_to_inner(
201-
param_env,
202-
lhs.to_alias_ty(ecx.tcx()).unwrap(),
203-
rhs,
204-
direction,
205-
Invert::No,
206-
)?;
207-
ecx.normalizes_to_inner(
208-
param_env,
209-
rhs.to_alias_ty(ecx.tcx()).unwrap(),
210-
lhs,
211-
direction,
212-
Invert::Yes,
213-
)?;
214-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
215-
})
93+
}
21694
}
21795
}

Diff for: compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
751751
})
752752
}
753753

754+
#[instrument(level = "debug", skip(self, param_env), ret)]
755+
pub(super) fn relate<T: ToTrace<'tcx>>(
756+
&mut self,
757+
param_env: ty::ParamEnv<'tcx>,
758+
lhs: T,
759+
variance: ty::Variance,
760+
rhs: T,
761+
) -> Result<(), NoSolution> {
762+
self.infcx
763+
.at(&ObligationCause::dummy(), param_env)
764+
.relate(DefineOpaqueTypes::No, lhs, variance, rhs)
765+
.map(|InferOk { value: (), obligations }| {
766+
self.add_goals(obligations.into_iter().map(|o| o.into()));
767+
})
768+
.map_err(|e| {
769+
debug!(?e, "failed to relate");
770+
NoSolution
771+
})
772+
}
773+
754774
/// Equates two values returning the nested goals without adding them
755775
/// to the nested goals of the `EvalCtxt`.
756776
///

0 commit comments

Comments
 (0)