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, Vec<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(vec) = traits_types.get_mut(&callpath) {
599                    vec.push(self_entry.inner.key.type_id);
600                } else {
601                    traits_types.insert(callpath, vec![self_entry.inner.key.type_id]);
602                }
603            }
604        }
605        Ok(())
606    }
607
608    /// Filters the entries in `self` and return a new [TraitMap] with all of
609    /// the entries from `self` that implement a trait from the declaration with that span.
610    pub(crate) fn filter_by_trait_decl_span(&self, trait_decl_span: Span) -> TraitMap {
611        let mut trait_map = TraitMap::default();
612        for key in self.trait_impls.keys() {
613            let vec = &self.trait_impls[key];
614            for entry in vec {
615                if entry.inner.key.trait_decl_span.as_ref() == Some(&trait_decl_span) {
616                    let trait_map_vec =
617                        if let Some(trait_map_vec) = trait_map.trait_impls.get_mut(key) {
618                            trait_map_vec
619                        } else {
620                            trait_map.trait_impls.insert(key.clone(), Vec::<_>::new());
621                            trait_map.trait_impls.get_mut(key).unwrap()
622                        };
623
624                    trait_map_vec.push(entry.clone());
625                }
626            }
627        }
628        trait_map
629    }
630
631    /// Filters the entries in `self` with the given [TypeId] `type_id` and
632    /// return a new [TraitMap] with all of the entries from `self` for which
633    /// `type_id` is a subtype or a supertype. Additionally, the new [TraitMap]
634    /// contains the entries for the inner types of `self`.
635    ///
636    /// This is used for handling the case in which we need to import an impl
637    /// block from another module, and the type that that impl block is defined
638    /// for is of the type that we are importing, but in a more concrete form.
639    ///
640    /// Here is some example Sway code that we should expect to compile:
641    ///
642    /// `my_double.sw`:
643    /// ```ignore
644    /// library;
645    ///
646    /// pub trait MyDouble<T> {
647    ///     fn my_double(self, input: T) -> T;
648    /// }
649    /// ```
650    ///
651    /// `my_point.sw`:
652    /// ```ignore
653    /// library;
654    ///
655    /// use ::my_double::MyDouble;
656    ///
657    /// pub struct MyPoint<T> {
658    ///     x: T,
659    ///     y: T,
660    /// }
661    ///
662    /// impl MyDouble<u64> for MyPoint<u64> {
663    ///     fn my_double(self, value: u64) -> u64 {
664    ///         (self.x*2) + (self.y*2) + (value*2)
665    ///     }
666    /// }
667    /// ```
668    ///
669    /// `main.sw`:
670    /// ```ignore
671    /// script;
672    ///
673    /// mod my_double;
674    /// mod my_point;
675    ///
676    /// use my_point::MyPoint;
677    ///
678    /// fn main() -> u64 {
679    ///     let foo = MyPoint {
680    ///         x: 10u64,
681    ///         y: 10u64,
682    ///     };
683    ///     foo.my_double(100)
684    /// }
685    /// ```
686    ///
687    /// We need to be able to import the trait defined upon `MyPoint<u64>` just
688    /// from seeing `use ::my_double::MyDouble;`.
689    pub(crate) fn filter_by_type_item_import(
690        &self,
691        type_id: TypeId,
692        engines: &Engines,
693    ) -> TraitMap {
694        let unify_checker = UnifyCheck::constraint_subset(engines);
695        let unify_checker_for_item_import = UnifyCheck::non_generic_constraint_subset(engines);
696
697        // a curried version of the decider protocol to use in the helper functions
698        let decider = |left: TypeId, right: TypeId| {
699            unify_checker.check(left, right) || unify_checker_for_item_import.check(right, left)
700        };
701        let mut trait_map = self.filter_by_type_inner(engines, vec![type_id], decider);
702        let all_types = type_id
703            .extract_inner_types(engines, IncludeSelf::No)
704            .into_iter()
705            .collect::<Vec<_>>();
706        // a curried version of the decider protocol to use in the helper functions
707        let decider2 = |left: TypeId, right: TypeId| unify_checker.check(left, right);
708
709        trait_map.extend(
710            self.filter_by_type_inner(engines, all_types, decider2),
711            engines,
712        );
713        trait_map
714    }
715
716    fn filter_by_type_inner(
717        &self,
718        engines: &Engines,
719        mut all_types: Vec<TypeId>,
720        decider: impl Fn(TypeId, TypeId) -> bool,
721    ) -> TraitMap {
722        let type_engine = engines.te();
723        let mut trait_map = TraitMap::default();
724        for type_id in all_types.iter_mut() {
725            let type_info = type_engine.get(*type_id);
726            self.for_each_impls(engines, *type_id, true, |entry| {
727                let TraitEntry {
728                    key:
729                        TraitKey {
730                            name: map_trait_name,
731                            type_id: map_type_id,
732                            trait_decl_span: map_trait_decl_span,
733                            impl_type_parameters: map_impl_type_parameters,
734                            is_impl_interface_surface: _,
735                        },
736                    value:
737                        TraitValue {
738                            trait_items: map_trait_items,
739                            impl_span,
740                        },
741                } = entry.inner.as_ref();
742
743                if !type_engine.is_type_changeable(engines, &type_info) && *type_id == *map_type_id
744                {
745                    trait_map.insert_inner(
746                        map_trait_name.clone(),
747                        impl_span.clone(),
748                        map_trait_decl_span.clone(),
749                        *type_id,
750                        map_impl_type_parameters.clone(),
751                        map_trait_items.clone(),
752                        IsImplInterfaceSurface::No,
753                        engines,
754                    );
755                } else if decider(*type_id, *map_type_id) {
756                    trait_map.insert_inner(
757                        map_trait_name.clone(),
758                        impl_span.clone(),
759                        map_trait_decl_span.clone(),
760                        *map_type_id,
761                        map_impl_type_parameters.clone(),
762                        Self::filter_dummy_methods(
763                            map_trait_items,
764                            *type_id,
765                            *map_type_id,
766                            engines,
767                        )
768                        .map(|(name, item)| (name.to_string(), item))
769                        .collect(),
770                        IsImplInterfaceSurface::No,
771                        engines,
772                    );
773                }
774            });
775        }
776        trait_map
777    }
778
779    fn filter_dummy_methods<'a>(
780        map_trait_items: &'a TraitItems,
781        type_id: TypeId,
782        map_type_id: TypeId,
783        engines: &'a Engines,
784    ) -> impl Iterator<Item = (&'a str, ResolvedTraitImplItem)> + 'a {
785        let maybe_is_from_type_parameter = engines.te().map(map_type_id, |x| match x {
786            TypeInfo::UnknownGeneric {
787                is_from_type_parameter,
788                ..
789            } => Some(*is_from_type_parameter),
790            _ => None,
791        });
792        let insertable = if let Some(is_from_type_parameter) = maybe_is_from_type_parameter {
793            !is_from_type_parameter
794                || matches!(*engines.te().get(type_id), TypeInfo::UnknownGeneric { .. })
795        } else {
796            true
797        };
798
799        map_trait_items
800            .iter()
801            .filter_map(move |(name, item)| match item {
802                ResolvedTraitImplItem::Parsed(_item) => todo!(),
803                ResolvedTraitImplItem::Typed(item) => match item {
804                    ty::TyTraitItem::Fn(decl_ref) => engines.de().map(decl_ref.id(), |decl| {
805                        if decl.is_trait_method_dummy && !insertable {
806                            None
807                        } else {
808                            Some((
809                                name.as_str(),
810                                ResolvedTraitImplItem::Typed(TyImplItem::Fn(decl_ref.clone())),
811                            ))
812                        }
813                    }),
814                    ty::TyTraitItem::Constant(decl_ref) => Some((
815                        name.as_str(),
816                        ResolvedTraitImplItem::Typed(TyImplItem::Constant(decl_ref.clone())),
817                    )),
818                    ty::TyTraitItem::Type(decl_ref) => Some((
819                        name.as_str(),
820                        ResolvedTraitImplItem::Typed(TyImplItem::Type(decl_ref.clone())),
821                    )),
822                },
823            })
824    }
825
826    fn make_item_for_type_mapping(
827        engines: &Engines,
828        item: ResolvedTraitImplItem,
829        mut type_mapping: TypeSubstMap,
830        type_id: TypeId,
831        code_block_first_pass: CodeBlockFirstPass,
832    ) -> ResolvedTraitImplItem {
833        let decl_engine = engines.de();
834        match &item {
835            ResolvedTraitImplItem::Parsed(_item) => todo!(),
836            ResolvedTraitImplItem::Typed(item) => match item {
837                ty::TyTraitItem::Fn(decl_ref) => {
838                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
839                    if let Some(decl_implementing_for_typeid) = decl.implementing_for_typeid {
840                        type_mapping.insert(decl_implementing_for_typeid, type_id);
841                    }
842                    decl.subst(&SubstTypesContext::new(
843                        engines,
844                        &type_mapping,
845                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
846                    ));
847
848                    let new_ref = decl_engine
849                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref())
850                        .with_parent(decl_engine, decl_ref.id().into());
851
852                    ResolvedTraitImplItem::Typed(TyImplItem::Fn(new_ref))
853                }
854                ty::TyTraitItem::Constant(decl_ref) => {
855                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
856                    decl.subst(&SubstTypesContext::new(
857                        engines,
858                        &type_mapping,
859                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
860                    ));
861                    let new_ref = decl_engine
862                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
863                    ResolvedTraitImplItem::Typed(TyImplItem::Constant(new_ref))
864                }
865                ty::TyTraitItem::Type(decl_ref) => {
866                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
867                    decl.subst(&SubstTypesContext::new(
868                        engines,
869                        &type_mapping,
870                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
871                    ));
872                    let new_ref = decl_engine
873                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
874                    ResolvedTraitImplItem::Typed(TyImplItem::Type(new_ref))
875                }
876            },
877        }
878    }
879
880    /// Find the entries in `self` that are equivalent to `type_id`.
881    ///
882    /// Notes:
883    /// - equivalency is defined (1) based on whether the types contains types
884    ///   that are dynamic and can change and (2) whether the types hold
885    ///   equivalency after (1) is fulfilled
886    /// - this method does not translate types from the found entries to the
887    ///   `type_id` (like in `filter_by_type()`). This is because the only
888    ///   entries that qualify as hits are equivalents of `type_id`
889    pub(crate) fn append_items_for_type(
890        module: &Module,
891        engines: &Engines,
892        type_id: TypeId,
893        items: &mut Vec<ResolvedTraitImplItem>,
894    ) {
895        TraitMap::find_items_and_trait_key_for_type(module, engines, type_id, &mut |item, _| {
896            items.push(item);
897        });
898    }
899
900    pub(crate) fn find_items_and_trait_key_for_type(
901        module: &Module,
902        engines: &Engines,
903        type_id: TypeId,
904        callback: &mut impl FnMut(ResolvedTraitImplItem, TraitKey),
905    ) {
906        let type_engine = engines.te();
907        let type_id = engines.te().get_unaliased_type_id(type_id);
908
909        // small performance gain in bad case
910        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
911            return;
912        }
913
914        let unify_check = UnifyCheck::constraint_subset(engines);
915
916        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
917            lexical_scope.items.implemented_traits.for_each_impls(
918                engines,
919                type_id,
920                true,
921                |entry| {
922                    if unify_check.check(type_id, entry.inner.key.type_id) {
923                        let trait_items = Self::filter_dummy_methods(
924                            &entry.inner.value.trait_items,
925                            type_id,
926                            entry.inner.key.type_id,
927                            engines,
928                        )
929                        .map(|(_, i)| (i, entry.inner.key.clone()));
930
931                        for i in trait_items {
932                            callback(i.0, i.1);
933                        }
934                    }
935                },
936            );
937
938            Ok(None::<()>)
939        });
940    }
941
942    /// Find the spans of all impls for the given type.
943    ///
944    /// Notes:
945    /// - equivalency is defined (1) based on whether the types contains types
946    ///   that are dynamic and can change and (2) whether the types hold
947    ///   equivalency after (1) is fulfilled
948    /// - this method does not translate types from the found entries to the
949    ///   `type_id` (like in `filter_by_type()`). This is because the only
950    ///   entries that qualify as hits are equivalents of `type_id`
951    pub fn get_impl_spans_for_type(
952        module: &Module,
953        engines: &Engines,
954        type_id: &TypeId,
955    ) -> Vec<Span> {
956        let type_engine = engines.te();
957        let unify_check = UnifyCheck::constraint_subset(engines);
958
959        let type_id = &engines.te().get_unaliased_type_id(*type_id);
960
961        let mut spans = vec![];
962        // small performance gain in bad case
963        if matches!(&*type_engine.get(*type_id), TypeInfo::ErrorRecovery(_)) {
964            return spans;
965        }
966        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
967            lexical_scope.items.implemented_traits.for_each_impls(
968                engines,
969                *type_id,
970                false,
971                |entry| {
972                    if unify_check.check(*type_id, entry.inner.key.type_id) {
973                        spans.push(entry.inner.value.impl_span.clone());
974                    }
975                },
976            );
977
978            Ok(None::<()>)
979        });
980
981        spans
982    }
983
984    /// Find the spans of all impls for the given decl.
985    pub fn get_impl_spans_for_decl(
986        module: &Module,
987        engines: &Engines,
988        ty_decl: &TyDecl,
989    ) -> Vec<Span> {
990        let handler = Handler::default();
991        ty_decl
992            .return_type(&handler, engines)
993            .map(|type_id| TraitMap::get_impl_spans_for_type(module, engines, &type_id))
994            .unwrap_or_default()
995    }
996
997    /// Find the entries in `self` with trait name `trait_name` and return the
998    /// spans of the impls.
999    pub fn get_impl_spans_for_trait_name(module: &Module, trait_name: &CallPath) -> Vec<Span> {
1000        let mut spans = vec![];
1001        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1002            spans.push(
1003                lexical_scope
1004                    .items
1005                    .implemented_traits
1006                    .trait_impls
1007                    .values()
1008                    .map(|impls| {
1009                        impls
1010                            .iter()
1011                            .filter_map(|entry| {
1012                                let map_trait_name = CallPath {
1013                                    prefixes: entry.inner.key.name.prefixes.clone(),
1014                                    suffix: entry.inner.key.name.suffix.name.clone(),
1015                                    callpath_type: entry.inner.key.name.callpath_type,
1016                                };
1017                                if &map_trait_name == trait_name {
1018                                    Some(entry.inner.value.impl_span.clone())
1019                                } else {
1020                                    None
1021                                }
1022                            })
1023                            .collect::<Vec<Span>>()
1024                    })
1025                    .collect::<Vec<Vec<Span>>>()
1026                    .concat(),
1027            );
1028            Ok(None::<()>)
1029        });
1030
1031        spans.concat()
1032    }
1033
1034    /// Find the entries in `self` that are equivalent to `type_id` with trait
1035    /// name `trait_name` and with trait type arguments.
1036    ///
1037    /// Notes:
1038    /// - equivalency is defined (1) based on whether the types contains types
1039    ///   that are dynamic and can change and (2) whether the types hold
1040    ///   equivalency after (1) is fulfilled
1041    /// - this method does not translate types from the found entries to the
1042    ///   `type_id` (like in `filter_by_type()`). This is because the only
1043    ///   entries that qualify as hits are equivalents of `type_id`
1044    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments(
1045        module: &Module,
1046        engines: &Engines,
1047        type_id: TypeId,
1048        trait_name: &CallPath,
1049        trait_type_args: &[GenericArgument],
1050    ) -> Vec<ResolvedTraitImplItem> {
1051        let type_id = engines.te().get_unaliased_type_id(type_id);
1052
1053        let type_engine = engines.te();
1054        let unify_check = UnifyCheck::constraint_subset(engines);
1055        let mut items = vec![];
1056        // small performance gain in bad case
1057        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1058            return items;
1059        }
1060        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1061            lexical_scope
1062                .items
1063                .implemented_traits
1064                .for_each_impls(engines, type_id, false, |e| {
1065                    let map_trait_name = CallPath {
1066                        prefixes: e.inner.key.name.prefixes.clone(),
1067                        suffix: e.inner.key.name.suffix.name.clone(),
1068                        callpath_type: e.inner.key.name.callpath_type,
1069                    };
1070                    if &map_trait_name == trait_name
1071                        && unify_check.check(type_id, e.inner.key.type_id)
1072                        && trait_type_args.len() == e.inner.key.name.suffix.args.len()
1073                        && trait_type_args
1074                            .iter()
1075                            .zip(e.inner.key.name.suffix.args.iter())
1076                            .all(|(t1, t2)| unify_check.check(t1.type_id(), t2.type_id()))
1077                    {
1078                        let type_mapping = TypeSubstMap::from_superset_and_subset(
1079                            engines,
1080                            e.inner.key.type_id,
1081                            type_id,
1082                        );
1083
1084                        let mut trait_items = Self::filter_dummy_methods(
1085                            &e.inner.value.trait_items,
1086                            type_id,
1087                            e.inner.key.type_id,
1088                            engines,
1089                        )
1090                        .map(|(_, i)| {
1091                            Self::make_item_for_type_mapping(
1092                                engines,
1093                                i,
1094                                type_mapping.clone(),
1095                                type_id,
1096                                CodeBlockFirstPass::No,
1097                            )
1098                        })
1099                        .collect::<Vec<_>>();
1100
1101                        items.append(&mut trait_items);
1102                    }
1103                });
1104            Ok(None::<()>)
1105        });
1106        items
1107    }
1108
1109    /// Find the entries in `self` that are equivalent to `type_id` with trait
1110    /// name `trait_name` and with trait type arguments.
1111    ///
1112    /// Notes:
1113    /// - equivalency is defined (1) based on whether the types contains types
1114    ///   that are dynamic and can change and (2) whether the types hold
1115    ///   equivalency after (1) is fulfilled
1116    /// - this method does not translate types from the found entries to the
1117    ///   `type_id` (like in `filter_by_type()`). This is because the only
1118    //    entries that qualify as hits are equivalents of `type_id`
1119    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments_typed(
1120        module: &Module,
1121        engines: &Engines,
1122        type_id: TypeId,
1123        trait_name: &CallPath,
1124        trait_type_args: &[GenericArgument],
1125    ) -> Vec<ty::TyTraitItem> {
1126        TraitMap::get_items_for_type_and_trait_name_and_trait_type_arguments(
1127            module,
1128            engines,
1129            type_id,
1130            trait_name,
1131            trait_type_args,
1132        )
1133        .into_iter()
1134        .map(|item| item.expect_typed())
1135        .collect::<Vec<_>>()
1136    }
1137
1138    pub(crate) fn get_trait_names_and_type_arguments_for_type(
1139        module: &Module,
1140        engines: &Engines,
1141        type_id: TypeId,
1142    ) -> Vec<(CallPath, Vec<GenericArgument>)> {
1143        let type_id = engines.te().get_unaliased_type_id(type_id);
1144
1145        let type_engine = engines.te();
1146        let unify_check = UnifyCheck::constraint_subset(engines);
1147        let mut trait_names = vec![];
1148        // small performance gain in bad case
1149        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1150            return trait_names;
1151        }
1152        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1153            lexical_scope.items.implemented_traits.for_each_impls(
1154                engines,
1155                type_id,
1156                false,
1157                |entry| {
1158                    if unify_check.check(type_id, entry.inner.key.type_id) {
1159                        let trait_call_path = CallPath {
1160                            prefixes: entry.inner.key.name.prefixes.clone(),
1161                            suffix: entry.inner.key.name.suffix.name.clone(),
1162                            callpath_type: entry.inner.key.name.callpath_type,
1163                        };
1164                        trait_names
1165                            .push((trait_call_path, entry.inner.key.name.suffix.args.clone()));
1166                    }
1167                },
1168            );
1169            Ok(None::<()>)
1170        });
1171        trait_names
1172    }
1173
1174    /// Returns true if the type represented by the `type_id` implements
1175    /// any trait that satisfies the `predicate`.
1176    pub(crate) fn type_implements_trait<F: Fn(&SharedTraitEntry) -> bool>(
1177        module: &Module,
1178        engines: &Engines,
1179        type_id: TypeId,
1180        predicate: F,
1181    ) -> bool {
1182        let type_id = engines.te().get_unaliased_type_id(type_id);
1183
1184        // small performance gain in bad case
1185        if matches!(&*engines.te().get(type_id), TypeInfo::ErrorRecovery(_)) {
1186            return false;
1187        }
1188
1189        let unify_check = UnifyCheck::constraint_subset(engines);
1190        let mut implements_trait = false;
1191        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1192            lexical_scope.items.implemented_traits.for_each_impls(
1193                engines,
1194                type_id,
1195                false,
1196                |entry| {
1197                    // We don't have a suitable way to cancel traversal, so we just
1198                    // skip the checks if any of the previous traits has already matched.
1199                    if !implements_trait
1200                        && unify_check.check(type_id, entry.inner.key.type_id)
1201                        && predicate(entry)
1202                    {
1203                        implements_trait = true;
1204                    }
1205                },
1206            );
1207            Ok(None::<()>)
1208        });
1209        implements_trait
1210    }
1211
1212    pub(crate) fn get_trait_item_for_type(
1213        module: &Module,
1214        handler: &Handler,
1215        engines: &Engines,
1216        symbol: &Ident,
1217        type_id: TypeId,
1218        as_trait: Option<CallPath>,
1219    ) -> Result<ResolvedTraitImplItem, ErrorEmitted> {
1220        let type_id = engines.te().get_unaliased_type_id(type_id);
1221
1222        let mut candidates = HashMap::<String, ResolvedTraitImplItem>::new();
1223
1224        TraitMap::find_items_and_trait_key_for_type(
1225            module,
1226            engines,
1227            type_id,
1228            &mut |trait_item, trait_key| match trait_item {
1229                ResolvedTraitImplItem::Parsed(impl_item) => match impl_item {
1230                    ImplItem::Fn(fn_ref) => {
1231                        let decl = engines.pe().get_function(&fn_ref);
1232                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1233                        if decl.name.as_str() == symbol.as_str()
1234                            && (as_trait.is_none()
1235                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1236                        {
1237                            candidates.insert(
1238                                trait_call_path_string,
1239                                ResolvedTraitImplItem::Parsed(ImplItem::Fn(fn_ref)),
1240                            );
1241                        }
1242                    }
1243                    ImplItem::Constant(const_ref) => {
1244                        let decl = engines.pe().get_constant(&const_ref);
1245                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1246                        if decl.name.as_str() == symbol.as_str()
1247                            && (as_trait.is_none()
1248                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1249                        {
1250                            candidates.insert(
1251                                trait_call_path_string,
1252                                ResolvedTraitImplItem::Parsed(ImplItem::Constant(const_ref)),
1253                            );
1254                        }
1255                    }
1256                    ImplItem::Type(type_ref) => {
1257                        let decl = engines.pe().get_trait_type(&type_ref);
1258                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1259                        if decl.name.as_str() == symbol.as_str()
1260                            && (as_trait.is_none()
1261                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1262                        {
1263                            candidates.insert(
1264                                trait_call_path_string,
1265                                ResolvedTraitImplItem::Parsed(ImplItem::Type(type_ref)),
1266                            );
1267                        }
1268                    }
1269                },
1270                ResolvedTraitImplItem::Typed(ty_impl_item) => match ty_impl_item {
1271                    ty::TyTraitItem::Fn(fn_ref) => {
1272                        let decl = engines.de().get_function(&fn_ref);
1273                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1274                        if decl.name.as_str() == symbol.as_str()
1275                            && (as_trait.is_none()
1276                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1277                        {
1278                            candidates.insert(
1279                                trait_call_path_string,
1280                                ResolvedTraitImplItem::Typed(TyTraitItem::Fn(fn_ref)),
1281                            );
1282                        }
1283                    }
1284                    ty::TyTraitItem::Constant(const_ref) => {
1285                        let decl = engines.de().get_constant(&const_ref);
1286                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1287                        if decl.call_path.suffix.as_str() == symbol.as_str()
1288                            && (as_trait.is_none()
1289                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1290                        {
1291                            candidates.insert(
1292                                trait_call_path_string,
1293                                ResolvedTraitImplItem::Typed(TyTraitItem::Constant(const_ref)),
1294                            );
1295                        }
1296                    }
1297                    ty::TyTraitItem::Type(type_ref) => {
1298                        let decl = engines.de().get_type(&type_ref);
1299                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1300                        if decl.name.as_str() == symbol.as_str()
1301                            && (as_trait.is_none()
1302                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1303                        {
1304                            candidates.insert(
1305                                trait_call_path_string,
1306                                ResolvedTraitImplItem::Typed(TyTraitItem::Type(type_ref)),
1307                            );
1308                        }
1309                    }
1310                },
1311            },
1312        );
1313
1314        match candidates.len().cmp(&1) {
1315            Ordering::Greater => Err(handler.emit_err(
1316                CompileError::MultipleApplicableItemsInScope {
1317                    item_name: symbol.as_str().to_string(),
1318                    item_kind: "item".to_string(),
1319                    as_traits: candidates
1320                        .keys()
1321                        .map(|k| {
1322                            (
1323                                k.clone()
1324                                    .split("::")
1325                                    .collect::<Vec<_>>()
1326                                    .last()
1327                                    .unwrap()
1328                                    .to_string(),
1329                                engines.help_out(type_id).to_string(),
1330                            )
1331                        })
1332                        .collect::<Vec<_>>(),
1333                    span: symbol.span(),
1334                },
1335            )),
1336            Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound {
1337                name: symbol.clone(),
1338                span: symbol.span(),
1339            })),
1340            Ordering::Equal => Ok(candidates.values().next().unwrap().clone()),
1341        }
1342    }
1343
1344    /// Checks to see if the trait constraints are satisfied for a given type.
1345    #[allow(clippy::too_many_arguments)]
1346    pub(crate) fn check_if_trait_constraints_are_satisfied_for_type(
1347        handler: &Handler,
1348        module: &mut Module,
1349        type_id: TypeId,
1350        constraints: &[TraitConstraint],
1351        access_span: &Span,
1352        engines: &Engines,
1353    ) -> Result<(), ErrorEmitted> {
1354        let type_engine = engines.te();
1355
1356        let type_id = type_engine.get_unaliased_type_id(type_id);
1357
1358        // resolving trait constraints require a concrete type, we need to default numeric to u64
1359        type_engine.decay_numeric(handler, engines, type_id, access_span)?;
1360
1361        if constraints.is_empty() {
1362            return Ok(());
1363        }
1364
1365        // Check we can use the cache
1366        let mut hasher = DefaultHasher::default();
1367        type_id.hash(&mut hasher);
1368        for c in constraints {
1369            c.hash(&mut hasher, engines);
1370        }
1371        let hash = hasher.finish();
1372
1373        {
1374            let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1375            if trait_map.satisfied_cache.contains(&hash) {
1376                return Ok(());
1377            }
1378        }
1379
1380        let all_impld_traits: BTreeSet<(Ident, TypeId)> =
1381            Self::get_all_implemented_traits(module, type_id, engines);
1382
1383        // Call the real implementation and cache when true
1384        match Self::check_if_trait_constraints_are_satisfied_for_type_inner(
1385            handler,
1386            type_id,
1387            constraints,
1388            access_span,
1389            engines,
1390            all_impld_traits,
1391        ) {
1392            Ok(()) => {
1393                let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1394                trait_map.satisfied_cache.insert(hash);
1395                Ok(())
1396            }
1397            r => r,
1398        }
1399    }
1400
1401    fn get_all_implemented_traits(
1402        module: &Module,
1403        type_id: TypeId,
1404        engines: &Engines,
1405    ) -> BTreeSet<(Ident, TypeId)> {
1406        let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default();
1407        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1408            all_impld_traits.extend(
1409                lexical_scope
1410                    .items
1411                    .implemented_traits
1412                    .get_implemented_traits(type_id, engines),
1413            );
1414            Ok(None::<()>)
1415        });
1416        all_impld_traits
1417    }
1418
1419    fn get_implemented_traits(
1420        &self,
1421        type_id: TypeId,
1422        engines: &Engines,
1423    ) -> BTreeSet<(Ident, TypeId)> {
1424        let type_engine = engines.te();
1425        let unify_check = UnifyCheck::constraint_subset(engines);
1426        let mut all_impld_traits = BTreeSet::<(Ident, TypeId)>::new();
1427        self.for_each_impls(engines, type_id, true, |e| {
1428            let key = &e.inner.key;
1429            let suffix = &key.name.suffix;
1430            if unify_check.check(type_id, key.type_id) {
1431                let map_trait_type_id = type_engine.new_custom(
1432                    engines,
1433                    suffix.name.clone().into(),
1434                    if suffix.args.is_empty() {
1435                        None
1436                    } else {
1437                        Some(suffix.args.to_vec())
1438                    },
1439                );
1440                all_impld_traits.insert((suffix.name.clone(), map_trait_type_id));
1441            }
1442        });
1443        all_impld_traits
1444    }
1445
1446    #[allow(clippy::too_many_arguments)]
1447    fn check_if_trait_constraints_are_satisfied_for_type_inner(
1448        handler: &Handler,
1449        type_id: TypeId,
1450        constraints: &[TraitConstraint],
1451        access_span: &Span,
1452        engines: &Engines,
1453        all_impld_traits: BTreeSet<(Ident, TypeId)>,
1454    ) -> Result<(), ErrorEmitted> {
1455        let type_engine = engines.te();
1456        let unify_check = UnifyCheck::constraint_subset(engines);
1457
1458        let required_traits: BTreeSet<(Ident, TypeId)> = constraints
1459            .iter()
1460            .map(|c| {
1461                let TraitConstraint {
1462                    trait_name: constraint_trait_name,
1463                    type_arguments: constraint_type_arguments,
1464                } = c;
1465                let constraint_type_id = type_engine.new_custom(
1466                    engines,
1467                    constraint_trait_name.suffix.clone().into(),
1468                    if constraint_type_arguments.is_empty() {
1469                        None
1470                    } else {
1471                        Some(constraint_type_arguments.clone())
1472                    },
1473                );
1474                (c.trait_name.suffix.clone(), constraint_type_id)
1475            })
1476            .collect();
1477
1478        let traits_not_found: BTreeSet<(BaseIdent, TypeId)> = required_traits
1479            .into_iter()
1480            .filter(|(required_trait_name, required_trait_type_id)| {
1481                !all_impld_traits
1482                    .iter()
1483                    .any(|(trait_name, constraint_type_id)| {
1484                        trait_name == required_trait_name
1485                            && unify_check.check(*constraint_type_id, *required_trait_type_id)
1486                    })
1487            })
1488            .collect();
1489
1490        handler.scope(|handler| {
1491            for (trait_name, constraint_type_id) in traits_not_found.iter() {
1492                let mut type_arguments_string = "".to_string();
1493                if let TypeInfo::Custom {
1494                    qualified_call_path: _,
1495                    type_arguments: Some(type_arguments),
1496                } = &*type_engine.get(*constraint_type_id)
1497                {
1498                    type_arguments_string = format!("<{}>", engines.help_out(type_arguments));
1499                }
1500
1501                // TODO: use a better span
1502                handler.emit_err(CompileError::TraitConstraintNotSatisfied {
1503                    type_id: type_id.index(),
1504                    ty: engines.help_out(type_id).to_string(),
1505                    trait_name: format!("{}{}", trait_name, type_arguments_string),
1506                    span: access_span.clone(),
1507                });
1508            }
1509
1510            Ok(())
1511        })
1512    }
1513
1514    pub fn get_trait_constraints_are_satisfied_for_types(
1515        module: &Module,
1516        _handler: &Handler,
1517        type_id: TypeId,
1518        constraints: &[TraitConstraint],
1519        engines: &Engines,
1520    ) -> Result<Vec<(TypeId, String)>, ErrorEmitted> {
1521        let type_id = engines.te().get_unaliased_type_id(type_id);
1522
1523        let _decl_engine = engines.de();
1524        let unify_check = UnifyCheck::coercion(engines);
1525        let unify_check_equality = UnifyCheck::constraint_subset(engines);
1526
1527        let mut impld_traits_type_ids: Vec<Vec<(TypeId, String)>> = vec![];
1528        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1529            lexical_scope
1530                .items
1531                .implemented_traits
1532                .for_each_impls(engines, type_id, true, |e| {
1533                    let mut traits: Vec<(TypeId, String)> = vec![];
1534
1535                    let key = &e.inner.key;
1536                    for constraint in constraints {
1537                        if key.name.suffix.name == constraint.trait_name.suffix
1538                            && key
1539                                .name
1540                                .suffix
1541                                .args
1542                                .iter()
1543                                .zip(constraint.type_arguments.iter())
1544                                .all(|(a1, a2)| {
1545                                    unify_check_equality.check(a1.type_id(), a2.type_id())
1546                                })
1547                            && unify_check.check(type_id, key.type_id)
1548                        {
1549                            let name_type_args = if !key.name.suffix.args.is_empty() {
1550                                format!("<{}>", engines.help_out(key.name.suffix.args.clone()))
1551                            } else {
1552                                "".to_string()
1553                            };
1554                            let name =
1555                                format!("{}{}", key.name.suffix.name.as_str(), name_type_args);
1556                            traits.push((key.type_id, name));
1557                            break;
1558                        }
1559                    }
1560                    impld_traits_type_ids.push(traits);
1561                });
1562
1563            Ok(None::<()>)
1564        });
1565        Ok(impld_traits_type_ids.concat())
1566    }
1567
1568    fn get_impls_mut(&mut self, engines: &Engines, type_id: TypeId) -> &mut Vec<SharedTraitEntry> {
1569        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1570        if !self.trait_impls.contains_key(&type_root_filter) {
1571            self.trait_impls
1572                .insert(type_root_filter.clone(), Vec::new());
1573        }
1574
1575        self.trait_impls.get_mut(&type_root_filter).unwrap()
1576    }
1577
1578    pub(crate) fn for_each_impls<F>(
1579        &self,
1580        engines: &Engines,
1581        type_id: TypeId,
1582        include_placeholder: bool,
1583        mut callback: F,
1584    ) where
1585        F: FnMut(&SharedTraitEntry),
1586    {
1587        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1588        self.trait_impls
1589            .get(&type_root_filter)
1590            .iter()
1591            .for_each(|vec| vec.iter().for_each(&mut callback));
1592        if include_placeholder && type_root_filter != TypeRootFilter::Placeholder {
1593            self.trait_impls
1594                .get(&TypeRootFilter::Placeholder)
1595                .iter()
1596                .for_each(|vec| vec.iter().for_each(&mut callback));
1597        }
1598    }
1599
1600    // Return a string representing only the base type.
1601    // This is used by the trait map to filter the entries into a HashMap with the return type string as key.
1602    fn get_type_root_filter(engines: &Engines, type_id: TypeId) -> TypeRootFilter {
1603        use TypeInfo::*;
1604        match &*engines.te().get(type_id) {
1605            Unknown => TypeRootFilter::Unknown,
1606            Never => TypeRootFilter::Never,
1607            UnknownGeneric { .. } | Placeholder(_) => TypeRootFilter::Placeholder,
1608            TypeParam(_param) => unreachable!(),
1609            StringSlice => TypeRootFilter::StringSlice,
1610            StringArray(_) => TypeRootFilter::StringArray,
1611            UnsignedInteger(x) => match x {
1612                IntegerBits::Eight => TypeRootFilter::U8,
1613                IntegerBits::Sixteen => TypeRootFilter::U16,
1614                IntegerBits::ThirtyTwo => TypeRootFilter::U32,
1615                IntegerBits::SixtyFour => TypeRootFilter::U64,
1616                IntegerBits::V256 => TypeRootFilter::U256,
1617            },
1618            Boolean => TypeRootFilter::Bool,
1619            Custom {
1620                qualified_call_path: call_path,
1621                ..
1622            } => TypeRootFilter::Custom(call_path.call_path.suffix.to_string()),
1623            B256 => TypeRootFilter::B256,
1624            Numeric => TypeRootFilter::U64, // u64 is the default
1625            Contract => TypeRootFilter::Contract,
1626            ErrorRecovery(_) => TypeRootFilter::ErrorRecovery,
1627            Tuple(fields) => TypeRootFilter::Tuple(fields.len()),
1628            UntypedEnum(decl_id) => TypeRootFilter::Enum(*decl_id),
1629            UntypedStruct(decl_id) => TypeRootFilter::Struct(*decl_id),
1630            Enum(decl_id) => {
1631                // TODO Remove unwrap once #6475 is fixed
1632                TypeRootFilter::Enum(engines.de().get_parsed_decl_id(decl_id).unwrap())
1633            }
1634            Struct(decl_id) => {
1635                // TODO Remove unwrap once #6475 is fixed
1636                TypeRootFilter::Struct(engines.de().get_parsed_decl_id(decl_id).unwrap())
1637            }
1638            ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()),
1639            Array(_, _) => TypeRootFilter::Array,
1640            RawUntypedPtr => TypeRootFilter::RawUntypedPtr,
1641            RawUntypedSlice => TypeRootFilter::RawUntypedSlice,
1642            Ptr(_) => TypeRootFilter::Ptr,
1643            Slice(_) => TypeRootFilter::Slice,
1644            Alias { ty, .. } => Self::get_type_root_filter(engines, ty.type_id()),
1645            TraitType { name, .. } => TypeRootFilter::TraitType(name.to_string()),
1646            Ref {
1647                referenced_type, ..
1648            } => Self::get_type_root_filter(engines, referenced_type.type_id()),
1649        }
1650    }
1651}