|
1 | 1 | //! Computes a normalizes-to (projection) goal for opaque types. This goal |
2 | 2 | //! behaves differently depending on the current `TypingMode`. |
3 | 3 |
|
4 | | -use rustc_index::bit_set::GrowableBitSet; |
5 | 4 | use rustc_type_ir::inherent::*; |
6 | 5 | use rustc_type_ir::solve::GoalSource; |
7 | | -use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions}; |
| 6 | +use rustc_type_ir::{self as ty, GenericArgKind, Interner, TypingMode, fold_regions}; |
8 | 7 |
|
9 | 8 | use crate::delegate::SolverDelegate; |
10 | | -use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; |
| 9 | +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; |
11 | 10 |
|
12 | 11 | impl<D, I> EvalCtxt<'_, D> |
13 | 12 | where |
@@ -49,54 +48,29 @@ where |
49 | 48 | return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); |
50 | 49 | }; |
51 | 50 |
|
52 | | - // FIXME: This may have issues when the args contain aliases... |
53 | | - 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 | | - // Prefer opaques registered already. |
65 | | - let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; |
66 | | - // FIXME: This also unifies the previous hidden type with the expected. |
67 | | - // |
68 | | - // If that fails, we insert `expected` as a new hidden type instead of |
69 | | - // eagerly emitting an error. |
70 | | - 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 | | - }); |
| 51 | + // We structurally normalize the args so that we're able to detect defining uses |
| 52 | + // later on. It also reduces the amount of duplicate definitions in the |
| 53 | + // `opaque_type_storage`. |
| 54 | + let normalized_args = |
| 55 | + cx.mk_args_from_iter(opaque_ty.args.iter().map(|arg| match arg.kind() { |
| 56 | + GenericArgKind::Lifetime(lt) => Ok(lt.into()), |
| 57 | + GenericArgKind::Type(ty) => { |
| 58 | + self.structurally_normalize_ty(goal.param_env, ty).map(Into::into) |
| 59 | + } |
| 60 | + GenericArgKind::Const(ct) => { |
| 61 | + self.structurally_normalize_const(goal.param_env, ct).map(Into::into) |
| 62 | + } |
| 63 | + }))?; |
| 64 | + |
| 65 | + let opaque_type_key = ty::OpaqueTypeKey { def_id, args: normalized_args }; |
| 66 | + if let Some(prev) = self.register_hidden_type_in_storage(opaque_type_key, expected) |
| 67 | + { |
| 68 | + self.eq(goal.param_env, expected, prev)?; |
92 | 69 | } |
93 | 70 |
|
94 | | - // Otherwise, define a new opaque type |
95 | | - let prev = self.register_hidden_type_in_storage(opaque_type_key, expected); |
96 | | - assert_eq!(prev, None); |
97 | 71 | self.add_item_bounds_for_hidden_type( |
98 | 72 | def_id.into(), |
99 | | - opaque_ty.args, |
| 73 | + normalized_args, |
100 | 74 | goal.param_env, |
101 | 75 | expected, |
102 | 76 | ); |
@@ -168,44 +142,3 @@ where |
168 | 142 | } |
169 | 143 | } |
170 | 144 | } |
171 | | - |
172 | | -/// Checks whether each generic argument is simply a unique generic placeholder. |
173 | | -/// |
174 | | -/// FIXME: Interner argument is needed to constrain the `I` parameter. |
175 | | -fn 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 | | - // Ignore regions, since we can't resolve those in a canonicalized |
183 | | - // query in the trait solver. |
184 | | - 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 | | - |
207 | | -// FIXME: This should check for dupes and non-params first, then infer vars. |
208 | | -enum NotUniqueParam<I: Interner> { |
209 | | - DuplicateParam(I::GenericArg), |
210 | | - NotParam(I::GenericArg), |
211 | | -} |
0 commit comments