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