rustc_next_trait_solver/solve/normalizes_to/
opaque_types.rs1use rustc_index::bit_set::GrowableBitSet;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions};
7
8use crate::delegate::SolverDelegate;
9use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
10
11impl<D, I> EvalCtxt<'_, D>
12where
13 D: SolverDelegate<Interner = I>,
14 I: Interner,
15{
16 pub(super) fn normalize_opaque_type(
17 &mut self,
18 goal: Goal<I, ty::NormalizesTo<I>>,
19 ) -> QueryResult<I> {
20 let cx = self.cx();
21 let opaque_ty = goal.predicate.alias;
22 let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
23
24 match self.typing_mode() {
25 TypingMode::Coherence => {
26 self.add_item_bounds_for_hidden_type(
29 opaque_ty.def_id,
30 opaque_ty.args,
31 goal.param_env,
32 expected,
33 );
34 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
35 }
36 TypingMode::Analysis { defining_opaque_types } => {
37 let Some(def_id) = opaque_ty
38 .def_id
39 .as_local()
40 .filter(|&def_id| defining_opaque_types.contains(&def_id))
41 else {
42 self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
43 return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
44 };
45
46 match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
48 Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
49 return self.evaluate_added_goals_and_make_canonical_response(
50 Certainty::AMBIGUOUS,
51 );
52 }
53 Err(_) => {
54 return Err(NoSolution);
55 }
56 Ok(()) => {}
57 }
58 let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
60 let existing = self.probe_existing_opaque_ty(opaque_type_key);
65 if let Some((candidate_key, candidate_ty)) = existing {
66 return self
67 .probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
68 result: *result,
69 })
70 .enter(|ecx| {
71 for (a, b) in std::iter::zip(
72 candidate_key.args.iter(),
73 opaque_type_key.args.iter(),
74 ) {
75 ecx.eq(goal.param_env, a, b)?;
76 }
77 ecx.eq(goal.param_env, candidate_ty, expected)?;
78 ecx.add_item_bounds_for_hidden_type(
79 def_id.into(),
80 candidate_key.args,
81 goal.param_env,
82 candidate_ty,
83 );
84 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
85 });
86 }
87
88 self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
91 self.add_item_bounds_for_hidden_type(
92 def_id.into(),
93 opaque_ty.args,
94 goal.param_env,
95 expected,
96 );
97 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
98 }
99 TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
100 let Some(def_id) = opaque_ty
101 .def_id
102 .as_local()
103 .filter(|&def_id| defined_opaque_types.contains(&def_id))
104 else {
105 self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
106 return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
107 };
108
109 let actual = cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args);
110 let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
114 ty::ReErased => self.next_region_var(),
115 _ => re,
116 });
117 self.eq(goal.param_env, expected, actual)?;
118 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
119 }
120 TypingMode::PostAnalysis => {
121 let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
123 self.eq(goal.param_env, expected, actual)?;
124 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
125 }
126 }
127 }
128}
129
130fn uses_unique_placeholders_ignoring_regions<I: Interner>(
134 _cx: I,
135 args: I::GenericArgs,
136) -> Result<(), NotUniqueParam<I>> {
137 let mut seen = GrowableBitSet::default();
138 for arg in args.iter() {
139 match arg.kind() {
140 ty::GenericArgKind::Lifetime(_) => {}
143 ty::GenericArgKind::Type(t) => match t.kind() {
144 ty::Placeholder(p) => {
145 if !seen.insert(p.var()) {
146 return Err(NotUniqueParam::DuplicateParam(t.into()));
147 }
148 }
149 _ => return Err(NotUniqueParam::NotParam(t.into())),
150 },
151 ty::GenericArgKind::Const(c) => match c.kind() {
152 ty::ConstKind::Placeholder(p) => {
153 if !seen.insert(p.var()) {
154 return Err(NotUniqueParam::DuplicateParam(c.into()));
155 }
156 }
157 _ => return Err(NotUniqueParam::NotParam(c.into())),
158 },
159 }
160 }
161
162 Ok(())
163}
164
165enum NotUniqueParam<I: Interner> {
167 DuplicateParam(I::GenericArg),
168 NotParam(I::GenericArg),
169}