1use std::hash::Hash;
2
3use cairo_lang_defs::ids::{TraitConstantId, TraitTypeId};
4use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
5use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
6use cairo_lang_utils::{Intern, LookupIntern};
7use itertools::zip_eq;
8
9use super::canonic::{NoError, ResultNoErrEx};
10use super::{
11 ErrorSet, ImplVarId, ImplVarTraitItemMappings, Inference, InferenceError, InferenceResult,
12 InferenceVar,
13};
14use crate::corelib::never_ty;
15use crate::items::constant::{ConstValue, ConstValueId, ImplConstantId};
16use crate::items::functions::{GenericFunctionId, ImplGenericFunctionId};
17use crate::items::imp::{ImplId, ImplImplId, ImplLongId, ImplLookupContext};
18use crate::items::trt::ConcreteTraitImplId;
19use crate::substitution::SemanticRewriter;
20use crate::types::{ClosureTypeLongId, ImplTypeId, peel_snapshots};
21use crate::{
22 ConcreteFunction, ConcreteImplLongId, ConcreteTraitId, ConcreteTraitLongId, ConcreteTypeId,
23 FunctionId, FunctionLongId, GenericArgumentId, TypeId, TypeLongId,
24};
25
26pub trait InferenceConform {
28 fn conform_ty(&mut self, ty0: TypeId, ty1: TypeId) -> InferenceResult<TypeId>;
29 fn conform_ty_ex(
30 &mut self,
31 ty0: TypeId,
32 ty1: TypeId,
33 ty0_is_self: bool,
34 ) -> InferenceResult<(TypeId, usize)>;
35 fn conform_const(
36 &mut self,
37 ty0: ConstValueId,
38 ty1: ConstValueId,
39 ) -> InferenceResult<ConstValueId>;
40 fn maybe_peel_snapshots(&mut self, ty0_is_self: bool, ty1: TypeId) -> (usize, TypeLongId);
41 fn conform_generic_args(
42 &mut self,
43 gargs0: &[GenericArgumentId],
44 gargs1: &[GenericArgumentId],
45 ) -> InferenceResult<Vec<GenericArgumentId>>;
46 fn conform_generic_arg(
47 &mut self,
48 garg0: GenericArgumentId,
49 garg1: GenericArgumentId,
50 ) -> InferenceResult<GenericArgumentId>;
51 fn conform_impl(&mut self, impl0: ImplId, impl1: ImplId) -> InferenceResult<ImplId>;
52 fn conform_traits(
53 &mut self,
54 trt0: ConcreteTraitId,
55 trt1: ConcreteTraitId,
56 ) -> InferenceResult<ConcreteTraitId>;
57 fn conform_generic_function(
58 &mut self,
59 trt0: GenericFunctionId,
60 trt1: GenericFunctionId,
61 ) -> InferenceResult<GenericFunctionId>;
62 fn ty_contains_var(&mut self, ty: TypeId, var: InferenceVar) -> bool;
63 fn generic_args_contain_var(
64 &mut self,
65 generic_args: &[GenericArgumentId],
66 var: InferenceVar,
67 ) -> bool;
68 fn impl_contains_var(&mut self, impl_id: ImplId, var: InferenceVar) -> bool;
69 fn function_contains_var(&mut self, function_id: FunctionId, var: InferenceVar) -> bool;
70}
71
72impl InferenceConform for Inference<'_> {
73 fn conform_ty(&mut self, ty0: TypeId, ty1: TypeId) -> InferenceResult<TypeId> {
76 Ok(self.conform_ty_ex(ty0, ty1, false)?.0)
77 }
78
79 fn conform_ty_ex(
83 &mut self,
84 ty0: TypeId,
85 ty1: TypeId,
86 ty0_is_self: bool,
87 ) -> InferenceResult<(TypeId, usize)> {
88 let ty0 = self.rewrite(ty0).no_err();
89 let ty1 = self.rewrite(ty1).no_err();
90 if ty0 == never_ty(self.db) || ty0.is_missing(self.db) {
91 return Ok((ty1, 0));
92 }
93 if ty0 == ty1 {
94 return Ok((ty0, 0));
95 }
96 let long_ty1 = ty1.lookup_intern(self.db);
97 match long_ty1 {
98 TypeLongId::Var(var) => return Ok((self.assign_ty(var, ty0)?, 0)),
99 TypeLongId::Missing(_) => return Ok((ty1, 0)),
100 TypeLongId::Snapshot(inner_ty) => {
101 if ty0_is_self {
102 if inner_ty == ty0 {
103 return Ok((ty1, 1));
104 }
105 if !matches!(ty0.lookup_intern(self.db), TypeLongId::Snapshot(_)) {
106 if let TypeLongId::Var(var) = inner_ty.lookup_intern(self.db) {
107 return Ok((self.assign_ty(var, ty0)?, 1));
108 }
109 }
110 }
111 }
112 TypeLongId::ImplType(impl_type) => {
113 if let Some(ty) = self.impl_type_bounds.get(&impl_type) {
114 return self.conform_ty_ex(ty0, *ty, ty0_is_self);
115 }
116 }
117 _ => {}
118 }
119 let n_snapshots = 0;
120 let long_ty0 = ty0.lookup_intern(self.db);
121
122 match long_ty0 {
123 TypeLongId::Concrete(concrete0) => {
124 let (n_snapshots, long_ty1) = self.maybe_peel_snapshots(ty0_is_self, ty1);
125 let TypeLongId::Concrete(concrete1) = long_ty1 else {
126 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
127 };
128 if concrete0.generic_type(self.db) != concrete1.generic_type(self.db) {
129 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
130 }
131 let gargs0 = concrete0.generic_args(self.db);
132 let gargs1 = concrete1.generic_args(self.db);
133 let gargs = self.conform_generic_args(&gargs0, &gargs1)?;
134 let long_ty = TypeLongId::Concrete(ConcreteTypeId::new(
135 self.db,
136 concrete0.generic_type(self.db),
137 gargs,
138 ));
139 Ok((long_ty.intern(self.db), n_snapshots))
140 }
141 TypeLongId::Tuple(tys0) => {
142 let (n_snapshots, long_ty1) = self.maybe_peel_snapshots(ty0_is_self, ty1);
143 let TypeLongId::Tuple(tys1) = long_ty1 else {
144 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
145 };
146 if tys0.len() != tys1.len() {
147 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
148 }
149 let tys = zip_eq(tys0, tys1)
150 .map(|(subty0, subty1)| self.conform_ty(subty0, subty1))
151 .collect::<Result<Vec<_>, _>>()?;
152 Ok((TypeLongId::Tuple(tys).intern(self.db), n_snapshots))
153 }
154 TypeLongId::Closure(closure0) => {
155 let (n_snapshots, long_ty1) = self.maybe_peel_snapshots(ty0_is_self, ty1);
156 let TypeLongId::Closure(closure1) = long_ty1 else {
157 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
158 };
159 if closure0.wrapper_location != closure1.wrapper_location {
160 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
161 }
162 let param_tys = zip_eq(closure0.param_tys, closure1.param_tys)
163 .map(|(subty0, subty1)| self.conform_ty(subty0, subty1))
164 .collect::<Result<Vec<_>, _>>()?;
165 let captured_types = zip_eq(closure0.captured_types, closure1.captured_types)
166 .map(|(subty0, subty1)| self.conform_ty(subty0, subty1))
167 .collect::<Result<Vec<_>, _>>()?;
168 let ret_ty = self.conform_ty(closure0.ret_ty, closure1.ret_ty)?;
169 Ok((
170 TypeLongId::Closure(ClosureTypeLongId {
171 param_tys,
172 ret_ty,
173 captured_types,
174 wrapper_location: closure0.wrapper_location,
175 parent_function: closure0.parent_function,
176 })
177 .intern(self.db),
178 n_snapshots,
179 ))
180 }
181 TypeLongId::FixedSizeArray { type_id, size } => {
182 let (n_snapshots, long_ty1) = self.maybe_peel_snapshots(ty0_is_self, ty1);
183 let TypeLongId::FixedSizeArray { type_id: type_id1, size: size1 } = long_ty1 else {
184 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
185 };
186 let size = self.conform_const(size, size1)?;
187 let ty = self.conform_ty(type_id, type_id1)?;
188 Ok((TypeLongId::FixedSizeArray { type_id: ty, size }.intern(self.db), n_snapshots))
189 }
190 TypeLongId::Snapshot(ty0) => {
191 let TypeLongId::Snapshot(ty1) = long_ty1 else {
192 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
193 };
194 let (ty, n_snapshots) = self.conform_ty_ex(ty0, ty1, ty0_is_self)?;
195 Ok((TypeLongId::Snapshot(ty).intern(self.db), n_snapshots))
196 }
197 TypeLongId::GenericParameter(_) => {
198 Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }))
199 }
200 TypeLongId::TraitType(_) => {
201 Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }))
204 }
205 TypeLongId::Var(var) => Ok((self.assign_ty(var, ty1)?, n_snapshots)),
206 TypeLongId::ImplType(impl_type) => {
207 if let Some(ty) = self.impl_type_bounds.get(&impl_type) {
208 return self.conform_ty_ex(*ty, ty1, ty0_is_self);
209 }
210 Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }))
211 }
212 TypeLongId::Missing(_) => Ok((ty0, n_snapshots)),
213 TypeLongId::Coupon(function_id0) => {
214 let TypeLongId::Coupon(function_id1) = long_ty1 else {
215 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
216 };
217
218 let func0 = function_id0.lookup_intern(self.db).function;
219 let func1 = function_id1.lookup_intern(self.db).function;
220
221 let generic_function =
222 self.conform_generic_function(func0.generic_function, func1.generic_function)?;
223
224 if func0.generic_args.len() != func1.generic_args.len() {
225 return Err(self.set_error(InferenceError::TypeKindMismatch { ty0, ty1 }));
226 }
227
228 let generic_args =
229 self.conform_generic_args(&func0.generic_args, &func1.generic_args)?;
230
231 Ok((
232 TypeLongId::Coupon(
233 FunctionLongId {
234 function: ConcreteFunction { generic_function, generic_args },
235 }
236 .intern(self.db),
237 )
238 .intern(self.db),
239 n_snapshots,
240 ))
241 }
242 }
243 }
244
245 fn conform_const(
248 &mut self,
249 id0: ConstValueId,
250 id1: ConstValueId,
251 ) -> InferenceResult<ConstValueId> {
252 let id0 = self.rewrite(id0).no_err();
253 let id1 = self.rewrite(id1).no_err();
254 self.conform_ty(id0.ty(self.db).unwrap(), id1.ty(self.db).unwrap())?;
255 if id0 == id1 {
256 return Ok(id0);
257 }
258 let const_value0 = id0.lookup_intern(self.db);
259 if matches!(const_value0, ConstValue::Missing(_)) {
260 return Ok(id1);
261 }
262 match id1.lookup_intern(self.db) {
263 ConstValue::Missing(_) => return Ok(id1),
264 ConstValue::Var(var, _) => return self.assign_const(var, id0),
265 _ => {}
266 }
267 match const_value0 {
268 ConstValue::Var(var, _) => Ok(self.assign_const(var, id1)?),
269 ConstValue::ImplConstant(_) => {
270 Err(self.set_error(InferenceError::ConstKindMismatch { const0: id0, const1: id1 }))
271 }
272 _ => {
273 Err(self.set_error(InferenceError::ConstKindMismatch { const0: id0, const1: id1 }))
274 }
275 }
276 }
277
278 fn maybe_peel_snapshots(&mut self, ty0_is_self: bool, ty1: TypeId) -> (usize, TypeLongId) {
280 let (n_snapshots, long_ty1) = if ty0_is_self {
281 peel_snapshots(self.db, ty1)
282 } else {
283 (0, ty1.lookup_intern(self.db))
284 };
285 (n_snapshots, long_ty1)
286 }
287
288 fn conform_generic_args(
290 &mut self,
291 gargs0: &[GenericArgumentId],
292 gargs1: &[GenericArgumentId],
293 ) -> InferenceResult<Vec<GenericArgumentId>> {
294 zip_eq(gargs0, gargs1)
295 .map(|(garg0, garg1)| self.conform_generic_arg(*garg0, *garg1))
296 .collect::<Result<Vec<_>, _>>()
297 }
298
299 fn conform_generic_arg(
301 &mut self,
302 garg0: GenericArgumentId,
303 garg1: GenericArgumentId,
304 ) -> InferenceResult<GenericArgumentId> {
305 if garg0 == garg1 {
306 return Ok(garg0);
307 }
308 match garg0 {
309 GenericArgumentId::Type(gty0) => {
310 let GenericArgumentId::Type(gty1) = garg1 else {
311 return Err(self.set_error(InferenceError::GenericArgMismatch { garg0, garg1 }));
312 };
313 Ok(GenericArgumentId::Type(self.conform_ty(gty0, gty1)?))
314 }
315 GenericArgumentId::Constant(gc0) => {
316 let GenericArgumentId::Constant(gc1) = garg1 else {
317 return Err(self.set_error(InferenceError::GenericArgMismatch { garg0, garg1 }));
318 };
319
320 Ok(GenericArgumentId::Constant(self.conform_const(gc0, gc1)?))
321 }
322 GenericArgumentId::Impl(impl0) => {
323 let GenericArgumentId::Impl(impl1) = garg1 else {
324 return Err(self.set_error(InferenceError::GenericArgMismatch { garg0, garg1 }));
325 };
326 Ok(GenericArgumentId::Impl(self.conform_impl(impl0, impl1)?))
327 }
328 GenericArgumentId::NegImpl => match garg1 {
329 GenericArgumentId::NegImpl => Ok(GenericArgumentId::NegImpl),
330 GenericArgumentId::Constant(_)
331 | GenericArgumentId::Type(_)
332 | GenericArgumentId::Impl(_) => {
333 Err(self.set_error(InferenceError::GenericArgMismatch { garg0, garg1 }))
334 }
335 },
336 }
337 }
338
339 fn conform_impl(&mut self, impl0: ImplId, impl1: ImplId) -> InferenceResult<ImplId> {
341 let impl0 = self.rewrite(impl0).no_err();
342 let impl1 = self.rewrite(impl1).no_err();
343 let long_impl1 = impl1.lookup_intern(self.db);
344 if impl0 == impl1 {
345 return Ok(impl0);
346 }
347 if let ImplLongId::ImplVar(var) = long_impl1 {
348 let impl_concrete_trait = self
349 .db
350 .impl_concrete_trait(impl0)
351 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
352 self.conform_traits(var.lookup_intern(self.db).concrete_trait_id, impl_concrete_trait)?;
353 let impl_id = self.rewrite(impl0).no_err();
354 return self.assign_impl(var, impl_id);
355 }
356 match impl0.lookup_intern(self.db) {
357 ImplLongId::ImplVar(var) => {
358 let impl_concrete_trait = self
359 .db
360 .impl_concrete_trait(impl1)
361 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
362 self.conform_traits(
363 var.lookup_intern(self.db).concrete_trait_id,
364 impl_concrete_trait,
365 )?;
366 let impl_id = self.rewrite(impl1).no_err();
367 self.assign_impl(var, impl_id)
368 }
369 ImplLongId::Concrete(concrete0) => {
370 let ImplLongId::Concrete(concrete1) = long_impl1 else {
371 return Err(self.set_error(InferenceError::ImplKindMismatch { impl0, impl1 }));
372 };
373 let concrete0 = concrete0.lookup_intern(self.db);
374 let concrete1 = concrete1.lookup_intern(self.db);
375 if concrete0.impl_def_id != concrete1.impl_def_id {
376 return Err(self.set_error(InferenceError::ImplKindMismatch { impl0, impl1 }));
377 }
378 let gargs0 = concrete0.generic_args;
379 let gargs1 = concrete1.generic_args;
380 let generic_args = self.conform_generic_args(&gargs0, &gargs1)?;
381 Ok(ImplLongId::Concrete(
382 ConcreteImplLongId { impl_def_id: concrete0.impl_def_id, generic_args }
383 .intern(self.db),
384 )
385 .intern(self.db))
386 }
387 ImplLongId::GenericParameter(_)
388 | ImplLongId::ImplImpl(_)
389 | ImplLongId::TraitImpl(_)
390 | ImplLongId::GeneratedImpl(_) => {
391 Err(self.set_error(InferenceError::ImplKindMismatch { impl0, impl1 }))
392 }
393 }
394 }
395
396 fn conform_traits(
398 &mut self,
399 trt0: ConcreteTraitId,
400 trt1: ConcreteTraitId,
401 ) -> InferenceResult<ConcreteTraitId> {
402 let trt0 = trt0.lookup_intern(self.db);
403 let trt1 = trt1.lookup_intern(self.db);
404 if trt0.trait_id != trt1.trait_id {
405 return Err(self.set_error(InferenceError::TraitMismatch {
406 trt0: trt0.trait_id,
407 trt1: trt1.trait_id,
408 }));
409 }
410 let generic_args = self.conform_generic_args(&trt0.generic_args, &trt1.generic_args)?;
411 Ok(ConcreteTraitLongId { trait_id: trt0.trait_id, generic_args }.intern(self.db))
412 }
413
414 fn conform_generic_function(
415 &mut self,
416 func0: GenericFunctionId,
417 func1: GenericFunctionId,
418 ) -> InferenceResult<GenericFunctionId> {
419 if let (GenericFunctionId::Impl(id0), GenericFunctionId::Impl(id1)) = (func0, func1) {
420 if id0.function != id1.function {
421 return Err(
422 self.set_error(InferenceError::GenericFunctionMismatch { func0, func1 })
423 );
424 }
425 let function = id0.function;
426 let impl_id = self.conform_impl(id0.impl_id, id1.impl_id)?;
427 return Ok(GenericFunctionId::Impl(ImplGenericFunctionId { impl_id, function }));
428 }
429
430 if func0 != func1 {
431 return Err(self.set_error(InferenceError::GenericFunctionMismatch { func0, func1 }));
432 }
433 Ok(func0)
434 }
435
436 fn ty_contains_var(&mut self, ty: TypeId, var: InferenceVar) -> bool {
439 let ty = self.rewrite(ty).no_err();
440 self.internal_ty_contains_var(ty, var)
441 }
442
443 fn generic_args_contain_var(
446 &mut self,
447 generic_args: &[GenericArgumentId],
448 var: InferenceVar,
449 ) -> bool {
450 for garg in generic_args {
451 if match *garg {
452 GenericArgumentId::Type(ty) => self.internal_ty_contains_var(ty, var),
453 GenericArgumentId::Constant(_) => false,
454 GenericArgumentId::Impl(impl_id) => self.impl_contains_var(impl_id, var),
455 GenericArgumentId::NegImpl => false,
456 } {
457 return true;
458 }
459 }
460 false
461 }
462
463 fn impl_contains_var(&mut self, impl_id: ImplId, var: InferenceVar) -> bool {
466 match impl_id.lookup_intern(self.db) {
467 ImplLongId::Concrete(concrete_impl_id) => self.generic_args_contain_var(
468 &concrete_impl_id.lookup_intern(self.db).generic_args,
469 var,
470 ),
471 ImplLongId::GenericParameter(_) | ImplLongId::TraitImpl(_) => false,
472 ImplLongId::ImplVar(new_var) => {
473 let new_var_long_id = new_var.lookup_intern(self.db);
474 let new_var_local_id = new_var_long_id.id;
475 if InferenceVar::Impl(new_var_local_id) == var {
476 return true;
477 }
478 if let Some(impl_id) = self.impl_assignment(new_var_local_id) {
479 return self.impl_contains_var(impl_id, var);
480 }
481 self.generic_args_contain_var(
482 &new_var_long_id.concrete_trait_id.generic_args(self.db),
483 var,
484 )
485 }
486 ImplLongId::ImplImpl(impl_impl) => self.impl_contains_var(impl_impl.impl_id(), var),
487 ImplLongId::GeneratedImpl(generated_impl) => self.generic_args_contain_var(
488 &generated_impl.concrete_trait(self.db).generic_args(self.db),
489 var,
490 ),
491 }
492 }
493
494 fn function_contains_var(&mut self, function_id: FunctionId, var: InferenceVar) -> bool {
500 let function = function_id.get_concrete(self.db);
501 let generic_args = function.generic_args;
502 self.generic_args_contain_var(&generic_args, var)
504 || matches!(function.generic_function,
505 GenericFunctionId::Impl(impl_generic_function_id)
506 if self.impl_contains_var(impl_generic_function_id.impl_id, var)
507 )
508 }
509}
510
511impl Inference<'_> {
512 pub fn reduce_impl_ty(&mut self, impl_type_id: ImplTypeId) -> InferenceResult<TypeId> {
514 let impl_id = impl_type_id.impl_id();
515 let trait_ty = impl_type_id.ty();
516 if let ImplLongId::ImplVar(var) = impl_id.lookup_intern(self.db) {
517 Ok(self.rewritten_impl_type(var, trait_ty))
518 } else if let Ok(ty) =
519 self.db.impl_type_concrete_implized(ImplTypeId::new(impl_id, trait_ty, self.db))
520 {
521 Ok(ty)
522 } else {
523 Err(self.set_impl_reduction_error(impl_id))
524 }
525 }
526
527 pub fn reduce_impl_constant(
529 &mut self,
530 impl_const_id: ImplConstantId,
531 ) -> InferenceResult<ConstValueId> {
532 let impl_id = impl_const_id.impl_id();
533 let trait_constant = impl_const_id.trait_constant_id();
534 if let ImplLongId::ImplVar(var) = impl_id.lookup_intern(self.db) {
535 Ok(self.rewritten_impl_constant(var, trait_constant))
536 } else if let Ok(constant) = self.db.impl_constant_concrete_implized_value(
537 ImplConstantId::new(impl_id, trait_constant, self.db),
538 ) {
539 Ok(constant)
540 } else {
541 Err(self.set_impl_reduction_error(impl_id))
542 }
543 }
544
545 pub fn reduce_impl_impl(&mut self, impl_impl_id: ImplImplId) -> InferenceResult<ImplId> {
547 let impl_id = impl_impl_id.impl_id();
548 let concrete_trait_impl = impl_impl_id
549 .concrete_trait_impl_id(self.db)
550 .map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
551
552 if let ImplLongId::ImplVar(var) = impl_id.lookup_intern(self.db) {
553 Ok(self.rewritten_impl_impl(var, concrete_trait_impl))
554 } else if let Ok(imp) = self.db.impl_impl_concrete_implized(ImplImplId::new(
555 impl_id,
556 impl_impl_id.trait_impl_id(),
557 self.db,
558 )) {
559 Ok(imp)
560 } else {
561 Err(self.set_impl_reduction_error(impl_id))
562 }
563 }
564
565 pub fn rewritten_impl_type(&mut self, id: ImplVarId, trait_type_id: TraitTypeId) -> TypeId {
569 self.rewritten_impl_item(
570 id,
571 trait_type_id,
572 |m| &mut m.types,
573 |inference, stable_ptr| inference.new_type_var(stable_ptr),
574 )
575 }
576
577 pub fn rewritten_impl_constant(
581 &mut self,
582 id: ImplVarId,
583 trait_constant: TraitConstantId,
584 ) -> ConstValueId {
585 self.rewritten_impl_item(
586 id,
587 trait_constant,
588 |m| &mut m.constants,
589 |inference, stable_ptr| {
590 inference.new_const_var(
591 stable_ptr,
592 inference.db.trait_constant_type(trait_constant).unwrap(),
593 )
594 },
595 )
596 }
597
598 pub fn rewritten_impl_impl(
602 &mut self,
603 id: ImplVarId,
604 concrete_trait_impl: ConcreteTraitImplId,
605 ) -> ImplId {
606 self.rewritten_impl_item(
607 id,
608 concrete_trait_impl.trait_impl(self.db),
609 |m| &mut m.impls,
610 |inference, stable_ptr| {
611 inference.new_impl_var(
612 inference.db.concrete_trait_impl_concrete_trait(concrete_trait_impl).unwrap(),
613 stable_ptr,
614 ImplLookupContext::default(),
615 )
616 },
617 )
618 }
619
620 fn rewritten_impl_item<K: Hash + PartialEq + Eq, V: Copy>(
624 &mut self,
625 id: ImplVarId,
626 key: K,
627 get_map: impl Fn(&mut ImplVarTraitItemMappings) -> &mut OrderedHashMap<K, V>,
628 new_var: impl FnOnce(&mut Self, Option<SyntaxStablePtrId>) -> V,
629 ) -> V
630 where
631 Self: SemanticRewriter<V, NoError>,
632 {
633 let var_id = id.id(self.db);
634 if let Some(value) = self
635 .data
636 .impl_vars_trait_item_mappings
637 .get_mut(&var_id)
638 .and_then(|mappings| get_map(mappings).get(&key))
639 {
640 let value = *value;
642 self.rewrite(value).no_err()
644 } else {
645 let value =
646 new_var(self, self.data.stable_ptrs.get(&InferenceVar::Impl(var_id)).cloned());
647 get_map(self.data.impl_vars_trait_item_mappings.entry(var_id).or_default())
648 .insert(key, value);
649 value
650 }
651 }
652
653 fn set_impl_reduction_error(&mut self, impl_id: ImplId) -> ErrorSet {
655 self.set_error(
656 impl_id
657 .concrete_trait(self.db)
658 .map(InferenceError::NoImplsFound)
659 .unwrap_or_else(InferenceError::Reported),
660 )
661 }
662
663 pub fn conform_ty_for_diag(
666 &mut self,
667 ty0: TypeId,
668 ty1: TypeId,
669 ) -> Result<(), (ErrorSet, TypeId, TypeId)> {
670 match self.conform_ty(ty0, ty1) {
671 Ok(_ty) => Ok(()),
672 Err(err) => Err((err, self.rewrite(ty0).no_err(), self.rewrite(ty1).no_err())),
673 }
674 }
675
676 #[doc(hidden)]
679 fn internal_ty_contains_var(&mut self, ty: TypeId, var: InferenceVar) -> bool {
680 match ty.lookup_intern(self.db) {
681 TypeLongId::Concrete(concrete) => {
682 let generic_args = concrete.generic_args(self.db);
683 self.generic_args_contain_var(&generic_args, var)
684 }
685 TypeLongId::Tuple(tys) => {
686 tys.into_iter().any(|ty| self.internal_ty_contains_var(ty, var))
687 }
688 TypeLongId::Snapshot(ty) => self.internal_ty_contains_var(ty, var),
689 TypeLongId::Var(new_var) => {
690 if InferenceVar::Type(new_var.id) == var {
691 return true;
692 }
693 if let Some(ty) = self.type_assignment.get(&new_var.id) {
694 return self.internal_ty_contains_var(*ty, var);
695 }
696 false
697 }
698 TypeLongId::ImplType(id) => self.impl_contains_var(id.impl_id(), var),
699 TypeLongId::TraitType(_) | TypeLongId::GenericParameter(_) | TypeLongId::Missing(_) => {
700 false
701 }
702 TypeLongId::Coupon(function_id) => self.function_contains_var(function_id, var),
703 TypeLongId::FixedSizeArray { type_id, .. } => {
704 self.internal_ty_contains_var(type_id, var)
705 }
706 TypeLongId::Closure(closure) => {
707 closure.param_tys.into_iter().any(|ty| self.internal_ty_contains_var(ty, var))
708 || self.internal_ty_contains_var(closure.ret_ty, var)
709 }
710 }
711 }
712}