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        handler: &Handler,
987        engines: &Engines,
988        item: ResolvedTraitImplItem,
989        mut type_mapping: TypeSubstMap,
990        type_id: TypeId,
991        code_block_first_pass: CodeBlockFirstPass,
992    ) -> ResolvedTraitImplItem {
993        let decl_engine = engines.de();
994        match &item {
995            ResolvedTraitImplItem::Parsed(_item) => todo!(),
996            ResolvedTraitImplItem::Typed(item) => match item {
997                ty::TyTraitItem::Fn(decl_ref) => {
998                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
999                    if let Some(decl_implementing_for) = decl.implementing_for {
1000                        type_mapping.insert(decl_implementing_for, type_id);
1001                    }
1002                    decl.subst(&SubstTypesContext::new(
1003                        handler,
1004                        engines,
1005                        &type_mapping,
1006                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
1007                    ));
1008
1009                    let new_ref = decl_engine
1010                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref())
1011                        .with_parent(decl_engine, decl_ref.id().into());
1012
1013                    ResolvedTraitImplItem::Typed(TyImplItem::Fn(new_ref))
1014                }
1015                ty::TyTraitItem::Constant(decl_ref) => {
1016                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
1017                    decl.subst(&SubstTypesContext::new(
1018                        handler,
1019                        engines,
1020                        &type_mapping,
1021                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
1022                    ));
1023                    let new_ref = decl_engine
1024                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
1025                    ResolvedTraitImplItem::Typed(TyImplItem::Constant(new_ref))
1026                }
1027                ty::TyTraitItem::Type(decl_ref) => {
1028                    let mut decl = (*decl_engine.get(decl_ref.id())).clone();
1029                    decl.subst(&SubstTypesContext::new(
1030                        handler,
1031                        engines,
1032                        &type_mapping,
1033                        matches!(code_block_first_pass, CodeBlockFirstPass::No),
1034                    ));
1035                    let new_ref = decl_engine
1036                        .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
1037                    ResolvedTraitImplItem::Typed(TyImplItem::Type(new_ref))
1038                }
1039            },
1040        }
1041    }
1042
1043    /// Find the entries in `self` that are equivalent to `type_id`.
1044    ///
1045    /// Notes:
1046    /// - equivalency is defined (1) based on whether the types contains types
1047    ///   that are dynamic and can change and (2) whether the types hold
1048    ///   equivalency after (1) is fulfilled
1049    /// - this method does not translate types from the found entries to the
1050    ///   `type_id` (like in `filter_by_type()`). This is because the only
1051    ///   entries that qualify as hits are equivalents of `type_id`
1052    pub(crate) fn append_items_for_type(
1053        module: &Module,
1054        engines: &Engines,
1055        type_id: TypeId,
1056        items: &mut Vec<ResolvedTraitImplItem>,
1057    ) {
1058        TraitMap::find_items_and_trait_key_for_type(module, engines, type_id, &mut |item, _| {
1059            items.push(item);
1060        });
1061    }
1062
1063    pub(crate) fn find_items_and_trait_key_for_type(
1064        module: &Module,
1065        engines: &Engines,
1066        type_id: TypeId,
1067        callback: &mut impl FnMut(ResolvedTraitImplItem, TraitKey),
1068    ) {
1069        let type_engine = engines.te();
1070        let type_id = engines.te().get_unaliased_type_id(type_id);
1071
1072        // small performance gain in bad case
1073        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1074            return;
1075        }
1076
1077        let unify_check = UnifyCheck::constraint_subset(engines);
1078
1079        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1080            lexical_scope.items.implemented_traits.for_each_impls(
1081                engines,
1082                type_id,
1083                true,
1084                |entry| {
1085                    if unify_check.check(type_id, entry.inner.key.type_id) {
1086                        let trait_items = Self::filter_dummy_methods(
1087                            &entry.inner.value.trait_items,
1088                            type_id,
1089                            entry.inner.key.type_id,
1090                            engines,
1091                        )
1092                        .map(|(_, i)| (i, entry.inner.key.clone()));
1093
1094                        for i in trait_items {
1095                            callback(i.0, i.1);
1096                        }
1097                    }
1098                },
1099            );
1100
1101            Ok(None::<()>)
1102        });
1103    }
1104
1105    /// Find the spans of all impls for the given type.
1106    ///
1107    /// Notes:
1108    /// - equivalency is defined (1) based on whether the types contains types
1109    ///   that are dynamic and can change and (2) whether the types hold
1110    ///   equivalency after (1) is fulfilled
1111    /// - this method does not translate types from the found entries to the
1112    ///   `type_id` (like in `filter_by_type()`). This is because the only
1113    ///   entries that qualify as hits are equivalents of `type_id`
1114    pub fn get_impl_spans_for_type(
1115        module: &Module,
1116        engines: &Engines,
1117        type_id: &TypeId,
1118    ) -> Vec<Span> {
1119        let type_engine = engines.te();
1120        let unify_check = UnifyCheck::constraint_subset(engines);
1121
1122        let type_id = &engines.te().get_unaliased_type_id(*type_id);
1123
1124        let mut spans = vec![];
1125        // small performance gain in bad case
1126        if matches!(&*type_engine.get(*type_id), TypeInfo::ErrorRecovery(_)) {
1127            return spans;
1128        }
1129        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1130            lexical_scope.items.implemented_traits.for_each_impls(
1131                engines,
1132                *type_id,
1133                false,
1134                |entry| {
1135                    if unify_check.check(*type_id, entry.inner.key.type_id) {
1136                        spans.push(entry.inner.value.impl_span.clone());
1137                    }
1138                },
1139            );
1140
1141            Ok(None::<()>)
1142        });
1143
1144        spans
1145    }
1146
1147    /// Find the spans of all impls for the given decl.
1148    pub fn get_impl_spans_for_decl(
1149        module: &Module,
1150        engines: &Engines,
1151        ty_decl: &TyDecl,
1152    ) -> Vec<Span> {
1153        let handler = Handler::default();
1154        ty_decl
1155            .return_type(&handler, engines)
1156            .map(|type_id| TraitMap::get_impl_spans_for_type(module, engines, &type_id))
1157            .unwrap_or_default()
1158    }
1159
1160    /// Find the entries in `self` with trait name `trait_name` and return the
1161    /// spans of the impls.
1162    pub fn get_impl_spans_for_trait_name(module: &Module, trait_name: &CallPath) -> Vec<Span> {
1163        let mut spans = vec![];
1164        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1165            spans.push(
1166                lexical_scope
1167                    .items
1168                    .implemented_traits
1169                    .trait_impls
1170                    .values()
1171                    .map(|impls| {
1172                        impls
1173                            .iter()
1174                            .filter_map(|entry| {
1175                                let map_trait_name = CallPath {
1176                                    prefixes: entry.inner.key.name.prefixes.clone(),
1177                                    suffix: entry.inner.key.name.suffix.name.clone(),
1178                                    callpath_type: entry.inner.key.name.callpath_type,
1179                                };
1180                                if &map_trait_name == trait_name {
1181                                    Some(entry.inner.value.impl_span.clone())
1182                                } else {
1183                                    None
1184                                }
1185                            })
1186                            .collect::<Vec<Span>>()
1187                    })
1188                    .collect::<Vec<Vec<Span>>>()
1189                    .concat(),
1190            );
1191            Ok(None::<()>)
1192        });
1193
1194        spans.concat()
1195    }
1196
1197    /// Find the entries in `self` that are equivalent to `type_id` with trait
1198    /// name `trait_name` and with trait type arguments.
1199    ///
1200    /// Notes:
1201    /// - equivalency is defined (1) based on whether the types contains types
1202    ///   that are dynamic and can change and (2) whether the types hold
1203    ///   equivalency after (1) is fulfilled
1204    /// - this method does not translate types from the found entries to the
1205    ///   `type_id` (like in `filter_by_type()`). This is because the only
1206    ///   entries that qualify as hits are equivalents of `type_id`
1207    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments(
1208        handler: &Handler,
1209        module: &Module,
1210        engines: &Engines,
1211        type_id: TypeId,
1212        trait_name: &CallPath,
1213        trait_type_args: &[GenericArgument],
1214    ) -> Vec<ResolvedTraitImplItem> {
1215        let type_id = engines.te().get_unaliased_type_id(type_id);
1216
1217        let type_engine = engines.te();
1218        let unify_check = UnifyCheck::constraint_subset(engines);
1219        let mut items = vec![];
1220        // small performance gain in bad case
1221        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1222            return items;
1223        }
1224        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1225            lexical_scope
1226                .items
1227                .implemented_traits
1228                .for_each_impls(engines, type_id, false, |e| {
1229                    let map_trait_name = CallPath {
1230                        prefixes: e.inner.key.name.prefixes.clone(),
1231                        suffix: e.inner.key.name.suffix.name.clone(),
1232                        callpath_type: e.inner.key.name.callpath_type,
1233                    };
1234                    if &map_trait_name == trait_name
1235                        && unify_check.check(type_id, e.inner.key.type_id)
1236                        && trait_type_args.len() == e.inner.key.name.suffix.args.len()
1237                        && trait_type_args
1238                            .iter()
1239                            .zip(e.inner.key.name.suffix.args.iter())
1240                            .all(|(t1, t2)| unify_check.check(t1.type_id(), t2.type_id()))
1241                    {
1242                        let type_mapping = TypeSubstMap::from_superset_and_subset(
1243                            engines,
1244                            e.inner.key.type_id,
1245                            type_id,
1246                        );
1247
1248                        let mut trait_items = Self::filter_dummy_methods(
1249                            &e.inner.value.trait_items,
1250                            type_id,
1251                            e.inner.key.type_id,
1252                            engines,
1253                        )
1254                        .map(|(_, i)| {
1255                            Self::make_item_for_type_mapping(
1256                                handler,
1257                                engines,
1258                                i,
1259                                type_mapping.clone(),
1260                                type_id,
1261                                CodeBlockFirstPass::No,
1262                            )
1263                        })
1264                        .collect::<Vec<_>>();
1265
1266                        items.append(&mut trait_items);
1267                    }
1268                });
1269            Ok(None::<()>)
1270        });
1271        items
1272    }
1273
1274    /// Find the entries in `self` that are equivalent to `type_id` with trait
1275    /// name `trait_name` and with trait type arguments.
1276    ///
1277    /// Notes:
1278    /// - equivalency is defined (1) based on whether the types contains types
1279    ///   that are dynamic and can change and (2) whether the types hold
1280    ///   equivalency after (1) is fulfilled
1281    /// - this method does not translate types from the found entries to the
1282    ///   `type_id` (like in `filter_by_type()`). This is because the only
1283    //    entries that qualify as hits are equivalents of `type_id`
1284    pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments_typed(
1285        handler: &Handler,
1286        module: &Module,
1287        engines: &Engines,
1288        type_id: TypeId,
1289        trait_name: &CallPath,
1290        trait_type_args: &[GenericArgument],
1291    ) -> Vec<ty::TyTraitItem> {
1292        TraitMap::get_items_for_type_and_trait_name_and_trait_type_arguments(
1293            handler,
1294            module,
1295            engines,
1296            type_id,
1297            trait_name,
1298            trait_type_args,
1299        )
1300        .into_iter()
1301        .map(|item| item.expect_typed())
1302        .collect::<Vec<_>>()
1303    }
1304
1305    pub(crate) fn get_trait_names_and_type_arguments_for_type(
1306        module: &Module,
1307        engines: &Engines,
1308        type_id: TypeId,
1309    ) -> Vec<(CallPath, Vec<GenericArgument>)> {
1310        let type_id = engines.te().get_unaliased_type_id(type_id);
1311
1312        let type_engine = engines.te();
1313        let unify_check = UnifyCheck::constraint_subset(engines);
1314        let mut trait_names = vec![];
1315        // small performance gain in bad case
1316        if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1317            return trait_names;
1318        }
1319        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1320            lexical_scope.items.implemented_traits.for_each_impls(
1321                engines,
1322                type_id,
1323                false,
1324                |entry| {
1325                    if unify_check.check(type_id, entry.inner.key.type_id) {
1326                        let trait_call_path = CallPath {
1327                            prefixes: entry.inner.key.name.prefixes.clone(),
1328                            suffix: entry.inner.key.name.suffix.name.clone(),
1329                            callpath_type: entry.inner.key.name.callpath_type,
1330                        };
1331                        trait_names
1332                            .push((trait_call_path, entry.inner.key.name.suffix.args.clone()));
1333                    }
1334                },
1335            );
1336            Ok(None::<()>)
1337        });
1338        trait_names
1339    }
1340
1341    /// Returns true if the type represented by the `type_id` implements
1342    /// any trait that satisfies the `predicate`.
1343    pub(crate) fn type_implements_trait<F: Fn(&SharedTraitEntry) -> bool>(
1344        module: &Module,
1345        engines: &Engines,
1346        type_id: TypeId,
1347        predicate: F,
1348    ) -> bool {
1349        let type_id = engines.te().get_unaliased_type_id(type_id);
1350
1351        // small performance gain in bad case
1352        if matches!(&*engines.te().get(type_id), TypeInfo::ErrorRecovery(_)) {
1353            return false;
1354        }
1355
1356        let unify_check = UnifyCheck::constraint_subset(engines);
1357        let mut implements_trait = false;
1358        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1359            lexical_scope.items.implemented_traits.for_each_impls(
1360                engines,
1361                type_id,
1362                false,
1363                |entry| {
1364                    // We don't have a suitable way to cancel traversal, so we just
1365                    // skip the checks if any of the previous traits has already matched.
1366                    if !implements_trait
1367                        && unify_check.check(type_id, entry.inner.key.type_id)
1368                        && predicate(entry)
1369                    {
1370                        implements_trait = true;
1371                    }
1372                },
1373            );
1374            Ok(None::<()>)
1375        });
1376        implements_trait
1377    }
1378
1379    pub(crate) fn get_trait_item_for_type(
1380        module: &Module,
1381        handler: &Handler,
1382        engines: &Engines,
1383        symbol: &Ident,
1384        type_id: TypeId,
1385        as_trait: Option<CallPath>,
1386    ) -> Result<ResolvedTraitImplItem, ErrorEmitted> {
1387        let type_id = engines.te().get_unaliased_type_id(type_id);
1388
1389        let mut candidates = HashMap::<String, ResolvedTraitImplItem>::new();
1390
1391        TraitMap::find_items_and_trait_key_for_type(
1392            module,
1393            engines,
1394            type_id,
1395            &mut |trait_item, trait_key| match trait_item {
1396                ResolvedTraitImplItem::Parsed(impl_item) => match impl_item {
1397                    ImplItem::Fn(fn_ref) => {
1398                        let decl = engines.pe().get_function(&fn_ref);
1399                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1400                        if decl.name.as_str() == symbol.as_str()
1401                            && (as_trait.is_none()
1402                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1403                        {
1404                            candidates.insert(
1405                                trait_call_path_string,
1406                                ResolvedTraitImplItem::Parsed(ImplItem::Fn(fn_ref)),
1407                            );
1408                        }
1409                    }
1410                    ImplItem::Constant(const_ref) => {
1411                        let decl = engines.pe().get_constant(&const_ref);
1412                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1413                        if decl.name.as_str() == symbol.as_str()
1414                            && (as_trait.is_none()
1415                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1416                        {
1417                            candidates.insert(
1418                                trait_call_path_string,
1419                                ResolvedTraitImplItem::Parsed(ImplItem::Constant(const_ref)),
1420                            );
1421                        }
1422                    }
1423                    ImplItem::Type(type_ref) => {
1424                        let decl = engines.pe().get_trait_type(&type_ref);
1425                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1426                        if decl.name.as_str() == symbol.as_str()
1427                            && (as_trait.is_none()
1428                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1429                        {
1430                            candidates.insert(
1431                                trait_call_path_string,
1432                                ResolvedTraitImplItem::Parsed(ImplItem::Type(type_ref)),
1433                            );
1434                        }
1435                    }
1436                },
1437                ResolvedTraitImplItem::Typed(ty_impl_item) => match ty_impl_item {
1438                    ty::TyTraitItem::Fn(fn_ref) => {
1439                        let decl = engines.de().get_function(&fn_ref);
1440                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1441                        if decl.name.as_str() == symbol.as_str()
1442                            && (as_trait.is_none()
1443                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1444                        {
1445                            candidates.insert(
1446                                trait_call_path_string,
1447                                ResolvedTraitImplItem::Typed(TyTraitItem::Fn(fn_ref)),
1448                            );
1449                        }
1450                    }
1451                    ty::TyTraitItem::Constant(const_ref) => {
1452                        let decl = engines.de().get_constant(&const_ref);
1453                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1454                        if decl.call_path.suffix.as_str() == symbol.as_str()
1455                            && (as_trait.is_none()
1456                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1457                        {
1458                            candidates.insert(
1459                                trait_call_path_string,
1460                                ResolvedTraitImplItem::Typed(TyTraitItem::Constant(const_ref)),
1461                            );
1462                        }
1463                    }
1464                    ty::TyTraitItem::Type(type_ref) => {
1465                        let decl = engines.de().get_type(&type_ref);
1466                        let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1467                        if decl.name.as_str() == symbol.as_str()
1468                            && (as_trait.is_none()
1469                                || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1470                        {
1471                            candidates.insert(
1472                                trait_call_path_string,
1473                                ResolvedTraitImplItem::Typed(TyTraitItem::Type(type_ref)),
1474                            );
1475                        }
1476                    }
1477                },
1478            },
1479        );
1480
1481        match candidates.len().cmp(&1) {
1482            Ordering::Greater => Err(handler.emit_err(
1483                CompileError::MultipleApplicableItemsInScope {
1484                    item_name: symbol.as_str().to_string(),
1485                    item_kind: "item".to_string(),
1486                    as_traits: candidates
1487                        .keys()
1488                        .map(|k| {
1489                            (
1490                                k.clone()
1491                                    .split("::")
1492                                    .collect::<Vec<_>>()
1493                                    .last()
1494                                    .unwrap()
1495                                    .to_string(),
1496                                engines.help_out(type_id).to_string(),
1497                            )
1498                        })
1499                        .collect::<Vec<_>>(),
1500                    span: symbol.span(),
1501                },
1502            )),
1503            Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound {
1504                name: symbol.clone(),
1505                span: symbol.span(),
1506            })),
1507            Ordering::Equal => Ok(candidates.values().next().unwrap().clone()),
1508        }
1509    }
1510
1511    /// Checks to see if the trait constraints are satisfied for a given type.
1512    #[allow(clippy::too_many_arguments)]
1513    pub(crate) fn check_if_trait_constraints_are_satisfied_for_type(
1514        handler: &Handler,
1515        module: &mut Module,
1516        type_id: TypeId,
1517        constraints: &[TraitConstraint],
1518        access_span: &Span,
1519        engines: &Engines,
1520    ) -> Result<(), ErrorEmitted> {
1521        let type_engine = engines.te();
1522
1523        let type_id = type_engine.get_unaliased_type_id(type_id);
1524
1525        // resolving trait constraints require a concrete type, we need to default numeric to u64
1526        type_engine.decay_numeric(handler, engines, type_id, access_span)?;
1527
1528        if constraints.is_empty() {
1529            return Ok(());
1530        }
1531
1532        // Check we can use the cache
1533        let mut hasher = DefaultHasher::default();
1534        type_id.hash(&mut hasher);
1535        for c in constraints {
1536            c.hash(&mut hasher, engines);
1537        }
1538        let hash = hasher.finish();
1539
1540        {
1541            let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1542            if trait_map.satisfied_cache.contains(&hash) {
1543                return Ok(());
1544            }
1545        }
1546
1547        let all_impld_traits: BTreeSet<(Ident, TypeId)> =
1548            Self::get_all_implemented_traits(module, type_id, engines);
1549
1550        // Call the real implementation and cache when true
1551        match Self::check_if_trait_constraints_are_satisfied_for_type_inner(
1552            handler,
1553            type_id,
1554            constraints,
1555            access_span,
1556            engines,
1557            all_impld_traits,
1558        ) {
1559            Ok(()) => {
1560                let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1561                trait_map.satisfied_cache.insert(hash);
1562                Ok(())
1563            }
1564            r => r,
1565        }
1566    }
1567
1568    fn get_all_implemented_traits(
1569        module: &Module,
1570        type_id: TypeId,
1571        engines: &Engines,
1572    ) -> BTreeSet<(Ident, TypeId)> {
1573        let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default();
1574        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1575            all_impld_traits.extend(
1576                lexical_scope
1577                    .items
1578                    .implemented_traits
1579                    .get_implemented_traits(type_id, engines),
1580            );
1581            Ok(None::<()>)
1582        });
1583        all_impld_traits
1584    }
1585
1586    fn get_implemented_traits(
1587        &self,
1588        type_id: TypeId,
1589        engines: &Engines,
1590    ) -> BTreeSet<(Ident, TypeId)> {
1591        let type_engine = engines.te();
1592        let unify_check = UnifyCheck::constraint_subset(engines);
1593        let mut all_impld_traits = BTreeSet::<(Ident, TypeId)>::new();
1594        self.for_each_impls(engines, type_id, true, |e| {
1595            let key = &e.inner.key;
1596            let suffix = &key.name.suffix;
1597            if unify_check.check(type_id, key.type_id) {
1598                let map_trait_type_id = type_engine.new_custom(
1599                    engines,
1600                    suffix.name.clone().into(),
1601                    if suffix.args.is_empty() {
1602                        None
1603                    } else {
1604                        Some(suffix.args.to_vec())
1605                    },
1606                );
1607                all_impld_traits.insert((suffix.name.clone(), map_trait_type_id));
1608            }
1609        });
1610        all_impld_traits
1611    }
1612
1613    #[allow(clippy::too_many_arguments)]
1614    fn check_if_trait_constraints_are_satisfied_for_type_inner(
1615        handler: &Handler,
1616        type_id: TypeId,
1617        constraints: &[TraitConstraint],
1618        access_span: &Span,
1619        engines: &Engines,
1620        all_impld_traits: BTreeSet<(Ident, TypeId)>,
1621    ) -> Result<(), ErrorEmitted> {
1622        let type_engine = engines.te();
1623        let unify_check = UnifyCheck::constraint_subset(engines);
1624
1625        let required_traits: BTreeSet<(Ident, TypeId)> = constraints
1626            .iter()
1627            .map(|c| {
1628                let TraitConstraint {
1629                    trait_name: constraint_trait_name,
1630                    type_arguments: constraint_type_arguments,
1631                } = c;
1632                let constraint_type_id = type_engine.new_custom(
1633                    engines,
1634                    constraint_trait_name.suffix.clone().into(),
1635                    if constraint_type_arguments.is_empty() {
1636                        None
1637                    } else {
1638                        Some(constraint_type_arguments.clone())
1639                    },
1640                );
1641                (c.trait_name.suffix.clone(), constraint_type_id)
1642            })
1643            .collect();
1644
1645        let traits_not_found: BTreeSet<(BaseIdent, TypeId)> = required_traits
1646            .into_iter()
1647            .filter(|(required_trait_name, required_trait_type_id)| {
1648                !all_impld_traits
1649                    .iter()
1650                    .any(|(trait_name, constraint_type_id)| {
1651                        trait_name == required_trait_name
1652                            && unify_check.check(*constraint_type_id, *required_trait_type_id)
1653                    })
1654            })
1655            .collect();
1656
1657        handler.scope(|handler| {
1658            for (trait_name, constraint_type_id) in traits_not_found.iter() {
1659                let mut type_arguments_string = "".to_string();
1660                if let TypeInfo::Custom {
1661                    qualified_call_path: _,
1662                    type_arguments: Some(type_arguments),
1663                } = &*type_engine.get(*constraint_type_id)
1664                {
1665                    type_arguments_string = format!("<{}>", engines.help_out(type_arguments));
1666                }
1667
1668                // TODO: use a better span
1669                handler.emit_err(CompileError::TraitConstraintNotSatisfied {
1670                    type_id: type_id.index(),
1671                    ty: engines.help_out(type_id).to_string(),
1672                    trait_name: format!("{trait_name}{type_arguments_string}"),
1673                    span: access_span.clone(),
1674                });
1675            }
1676
1677            Ok(())
1678        })
1679    }
1680
1681    pub fn get_trait_constraints_are_satisfied_for_types(
1682        module: &Module,
1683        _handler: &Handler,
1684        type_id: TypeId,
1685        constraints: &[TraitConstraint],
1686        engines: &Engines,
1687    ) -> Result<Vec<(TypeId, String)>, ErrorEmitted> {
1688        let type_id = engines.te().get_unaliased_type_id(type_id);
1689
1690        let _decl_engine = engines.de();
1691        let unify_check = UnifyCheck::coercion(engines);
1692        let unify_check_equality = UnifyCheck::constraint_subset(engines);
1693
1694        let mut impld_traits_type_ids: Vec<Vec<(TypeId, String)>> = vec![];
1695        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1696            lexical_scope
1697                .items
1698                .implemented_traits
1699                .for_each_impls(engines, type_id, true, |e| {
1700                    let mut traits: Vec<(TypeId, String)> = vec![];
1701
1702                    let key = &e.inner.key;
1703                    for constraint in constraints {
1704                        if key.name.suffix.name == constraint.trait_name.suffix
1705                            && key
1706                                .name
1707                                .suffix
1708                                .args
1709                                .iter()
1710                                .zip(constraint.type_arguments.iter())
1711                                .all(|(a1, a2)| {
1712                                    unify_check_equality.check(a1.type_id(), a2.type_id())
1713                                })
1714                            && unify_check.check(type_id, key.type_id)
1715                        {
1716                            let name_type_args = if !key.name.suffix.args.is_empty() {
1717                                format!("<{}>", engines.help_out(key.name.suffix.args.clone()))
1718                            } else {
1719                                "".to_string()
1720                            };
1721                            let name =
1722                                format!("{}{}", key.name.suffix.name.as_str(), name_type_args);
1723                            traits.push((key.type_id, name));
1724                            break;
1725                        }
1726                    }
1727                    impld_traits_type_ids.push(traits);
1728                });
1729
1730            Ok(None::<()>)
1731        });
1732        Ok(impld_traits_type_ids.concat())
1733    }
1734
1735    fn get_impls_mut(&mut self, engines: &Engines, type_id: TypeId) -> &mut Vec<SharedTraitEntry> {
1736        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1737        if !self.trait_impls.contains_key(&type_root_filter) {
1738            self.trait_impls
1739                .insert(type_root_filter.clone(), Vec::new());
1740        }
1741
1742        self.trait_impls.get_mut(&type_root_filter).unwrap()
1743    }
1744
1745    pub(crate) fn for_each_impls<F>(
1746        &self,
1747        engines: &Engines,
1748        type_id: TypeId,
1749        include_placeholder: bool,
1750        mut callback: F,
1751    ) where
1752        F: FnMut(&SharedTraitEntry),
1753    {
1754        let type_root_filter = Self::get_type_root_filter(engines, type_id);
1755        self.trait_impls
1756            .get(&type_root_filter)
1757            .iter()
1758            .for_each(|vec| vec.iter().for_each(&mut callback));
1759        if include_placeholder && type_root_filter != TypeRootFilter::Placeholder {
1760            self.trait_impls
1761                .get(&TypeRootFilter::Placeholder)
1762                .iter()
1763                .for_each(|vec| vec.iter().for_each(&mut callback));
1764        }
1765    }
1766
1767    // Return a string representing only the base type.
1768    // This is used by the trait map to filter the entries into a HashMap with the return type string as key.
1769    fn get_type_root_filter(engines: &Engines, type_id: TypeId) -> TypeRootFilter {
1770        use TypeInfo::*;
1771        match &*engines.te().get(type_id) {
1772            Unknown => TypeRootFilter::Unknown,
1773            Never => TypeRootFilter::Never,
1774            UnknownGeneric { .. } | Placeholder(_) => TypeRootFilter::Placeholder,
1775            TypeParam(_param) => unreachable!(),
1776            StringSlice => TypeRootFilter::StringSlice,
1777            StringArray(_) => TypeRootFilter::StringArray,
1778            UnsignedInteger(x) => match x {
1779                IntegerBits::Eight => TypeRootFilter::U8,
1780                IntegerBits::Sixteen => TypeRootFilter::U16,
1781                IntegerBits::ThirtyTwo => TypeRootFilter::U32,
1782                IntegerBits::SixtyFour => TypeRootFilter::U64,
1783                IntegerBits::V256 => TypeRootFilter::U256,
1784            },
1785            Boolean => TypeRootFilter::Bool,
1786            Custom {
1787                qualified_call_path: call_path,
1788                ..
1789            } => TypeRootFilter::Custom(call_path.call_path.suffix.to_string()),
1790            B256 => TypeRootFilter::B256,
1791            Numeric => TypeRootFilter::U64, // u64 is the default
1792            Contract => TypeRootFilter::Contract,
1793            ErrorRecovery(_) => TypeRootFilter::ErrorRecovery,
1794            Tuple(fields) => TypeRootFilter::Tuple(fields.len()),
1795            UntypedEnum(decl_id) => TypeRootFilter::Enum(*decl_id),
1796            UntypedStruct(decl_id) => TypeRootFilter::Struct(*decl_id),
1797            Enum(decl_id) => {
1798                // TODO Remove unwrap once #6475 is fixed
1799                TypeRootFilter::Enum(engines.de().get_parsed_decl_id(decl_id).unwrap())
1800            }
1801            Struct(decl_id) => {
1802                // TODO Remove unwrap once #6475 is fixed
1803                TypeRootFilter::Struct(engines.de().get_parsed_decl_id(decl_id).unwrap())
1804            }
1805            ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()),
1806            Array(_, _) => TypeRootFilter::Array,
1807            RawUntypedPtr => TypeRootFilter::RawUntypedPtr,
1808            RawUntypedSlice => TypeRootFilter::RawUntypedSlice,
1809            Ptr(_) => TypeRootFilter::Ptr,
1810            Slice(_) => TypeRootFilter::Slice,
1811            Alias { ty, .. } => Self::get_type_root_filter(engines, ty.type_id),
1812            TraitType { name, .. } => TypeRootFilter::TraitType(name.to_string()),
1813            Ref {
1814                referenced_type, ..
1815            } => Self::get_type_root_filter(engines, referenced_type.type_id),
1816        }
1817    }
1818}