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