rustc_next_trait_solver/solve/normalizes_to/
opaque_types.rs1use rustc_index::bit_set::GrowableBitSet;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::solve::GoalSource;
7use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions};
8
9use crate::delegate::SolverDelegate;
10use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
11
12impl<D, I> EvalCtxt<'_, D>
13where
14 D: SolverDelegate<Interner = I>,
15 I: Interner,
16{
17 pub(super) fn normalize_opaque_type(
18 &mut self,
19 goal: Goal<I, ty::NormalizesTo<I>>,
20 ) -> QueryResult<I> {
21 let cx = self.cx();
22 let opaque_ty = goal.predicate.alias;
23 let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
24
25 match self.typing_mode() {
26 TypingMode::Coherence => {
27 self.add_item_bounds_for_hidden_type(
30 opaque_ty.def_id,
31 opaque_ty.args,
32 goal.param_env,
33 expected,
34 );
35 self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous));
40 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
41 }
42 TypingMode::Analysis { defining_opaque_types_and_generators } => {
43 let Some(def_id) = opaque_ty
44 .def_id
45 .as_local()
46 .filter(|&def_id| defining_opaque_types_and_generators.contains(&def_id))
47 else {
48 self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
49 return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
50 };
51
52 match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
54 Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
55 return self.evaluate_added_goals_and_make_canonical_response(
56 Certainty::AMBIGUOUS,
57 );
58 }
59 Err(_) => {
60 return Err(NoSolution);
61 }
62 Ok(()) => {}
63 }
64 let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
66 let existing = self.probe_existing_opaque_ty(opaque_type_key);
71 if let Some((candidate_key, candidate_ty)) = existing {
72 return self
73 .probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
74 result: *result,
75 })
76 .enter(|ecx| {
77 for (a, b) in std::iter::zip(
78 candidate_key.args.iter(),
79 opaque_type_key.args.iter(),
80 ) {
81 ecx.eq(goal.param_env, a, b)?;
82 }
83 ecx.eq(goal.param_env, candidate_ty, expected)?;
84 ecx.add_item_bounds_for_hidden_type(
85 def_id.into(),
86 candidate_key.args,
87 goal.param_env,
88 candidate_ty,
89 );
90 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
91 });
92 }
93
94 let prev = self.register_hidden_type_in_storage(opaque_type_key, expected);
96 assert_eq!(prev, None);
97 self.add_item_bounds_for_hidden_type(
98 def_id.into(),
99 opaque_ty.args,
100 goal.param_env,
101 expected,
102 );
103 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
104 }
105 TypingMode::Borrowck { defining_opaque_types } => {
111 let Some(def_id) = opaque_ty
112 .def_id
113 .as_local()
114 .filter(|&def_id| defining_opaque_types.contains(&def_id))
115 else {
116 self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
117 return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
118 };
119
120 let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
121 let actual = self
122 .register_hidden_type_in_storage(opaque_type_key, expected)
123 .unwrap_or_else(|| {
124 let actual =
125 cx.type_of_opaque_hir_typeck(def_id).instantiate(cx, opaque_ty.args);
126 let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
127 ty::ReErased => self.next_region_var(),
128 _ => re,
129 });
130 actual
131 });
132 self.eq(goal.param_env, expected, actual)?;
133 self.add_item_bounds_for_hidden_type(
134 def_id.into(),
135 opaque_ty.args,
136 goal.param_env,
137 expected,
138 );
139 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
140 }
141 TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
142 let Some(def_id) = opaque_ty
143 .def_id
144 .as_local()
145 .filter(|&def_id| defined_opaque_types.contains(&def_id))
146 else {
147 self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
148 return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
149 };
150
151 let actual = cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args);
152 let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
156 ty::ReErased => self.next_region_var(),
157 _ => re,
158 });
159 self.eq(goal.param_env, expected, actual)?;
160 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
161 }
162 TypingMode::PostAnalysis => {
163 let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
165 self.eq(goal.param_env, expected, actual)?;
166 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
167 }
168 }
169 }
170}
171
172fn uses_unique_placeholders_ignoring_regions<I: Interner>(
176 _cx: I,
177 args: I::GenericArgs,
178) -> Result<(), NotUniqueParam<I>> {
179 let mut seen = GrowableBitSet::default();
180 for arg in args.iter() {
181 match arg.kind() {
182 ty::GenericArgKind::Lifetime(_) => {}
185 ty::GenericArgKind::Type(t) => match t.kind() {
186 ty::Placeholder(p) => {
187 if !seen.insert(p.var()) {
188 return Err(NotUniqueParam::DuplicateParam(t.into()));
189 }
190 }
191 _ => return Err(NotUniqueParam::NotParam(t.into())),
192 },
193 ty::GenericArgKind::Const(c) => match c.kind() {
194 ty::ConstKind::Placeholder(p) => {
195 if !seen.insert(p.var()) {
196 return Err(NotUniqueParam::DuplicateParam(c.into()));
197 }
198 }
199 _ => return Err(NotUniqueParam::NotParam(c.into())),
200 },
201 }
202 }
203
204 Ok(())
205}
206
207enum NotUniqueParam<I: Interner> {
209 DuplicateParam(I::GenericArg),
210 NotParam(I::GenericArg),
211}