1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use cairo_lang_debug::DebugWithDb;
5use cairo_lang_defs::ids::LanguageElementId;
6use cairo_lang_proc_macros::SemanticObject;
7use cairo_lang_utils::ordered_hash_map::Entry;
8use cairo_lang_utils::{Intern, LookupIntern};
9use itertools::{Itertools, chain, zip_eq};
10
11use super::canonic::{CanonicalImpl, CanonicalTrait, MapperError, ResultNoErrEx};
12use super::conform::InferenceConform;
13use super::infers::InferenceEmbeddings;
14use super::{
15 ImplVarTraitItemMappings, InferenceData, InferenceError, InferenceId, InferenceResult,
16 InferenceVar, LocalImplVarId,
17};
18use crate::db::SemanticGroup;
19use crate::items::constant::{ConstValue, ConstValueId, ImplConstantId};
20use crate::items::imp::{
21 ImplId, ImplImplId, ImplLongId, ImplLookupContext, UninferredImpl, find_candidates_at_context,
22 find_closure_generated_candidate,
23};
24use crate::substitution::{GenericSubstitution, SemanticRewriter};
25use crate::types::{ImplTypeById, ImplTypeId};
26use crate::{
27 ConcreteImplLongId, ConcreteTraitId, GenericArgumentId, GenericParam, TypeId, TypeLongId,
28};
29
30#[derive(Clone, PartialEq, Eq, Debug)]
32pub enum SolutionSet<T> {
33 None,
34 Unique(T),
35 Ambiguous(Ambiguity),
36}
37
38#[derive(Clone, Debug, Eq, Hash, PartialEq, SemanticObject)]
40pub enum Ambiguity {
41 MultipleImplsFound {
42 concrete_trait_id: ConcreteTraitId,
43 impls: Vec<ImplId>,
44 },
45 FreeVariable {
46 impl_id: ImplId,
47 #[dont_rewrite]
48 var: InferenceVar,
49 },
50 WillNotInfer(ConcreteTraitId),
51 NegativeImplWithUnresolvedGenericArgs {
52 impl_id: ImplId,
53 ty: TypeId,
54 },
55}
56impl Ambiguity {
57 pub fn format(&self, db: &(dyn SemanticGroup + 'static)) -> String {
58 match self {
59 Ambiguity::MultipleImplsFound { concrete_trait_id, impls } => {
60 let impls_str = impls.iter().map(|imp| format!("`{}`", imp.format(db))).join(", ");
61 format!(
62 "Trait `{:?}` has multiple implementations, in: {impls_str}",
63 concrete_trait_id.debug(db)
64 )
65 }
66 Ambiguity::FreeVariable { impl_id, var: _ } => {
67 format!("Candidate impl {:?} has an unused generic parameter.", impl_id.debug(db),)
68 }
69 Ambiguity::WillNotInfer(concrete_trait_id) => {
70 format!(
71 "Cannot infer trait {:?}. First generic argument must be known.",
72 concrete_trait_id.debug(db)
73 )
74 }
75 Ambiguity::NegativeImplWithUnresolvedGenericArgs { impl_id, ty } => format!(
76 "Cannot infer negative impl in `{}` as it contains the unresolved type `{}`",
77 impl_id.format(db),
78 ty.format(db)
79 ),
80 }
81 }
82}
83
84pub fn canonic_trait_solutions(
87 db: &dyn SemanticGroup,
88 canonical_trait: CanonicalTrait,
89 lookup_context: ImplLookupContext,
90 impl_type_bounds: BTreeMap<ImplTypeById, TypeId>,
91) -> Result<SolutionSet<CanonicalImpl>, InferenceError> {
92 let mut concrete_trait_id = canonical_trait.id;
93 let impl_type_bounds = Arc::new(impl_type_bounds);
94 if !concrete_trait_id.is_fully_concrete(db) {
97 match solve_canonical_trait(
98 db,
99 canonical_trait,
100 lookup_context.clone(),
101 impl_type_bounds.clone(),
102 ) {
103 SolutionSet::None => {}
104 SolutionSet::Unique(imp) => {
105 concrete_trait_id =
106 imp.0.concrete_trait(db).expect("A solved impl must have a concrete trait");
107 }
108 SolutionSet::Ambiguous(ambiguity) => {
109 return Ok(SolutionSet::Ambiguous(ambiguity));
110 }
111 }
112 }
113 Ok(solve_canonical_trait(
115 db,
116 CanonicalTrait { id: concrete_trait_id, mappings: ImplVarTraitItemMappings::default() },
117 lookup_context,
118 impl_type_bounds,
119 ))
120}
121
122pub fn canonic_trait_solutions_cycle(
124 _db: &dyn SemanticGroup,
125 _cycle: &salsa::Cycle,
126 _canonical_trait: &CanonicalTrait,
127 _lookup_context: &ImplLookupContext,
128 _impl_type_bounds: &BTreeMap<ImplTypeById, TypeId>,
129) -> Result<SolutionSet<CanonicalImpl>, InferenceError> {
130 Err(InferenceError::Cycle(InferenceVar::Impl(LocalImplVarId(0))))
131}
132
133pub fn enrich_lookup_context(
135 db: &dyn SemanticGroup,
136 concrete_trait_id: ConcreteTraitId,
137 lookup_context: &mut ImplLookupContext,
138) {
139 lookup_context.insert_module(concrete_trait_id.trait_id(db).module_file_id(db).0);
140 let generic_args = concrete_trait_id.generic_args(db);
141 for generic_arg in &generic_args {
143 if let GenericArgumentId::Type(ty) = generic_arg {
144 enrich_lookup_context_with_ty(db, *ty, lookup_context);
145 }
146 }
147}
148
149pub fn enrich_lookup_context_with_ty(
151 db: &dyn SemanticGroup,
152 ty: TypeId,
153 lookup_context: &mut ImplLookupContext,
154) {
155 match ty.lookup_intern(db) {
156 TypeLongId::ImplType(impl_type_id) => {
157 lookup_context.insert_impl(impl_type_id.impl_id());
158 }
159 long_ty => {
160 if let Some(module_id) = long_ty.module_id(db) {
161 lookup_context.insert_module(module_id);
162 }
163 }
164 }
165}
166
167fn solve_canonical_trait(
170 db: &dyn SemanticGroup,
171 canonical_trait: CanonicalTrait,
172 lookup_context: ImplLookupContext,
173 impl_type_bounds: Arc<BTreeMap<ImplTypeById, TypeId>>,
174) -> SolutionSet<CanonicalImpl> {
175 let filter = canonical_trait.id.filter(db);
176 let mut candidates =
177 find_candidates_at_context(db, &lookup_context, &filter).unwrap_or_default();
178 find_closure_generated_candidate(db, canonical_trait.id)
179 .map(|candidate| candidates.insert(candidate));
180
181 let mut unique_solution: Option<CanonicalImpl> = None;
182 for candidate in candidates.into_iter() {
183 let Ok(candidate_solution_set) = solve_candidate(
184 db,
185 &canonical_trait,
186 candidate,
187 &lookup_context,
188 impl_type_bounds.clone(),
189 ) else {
190 continue;
191 };
192
193 let candidate_solution = match candidate_solution_set {
194 SolutionSet::None => continue,
195 SolutionSet::Unique(candidate_solution) => candidate_solution,
196 SolutionSet::Ambiguous(ambiguity) => return SolutionSet::Ambiguous(ambiguity),
197 };
198 if let Some(unique_solution) = unique_solution {
199 if unique_solution.0 != candidate_solution.0 {
203 return SolutionSet::Ambiguous(Ambiguity::MultipleImplsFound {
204 concrete_trait_id: canonical_trait.id,
205 impls: vec![unique_solution.0, candidate_solution.0],
206 });
207 }
208 }
209 unique_solution = Some(candidate_solution);
210 }
211 unique_solution.map(SolutionSet::Unique).unwrap_or(SolutionSet::None)
212}
213
214fn solve_candidate(
216 db: &dyn SemanticGroup,
217 canonical_trait: &CanonicalTrait,
218 candidate: UninferredImpl,
219 lookup_context: &ImplLookupContext,
220 impl_type_bounds: Arc<BTreeMap<ImplTypeById, TypeId>>,
221) -> InferenceResult<SolutionSet<CanonicalImpl>> {
222 let candidate_concrete_trait = candidate.concrete_trait(db).unwrap();
223 let candidate_final = matches!(candidate, UninferredImpl::GenericParam(_))
226 && candidate_concrete_trait.is_var_free(db)
227 || candidate_concrete_trait.is_fully_concrete(db);
228 let target_final = canonical_trait.id.is_var_free(db);
229 let mut lite_inference = LiteInference::new(db);
230 if candidate_final && target_final && candidate_concrete_trait != canonical_trait.id {
231 return Err(super::ErrorSet);
232 }
233
234 let mut res = lite_inference.can_conform_generic_args(
235 (&candidate_concrete_trait.generic_args(db), candidate_final),
236 (&canonical_trait.id.generic_args(db), target_final),
237 );
238
239 if matches!(candidate, UninferredImpl::GenericParam(_))
241 && !lite_inference.substitution.is_empty()
242 {
243 return Err(super::ErrorSet);
244 }
245
246 if res == CanConformResult::Accepted {
248 let Ok(trait_types) = db.trait_types(canonical_trait.id.trait_id(db)) else {
249 return Err(super::ErrorSet);
250 };
251 if !trait_types.is_empty() && !canonical_trait.mappings.types.is_empty() {
252 res = CanConformResult::InferenceRequired;
253 }
254 }
255
256 let mut lookup_context = lookup_context.clone();
258 lookup_context.insert_lookup_scope(db, &candidate);
259 if res == CanConformResult::Rejected {
260 return Err(super::ErrorSet);
261 } else if CanConformResult::Accepted == res {
262 match candidate {
263 UninferredImpl::Def(impl_def_id) => {
264 let imp_generic_params =
265 db.impl_def_generic_params(impl_def_id).map_err(|_| super::ErrorSet)?;
266
267 match lite_inference.infer_generic_assignment(
268 imp_generic_params,
269 &lookup_context,
270 impl_type_bounds.clone(),
271 ) {
272 Ok(SolutionSet::None) => {
273 return Ok(SolutionSet::None);
274 }
275 Ok(SolutionSet::Ambiguous(ambiguity)) => {
276 return Ok(SolutionSet::Ambiguous(ambiguity));
277 }
278 Ok(SolutionSet::Unique(generic_args)) => {
279 let concrete_impl =
280 ConcreteImplLongId { impl_def_id, generic_args }.intern(db);
281 let impl_id = ImplLongId::Concrete(concrete_impl).intern(db);
282 return Ok(SolutionSet::Unique(CanonicalImpl(impl_id)));
283 }
284 _ => {}
285 }
286 }
287 UninferredImpl::GenericParam(generic_param_id) => {
288 let impl_id = ImplLongId::GenericParameter(generic_param_id).intern(db);
289 return Ok(SolutionSet::Unique(CanonicalImpl(impl_id)));
290 }
291 UninferredImpl::ImplAlias(_) => {}
293 UninferredImpl::ImplImpl(_) | UninferredImpl::GeneratedImpl(_) => {}
294 }
295 }
296
297 let mut inference_data: InferenceData = InferenceData::new(InferenceId::Canonical);
298 let mut inference = inference_data.inference(db);
299 inference.data.impl_type_bounds = impl_type_bounds;
300 let (canonical_trait, canonical_embedding) = canonical_trait.embed(&mut inference);
301
302 if let UninferredImpl::GeneratedImpl(imp) = candidate {
305 inference.conform_traits(imp.lookup_intern(db).concrete_trait, canonical_trait.id)?;
306 }
307
308 let candidate_impl =
310 inference.infer_impl(candidate, canonical_trait.id, &lookup_context, None)?;
311 for (trait_type, ty) in canonical_trait.mappings.types.iter() {
312 let mapped_ty =
313 inference.reduce_impl_ty(ImplTypeId::new(candidate_impl, *trait_type, db))?;
314
315 inference.conform_ty(mapped_ty, *ty)?;
317 }
318 for (trait_const, const_id) in canonical_trait.mappings.constants.iter() {
319 let mapped_const_id = inference.reduce_impl_constant(ImplConstantId::new(
320 candidate_impl,
321 *trait_const,
322 db,
323 ))?;
324 inference.conform_const(mapped_const_id, *const_id)?;
326 }
327
328 for (trait_impl, impl_id) in canonical_trait.mappings.impls.iter() {
329 let mapped_impl_id =
330 inference.reduce_impl_impl(ImplImplId::new(candidate_impl, *trait_impl, db))?;
331 inference.conform_impl(mapped_impl_id, *impl_id)?;
333 }
334
335 let mut inference = inference_data.inference(db);
336 let solution_set = inference.solution_set()?;
337 Ok(match solution_set {
338 SolutionSet::None => SolutionSet::None,
339 SolutionSet::Ambiguous(ambiguity) => SolutionSet::Ambiguous(ambiguity),
340 SolutionSet::Unique(_) => {
341 let candidate_impl = inference.rewrite(candidate_impl).no_err();
342 match CanonicalImpl::canonicalize(db, candidate_impl, &canonical_embedding) {
343 Ok(canonical_impl) => {
344 inference.validate_neg_impls(&lookup_context, canonical_impl)?
345 }
346 Err(MapperError(var)) => {
347 return Ok(SolutionSet::Ambiguous(Ambiguity::FreeVariable {
348 impl_id: candidate_impl,
349 var,
350 }));
351 }
352 }
353 }
354 })
355}
356
357#[derive(Clone, Copy, Debug, PartialEq, Eq)]
359enum CanConformResult {
360 Accepted,
361 InferenceRequired,
362 Rejected,
363}
364
365impl CanConformResult {
366 fn fold(iter: impl IntoIterator<Item = CanConformResult>) -> CanConformResult {
367 let mut res = CanConformResult::Accepted; for item in iter {
369 match item {
370 CanConformResult::Rejected => return CanConformResult::Rejected,
371 CanConformResult::Accepted => continue,
372 CanConformResult::InferenceRequired => {
373 res = CanConformResult::InferenceRequired;
374 }
375 }
376 }
377 res }
379}
380struct LiteInference<'db> {
383 db: &'db dyn SemanticGroup,
384 substitution: GenericSubstitution,
385}
386
387impl<'db> LiteInference<'db> {
388 fn new(db: &'db dyn SemanticGroup) -> Self {
389 LiteInference { db, substitution: GenericSubstitution::default() }
390 }
391
392 fn infer_generic_assignment(
395 &mut self,
396 params: Vec<GenericParam>,
397 lookup_context: &ImplLookupContext,
398 impl_type_bounds: Arc<BTreeMap<ImplTypeById, TypeId>>,
399 ) -> InferenceResult<SolutionSet<Vec<GenericArgumentId>>> {
400 let mut generic_args = Vec::with_capacity(params.len());
401 for param in params {
402 match param {
403 GenericParam::Type(generic_param_type) => {
404 if self.substitution.contains_key(&generic_param_type.id) {
405 generic_args.push(*self.substitution.get(&generic_param_type.id).unwrap());
406 } else {
407 return Err(super::ErrorSet);
410 }
411 }
412 GenericParam::Const(generic_param_const) => {
413 if self.substitution.contains_key(&generic_param_const.id) {
414 generic_args.push(*self.substitution.get(&generic_param_const.id).unwrap());
415 } else {
416 return Err(super::ErrorSet);
419 }
420 }
421 GenericParam::Impl(generic_param_impl) => {
422 if !generic_param_impl.type_constraints.is_empty() {
423 return Err(super::ErrorSet);
424 }
425 if self.substitution.contains_key(&generic_param_impl.id) {
426 generic_args.push(*self.substitution.get(&generic_param_impl.id).unwrap());
427 continue;
428 }
429
430 let Ok(Ok(imp_concrete_trait_id)) =
431 self.substitution.substitute(self.db, generic_param_impl.concrete_trait)
432 else {
433 return Err(super::ErrorSet);
434 };
435 let canonical_trait = CanonicalTrait {
436 id: imp_concrete_trait_id,
437 mappings: ImplVarTraitItemMappings::default(),
438 };
439 let mut inner_context = lookup_context.clone();
440 enrich_lookup_context(self.db, imp_concrete_trait_id, &mut inner_context);
441 let Ok(solution) = self.db.canonic_trait_solutions(
442 canonical_trait,
443 inner_context,
444 (*impl_type_bounds).clone(),
445 ) else {
446 return Err(super::ErrorSet);
447 };
448 match solution {
449 SolutionSet::None => return Ok(SolutionSet::None),
450 SolutionSet::Unique(imp) => {
451 self.substitution
452 .insert(generic_param_impl.id, GenericArgumentId::Impl(imp.0));
453 generic_args.push(GenericArgumentId::Impl(imp.0));
454 }
455 SolutionSet::Ambiguous(ambiguity) => {
456 return Ok(SolutionSet::Ambiguous(ambiguity));
457 }
458 }
459 }
460 GenericParam::NegImpl(_) => return Err(super::ErrorSet),
461 }
462 }
463 Ok(SolutionSet::Unique(generic_args))
464 }
465
466 fn can_conform_generic_args(
470 &mut self,
471 (candidate_args, candidate_final): (&[GenericArgumentId], bool),
472 (target_args, target_final): (&[GenericArgumentId], bool),
473 ) -> CanConformResult {
474 CanConformResult::fold(zip_eq(candidate_args, target_args).map(
475 |(candidate_arg, target_arg)| {
476 self.can_conform_generic_arg(
477 (*candidate_arg, candidate_final),
478 (*target_arg, target_final),
479 )
480 },
481 ))
482 }
483
484 fn can_conform_generic_arg(
487 &mut self,
488 (candidate_arg, mut candidate_final): (GenericArgumentId, bool),
489 (target_arg, mut target_final): (GenericArgumentId, bool),
490 ) -> CanConformResult {
491 if candidate_arg == target_arg {
492 return CanConformResult::Accepted;
493 }
494 candidate_final = candidate_final || candidate_arg.is_fully_concrete(self.db);
495 target_final = target_final || target_arg.is_var_free(self.db);
496 if candidate_final && target_final {
497 return CanConformResult::Rejected;
498 }
499 match (candidate_arg, target_arg) {
500 (GenericArgumentId::Type(candidate), GenericArgumentId::Type(target)) => {
501 self.can_conform_ty((candidate, candidate_final), (target, target_final))
502 }
503 (GenericArgumentId::Constant(candidate), GenericArgumentId::Constant(target)) => {
504 self.can_conform_const((candidate, candidate_final), (target, target_final))
505 }
506 (GenericArgumentId::Impl(candidate), GenericArgumentId::Impl(target)) => {
507 self.can_conform_impl((candidate, candidate_final), (target, target_final))
508 }
509 (GenericArgumentId::NegImpl, GenericArgumentId::NegImpl) => {
510 CanConformResult::InferenceRequired
511 }
512 _ => CanConformResult::Rejected,
513 }
514 }
515
516 fn can_conform_ty(
519 &mut self,
520 (candidate_ty, mut candidate_final): (TypeId, bool),
521 (target_ty, mut target_final): (TypeId, bool),
522 ) -> CanConformResult {
523 if candidate_ty == target_ty {
524 return CanConformResult::Accepted;
525 }
526 candidate_final = candidate_final || candidate_ty.is_fully_concrete(self.db);
527 target_final = target_final || target_ty.is_var_free(self.db);
528 if candidate_final && target_final {
529 return CanConformResult::Rejected;
530 }
531 let target_long_ty = target_ty.lookup_intern(self.db);
532
533 if let TypeLongId::Var(_) = target_long_ty {
534 return CanConformResult::InferenceRequired;
535 }
536
537 let long_ty_candidate = candidate_ty.lookup_intern(self.db);
538
539 match (long_ty_candidate, target_long_ty) {
540 (TypeLongId::Concrete(candidate), TypeLongId::Concrete(target)) => {
541 if candidate.generic_type(self.db) != target.generic_type(self.db) {
542 return CanConformResult::Rejected;
543 }
544
545 self.can_conform_generic_args(
546 (&candidate.generic_args(self.db), candidate_final),
547 (&target.generic_args(self.db), target_final),
548 )
549 }
550 (TypeLongId::Concrete(_), _) => CanConformResult::Rejected,
551 (TypeLongId::Tuple(candidate_tys), TypeLongId::Tuple(target_tys)) => {
552 if candidate_tys.len() != target_tys.len() {
553 return CanConformResult::Rejected;
554 }
555
556 CanConformResult::fold(zip_eq(candidate_tys, target_tys).map(
557 |(candidate_subty, target_subty)| {
558 self.can_conform_ty(
559 (candidate_subty, candidate_final),
560 (target_subty, target_final),
561 )
562 },
563 ))
564 }
565 (TypeLongId::Tuple(_), _) => CanConformResult::Rejected,
566 (TypeLongId::Closure(candidate), TypeLongId::Closure(target)) => {
567 if candidate.wrapper_location != target.wrapper_location {
568 return CanConformResult::Rejected;
569 }
570
571 let params_check =
572 CanConformResult::fold(zip_eq(candidate.param_tys, target.param_tys).map(
573 |(candidate_subty, target_subty)| {
574 self.can_conform_ty(
575 (candidate_subty, candidate_final),
576 (target_subty, target_final),
577 )
578 },
579 ));
580 if params_check == CanConformResult::Rejected {
581 return CanConformResult::Rejected;
582 }
583 let captured_types_check = CanConformResult::fold(
584 zip_eq(candidate.captured_types, target.captured_types).map(
585 |(candidate_subty, target_subty)| {
586 self.can_conform_ty(
587 (candidate_subty, candidate_final),
588 (target_subty, target_final),
589 )
590 },
591 ),
592 );
593 if captured_types_check == CanConformResult::Rejected {
594 return CanConformResult::Rejected;
595 }
596 let return_type_check = self.can_conform_ty(
597 (candidate.ret_ty, candidate_final),
598 (target.ret_ty, target_final),
599 );
600 if return_type_check == CanConformResult::Rejected {
601 return CanConformResult::Rejected;
602 }
603 if params_check == CanConformResult::InferenceRequired
604 || captured_types_check == CanConformResult::InferenceRequired
605 || return_type_check == CanConformResult::InferenceRequired
606 {
607 return CanConformResult::InferenceRequired;
608 }
609 CanConformResult::Accepted
610 }
611 (TypeLongId::Closure(_), _) => CanConformResult::Rejected,
612 (
613 TypeLongId::FixedSizeArray { type_id: candidate_type_id, size: candidate_size },
614 TypeLongId::FixedSizeArray { type_id: target_type_id, size: target_size },
615 ) => CanConformResult::fold([
616 self.can_conform_const(
617 (candidate_size, candidate_final),
618 (target_size, target_final),
619 ),
620 self.can_conform_ty(
621 (candidate_type_id, candidate_final),
622 (target_type_id, target_final),
623 ),
624 ]),
625 (TypeLongId::FixedSizeArray { type_id: _, size: _ }, _) => CanConformResult::Rejected,
626 (TypeLongId::Snapshot(candidate_inner_ty), TypeLongId::Snapshot(target_inner_ty)) => {
627 self.can_conform_ty(
628 (candidate_inner_ty, candidate_final),
629 (target_inner_ty, target_final),
630 )
631 }
632 (TypeLongId::Snapshot(_), _) => CanConformResult::Rejected,
633 (TypeLongId::GenericParameter(param), _) => {
634 let mut res = CanConformResult::Accepted;
635 match self.substitution.entry(param) {
637 Entry::Occupied(entry) => {
638 if let GenericArgumentId::Type(existing_ty) = entry.get() {
639 if *existing_ty != target_ty {
640 res = CanConformResult::Rejected;
641 }
642 if !existing_ty.is_var_free(self.db) {
643 return CanConformResult::InferenceRequired;
644 }
645 } else {
646 res = CanConformResult::Rejected;
647 }
648 }
649 Entry::Vacant(e) => {
650 e.insert(GenericArgumentId::Type(target_ty));
651 }
652 }
653
654 if target_ty.is_var_free(self.db) {
655 res
656 } else {
657 CanConformResult::InferenceRequired
658 }
659 }
660 (
661 TypeLongId::Var(_)
662 | TypeLongId::ImplType(_)
663 | TypeLongId::Missing(_)
664 | TypeLongId::Coupon(_),
665 _,
666 ) => CanConformResult::InferenceRequired,
667 }
668 }
669
670 fn can_conform_impl(
673 &mut self,
674 (candidate_impl, mut candidate_final): (ImplId, bool),
675 (target_impl, mut target_final): (ImplId, bool),
676 ) -> CanConformResult {
677 let long_impl_trait = target_impl.lookup_intern(self.db);
678 if candidate_impl == target_impl {
679 return CanConformResult::Accepted;
680 }
681 candidate_final = candidate_final || candidate_impl.is_fully_concrete(self.db);
682 target_final = target_final || target_impl.is_var_free(self.db);
683 if candidate_final && target_final {
684 return CanConformResult::Rejected;
685 }
686 if let ImplLongId::ImplVar(_) = long_impl_trait {
687 return CanConformResult::InferenceRequired;
688 }
689 match (candidate_impl.lookup_intern(self.db), long_impl_trait) {
690 (ImplLongId::Concrete(candidate), ImplLongId::Concrete(target)) => {
691 let candidate = candidate.lookup_intern(self.db);
692 let target = target.lookup_intern(self.db);
693 if candidate.impl_def_id != target.impl_def_id {
694 return CanConformResult::Rejected;
695 }
696 let candidate_args = candidate.generic_args;
697 let target_args = target.generic_args;
698 self.can_conform_generic_args(
699 (&candidate_args, candidate_final),
700 (&target_args, target_final),
701 )
702 }
703 (ImplLongId::Concrete(_), _) => CanConformResult::Rejected,
704 (ImplLongId::GenericParameter(param), _) => {
705 let mut res = CanConformResult::Accepted;
706 match self.substitution.entry(param) {
708 Entry::Occupied(entry) => {
709 if let GenericArgumentId::Impl(existing_impl) = entry.get() {
710 if *existing_impl != target_impl {
711 res = CanConformResult::Rejected;
712 }
713 if !existing_impl.is_var_free(self.db) {
714 return CanConformResult::InferenceRequired;
715 }
716 } else {
717 res = CanConformResult::Rejected;
718 }
719 }
720 Entry::Vacant(e) => {
721 e.insert(GenericArgumentId::Impl(target_impl));
722 }
723 }
724
725 if target_impl.is_var_free(self.db) {
726 res
727 } else {
728 CanConformResult::InferenceRequired
729 }
730 }
731 (
732 ImplLongId::ImplVar(_)
733 | ImplLongId::ImplImpl(_)
734 | ImplLongId::SelfImpl(_)
735 | ImplLongId::GeneratedImpl(_),
736 _,
737 ) => CanConformResult::InferenceRequired,
738 }
739 }
740
741 fn can_conform_const(
744 &mut self,
745 (candidate_id, mut candidate_final): (ConstValueId, bool),
746 (target_id, mut target_final): (ConstValueId, bool),
747 ) -> CanConformResult {
748 if candidate_id == target_id {
749 return CanConformResult::Accepted;
750 }
751 candidate_final = candidate_final || candidate_id.is_fully_concrete(self.db);
752 target_final = target_final || target_id.is_var_free(self.db);
753 if candidate_final && target_final {
754 return CanConformResult::Rejected;
755 }
756 let target_long_const = target_id.lookup_intern(self.db);
757 if let ConstValue::Var(_, _) = target_long_const {
758 return CanConformResult::InferenceRequired;
759 }
760 match (candidate_id.lookup_intern(self.db), target_long_const) {
761 (
762 ConstValue::Int(big_int, type_id),
763 ConstValue::Int(target_big_int, target_type_id),
764 ) => {
765 if big_int != target_big_int {
766 return CanConformResult::Rejected;
767 }
768 self.can_conform_ty((type_id, candidate_final), (target_type_id, target_final))
769 }
770 (ConstValue::Int(_, _), _) => CanConformResult::Rejected,
771 (
772 ConstValue::Struct(const_values, type_id),
773 ConstValue::Struct(target_const_values, target_type_id),
774 ) => {
775 if const_values.len() != target_const_values.len() {
776 return CanConformResult::Rejected;
777 };
778 CanConformResult::fold(chain!(
779 [self.can_conform_ty(
780 (type_id, candidate_final),
781 (target_type_id, target_final)
782 )],
783 zip_eq(const_values, target_const_values).map(
784 |(const_value, target_const_value)| {
785 self.can_conform_const(
786 (const_value.intern(self.db), candidate_final),
787 (target_const_value.intern(self.db), target_final),
788 )
789 }
790 )
791 ))
792 }
793 (ConstValue::Struct(_, _), _) => CanConformResult::Rejected,
794
795 (
796 ConstValue::Enum(concrete_variant, const_value),
797 ConstValue::Enum(target_concrete_variant, target_const_value),
798 ) => CanConformResult::fold([
799 self.can_conform_ty(
800 (concrete_variant.ty, candidate_final),
801 (target_concrete_variant.ty, target_final),
802 ),
803 self.can_conform_const(
804 (const_value.intern(self.db), candidate_final),
805 (target_const_value.intern(self.db), target_final),
806 ),
807 ]),
808 (ConstValue::Enum(_, _), _) => CanConformResult::Rejected,
809 (ConstValue::NonZero(const_value), ConstValue::NonZero(target_const_value)) => self
810 .can_conform_const(
811 (const_value.intern(self.db), candidate_final),
812 (target_const_value.intern(self.db), target_final),
813 ),
814 (ConstValue::NonZero(_), _) => CanConformResult::Rejected,
815 (ConstValue::Boxed(const_value), ConstValue::Boxed(target_const_value)) => self
816 .can_conform_const(
817 (const_value.intern(self.db), candidate_final),
818 (target_const_value.intern(self.db), target_final),
819 ),
820 (ConstValue::Boxed(_), _) => CanConformResult::Rejected,
821 (ConstValue::Generic(param), _) => {
822 let mut res = CanConformResult::Accepted;
823 match self.substitution.entry(param) {
824 Entry::Occupied(entry) => {
825 if let GenericArgumentId::Constant(existing_const) = entry.get() {
826 if *existing_const != target_id {
827 res = CanConformResult::Rejected;
828 }
829
830 if !existing_const.is_var_free(self.db) {
831 return CanConformResult::InferenceRequired;
832 }
833 } else {
834 res = CanConformResult::Rejected;
835 }
836 }
837 Entry::Vacant(e) => {
838 e.insert(GenericArgumentId::Constant(target_id));
839 }
840 }
841 if target_id.is_var_free(self.db) {
842 res
843 } else {
844 CanConformResult::InferenceRequired
845 }
846 }
847 (ConstValue::ImplConstant(_) | ConstValue::Var(_, _) | ConstValue::Missing(_), _) => {
848 CanConformResult::InferenceRequired
849 }
850 }
851 }
852}