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