sway_core/semantic_analysis/namespace/
trait_map.rs

1use std::{
2    cmp::Ordering,
3    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
4    fmt,
5    hash::{DefaultHasher, Hash, Hasher},
6    sync::Arc,
7};
8
9use sway_error::{
10    error::CompileError,
11    handler::{ErrorEmitted, Handler},
12};
13use sway_types::{integer_bits::IntegerBits, BaseIdent, Ident, Span, Spanned};
14
15use crate::{
16    decl_engine::{
17        parsed_id::ParsedDeclId, DeclEngineGet, DeclEngineGetParsedDeclId, DeclEngineInsert,
18    },
19    engine_threading::*,
20    language::{
21        parsed::{EnumDeclaration, ImplItem, StructDeclaration},
22        ty::{self, TyDecl, TyImplItem, TyTraitItem},
23        CallPath,
24    },
25    type_system::{SubstTypes, TypeId},
26    GenericArgument, IncludeSelf, SubstTypesContext, TraitConstraint, TypeEngine, TypeInfo,
27    TypeSubstMap, UnifyCheck,
28};
29
30use super::Module;
31
32/// Enum used to pass a value asking for insertion of type into trait map when an implementation
33/// of the trait cannot be found.
34#[derive(Debug, Clone)]
35pub enum TryInsertingTraitImplOnFailure {
36    Yes,
37    No,
38}
39
40#[derive(Clone)]
41pub enum CodeBlockFirstPass {
42    Yes,
43    No,
44}
45
46impl From<bool> for CodeBlockFirstPass {
47    fn from(value: bool) -> Self {
48        if value {
49            CodeBlockFirstPass::Yes
50        } else {
51            CodeBlockFirstPass::No
52        }
53    }
54}
55
56#[derive(Clone, Debug)]
57pub(crate) struct TraitSuffix {
58    pub(crate) name: Ident,
59    pub(crate) args: Vec<GenericArgument>,
60}
61impl PartialEqWithEngines for TraitSuffix {
62    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
63        self.name == other.name && self.args.eq(&other.args, ctx)
64    }
65}
66impl OrdWithEngines for TraitSuffix {
67    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> std::cmp::Ordering {
68        self.name
69            .cmp(&other.name)
70            .then_with(|| self.args.cmp(&other.args, ctx))
71    }
72}
73
74impl DisplayWithEngines for TraitSuffix {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
76        let res = write!(f, "{}", self.name.as_str());
77        if !self.args.is_empty() {
78            write!(
79                f,
80                "<{}>",
81                self.args
82                    .iter()
83                    .map(|i| engines.help_out(i.type_id()).to_string())
84                    .collect::<Vec<_>>()
85                    .join(", ")
86            )
87        } else {
88            res
89        }
90    }
91}
92
93impl DebugWithEngines for TraitSuffix {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
95        write!(f, "{}", engines.help_out(self))
96    }
97}
98
99type TraitName = Arc<CallPath<TraitSuffix>>;
100
101#[derive(Clone, Debug)]
102pub(crate) struct TraitKey {
103    pub(crate) name: TraitName,
104    pub(crate) type_id: TypeId,
105    pub(crate) impl_type_parameters: Vec<TypeId>,
106    pub(crate) trait_decl_span: Option<Span>,
107}
108
109impl OrdWithEngines for TraitKey {
110    fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> std::cmp::Ordering {
111        self.name.cmp(&other.name, ctx).then_with(|| {
112            self.type_id
113                .cmp(&other.type_id)
114                .then_with(|| self.impl_type_parameters.cmp(&other.impl_type_parameters))
115        })
116    }
117}
118
119#[derive(Clone, Debug)]
120pub enum ResolvedTraitImplItem {
121    Parsed(ImplItem),
122    Typed(TyImplItem),
123}
124
125impl DebugWithEngines for ResolvedTraitImplItem {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
127        match self {
128            ResolvedTraitImplItem::Parsed(_) => panic!(),
129            ResolvedTraitImplItem::Typed(ty) => write!(f, "{:?}", engines.help_out(ty)),
130        }
131    }
132}
133
134impl ResolvedTraitImplItem {
135    fn expect_typed(self) -> TyImplItem {
136        match self {
137            ResolvedTraitImplItem::Parsed(_) => panic!(),
138            ResolvedTraitImplItem::Typed(ty) => ty,
139        }
140    }
141
142    pub fn span(&self, engines: &Engines) -> Span {
143        match self {
144            ResolvedTraitImplItem::Parsed(item) => item.span(engines),
145            ResolvedTraitImplItem::Typed(item) => item.span(),
146        }
147    }
148}
149
150/// Map of name to [ResolvedTraitImplItem](ResolvedTraitImplItem)
151type TraitItems = BTreeMap<String, ResolvedTraitImplItem>;
152
153#[derive(Clone, Debug)]
154pub(crate) struct TraitValue {
155    pub(crate) trait_items: TraitItems,
156    /// The span of the entire impl block.
157    pub(crate) impl_span: Span,
158}
159
160#[derive(Clone, Debug)]
161pub(crate) struct TraitEntry {
162    pub(crate) key: TraitKey,
163    pub(crate) value: TraitValue,
164}
165
166/// Map of string of type entry id and vec of [TraitEntry].
167/// We are using the HashMap as a wrapper to the vec so the TraitMap algorithms
168/// don't need to traverse every TraitEntry.
169pub(crate) type TraitImpls = BTreeMap<TypeRootFilter, Vec<TraitEntry>>;
170
171#[derive(Clone, Hash, Eq, PartialOrd, Ord, PartialEq, Debug)]
172pub(crate) enum TypeRootFilter {
173    Unknown,
174    Never,
175    Placeholder,
176    StringSlice,
177    StringArray(usize),
178    U8,
179    U16,
180    U32,
181    U64,
182    U256,
183    Bool,
184    Custom(String),
185    B256,
186    Contract,
187    ErrorRecovery,
188    Tuple(usize),
189    Enum(ParsedDeclId<EnumDeclaration>),
190    Struct(ParsedDeclId<StructDeclaration>),
191    ContractCaller(String),
192    Array,
193    RawUntypedPtr,
194    RawUntypedSlice,
195    Ptr,
196    Slice,
197    TraitType(String),
198}
199
200/// Map holding trait implementations for types.
201///
202/// Note: "impl self" blocks are considered traits and are stored in the
203/// [TraitMap].
204#[derive(Clone, Debug, Default)]
205pub struct TraitMap {
206    pub(crate) trait_impls: TraitImpls,
207    satisfied_cache: HashSet<u64>,
208}
209
210pub(crate) enum IsImplSelf {
211    Yes,
212    No,
213}
214
215pub(crate) enum IsExtendingExistingImpl {
216    Yes,
217    No,
218}
219
220impl TraitMap {
221    /// Given a [TraitName] `trait_name`, [TypeId] `type_id`, and list of
222    /// [TyImplItem](ty::TyImplItem) `items`, inserts
223    /// `items` into the [TraitMap] with the key `(trait_name, type_id)`.
224    ///
225    /// This method is as conscious as possible of existing entries in the
226    /// [TraitMap], and tries to append `items` to an existing list of
227    /// declarations for the key `(trait_name, type_id)` whenever possible.
228    #[allow(clippy::too_many_arguments)]
229    pub(crate) fn insert(
230        &mut self,
231        handler: &Handler,
232        trait_name: CallPath,
233        trait_type_args: Vec<GenericArgument>,
234        type_id: TypeId,
235        impl_type_parameters: Vec<TypeId>,
236        items: &[ResolvedTraitImplItem],
237        impl_span: &Span,
238        trait_decl_span: Option<Span>,
239        is_impl_self: IsImplSelf,
240        is_extending_existing_impl: IsExtendingExistingImpl,
241        engines: &Engines,
242    ) -> Result<(), ErrorEmitted> {
243        let unaliased_type_id = engines.te().get_unaliased_type_id(type_id);
244
245        handler.scope(|handler| {
246            let mut trait_items: TraitItems = BTreeMap::new();
247            for item in items.iter() {
248                match item {
249                    ResolvedTraitImplItem::Parsed(_) => todo!(),
250                    ResolvedTraitImplItem::Typed(ty_item) => match ty_item {
251                        TyImplItem::Fn(decl_ref) => {
252                            if trait_items
253                                .insert(decl_ref.name().clone().to_string(), item.clone())
254                                .is_some()
255                            {
256                                // duplicate method name
257                                handler.emit_err(CompileError::MultipleDefinitionsOfName {
258                                    name: decl_ref.name().clone(),
259                                    span: decl_ref.span(),
260                                });
261                            }
262                        }
263                        TyImplItem::Constant(decl_ref) => {
264                            trait_items.insert(decl_ref.name().to_string(), item.clone());
265                        }
266                        TyImplItem::Type(decl_ref) => {
267                            trait_items.insert(decl_ref.name().to_string(), item.clone());
268                        }
269                    },
270                }
271            }
272
273            let trait_impls = self.get_impls_mut(engines, unaliased_type_id);
274
275            // check to see if adding this trait will produce a conflicting definition
276            for TraitEntry {
277                key:
278                    TraitKey {
279                        name: map_trait_name,
280                        type_id: map_type_id,
281                        trait_decl_span: _,
282                        impl_type_parameters: _,
283                    },
284                value:
285                    TraitValue {
286                        trait_items: map_trait_items,
287                        impl_span: existing_impl_span,
288                    },
289            } in trait_impls.iter()
290            {
291                let CallPath {
292                    suffix:
293                        TraitSuffix {
294                            name: map_trait_name_suffix,
295                            args: map_trait_type_args,
296                        },
297                    ..
298                } = &*map_trait_name.clone();
299
300                let unify_checker = UnifyCheck::non_generic_constraint_subset(engines);
301
302                // Types are subset if the `unaliased_type_id` that we want to insert can unify with the
303                // existing `map_type_id`. In addition we need to additionally check for the case of
304                // `&mut <type>` and `&<type>`.
305                let types_are_subset = unify_checker.check(unaliased_type_id, *map_type_id)
306                    && is_unified_type_subset(engines.te(), unaliased_type_id, *map_type_id);
307
308                /// `left` can unify into `right`. Additionally we need to check subset condition in case of
309                /// [TypeInfo::Ref] types.  Although `&mut <type>` can unify with `&<type>`
310                /// when it comes to trait and self impls, we considered them to be different types.
311                /// E.g., we can have `impl Foo for &T` and at the same time `impl Foo for &mut T`.
312                /// Or in general, `impl Foo for & &mut .. &T` is different type then, e.g., `impl Foo for &mut & .. &mut T`.
313                fn is_unified_type_subset(
314                    type_engine: &TypeEngine,
315                    mut left: TypeId,
316                    mut right: TypeId,
317                ) -> bool {
318                    // The loop cannot be endless, because at the end we must hit a referenced type which is not
319                    // a reference.
320                    loop {
321                        let left_ty_info = &*type_engine.get_unaliased(left);
322                        let right_ty_info = &*type_engine.get_unaliased(right);
323                        match (left_ty_info, right_ty_info) {
324                            (
325                                TypeInfo::Ref {
326                                    to_mutable_value: l_to_mut,
327                                    ..
328                                },
329                                TypeInfo::Ref {
330                                    to_mutable_value: r_to_mut,
331                                    ..
332                                },
333                            ) if *l_to_mut != *r_to_mut => return false, // Different mutability means not subset.
334                            (
335                                TypeInfo::Ref {
336                                    referenced_type: l_ty,
337                                    ..
338                                },
339                                TypeInfo::Ref {
340                                    referenced_type: r_ty,
341                                    ..
342                                },
343                            ) => {
344                                left = l_ty.type_id();
345                                right = r_ty.type_id();
346                            }
347                            _ => return true,
348                        }
349                    }
350                }
351
352                let mut traits_are_subset = true;
353                if *map_trait_name_suffix != trait_name.suffix
354                    || map_trait_type_args.len() != trait_type_args.len()
355                {
356                    traits_are_subset = false;
357                } else {
358                    for (map_arg_type, arg_type) in
359                        map_trait_type_args.iter().zip(trait_type_args.iter())
360                    {
361                        if !unify_checker.check(arg_type.type_id(), map_arg_type.type_id()) {
362                            traits_are_subset = false;
363                        }
364                    }
365                }
366
367                if matches!(is_extending_existing_impl, IsExtendingExistingImpl::No)
368                    && types_are_subset
369                    && traits_are_subset
370                    && matches!(is_impl_self, IsImplSelf::No)
371                {
372                    handler.emit_err(CompileError::ConflictingImplsForTraitAndType {
373                        trait_name: trait_name.to_string_with_args(engines, &trait_type_args),
374                        type_implementing_for: engines.help_out(type_id).to_string(),
375                        type_implementing_for_unaliased: engines
376                            .help_out(unaliased_type_id)
377                            .to_string(),
378                        existing_impl_span: existing_impl_span.clone(),
379                        second_impl_span: impl_span.clone(),
380                    });
381                } else if types_are_subset
382                    && (traits_are_subset || matches!(is_impl_self, IsImplSelf::Yes))
383                {
384                    for name in trait_items.keys() {
385                        let item = &trait_items[name];
386                        match item {
387                            ResolvedTraitImplItem::Parsed(_item) => todo!(),
388                            ResolvedTraitImplItem::Typed(item) => match item {
389                                ty::TyTraitItem::Fn(decl_ref) => {
390                                    if let Some(existing_item) = map_trait_items.get(name) {
391                                        handler.emit_err(
392                                            CompileError::DuplicateDeclDefinedForType {
393                                                decl_kind: "method".into(),
394                                                decl_name: decl_ref.name().to_string(),
395                                                type_implementing_for: engines
396                                                    .help_out(type_id)
397                                                    .to_string(),
398                                                type_implementing_for_unaliased: engines
399                                                    .help_out(unaliased_type_id)
400                                                    .to_string(),
401                                                existing_impl_span: existing_item
402                                                    .span(engines)
403                                                    .clone(),
404                                                second_impl_span: decl_ref.name().span(),
405                                            },
406                                        );
407                                    }
408                                }
409                                ty::TyTraitItem::Constant(decl_ref) => {
410                                    if let Some(existing_item) = map_trait_items.get(name) {
411                                        handler.emit_err(
412                                            CompileError::DuplicateDeclDefinedForType {
413                                                decl_kind: "constant".into(),
414                                                decl_name: decl_ref.name().to_string(),
415                                                type_implementing_for: engines
416                                                    .help_out(type_id)
417                                                    .to_string(),
418                                                type_implementing_for_unaliased: engines
419                                                    .help_out(unaliased_type_id)
420                                                    .to_string(),
421                                                existing_impl_span: existing_item
422                                                    .span(engines)
423                                                    .clone(),
424                                                second_impl_span: decl_ref.name().span(),
425                                            },
426                                        );
427                                    }
428                                }
429                                ty::TyTraitItem::Type(decl_ref) => {
430                                    if let Some(existing_item) = map_trait_items.get(name) {
431                                        handler.emit_err(
432                                            CompileError::DuplicateDeclDefinedForType {
433                                                decl_kind: "type".into(),
434                                                decl_name: decl_ref.name().to_string(),
435                                                type_implementing_for: engines
436                                                    .help_out(type_id)
437                                                    .to_string(),
438                                                type_implementing_for_unaliased: engines
439                                                    .help_out(unaliased_type_id)
440                                                    .to_string(),
441                                                existing_impl_span: existing_item
442                                                    .span(engines)
443                                                    .clone(),
444                                                second_impl_span: decl_ref.name().span(),
445                                            },
446                                        );
447                                    }
448                                }
449                            },
450                        }
451                    }
452                }
453            }
454            let trait_name: TraitName = Arc::new(CallPath {
455                prefixes: trait_name.prefixes,
456                suffix: TraitSuffix {
457                    name: trait_name.suffix,
458                    args: trait_type_args,
459                },
460                callpath_type: trait_name.callpath_type,
461            });
462
463            // even if there is a conflicting definition, add the trait anyway
464            self.insert_inner(
465                trait_name,
466                impl_span.clone(),
467                trait_decl_span,
468                unaliased_type_id,
469                impl_type_parameters,
470                trait_items,
471                engines,
472            );
473
474            Ok(())
475        })
476    }
477
478    #[allow(clippy::too_many_arguments)]
479    fn insert_inner(
480        &mut self,
481        trait_name: TraitName,
482        impl_span: Span,
483        trait_decl_span: Option<Span>,
484        type_id: TypeId,
485        impl_type_parameters: Vec<TypeId>,
486        trait_methods: TraitItems,
487        engines: &Engines,
488    ) {
489        let key = TraitKey {
490            name: trait_name,
491            type_id,
492            trait_decl_span,
493            impl_type_parameters,
494        };
495        let value = TraitValue {
496            trait_items: trait_methods,
497            impl_span,
498        };
499        let entry = TraitEntry { key, value };
500        let mut trait_impls: TraitImpls = BTreeMap::<TypeRootFilter, Vec<TraitEntry>>::new();
501        let type_root_filter = Self::get_type_root_filter(engines, type_id);
502        let impls_vector = vec![entry];
503        trait_impls.insert(type_root_filter, impls_vector);
504
505        let trait_map = TraitMap {
506            trait_impls,
507            satisfied_cache: HashSet::default(),
508        };
509
510        self.extend(trait_map, engines);
511    }
512
513    /// Given [TraitMap]s `self` and `other`, extend `self` with `other`,
514    /// extending existing entries when possible.
515    pub(crate) fn extend(&mut self, other: TraitMap, engines: &Engines) {
516        for impls_key in other.trait_impls.keys() {
517            let oe_vec = &other.trait_impls[impls_key];
518            let self_vec = if let Some(self_vec) = self.trait_impls.get_mut(impls_key) {
519                self_vec
520            } else {
521                self.trait_impls
522                    .insert(impls_key.clone(), Vec::<TraitEntry>::new());
523                self.trait_impls.get_mut(impls_key).unwrap()
524            };
525
526            for oe in oe_vec.iter() {
527                let pos = self_vec.binary_search_by(|se| {
528                    se.key.cmp(&oe.key, &OrdWithEnginesContext::new(engines))
529                });
530
531                match pos {
532                    Ok(pos) => self_vec[pos]
533                        .value
534                        .trait_items
535                        .extend(oe.value.trait_items.clone()),
536                    Err(pos) => self_vec.insert(pos, oe.clone()),
537                }
538            }
539        }
540    }
541
542    pub(crate) fn get_traits_types(
543        &self,
544        traits_types: &mut HashMap<CallPath, Vec<TypeId>>,
545    ) -> Result<(), ErrorEmitted> {
546        for key in self.trait_impls.keys() {
547            for self_entry in self.trait_impls[key].iter() {
548                let callpath = CallPath {
549                    prefixes: self_entry.key.name.prefixes.clone(),
550                    suffix: self_entry.key.name.suffix.name.clone(),
551                    callpath_type: self_entry.key.name.callpath_type,
552                };
553                if let Some(vec) = traits_types.get_mut(&callpath) {
554                    vec.push(self_entry.key.type_id);
555                } else {
556                    traits_types.insert(callpath, vec![self_entry.key.type_id]);
557                }
558            }
559        }
560        Ok(())
561    }
562
563    /// Filters the entries in `self` and return a new [TraitMap] with all of
564    /// the entries from `self` that implement a trait from the declaration with that span.
565    pub(crate) fn filter_by_trait_decl_span(&self, trait_decl_span: Span) -> TraitMap {
566        let mut trait_map = TraitMap::default();
567        for key in self.trait_impls.keys() {
568            let vec = &self.trait_impls[key];
569            for entry in vec {
570                if entry.key.trait_decl_span.as_ref() == Some(&trait_decl_span) {
571                    let trait_map_vec =
572                        if let Some(trait_map_vec) = trait_map.trait_impls.get_mut(key) {
573                            trait_map_vec
574                        } else {
575                            trait_map
576                                .trait_impls
577                                .insert(key.clone(), Vec::<TraitEntry>::new());
578                            trait_map.trait_impls.get_mut(key).unwrap()
579                        };
580
581                    trait_map_vec.push(entry.clone());
582                }
583            }
584        }
585        trait_map
586    }
587
588    /// Filters the entries in `self` with the given [TypeId] `type_id` and
589    /// return a new [TraitMap] with all of the entries from `self` for which
590    /// `type_id` is a subtype or a supertype. Additionally, the new [TraitMap]
591    /// contains the entries for the inner types of `self`.
592    ///
593    /// This is used for handling the case in which we need to import an impl
594    /// block from another module, and the type that that impl block is defined
595    /// for is of the type that we are importing, but in a more concrete form.
596    ///
597    /// Here is some example Sway code that we should expect to compile:
598    ///
599    /// `my_double.sw`:
600    /// ```ignore
601    /// library;
602    ///
603    /// pub trait MyDouble<T> {
604    ///     fn my_double(self, input: T) -> T;
605    /// }
606    /// ```
607    ///
608    /// `my_point.sw`:
609    /// ```ignore
610    /// library;
611    ///
612    /// use ::my_double::MyDouble;
613    ///
614    /// pub struct MyPoint<T> {
615    ///     x: T,
616    ///     y: T,
617    /// }
618    ///
619    /// impl MyDouble<u64> for MyPoint<u64> {
620    ///     fn my_double(self, value: u64) -> u64 {
621    ///         (self.x*2) + (self.y*2) + (value*2)
622    ///     }
623    /// }
624    /// ```
625    ///
626    /// `main.sw`:
627    /// ```ignore
628    /// script;
629    ///
630    /// mod my_double;
631    /// mod my_point;
632    ///
633    /// use my_point::MyPoint;
634    ///
635    /// fn main() -> u64 {
636    ///     let foo = MyPoint {
637    ///         x: 10u64,
638    ///         y: 10u64,
639    ///     };
640    ///     foo.my_double(100)
641    /// }
642    /// ```
643    ///
644    /// We need to be able to import the trait defined upon `MyPoint<u64>` just
645    /// from seeing `use ::my_double::MyDouble;`.
646    pub(crate) fn filter_by_type_item_import(
647        &self,
648        type_id: TypeId,
649        engines: &Engines,
650    ) -> TraitMap {
651        let unify_checker = UnifyCheck::constraint_subset(engines);
652        let unify_checker_for_item_import = UnifyCheck::non_generic_constraint_subset(engines);
653
654        // a curried version of the decider protocol to use in the helper functions
655        let decider = |left: TypeId, right: TypeId| {
656            unify_checker.check(left, right) || unify_checker_for_item_import.check(right, left)
657        };
658        let mut trait_map = self.filter_by_type_inner(engines, vec![type_id], decider);
659        let all_types = type_id
660            .extract_inner_types(engines, IncludeSelf::No)
661            .into_iter()
662            .collect::<Vec<_>>();
663        // a curried version of the decider protocol to use in the helper functions
664        let decider2 = |left: TypeId, right: TypeId| unify_checker.check(left, right);
665
666        trait_map.extend(
667            self.filter_by_type_inner(engines, all_types, decider2),
668            engines,
669        );
670        trait_map
671    }
672
673    fn filter_by_type_inner(
674        &self,
675        engines: &Engines,
676        mut all_types: Vec<TypeId>,
677        decider: impl Fn(TypeId, TypeId) -> bool,
678    ) -> TraitMap {
679        let type_engine = engines.te();
680        let mut trait_map = TraitMap::default();
681        for type_id in all_types.iter_mut() {
682            let type_info = type_engine.get(*type_id);
683            self.for_each_impls(
684                engines,
685                *type_id,
686                true,
687                |TraitEntry {
688                     key:
689                         TraitKey {
690                             name: map_trait_name,
691                             type_id: map_type_id,
692                             trait_decl_span: map_trait_decl_span,
693                             impl_type_parameters: map_impl_type_parameters,
694                         },
695                     value:
696                         TraitValue {
697                             trait_items: map_trait_items,
698                             impl_span,
699                         },
700                 }| {
701                    if !type_engine.is_type_changeable(engines, &type_info)
702                        && *type_id == *map_type_id
703                    {
704                        trait_map.insert_inner(
705                            map_trait_name.clone(),
706                            impl_span.clone(),
707                            map_trait_decl_span.clone(),
708                            *type_id,
709                            map_impl_type_parameters.clone(),
710                            map_trait_items.clone(),
711                            engines,
712                        );
713                    } else if decider(*type_id, *map_type_id) {
714                        trait_map.insert_inner(
715                            map_trait_name.clone(),
716                            impl_span.clone(),
717                            map_trait_decl_span.clone(),
718                            *map_type_id,
719                            map_impl_type_parameters.clone(),
720                            Self::filter_dummy_methods(
721                                map_trait_items,
722                                *type_id,
723                                *map_type_id,
724                                engines,
725                            )
726                            .map(|(name, item)| (name.to_string(), item))
727                            .collect(),
728                            engines,
729                        );
730                    }
731                },
732            );
733        }
734        trait_map
735    }
736
737    fn filter_dummy_methods<'a>(
738        map_trait_items: &'a TraitItems,
739        type_id: TypeId,
740        map_type_id: TypeId,
741        engines: &'a Engines,
742    ) -> impl Iterator<Item = (&'a str, ResolvedTraitImplItem)> + 'a {
743        let maybe_is_from_type_parameter = engines.te().map(map_type_id, |x| match x {
744            TypeInfo::UnknownGeneric {
745                is_from_type_parameter,
746                ..
747            } => Some(*is_from_type_parameter),
748            _ => None,
749        });
750        let insertable = if let Some(is_from_type_parameter) = maybe_is_from_type_parameter {
751            !is_from_type_parameter
752                || matches!(*engines.te().get(type_id), TypeInfo::UnknownGeneric { .. })
753        } else {
754            true
755        };
756
757        map_trait_items
758            .iter()
759            .filter_map(move |(name, item)| match item {
760                ResolvedTraitImplItem::Parsed(_item) => todo!(),
761                ResolvedTraitImplItem::Typed(item) => match item {
762                    ty::TyTraitItem::Fn(decl_ref) => engines.de().map(decl_ref.id(), |decl| {
763                        if decl.is_trait_method_dummy && !insertable {
764                            None
765                        } else {
766                            Some((
767                                name.as_str(),
768                                ResolvedTraitImplItem::Typed(TyImplItem::Fn(decl_ref.clone())),
769                            ))
770                        }
771                    }),
772                    ty::TyTraitItem::Constant(decl_ref) => Some((
773                        name.as_str(),
774                        ResolvedTraitImplItem::Typed(TyImplItem::Constant(decl_ref.clone())),
775                    )),
776                    ty::TyTraitItem::Type(decl_ref) => Some((
777                        name.as_str(),
778                        ResolvedTraitImplItem::Typed(TyImplItem::Type(decl_ref.clone())),
779                    )),
780                },
781            })
782    }
783
784    fn make_item_for_type_mapping(
785        engines: &Engines,
786        item: ResolvedTraitImplItem,
787        mut type_mapping: TypeSubstMap,
788        type_id: TypeId,
789        code_block_first_pass: CodeBlockFirstPass,
790    ) -> ResolvedTraitImplItem {
791        let decl_engine = engines.de();
792        match &item {
793            ResolvedTraitImplItem::Parsed(_item) => todo!(),
794            ResolvedTraitImplItem::Typed(item) => match item {
795                ty::TyTraitItem::Fn(decl_ref) => {
796                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
797                    if let Some(decl_implementing_for_typeid) = decl.implementing_for_typeid {
798                        type_mapping.insert(decl_implementing_for_typeid, type_id);
799                    }
800                    decl.subst(&SubstTypesContext::new(
801                        engines,
802                        &type_mapping,
803                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
804                    ));
805
806                    let new_ref = decl_engine
807                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref())
808                        .with_parent(decl_engine, decl_ref.id().into());
809
810                    ResolvedTraitImplItem::Typed(TyImplItem::Fn(new_ref))
811                }
812                ty::TyTraitItem::Constant(decl_ref) => {
813                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
814                    decl.subst(&SubstTypesContext::new(
815                        engines,
816                        &type_mapping,
817                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
818                    ));
819                    let new_ref = decl_engine
820                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
821                    ResolvedTraitImplItem::Typed(TyImplItem::Constant(new_ref))
822                }
823                ty::TyTraitItem::Type(decl_ref) => {
824                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
825                    decl.subst(&SubstTypesContext::new(
826                        engines,
827                        &type_mapping,
828                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
829                    ));
830                    let new_ref = decl_engine
831                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
832                    ResolvedTraitImplItem::Typed(TyImplItem::Type(new_ref))
833                }
834            },
835        }
836    }
837
838    /// Find the entries in `self` that are equivalent to `type_id`.
839    ///
840    /// Notes:
841    /// - equivalency is defined (1) based on whether the types contains types
842    ///     that are dynamic and can change and (2) whether the types hold
843    ///     equivalency after (1) is fulfilled
844    /// - this method does not translate types from the found entries to the
845    ///     `type_id` (like in `filter_by_type()`). This is because the only
846    ///     entries that qualify as hits are equivalents of `type_id`
847    pub(crate) fn get_items_for_type(
848        module: &Module,
849        engines: &Engines,
850        type_id: TypeId,
851    ) -> Vec<ResolvedTraitImplItem> {
852        TraitMap::get_items_and_trait_key_for_type(module, engines, type_id)
853            .iter()
854            .map(|i| i.0.clone())
855            .collect::<Vec<_>>()
856    }
857
858    fn get_items_and_trait_key_for_type(
859        module: &Module,
860        engines: &Engines,
861        type_id: TypeId,
862    ) -> Vec<(ResolvedTraitImplItem, TraitKey)> {
863        let type_engine = engines.te();
864        let unify_check = UnifyCheck::constraint_subset(engines);
865
866        let type_id = engines.te().get_unaliased_type_id(type_id);
867
868        let mut items = vec![];
869        // small performance gain in bad case
870        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
871            return items;
872        }
873
874        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
875            lexical_scope.items.implemented_traits.for_each_impls(
876                engines,
877                type_id,
878                true,
879                |entry| {
880                    if unify_check.check(type_id, entry.key.type_id) {
881                        let trait_items = Self::filter_dummy_methods(
882                            &entry.value.trait_items,
883                            type_id,
884                            entry.key.type_id,
885                            engines,
886                        )
887                        .map(|(_, i)| (i, entry.key.clone()))
888                        .collect::<Vec<_>>();
889
890                        items.extend(trait_items);
891                    }
892                },
893            );
894
895            Ok(None::<()>)
896        });
897        items
898    }
899
900    /// Find the spans of all impls for the given type.
901    ///
902    /// Notes:
903    /// - equivalency is defined (1) based on whether the types contains types
904    ///     that are dynamic and can change and (2) whether the types hold
905    ///     equivalency after (1) is fulfilled
906    /// - this method does not translate types from the found entries to the
907    ///     `type_id` (like in `filter_by_type()`). This is because the only
908    ///     entries that qualify as hits are equivalents of `type_id`
909    pub fn get_impl_spans_for_type(
910        module: &Module,
911        engines: &Engines,
912        type_id: &TypeId,
913    ) -> Vec<Span> {
914        let type_engine = engines.te();
915        let unify_check = UnifyCheck::constraint_subset(engines);
916
917        let type_id = &engines.te().get_unaliased_type_id(*type_id);
918
919        let mut spans = vec![];
920        // small performance gain in bad case
921        if matches!(&*type_engine.get(*type_id), TypeInfo::ErrorRecovery(_)) {
922            return spans;
923        }
924        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
925            lexical_scope.items.implemented_traits.for_each_impls(
926                engines,
927                *type_id,
928                false,
929                |entry| {
930                    if unify_check.check(*type_id, entry.key.type_id) {
931                        spans.push(entry.value.impl_span.clone());
932                    }
933                },
934            );
935
936            Ok(None::<()>)
937        });
938
939        spans
940    }
941
942    /// Find the spans of all impls for the given decl.
943    pub fn get_impl_spans_for_decl(
944        module: &Module,
945        engines: &Engines,
946        ty_decl: &TyDecl,
947    ) -> Vec<Span> {
948        let handler = Handler::default();
949        ty_decl
950            .return_type(&handler, engines)
951            .map(|type_id| TraitMap::get_impl_spans_for_type(module, engines, &type_id))
952            .unwrap_or_default()
953    }
954
955    /// Find the entries in `self` with trait name `trait_name` and return the
956    /// spans of the impls.
957    pub fn get_impl_spans_for_trait_name(module: &Module, trait_name: &CallPath) -> Vec<Span> {
958        let mut spans = vec![];
959        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
960            spans.push(
961                lexical_scope
962                    .items
963                    .implemented_traits
964                    .trait_impls
965                    .values()
966                    .map(|impls| {
967                        impls
968                            .iter()
969                            .filter_map(|entry| {
970                                let map_trait_name = CallPath {
971                                    prefixes: entry.key.name.prefixes.clone(),
972                                    suffix: entry.key.name.suffix.name.clone(),
973                                    callpath_type: entry.key.name.callpath_type,
974                                };
975                                if &map_trait_name == trait_name {
976                                    Some(entry.value.impl_span.clone())
977                                } else {
978                                    None
979                                }
980                            })
981                            .collect::<Vec<Span>>()
982                    })
983                    .collect::<Vec<Vec<Span>>>()
984                    .concat(),
985            );
986            Ok(None::<()>)
987        });
988
989        spans.concat()
990    }
991
992    /// Find the entries in `self` that are equivalent to `type_id` with trait
993    /// name `trait_name` and with trait type arguments.
994    ///
995    /// Notes:
996    /// - equivalency is defined (1) based on whether the types contains types
997    ///     that are dynamic and can change and (2) whether the types hold
998    ///     equivalency after (1) is fulfilled
999    /// - this method does not translate types from the found entries to the
1000    ///     `type_id` (like in `filter_by_type()`). This is because the only
1001    ///     entries that qualify as hits are equivalents of `type_id`
1002    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments(
1003        module: &Module,
1004        engines: &Engines,
1005        type_id: TypeId,
1006        trait_name: &CallPath,
1007        trait_type_args: &[GenericArgument],
1008    ) -> Vec<ResolvedTraitImplItem> {
1009        let type_id = engines.te().get_unaliased_type_id(type_id);
1010
1011        let type_engine = engines.te();
1012        let unify_check = UnifyCheck::constraint_subset(engines);
1013        let mut items = vec![];
1014        // small performance gain in bad case
1015        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1016            return items;
1017        }
1018        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1019            lexical_scope
1020                .items
1021                .implemented_traits
1022                .for_each_impls(engines, type_id, false, |e| {
1023                    let map_trait_name = CallPath {
1024                        prefixes: e.key.name.prefixes.clone(),
1025                        suffix: e.key.name.suffix.name.clone(),
1026                        callpath_type: e.key.name.callpath_type,
1027                    };
1028                    if &map_trait_name == trait_name
1029                        && unify_check.check(type_id, e.key.type_id)
1030                        && trait_type_args.len() == e.key.name.suffix.args.len()
1031                        && trait_type_args
1032                            .iter()
1033                            .zip(e.key.name.suffix.args.iter())
1034                            .all(|(t1, t2)| unify_check.check(t1.type_id(), t2.type_id()))
1035                    {
1036                        let type_mapping =
1037                            TypeSubstMap::from_superset_and_subset(engines, e.key.type_id, type_id);
1038
1039                        let mut trait_items = Self::filter_dummy_methods(
1040                            &e.value.trait_items,
1041                            type_id,
1042                            e.key.type_id,
1043                            engines,
1044                        )
1045                        .map(|(_, i)| {
1046                            Self::make_item_for_type_mapping(
1047                                engines,
1048                                i,
1049                                type_mapping.clone(),
1050                                type_id,
1051                                CodeBlockFirstPass::No,
1052                            )
1053                        })
1054                        .collect::<Vec<_>>();
1055
1056                        items.append(&mut trait_items);
1057                    }
1058                });
1059            Ok(None::<()>)
1060        });
1061        items
1062    }
1063
1064    /// Find the entries in `self` that are equivalent to `type_id` with trait
1065    /// name `trait_name` and with trait type arguments.
1066    ///
1067    /// Notes:
1068    /// - equivalency is defined (1) based on whether the types contains types
1069    ///     that are dynamic and can change and (2) whether the types hold
1070    ///     equivalency after (1) is fulfilled
1071    /// - this method does not translate types from the found entries to the
1072    ///     `type_id` (like in `filter_by_type()`). This is because the only
1073    ///     entries that qualify as hits are equivalents of `type_id`
1074    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments_typed(
1075        module: &Module,
1076        engines: &Engines,
1077        type_id: TypeId,
1078        trait_name: &CallPath,
1079        trait_type_args: &[GenericArgument],
1080    ) -> Vec<ty::TyTraitItem> {
1081        TraitMap::get_items_for_type_and_trait_name_and_trait_type_arguments(
1082            module,
1083            engines,
1084            type_id,
1085            trait_name,
1086            trait_type_args,
1087        )
1088        .into_iter()
1089        .map(|item| item.expect_typed())
1090        .collect::<Vec<_>>()
1091    }
1092
1093    pub(crate) fn get_trait_names_and_type_arguments_for_type(
1094        module: &Module,
1095        engines: &Engines,
1096        type_id: TypeId,
1097    ) -> Vec<(CallPath, Vec<GenericArgument>)> {
1098        let type_id = engines.te().get_unaliased_type_id(type_id);
1099
1100        let type_engine = engines.te();
1101        let unify_check = UnifyCheck::constraint_subset(engines);
1102        let mut trait_names = vec![];
1103        // small performance gain in bad case
1104        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1105            return trait_names;
1106        }
1107        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1108            lexical_scope.items.implemented_traits.for_each_impls(
1109                engines,
1110                type_id,
1111                false,
1112                |entry| {
1113                    if unify_check.check(type_id, entry.key.type_id) {
1114                        let trait_call_path = CallPath {
1115                            prefixes: entry.key.name.prefixes.clone(),
1116                            suffix: entry.key.name.suffix.name.clone(),
1117                            callpath_type: entry.key.name.callpath_type,
1118                        };
1119                        trait_names.push((trait_call_path, entry.key.name.suffix.args.clone()));
1120                    }
1121                },
1122            );
1123            Ok(None::<()>)
1124        });
1125        trait_names
1126    }
1127
1128    pub(crate) fn get_trait_item_for_type(
1129        module: &Module,
1130        handler: &Handler,
1131        engines: &Engines,
1132        symbol: &Ident,
1133        type_id: TypeId,
1134        as_trait: Option<CallPath>,
1135    ) -> Result<ResolvedTraitImplItem, ErrorEmitted> {
1136        let type_id = engines.te().get_unaliased_type_id(type_id);
1137
1138        let mut candidates = HashMap::<String, ResolvedTraitImplItem>::new();
1139        for (trait_item, trait_key) in
1140            TraitMap::get_items_and_trait_key_for_type(module, engines, type_id)
1141        {
1142            match trait_item {
1143                ResolvedTraitImplItem::Parsed(impl_item) => match impl_item {
1144                    ImplItem::Fn(fn_ref) => {
1145                        let decl = engines.pe().get_function(&fn_ref);
1146                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1147                        if decl.name.as_str() == symbol.as_str()
1148                            && (as_trait.is_none()
1149                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1150                        {
1151                            candidates.insert(
1152                                trait_call_path_string,
1153                                ResolvedTraitImplItem::Parsed(ImplItem::Fn(fn_ref)),
1154                            );
1155                        }
1156                    }
1157                    ImplItem::Constant(const_ref) => {
1158                        let decl = engines.pe().get_constant(&const_ref);
1159                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1160                        if decl.name.as_str() == symbol.as_str()
1161                            && (as_trait.is_none()
1162                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1163                        {
1164                            candidates.insert(
1165                                trait_call_path_string,
1166                                ResolvedTraitImplItem::Parsed(ImplItem::Constant(const_ref)),
1167                            );
1168                        }
1169                    }
1170                    ImplItem::Type(type_ref) => {
1171                        let decl = engines.pe().get_trait_type(&type_ref);
1172                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1173                        if decl.name.as_str() == symbol.as_str()
1174                            && (as_trait.is_none()
1175                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1176                        {
1177                            candidates.insert(
1178                                trait_call_path_string,
1179                                ResolvedTraitImplItem::Parsed(ImplItem::Type(type_ref)),
1180                            );
1181                        }
1182                    }
1183                },
1184                ResolvedTraitImplItem::Typed(ty_impl_item) => match ty_impl_item {
1185                    ty::TyTraitItem::Fn(fn_ref) => {
1186                        let decl = engines.de().get_function(&fn_ref);
1187                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1188                        if decl.name.as_str() == symbol.as_str()
1189                            && (as_trait.is_none()
1190                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1191                        {
1192                            candidates.insert(
1193                                trait_call_path_string,
1194                                ResolvedTraitImplItem::Typed(TyTraitItem::Fn(fn_ref)),
1195                            );
1196                        }
1197                    }
1198                    ty::TyTraitItem::Constant(const_ref) => {
1199                        let decl = engines.de().get_constant(&const_ref);
1200                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1201                        if decl.call_path.suffix.as_str() == symbol.as_str()
1202                            && (as_trait.is_none()
1203                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1204                        {
1205                            candidates.insert(
1206                                trait_call_path_string,
1207                                ResolvedTraitImplItem::Typed(TyTraitItem::Constant(const_ref)),
1208                            );
1209                        }
1210                    }
1211                    ty::TyTraitItem::Type(type_ref) => {
1212                        let decl = engines.de().get_type(&type_ref);
1213                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1214                        if decl.name.as_str() == symbol.as_str()
1215                            && (as_trait.is_none()
1216                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1217                        {
1218                            candidates.insert(
1219                                trait_call_path_string,
1220                                ResolvedTraitImplItem::Typed(TyTraitItem::Type(type_ref)),
1221                            );
1222                        }
1223                    }
1224                },
1225            }
1226        }
1227
1228        match candidates.len().cmp(&1) {
1229            Ordering::Greater => Err(handler.emit_err(
1230                CompileError::MultipleApplicableItemsInScope {
1231                    item_name: symbol.as_str().to_string(),
1232                    item_kind: "item".to_string(),
1233                    as_traits: candidates
1234                        .keys()
1235                        .map(|k| {
1236                            (
1237                                k.clone()
1238                                    .split("::")
1239                                    .collect::<Vec<_>>()
1240                                    .last()
1241                                    .unwrap()
1242                                    .to_string(),
1243                                engines.help_out(type_id).to_string(),
1244                            )
1245                        })
1246                        .collect::<Vec<_>>(),
1247                    span: symbol.span(),
1248                },
1249            )),
1250            Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound {
1251                name: symbol.clone(),
1252                span: symbol.span(),
1253            })),
1254            Ordering::Equal => Ok(candidates.values().next().unwrap().clone()),
1255        }
1256    }
1257
1258    /// Checks to see if the trait constraints are satisfied for a given type.
1259    #[allow(clippy::too_many_arguments)]
1260    pub(crate) fn check_if_trait_constraints_are_satisfied_for_type(
1261        handler: &Handler,
1262        module: &mut Module,
1263        type_id: TypeId,
1264        constraints: &[TraitConstraint],
1265        access_span: &Span,
1266        engines: &Engines,
1267    ) -> Result<(), ErrorEmitted> {
1268        let type_engine = engines.te();
1269
1270        let type_id = type_engine.get_unaliased_type_id(type_id);
1271
1272        // resolving trait constraints require a concrete type, we need to default numeric to u64
1273        type_engine.decay_numeric(handler, engines, type_id, access_span)?;
1274
1275        if constraints.is_empty() {
1276            return Ok(());
1277        }
1278
1279        // Check we can use the cache
1280        let mut hasher = DefaultHasher::default();
1281        type_id.hash(&mut hasher);
1282        for c in constraints {
1283            c.hash(&mut hasher, engines);
1284        }
1285        let hash = hasher.finish();
1286
1287        {
1288            let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1289            if trait_map.satisfied_cache.contains(&hash) {
1290                return Ok(());
1291            }
1292        }
1293
1294        let all_impld_traits: BTreeSet<(Ident, TypeId)> =
1295            Self::get_all_implemented_traits(module, type_id, engines);
1296
1297        // Call the real implementation and cache when true
1298        match Self::check_if_trait_constraints_are_satisfied_for_type_inner(
1299            handler,
1300            type_id,
1301            constraints,
1302            access_span,
1303            engines,
1304            all_impld_traits,
1305        ) {
1306            Ok(()) => {
1307                let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1308                trait_map.satisfied_cache.insert(hash);
1309                Ok(())
1310            }
1311            r => r,
1312        }
1313    }
1314
1315    fn get_all_implemented_traits(
1316        module: &Module,
1317        type_id: TypeId,
1318        engines: &Engines,
1319    ) -> BTreeSet<(Ident, TypeId)> {
1320        let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default();
1321        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1322            all_impld_traits.extend(
1323                lexical_scope
1324                    .items
1325                    .implemented_traits
1326                    .get_implemented_traits(type_id, engines),
1327            );
1328            Ok(None::<()>)
1329        });
1330        all_impld_traits
1331    }
1332
1333    fn get_implemented_traits(
1334        &self,
1335        type_id: TypeId,
1336        engines: &Engines,
1337    ) -> BTreeSet<(Ident, TypeId)> {
1338        let type_engine = engines.te();
1339        let unify_check = UnifyCheck::constraint_subset(engines);
1340        let mut all_impld_traits = BTreeSet::<(Ident, TypeId)>::new();
1341        self.for_each_impls(engines, type_id, true, |e| {
1342            let key = &e.key;
1343            let suffix = &key.name.suffix;
1344            if unify_check.check(type_id, key.type_id) {
1345                let map_trait_type_id = type_engine.new_custom(
1346                    engines,
1347                    suffix.name.clone().into(),
1348                    if suffix.args.is_empty() {
1349                        None
1350                    } else {
1351                        Some(suffix.args.to_vec())
1352                    },
1353                );
1354                all_impld_traits.insert((suffix.name.clone(), map_trait_type_id));
1355            }
1356        });
1357        all_impld_traits
1358    }
1359
1360    #[allow(clippy::too_many_arguments)]
1361    fn check_if_trait_constraints_are_satisfied_for_type_inner(
1362        handler: &Handler,
1363        type_id: TypeId,
1364        constraints: &[TraitConstraint],
1365        access_span: &Span,
1366        engines: &Engines,
1367        all_impld_traits: BTreeSet<(Ident, TypeId)>,
1368    ) -> Result<(), ErrorEmitted> {
1369        let type_engine = engines.te();
1370        let unify_check = UnifyCheck::constraint_subset(engines);
1371
1372        let required_traits: BTreeSet<(Ident, TypeId)> = constraints
1373            .iter()
1374            .map(|c| {
1375                let TraitConstraint {
1376                    trait_name: constraint_trait_name,
1377                    type_arguments: constraint_type_arguments,
1378                } = c;
1379                let constraint_type_id = type_engine.new_custom(
1380                    engines,
1381                    constraint_trait_name.suffix.clone().into(),
1382                    if constraint_type_arguments.is_empty() {
1383                        None
1384                    } else {
1385                        Some(constraint_type_arguments.clone())
1386                    },
1387                );
1388                (c.trait_name.suffix.clone(), constraint_type_id)
1389            })
1390            .collect();
1391
1392        let traits_not_found: BTreeSet<(BaseIdent, TypeId)> = required_traits
1393            .into_iter()
1394            .filter(|(required_trait_name, required_trait_type_id)| {
1395                !all_impld_traits
1396                    .iter()
1397                    .any(|(trait_name, constraint_type_id)| {
1398                        trait_name == required_trait_name
1399                            && unify_check.check(*constraint_type_id, *required_trait_type_id)
1400                    })
1401            })
1402            .collect();
1403
1404        handler.scope(|handler| {
1405            for (trait_name, constraint_type_id) in traits_not_found.iter() {
1406                let mut type_arguments_string = "".to_string();
1407                if let TypeInfo::Custom {
1408                    qualified_call_path: _,
1409                    type_arguments: Some(type_arguments),
1410                } = &*type_engine.get(*constraint_type_id)
1411                {
1412                    type_arguments_string = format!("<{}>", engines.help_out(type_arguments));
1413                }
1414
1415                // TODO: use a better span
1416                handler.emit_err(CompileError::TraitConstraintNotSatisfied {
1417                    type_id: type_id.index(),
1418                    ty: engines.help_out(type_id).to_string(),
1419                    trait_name: format!("{}{}", trait_name, type_arguments_string),
1420                    span: access_span.clone(),
1421                });
1422            }
1423
1424            Ok(())
1425        })
1426    }
1427
1428    pub fn get_trait_constraints_are_satisfied_for_types(
1429        module: &Module,
1430        _handler: &Handler,
1431        type_id: TypeId,
1432        constraints: &[TraitConstraint],
1433        engines: &Engines,
1434    ) -> Result<Vec<(TypeId, String)>, ErrorEmitted> {
1435        let type_id = engines.te().get_unaliased_type_id(type_id);
1436
1437        let _decl_engine = engines.de();
1438        let unify_check = UnifyCheck::coercion(engines);
1439        let unify_check_equality = UnifyCheck::constraint_subset(engines);
1440
1441        let mut impld_traits_type_ids: Vec<Vec<(TypeId, String)>> = vec![];
1442        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1443            lexical_scope
1444                .items
1445                .implemented_traits
1446                .for_each_impls(engines, type_id, true, |e| {
1447                    let mut traits: Vec<(TypeId, String)> = vec![];
1448
1449                    let key = &e.key;
1450                    for constraint in constraints {
1451                        if key.name.suffix.name == constraint.trait_name.suffix
1452                            && key
1453                                .name
1454                                .suffix
1455                                .args
1456                                .iter()
1457                                .zip(constraint.type_arguments.iter())
1458                                .all(|(a1, a2)| {
1459                                    unify_check_equality.check(a1.type_id(), a2.type_id())
1460                                })
1461                            && unify_check.check(type_id, key.type_id)
1462                        {
1463                            let name_type_args = if !key.name.suffix.args.is_empty() {
1464                                format!("<{}>", engines.help_out(key.name.suffix.args.clone()))
1465                            } else {
1466                                "".to_string()
1467                            };
1468                            let name =
1469                                format!("{}{}", key.name.suffix.name.as_str(), name_type_args);
1470                            traits.push((key.type_id, name));
1471                            break;
1472                        }
1473                    }
1474                    impld_traits_type_ids.push(traits);
1475                });
1476
1477            Ok(None::<()>)
1478        });
1479        Ok(impld_traits_type_ids.concat())
1480    }
1481
1482    fn get_impls_mut(&mut self, engines: &Engines, type_id: TypeId) -> &mut Vec<TraitEntry> {
1483        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1484        if !self.trait_impls.contains_key(&type_root_filter) {
1485            self.trait_impls
1486                .insert(type_root_filter.clone(), Vec::new());
1487        }
1488
1489        self.trait_impls.get_mut(&type_root_filter).unwrap()
1490    }
1491
1492    pub(crate) fn for_each_impls<F>(
1493        &self,
1494        engines: &Engines,
1495        type_id: TypeId,
1496        include_placeholder: bool,
1497        mut callback: F,
1498    ) where
1499        F: FnMut(&TraitEntry),
1500    {
1501        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1502        self.trait_impls
1503            .get(&type_root_filter)
1504            .iter()
1505            .for_each(|vec| vec.iter().for_each(&mut callback));
1506        if include_placeholder && type_root_filter != TypeRootFilter::Placeholder {
1507            self.trait_impls
1508                .get(&TypeRootFilter::Placeholder)
1509                .iter()
1510                .for_each(|vec| vec.iter().for_each(&mut callback));
1511        }
1512    }
1513
1514    // Return a string representing only the base type.
1515    // This is used by the trait map to filter the entries into a HashMap with the return type string as key.
1516    fn get_type_root_filter(engines: &Engines, type_id: TypeId) -> TypeRootFilter {
1517        use TypeInfo::*;
1518        match &*engines.te().get(type_id) {
1519            Unknown => TypeRootFilter::Unknown,
1520            Never => TypeRootFilter::Never,
1521            UnknownGeneric { .. } | Placeholder(_) => TypeRootFilter::Placeholder,
1522            TypeParam(_param) => unreachable!(),
1523            StringSlice => TypeRootFilter::StringSlice,
1524            StringArray(x) => TypeRootFilter::StringArray(x.val()),
1525            UnsignedInteger(x) => match x {
1526                IntegerBits::Eight => TypeRootFilter::U8,
1527                IntegerBits::Sixteen => TypeRootFilter::U16,
1528                IntegerBits::ThirtyTwo => TypeRootFilter::U32,
1529                IntegerBits::SixtyFour => TypeRootFilter::U64,
1530                IntegerBits::V256 => TypeRootFilter::U256,
1531            },
1532            Boolean => TypeRootFilter::Bool,
1533            Custom {
1534                qualified_call_path: call_path,
1535                ..
1536            } => TypeRootFilter::Custom(call_path.call_path.suffix.to_string()),
1537            B256 => TypeRootFilter::B256,
1538            Numeric => TypeRootFilter::U64, // u64 is the default
1539            Contract => TypeRootFilter::Contract,
1540            ErrorRecovery(_) => TypeRootFilter::ErrorRecovery,
1541            Tuple(fields) => TypeRootFilter::Tuple(fields.len()),
1542            UntypedEnum(decl_id) => TypeRootFilter::Enum(*decl_id),
1543            UntypedStruct(decl_id) => TypeRootFilter::Struct(*decl_id),
1544            Enum(decl_id) => {
1545                // TODO Remove unwrap once #6475 is fixed
1546                TypeRootFilter::Enum(engines.de().get_parsed_decl_id(decl_id).unwrap())
1547            }
1548            Struct(decl_id) => {
1549                // TODO Remove unwrap once #6475 is fixed
1550                TypeRootFilter::Struct(engines.de().get_parsed_decl_id(decl_id).unwrap())
1551            }
1552            ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()),
1553            Array(_, _) => TypeRootFilter::Array,
1554            RawUntypedPtr => TypeRootFilter::RawUntypedPtr,
1555            RawUntypedSlice => TypeRootFilter::RawUntypedSlice,
1556            Ptr(_) => TypeRootFilter::Ptr,
1557            Slice(_) => TypeRootFilter::Slice,
1558            Alias { ty, .. } => Self::get_type_root_filter(engines, ty.type_id()),
1559            TraitType { name, .. } => TypeRootFilter::TraitType(name.to_string()),
1560            Ref {
1561                referenced_type, ..
1562            } => Self::get_type_root_filter(engines, referenced_type.type_id()),
1563        }
1564    }
1565}