Skip to main content

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