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#[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}
108
109impl OrdWithEngines for TraitKey {
110 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> std::cmp::Ordering {
111 self.name.cmp(&other.name, ctx).then_with(|| {
112 self.type_id
113 .cmp(&other.type_id)
114 .then_with(|| self.impl_type_parameters.cmp(&other.impl_type_parameters))
115 })
116 }
117}
118
119#[derive(Clone, Debug)]
120pub enum ResolvedTraitImplItem {
121 Parsed(ImplItem),
122 Typed(TyImplItem),
123}
124
125impl DebugWithEngines for ResolvedTraitImplItem {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
127 match self {
128 ResolvedTraitImplItem::Parsed(_) => panic!(),
129 ResolvedTraitImplItem::Typed(ty) => write!(f, "{:?}", engines.help_out(ty)),
130 }
131 }
132}
133
134impl ResolvedTraitImplItem {
135 fn expect_typed(self) -> TyImplItem {
136 match self {
137 ResolvedTraitImplItem::Parsed(_) => panic!(),
138 ResolvedTraitImplItem::Typed(ty) => ty,
139 }
140 }
141
142 pub fn span(&self, engines: &Engines) -> Span {
143 match self {
144 ResolvedTraitImplItem::Parsed(item) => item.span(engines),
145 ResolvedTraitImplItem::Typed(item) => item.span(),
146 }
147 }
148}
149
150type TraitItems = BTreeMap<String, ResolvedTraitImplItem>;
152
153#[derive(Clone, Debug)]
154pub(crate) struct TraitValue {
155 pub(crate) trait_items: TraitItems,
156 pub(crate) impl_span: Span,
158}
159
160#[derive(Clone, Debug)]
161pub(crate) struct TraitEntry {
162 pub(crate) key: TraitKey,
163 pub(crate) value: TraitValue,
164}
165
166pub(crate) type TraitImpls = BTreeMap<TypeRootFilter, Vec<TraitEntry>>;
170
171#[derive(Clone, Hash, Eq, PartialOrd, Ord, PartialEq, Debug)]
172pub(crate) enum TypeRootFilter {
173 Unknown,
174 Never,
175 Placeholder,
176 StringSlice,
177 StringArray(usize),
178 U8,
179 U16,
180 U32,
181 U64,
182 U256,
183 Bool,
184 Custom(String),
185 B256,
186 Contract,
187 ErrorRecovery,
188 Tuple(usize),
189 Enum(ParsedDeclId<EnumDeclaration>),
190 Struct(ParsedDeclId<StructDeclaration>),
191 ContractCaller(String),
192 Array,
193 RawUntypedPtr,
194 RawUntypedSlice,
195 Ptr,
196 Slice,
197 TraitType(String),
198}
199
200#[derive(Clone, Debug, Default)]
205pub struct TraitMap {
206 pub(crate) trait_impls: TraitImpls,
207 satisfied_cache: HashSet<u64>,
208}
209
210pub(crate) enum IsImplSelf {
211 Yes,
212 No,
213}
214
215pub(crate) enum IsExtendingExistingImpl {
216 Yes,
217 No,
218}
219
220impl TraitMap {
221 #[allow(clippy::too_many_arguments)]
229 pub(crate) fn insert(
230 &mut self,
231 handler: &Handler,
232 trait_name: CallPath,
233 trait_type_args: Vec<GenericArgument>,
234 type_id: TypeId,
235 impl_type_parameters: Vec<TypeId>,
236 items: &[ResolvedTraitImplItem],
237 impl_span: &Span,
238 trait_decl_span: Option<Span>,
239 is_impl_self: IsImplSelf,
240 is_extending_existing_impl: IsExtendingExistingImpl,
241 engines: &Engines,
242 ) -> Result<(), ErrorEmitted> {
243 let unaliased_type_id = engines.te().get_unaliased_type_id(type_id);
244
245 handler.scope(|handler| {
246 let mut trait_items: TraitItems = BTreeMap::new();
247 for item in items.iter() {
248 match item {
249 ResolvedTraitImplItem::Parsed(_) => todo!(),
250 ResolvedTraitImplItem::Typed(ty_item) => match ty_item {
251 TyImplItem::Fn(decl_ref) => {
252 if trait_items
253 .insert(decl_ref.name().clone().to_string(), item.clone())
254 .is_some()
255 {
256 handler.emit_err(CompileError::MultipleDefinitionsOfName {
258 name: decl_ref.name().clone(),
259 span: decl_ref.span(),
260 });
261 }
262 }
263 TyImplItem::Constant(decl_ref) => {
264 trait_items.insert(decl_ref.name().to_string(), item.clone());
265 }
266 TyImplItem::Type(decl_ref) => {
267 trait_items.insert(decl_ref.name().to_string(), item.clone());
268 }
269 },
270 }
271 }
272
273 let trait_impls = self.get_impls_mut(engines, unaliased_type_id);
274
275 for TraitEntry {
277 key:
278 TraitKey {
279 name: map_trait_name,
280 type_id: map_type_id,
281 trait_decl_span: _,
282 impl_type_parameters: _,
283 },
284 value:
285 TraitValue {
286 trait_items: map_trait_items,
287 impl_span: existing_impl_span,
288 },
289 } in trait_impls.iter()
290 {
291 let CallPath {
292 suffix:
293 TraitSuffix {
294 name: map_trait_name_suffix,
295 args: map_trait_type_args,
296 },
297 ..
298 } = &*map_trait_name.clone();
299
300 let unify_checker = UnifyCheck::non_generic_constraint_subset(engines);
301
302 let types_are_subset = unify_checker.check(unaliased_type_id, *map_type_id)
306 && is_unified_type_subset(engines.te(), unaliased_type_id, *map_type_id);
307
308 fn is_unified_type_subset(
314 type_engine: &TypeEngine,
315 mut left: TypeId,
316 mut right: TypeId,
317 ) -> bool {
318 loop {
321 let left_ty_info = &*type_engine.get_unaliased(left);
322 let right_ty_info = &*type_engine.get_unaliased(right);
323 match (left_ty_info, right_ty_info) {
324 (
325 TypeInfo::Ref {
326 to_mutable_value: l_to_mut,
327 ..
328 },
329 TypeInfo::Ref {
330 to_mutable_value: r_to_mut,
331 ..
332 },
333 ) if *l_to_mut != *r_to_mut => return false, (
335 TypeInfo::Ref {
336 referenced_type: l_ty,
337 ..
338 },
339 TypeInfo::Ref {
340 referenced_type: r_ty,
341 ..
342 },
343 ) => {
344 left = l_ty.type_id();
345 right = r_ty.type_id();
346 }
347 _ => return true,
348 }
349 }
350 }
351
352 let mut traits_are_subset = true;
353 if *map_trait_name_suffix != trait_name.suffix
354 || map_trait_type_args.len() != trait_type_args.len()
355 {
356 traits_are_subset = false;
357 } else {
358 for (map_arg_type, arg_type) in
359 map_trait_type_args.iter().zip(trait_type_args.iter())
360 {
361 if !unify_checker.check(arg_type.type_id(), map_arg_type.type_id()) {
362 traits_are_subset = false;
363 }
364 }
365 }
366
367 if matches!(is_extending_existing_impl, IsExtendingExistingImpl::No)
368 && types_are_subset
369 && traits_are_subset
370 && matches!(is_impl_self, IsImplSelf::No)
371 {
372 handler.emit_err(CompileError::ConflictingImplsForTraitAndType {
373 trait_name: trait_name.to_string_with_args(engines, &trait_type_args),
374 type_implementing_for: engines.help_out(type_id).to_string(),
375 type_implementing_for_unaliased: engines
376 .help_out(unaliased_type_id)
377 .to_string(),
378 existing_impl_span: existing_impl_span.clone(),
379 second_impl_span: impl_span.clone(),
380 });
381 } else if types_are_subset
382 && (traits_are_subset || matches!(is_impl_self, IsImplSelf::Yes))
383 {
384 for name in trait_items.keys() {
385 let item = &trait_items[name];
386 match item {
387 ResolvedTraitImplItem::Parsed(_item) => todo!(),
388 ResolvedTraitImplItem::Typed(item) => match item {
389 ty::TyTraitItem::Fn(decl_ref) => {
390 if let Some(existing_item) = map_trait_items.get(name) {
391 handler.emit_err(
392 CompileError::DuplicateDeclDefinedForType {
393 decl_kind: "method".into(),
394 decl_name: decl_ref.name().to_string(),
395 type_implementing_for: engines
396 .help_out(type_id)
397 .to_string(),
398 type_implementing_for_unaliased: engines
399 .help_out(unaliased_type_id)
400 .to_string(),
401 existing_impl_span: existing_item
402 .span(engines)
403 .clone(),
404 second_impl_span: decl_ref.name().span(),
405 },
406 );
407 }
408 }
409 ty::TyTraitItem::Constant(decl_ref) => {
410 if let Some(existing_item) = map_trait_items.get(name) {
411 handler.emit_err(
412 CompileError::DuplicateDeclDefinedForType {
413 decl_kind: "constant".into(),
414 decl_name: decl_ref.name().to_string(),
415 type_implementing_for: engines
416 .help_out(type_id)
417 .to_string(),
418 type_implementing_for_unaliased: engines
419 .help_out(unaliased_type_id)
420 .to_string(),
421 existing_impl_span: existing_item
422 .span(engines)
423 .clone(),
424 second_impl_span: decl_ref.name().span(),
425 },
426 );
427 }
428 }
429 ty::TyTraitItem::Type(decl_ref) => {
430 if let Some(existing_item) = map_trait_items.get(name) {
431 handler.emit_err(
432 CompileError::DuplicateDeclDefinedForType {
433 decl_kind: "type".into(),
434 decl_name: decl_ref.name().to_string(),
435 type_implementing_for: engines
436 .help_out(type_id)
437 .to_string(),
438 type_implementing_for_unaliased: engines
439 .help_out(unaliased_type_id)
440 .to_string(),
441 existing_impl_span: existing_item
442 .span(engines)
443 .clone(),
444 second_impl_span: decl_ref.name().span(),
445 },
446 );
447 }
448 }
449 },
450 }
451 }
452 }
453 }
454 let trait_name: TraitName = Arc::new(CallPath {
455 prefixes: trait_name.prefixes,
456 suffix: TraitSuffix {
457 name: trait_name.suffix,
458 args: trait_type_args,
459 },
460 callpath_type: trait_name.callpath_type,
461 });
462
463 self.insert_inner(
465 trait_name,
466 impl_span.clone(),
467 trait_decl_span,
468 unaliased_type_id,
469 impl_type_parameters,
470 trait_items,
471 engines,
472 );
473
474 Ok(())
475 })
476 }
477
478 #[allow(clippy::too_many_arguments)]
479 fn insert_inner(
480 &mut self,
481 trait_name: TraitName,
482 impl_span: Span,
483 trait_decl_span: Option<Span>,
484 type_id: TypeId,
485 impl_type_parameters: Vec<TypeId>,
486 trait_methods: TraitItems,
487 engines: &Engines,
488 ) {
489 let key = TraitKey {
490 name: trait_name,
491 type_id,
492 trait_decl_span,
493 impl_type_parameters,
494 };
495 let value = TraitValue {
496 trait_items: trait_methods,
497 impl_span,
498 };
499 let entry = TraitEntry { key, value };
500 let mut trait_impls: TraitImpls = BTreeMap::<TypeRootFilter, Vec<TraitEntry>>::new();
501 let type_root_filter = Self::get_type_root_filter(engines, type_id);
502 let impls_vector = vec![entry];
503 trait_impls.insert(type_root_filter, impls_vector);
504
505 let trait_map = TraitMap {
506 trait_impls,
507 satisfied_cache: HashSet::default(),
508 };
509
510 self.extend(trait_map, engines);
511 }
512
513 pub(crate) fn extend(&mut self, other: TraitMap, engines: &Engines) {
516 for impls_key in other.trait_impls.keys() {
517 let oe_vec = &other.trait_impls[impls_key];
518 let self_vec = if let Some(self_vec) = self.trait_impls.get_mut(impls_key) {
519 self_vec
520 } else {
521 self.trait_impls
522 .insert(impls_key.clone(), Vec::<TraitEntry>::new());
523 self.trait_impls.get_mut(impls_key).unwrap()
524 };
525
526 for oe in oe_vec.iter() {
527 let pos = self_vec.binary_search_by(|se| {
528 se.key.cmp(&oe.key, &OrdWithEnginesContext::new(engines))
529 });
530
531 match pos {
532 Ok(pos) => self_vec[pos]
533 .value
534 .trait_items
535 .extend(oe.value.trait_items.clone()),
536 Err(pos) => self_vec.insert(pos, oe.clone()),
537 }
538 }
539 }
540 }
541
542 pub(crate) fn get_traits_types(
543 &self,
544 traits_types: &mut HashMap<CallPath, Vec<TypeId>>,
545 ) -> Result<(), ErrorEmitted> {
546 for key in self.trait_impls.keys() {
547 for self_entry in self.trait_impls[key].iter() {
548 let callpath = CallPath {
549 prefixes: self_entry.key.name.prefixes.clone(),
550 suffix: self_entry.key.name.suffix.name.clone(),
551 callpath_type: self_entry.key.name.callpath_type,
552 };
553 if let Some(vec) = traits_types.get_mut(&callpath) {
554 vec.push(self_entry.key.type_id);
555 } else {
556 traits_types.insert(callpath, vec![self_entry.key.type_id]);
557 }
558 }
559 }
560 Ok(())
561 }
562
563 pub(crate) fn filter_by_trait_decl_span(&self, trait_decl_span: Span) -> TraitMap {
566 let mut trait_map = TraitMap::default();
567 for key in self.trait_impls.keys() {
568 let vec = &self.trait_impls[key];
569 for entry in vec {
570 if entry.key.trait_decl_span.as_ref() == Some(&trait_decl_span) {
571 let trait_map_vec =
572 if let Some(trait_map_vec) = trait_map.trait_impls.get_mut(key) {
573 trait_map_vec
574 } else {
575 trait_map
576 .trait_impls
577 .insert(key.clone(), Vec::<TraitEntry>::new());
578 trait_map.trait_impls.get_mut(key).unwrap()
579 };
580
581 trait_map_vec.push(entry.clone());
582 }
583 }
584 }
585 trait_map
586 }
587
588 pub(crate) fn filter_by_type_item_import(
647 &self,
648 type_id: TypeId,
649 engines: &Engines,
650 ) -> TraitMap {
651 let unify_checker = UnifyCheck::constraint_subset(engines);
652 let unify_checker_for_item_import = UnifyCheck::non_generic_constraint_subset(engines);
653
654 let decider = |left: TypeId, right: TypeId| {
656 unify_checker.check(left, right) || unify_checker_for_item_import.check(right, left)
657 };
658 let mut trait_map = self.filter_by_type_inner(engines, vec![type_id], decider);
659 let all_types = type_id
660 .extract_inner_types(engines, IncludeSelf::No)
661 .into_iter()
662 .collect::<Vec<_>>();
663 let decider2 = |left: TypeId, right: TypeId| unify_checker.check(left, right);
665
666 trait_map.extend(
667 self.filter_by_type_inner(engines, all_types, decider2),
668 engines,
669 );
670 trait_map
671 }
672
673 fn filter_by_type_inner(
674 &self,
675 engines: &Engines,
676 mut all_types: Vec<TypeId>,
677 decider: impl Fn(TypeId, TypeId) -> bool,
678 ) -> TraitMap {
679 let type_engine = engines.te();
680 let mut trait_map = TraitMap::default();
681 for type_id in all_types.iter_mut() {
682 let type_info = type_engine.get(*type_id);
683 self.for_each_impls(
684 engines,
685 *type_id,
686 true,
687 |TraitEntry {
688 key:
689 TraitKey {
690 name: map_trait_name,
691 type_id: map_type_id,
692 trait_decl_span: map_trait_decl_span,
693 impl_type_parameters: map_impl_type_parameters,
694 },
695 value:
696 TraitValue {
697 trait_items: map_trait_items,
698 impl_span,
699 },
700 }| {
701 if !type_engine.is_type_changeable(engines, &type_info)
702 && *type_id == *map_type_id
703 {
704 trait_map.insert_inner(
705 map_trait_name.clone(),
706 impl_span.clone(),
707 map_trait_decl_span.clone(),
708 *type_id,
709 map_impl_type_parameters.clone(),
710 map_trait_items.clone(),
711 engines,
712 );
713 } else if decider(*type_id, *map_type_id) {
714 trait_map.insert_inner(
715 map_trait_name.clone(),
716 impl_span.clone(),
717 map_trait_decl_span.clone(),
718 *map_type_id,
719 map_impl_type_parameters.clone(),
720 Self::filter_dummy_methods(
721 map_trait_items,
722 *type_id,
723 *map_type_id,
724 engines,
725 )
726 .map(|(name, item)| (name.to_string(), item))
727 .collect(),
728 engines,
729 );
730 }
731 },
732 );
733 }
734 trait_map
735 }
736
737 fn filter_dummy_methods<'a>(
738 map_trait_items: &'a TraitItems,
739 type_id: TypeId,
740 map_type_id: TypeId,
741 engines: &'a Engines,
742 ) -> impl Iterator<Item = (&'a str, ResolvedTraitImplItem)> + 'a {
743 let maybe_is_from_type_parameter = engines.te().map(map_type_id, |x| match x {
744 TypeInfo::UnknownGeneric {
745 is_from_type_parameter,
746 ..
747 } => Some(*is_from_type_parameter),
748 _ => None,
749 });
750 let insertable = if let Some(is_from_type_parameter) = maybe_is_from_type_parameter {
751 !is_from_type_parameter
752 || matches!(*engines.te().get(type_id), TypeInfo::UnknownGeneric { .. })
753 } else {
754 true
755 };
756
757 map_trait_items
758 .iter()
759 .filter_map(move |(name, item)| match item {
760 ResolvedTraitImplItem::Parsed(_item) => todo!(),
761 ResolvedTraitImplItem::Typed(item) => match item {
762 ty::TyTraitItem::Fn(decl_ref) => engines.de().map(decl_ref.id(), |decl| {
763 if decl.is_trait_method_dummy && !insertable {
764 None
765 } else {
766 Some((
767 name.as_str(),
768 ResolvedTraitImplItem::Typed(TyImplItem::Fn(decl_ref.clone())),
769 ))
770 }
771 }),
772 ty::TyTraitItem::Constant(decl_ref) => Some((
773 name.as_str(),
774 ResolvedTraitImplItem::Typed(TyImplItem::Constant(decl_ref.clone())),
775 )),
776 ty::TyTraitItem::Type(decl_ref) => Some((
777 name.as_str(),
778 ResolvedTraitImplItem::Typed(TyImplItem::Type(decl_ref.clone())),
779 )),
780 },
781 })
782 }
783
784 fn make_item_for_type_mapping(
785 engines: &Engines,
786 item: ResolvedTraitImplItem,
787 mut type_mapping: TypeSubstMap,
788 type_id: TypeId,
789 code_block_first_pass: CodeBlockFirstPass,
790 ) -> ResolvedTraitImplItem {
791 let decl_engine = engines.de();
792 match &item {
793 ResolvedTraitImplItem::Parsed(_item) => todo!(),
794 ResolvedTraitImplItem::Typed(item) => match item {
795 ty::TyTraitItem::Fn(decl_ref) => {
796 let mut decl = (*decl_engine.get(decl_ref.id())).clone();
797 if let Some(decl_implementing_for_typeid) = decl.implementing_for_typeid {
798 type_mapping.insert(decl_implementing_for_typeid, type_id);
799 }
800 decl.subst(&SubstTypesContext::new(
801 engines,
802 &type_mapping,
803 matches!(code_block_first_pass, CodeBlockFirstPass::No),
804 ));
805
806 let new_ref = decl_engine
807 .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref())
808 .with_parent(decl_engine, decl_ref.id().into());
809
810 ResolvedTraitImplItem::Typed(TyImplItem::Fn(new_ref))
811 }
812 ty::TyTraitItem::Constant(decl_ref) => {
813 let mut decl = (*decl_engine.get(decl_ref.id())).clone();
814 decl.subst(&SubstTypesContext::new(
815 engines,
816 &type_mapping,
817 matches!(code_block_first_pass, CodeBlockFirstPass::No),
818 ));
819 let new_ref = decl_engine
820 .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
821 ResolvedTraitImplItem::Typed(TyImplItem::Constant(new_ref))
822 }
823 ty::TyTraitItem::Type(decl_ref) => {
824 let mut decl = (*decl_engine.get(decl_ref.id())).clone();
825 decl.subst(&SubstTypesContext::new(
826 engines,
827 &type_mapping,
828 matches!(code_block_first_pass, CodeBlockFirstPass::No),
829 ));
830 let new_ref = decl_engine
831 .insert(decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref());
832 ResolvedTraitImplItem::Typed(TyImplItem::Type(new_ref))
833 }
834 },
835 }
836 }
837
838 pub(crate) fn get_items_for_type(
848 module: &Module,
849 engines: &Engines,
850 type_id: TypeId,
851 ) -> Vec<ResolvedTraitImplItem> {
852 TraitMap::get_items_and_trait_key_for_type(module, engines, type_id)
853 .iter()
854 .map(|i| i.0.clone())
855 .collect::<Vec<_>>()
856 }
857
858 fn get_items_and_trait_key_for_type(
859 module: &Module,
860 engines: &Engines,
861 type_id: TypeId,
862 ) -> Vec<(ResolvedTraitImplItem, TraitKey)> {
863 let type_engine = engines.te();
864 let unify_check = UnifyCheck::constraint_subset(engines);
865
866 let type_id = engines.te().get_unaliased_type_id(type_id);
867
868 let mut items = vec![];
869 if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
871 return items;
872 }
873
874 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
875 lexical_scope.items.implemented_traits.for_each_impls(
876 engines,
877 type_id,
878 true,
879 |entry| {
880 if unify_check.check(type_id, entry.key.type_id) {
881 let trait_items = Self::filter_dummy_methods(
882 &entry.value.trait_items,
883 type_id,
884 entry.key.type_id,
885 engines,
886 )
887 .map(|(_, i)| (i, entry.key.clone()))
888 .collect::<Vec<_>>();
889
890 items.extend(trait_items);
891 }
892 },
893 );
894
895 Ok(None::<()>)
896 });
897 items
898 }
899
900 pub fn get_impl_spans_for_type(
910 module: &Module,
911 engines: &Engines,
912 type_id: &TypeId,
913 ) -> Vec<Span> {
914 let type_engine = engines.te();
915 let unify_check = UnifyCheck::constraint_subset(engines);
916
917 let type_id = &engines.te().get_unaliased_type_id(*type_id);
918
919 let mut spans = vec![];
920 if matches!(&*type_engine.get(*type_id), TypeInfo::ErrorRecovery(_)) {
922 return spans;
923 }
924 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
925 lexical_scope.items.implemented_traits.for_each_impls(
926 engines,
927 *type_id,
928 false,
929 |entry| {
930 if unify_check.check(*type_id, entry.key.type_id) {
931 spans.push(entry.value.impl_span.clone());
932 }
933 },
934 );
935
936 Ok(None::<()>)
937 });
938
939 spans
940 }
941
942 pub fn get_impl_spans_for_decl(
944 module: &Module,
945 engines: &Engines,
946 ty_decl: &TyDecl,
947 ) -> Vec<Span> {
948 let handler = Handler::default();
949 ty_decl
950 .return_type(&handler, engines)
951 .map(|type_id| TraitMap::get_impl_spans_for_type(module, engines, &type_id))
952 .unwrap_or_default()
953 }
954
955 pub fn get_impl_spans_for_trait_name(module: &Module, trait_name: &CallPath) -> Vec<Span> {
958 let mut spans = vec![];
959 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
960 spans.push(
961 lexical_scope
962 .items
963 .implemented_traits
964 .trait_impls
965 .values()
966 .map(|impls| {
967 impls
968 .iter()
969 .filter_map(|entry| {
970 let map_trait_name = CallPath {
971 prefixes: entry.key.name.prefixes.clone(),
972 suffix: entry.key.name.suffix.name.clone(),
973 callpath_type: entry.key.name.callpath_type,
974 };
975 if &map_trait_name == trait_name {
976 Some(entry.value.impl_span.clone())
977 } else {
978 None
979 }
980 })
981 .collect::<Vec<Span>>()
982 })
983 .collect::<Vec<Vec<Span>>>()
984 .concat(),
985 );
986 Ok(None::<()>)
987 });
988
989 spans.concat()
990 }
991
992 pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments(
1003 module: &Module,
1004 engines: &Engines,
1005 type_id: TypeId,
1006 trait_name: &CallPath,
1007 trait_type_args: &[GenericArgument],
1008 ) -> Vec<ResolvedTraitImplItem> {
1009 let type_id = engines.te().get_unaliased_type_id(type_id);
1010
1011 let type_engine = engines.te();
1012 let unify_check = UnifyCheck::constraint_subset(engines);
1013 let mut items = vec![];
1014 if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1016 return items;
1017 }
1018 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1019 lexical_scope
1020 .items
1021 .implemented_traits
1022 .for_each_impls(engines, type_id, false, |e| {
1023 let map_trait_name = CallPath {
1024 prefixes: e.key.name.prefixes.clone(),
1025 suffix: e.key.name.suffix.name.clone(),
1026 callpath_type: e.key.name.callpath_type,
1027 };
1028 if &map_trait_name == trait_name
1029 && unify_check.check(type_id, e.key.type_id)
1030 && trait_type_args.len() == e.key.name.suffix.args.len()
1031 && trait_type_args
1032 .iter()
1033 .zip(e.key.name.suffix.args.iter())
1034 .all(|(t1, t2)| unify_check.check(t1.type_id(), t2.type_id()))
1035 {
1036 let type_mapping =
1037 TypeSubstMap::from_superset_and_subset(engines, e.key.type_id, type_id);
1038
1039 let mut trait_items = Self::filter_dummy_methods(
1040 &e.value.trait_items,
1041 type_id,
1042 e.key.type_id,
1043 engines,
1044 )
1045 .map(|(_, i)| {
1046 Self::make_item_for_type_mapping(
1047 engines,
1048 i,
1049 type_mapping.clone(),
1050 type_id,
1051 CodeBlockFirstPass::No,
1052 )
1053 })
1054 .collect::<Vec<_>>();
1055
1056 items.append(&mut trait_items);
1057 }
1058 });
1059 Ok(None::<()>)
1060 });
1061 items
1062 }
1063
1064 pub(crate) fn get_items_for_type_and_trait_name_and_trait_type_arguments_typed(
1075 module: &Module,
1076 engines: &Engines,
1077 type_id: TypeId,
1078 trait_name: &CallPath,
1079 trait_type_args: &[GenericArgument],
1080 ) -> Vec<ty::TyTraitItem> {
1081 TraitMap::get_items_for_type_and_trait_name_and_trait_type_arguments(
1082 module,
1083 engines,
1084 type_id,
1085 trait_name,
1086 trait_type_args,
1087 )
1088 .into_iter()
1089 .map(|item| item.expect_typed())
1090 .collect::<Vec<_>>()
1091 }
1092
1093 pub(crate) fn get_trait_names_and_type_arguments_for_type(
1094 module: &Module,
1095 engines: &Engines,
1096 type_id: TypeId,
1097 ) -> Vec<(CallPath, Vec<GenericArgument>)> {
1098 let type_id = engines.te().get_unaliased_type_id(type_id);
1099
1100 let type_engine = engines.te();
1101 let unify_check = UnifyCheck::constraint_subset(engines);
1102 let mut trait_names = vec![];
1103 if matches!(&*type_engine.get(type_id), TypeInfo::ErrorRecovery(_)) {
1105 return trait_names;
1106 }
1107 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1108 lexical_scope.items.implemented_traits.for_each_impls(
1109 engines,
1110 type_id,
1111 false,
1112 |entry| {
1113 if unify_check.check(type_id, entry.key.type_id) {
1114 let trait_call_path = CallPath {
1115 prefixes: entry.key.name.prefixes.clone(),
1116 suffix: entry.key.name.suffix.name.clone(),
1117 callpath_type: entry.key.name.callpath_type,
1118 };
1119 trait_names.push((trait_call_path, entry.key.name.suffix.args.clone()));
1120 }
1121 },
1122 );
1123 Ok(None::<()>)
1124 });
1125 trait_names
1126 }
1127
1128 pub(crate) fn get_trait_item_for_type(
1129 module: &Module,
1130 handler: &Handler,
1131 engines: &Engines,
1132 symbol: &Ident,
1133 type_id: TypeId,
1134 as_trait: Option<CallPath>,
1135 ) -> Result<ResolvedTraitImplItem, ErrorEmitted> {
1136 let type_id = engines.te().get_unaliased_type_id(type_id);
1137
1138 let mut candidates = HashMap::<String, ResolvedTraitImplItem>::new();
1139 for (trait_item, trait_key) in
1140 TraitMap::get_items_and_trait_key_for_type(module, engines, type_id)
1141 {
1142 match trait_item {
1143 ResolvedTraitImplItem::Parsed(impl_item) => match impl_item {
1144 ImplItem::Fn(fn_ref) => {
1145 let decl = engines.pe().get_function(&fn_ref);
1146 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1147 if decl.name.as_str() == symbol.as_str()
1148 && (as_trait.is_none()
1149 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1150 {
1151 candidates.insert(
1152 trait_call_path_string,
1153 ResolvedTraitImplItem::Parsed(ImplItem::Fn(fn_ref)),
1154 );
1155 }
1156 }
1157 ImplItem::Constant(const_ref) => {
1158 let decl = engines.pe().get_constant(&const_ref);
1159 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1160 if decl.name.as_str() == symbol.as_str()
1161 && (as_trait.is_none()
1162 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1163 {
1164 candidates.insert(
1165 trait_call_path_string,
1166 ResolvedTraitImplItem::Parsed(ImplItem::Constant(const_ref)),
1167 );
1168 }
1169 }
1170 ImplItem::Type(type_ref) => {
1171 let decl = engines.pe().get_trait_type(&type_ref);
1172 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1173 if decl.name.as_str() == symbol.as_str()
1174 && (as_trait.is_none()
1175 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1176 {
1177 candidates.insert(
1178 trait_call_path_string,
1179 ResolvedTraitImplItem::Parsed(ImplItem::Type(type_ref)),
1180 );
1181 }
1182 }
1183 },
1184 ResolvedTraitImplItem::Typed(ty_impl_item) => match ty_impl_item {
1185 ty::TyTraitItem::Fn(fn_ref) => {
1186 let decl = engines.de().get_function(&fn_ref);
1187 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1188 if decl.name.as_str() == symbol.as_str()
1189 && (as_trait.is_none()
1190 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1191 {
1192 candidates.insert(
1193 trait_call_path_string,
1194 ResolvedTraitImplItem::Typed(TyTraitItem::Fn(fn_ref)),
1195 );
1196 }
1197 }
1198 ty::TyTraitItem::Constant(const_ref) => {
1199 let decl = engines.de().get_constant(&const_ref);
1200 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1201 if decl.call_path.suffix.as_str() == symbol.as_str()
1202 && (as_trait.is_none()
1203 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1204 {
1205 candidates.insert(
1206 trait_call_path_string,
1207 ResolvedTraitImplItem::Typed(TyTraitItem::Constant(const_ref)),
1208 );
1209 }
1210 }
1211 ty::TyTraitItem::Type(type_ref) => {
1212 let decl = engines.de().get_type(&type_ref);
1213 let trait_call_path_string = engines.help_out(&*trait_key.name).to_string();
1214 if decl.name.as_str() == symbol.as_str()
1215 && (as_trait.is_none()
1216 || as_trait.clone().unwrap().to_string() == trait_call_path_string)
1217 {
1218 candidates.insert(
1219 trait_call_path_string,
1220 ResolvedTraitImplItem::Typed(TyTraitItem::Type(type_ref)),
1221 );
1222 }
1223 }
1224 },
1225 }
1226 }
1227
1228 match candidates.len().cmp(&1) {
1229 Ordering::Greater => Err(handler.emit_err(
1230 CompileError::MultipleApplicableItemsInScope {
1231 item_name: symbol.as_str().to_string(),
1232 item_kind: "item".to_string(),
1233 as_traits: candidates
1234 .keys()
1235 .map(|k| {
1236 (
1237 k.clone()
1238 .split("::")
1239 .collect::<Vec<_>>()
1240 .last()
1241 .unwrap()
1242 .to_string(),
1243 engines.help_out(type_id).to_string(),
1244 )
1245 })
1246 .collect::<Vec<_>>(),
1247 span: symbol.span(),
1248 },
1249 )),
1250 Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound {
1251 name: symbol.clone(),
1252 span: symbol.span(),
1253 })),
1254 Ordering::Equal => Ok(candidates.values().next().unwrap().clone()),
1255 }
1256 }
1257
1258 #[allow(clippy::too_many_arguments)]
1260 pub(crate) fn check_if_trait_constraints_are_satisfied_for_type(
1261 handler: &Handler,
1262 module: &mut Module,
1263 type_id: TypeId,
1264 constraints: &[TraitConstraint],
1265 access_span: &Span,
1266 engines: &Engines,
1267 ) -> Result<(), ErrorEmitted> {
1268 let type_engine = engines.te();
1269
1270 let type_id = type_engine.get_unaliased_type_id(type_id);
1271
1272 type_engine.decay_numeric(handler, engines, type_id, access_span)?;
1274
1275 if constraints.is_empty() {
1276 return Ok(());
1277 }
1278
1279 let mut hasher = DefaultHasher::default();
1281 type_id.hash(&mut hasher);
1282 for c in constraints {
1283 c.hash(&mut hasher, engines);
1284 }
1285 let hash = hasher.finish();
1286
1287 {
1288 let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1289 if trait_map.satisfied_cache.contains(&hash) {
1290 return Ok(());
1291 }
1292 }
1293
1294 let all_impld_traits: BTreeSet<(Ident, TypeId)> =
1295 Self::get_all_implemented_traits(module, type_id, engines);
1296
1297 match Self::check_if_trait_constraints_are_satisfied_for_type_inner(
1299 handler,
1300 type_id,
1301 constraints,
1302 access_span,
1303 engines,
1304 all_impld_traits,
1305 ) {
1306 Ok(()) => {
1307 let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits;
1308 trait_map.satisfied_cache.insert(hash);
1309 Ok(())
1310 }
1311 r => r,
1312 }
1313 }
1314
1315 fn get_all_implemented_traits(
1316 module: &Module,
1317 type_id: TypeId,
1318 engines: &Engines,
1319 ) -> BTreeSet<(Ident, TypeId)> {
1320 let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default();
1321 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1322 all_impld_traits.extend(
1323 lexical_scope
1324 .items
1325 .implemented_traits
1326 .get_implemented_traits(type_id, engines),
1327 );
1328 Ok(None::<()>)
1329 });
1330 all_impld_traits
1331 }
1332
1333 fn get_implemented_traits(
1334 &self,
1335 type_id: TypeId,
1336 engines: &Engines,
1337 ) -> BTreeSet<(Ident, TypeId)> {
1338 let type_engine = engines.te();
1339 let unify_check = UnifyCheck::constraint_subset(engines);
1340 let mut all_impld_traits = BTreeSet::<(Ident, TypeId)>::new();
1341 self.for_each_impls(engines, type_id, true, |e| {
1342 let key = &e.key;
1343 let suffix = &key.name.suffix;
1344 if unify_check.check(type_id, key.type_id) {
1345 let map_trait_type_id = type_engine.new_custom(
1346 engines,
1347 suffix.name.clone().into(),
1348 if suffix.args.is_empty() {
1349 None
1350 } else {
1351 Some(suffix.args.to_vec())
1352 },
1353 );
1354 all_impld_traits.insert((suffix.name.clone(), map_trait_type_id));
1355 }
1356 });
1357 all_impld_traits
1358 }
1359
1360 #[allow(clippy::too_many_arguments)]
1361 fn check_if_trait_constraints_are_satisfied_for_type_inner(
1362 handler: &Handler,
1363 type_id: TypeId,
1364 constraints: &[TraitConstraint],
1365 access_span: &Span,
1366 engines: &Engines,
1367 all_impld_traits: BTreeSet<(Ident, TypeId)>,
1368 ) -> Result<(), ErrorEmitted> {
1369 let type_engine = engines.te();
1370 let unify_check = UnifyCheck::constraint_subset(engines);
1371
1372 let required_traits: BTreeSet<(Ident, TypeId)> = constraints
1373 .iter()
1374 .map(|c| {
1375 let TraitConstraint {
1376 trait_name: constraint_trait_name,
1377 type_arguments: constraint_type_arguments,
1378 } = c;
1379 let constraint_type_id = type_engine.new_custom(
1380 engines,
1381 constraint_trait_name.suffix.clone().into(),
1382 if constraint_type_arguments.is_empty() {
1383 None
1384 } else {
1385 Some(constraint_type_arguments.clone())
1386 },
1387 );
1388 (c.trait_name.suffix.clone(), constraint_type_id)
1389 })
1390 .collect();
1391
1392 let traits_not_found: BTreeSet<(BaseIdent, TypeId)> = required_traits
1393 .into_iter()
1394 .filter(|(required_trait_name, required_trait_type_id)| {
1395 !all_impld_traits
1396 .iter()
1397 .any(|(trait_name, constraint_type_id)| {
1398 trait_name == required_trait_name
1399 && unify_check.check(*constraint_type_id, *required_trait_type_id)
1400 })
1401 })
1402 .collect();
1403
1404 handler.scope(|handler| {
1405 for (trait_name, constraint_type_id) in traits_not_found.iter() {
1406 let mut type_arguments_string = "".to_string();
1407 if let TypeInfo::Custom {
1408 qualified_call_path: _,
1409 type_arguments: Some(type_arguments),
1410 } = &*type_engine.get(*constraint_type_id)
1411 {
1412 type_arguments_string = format!("<{}>", engines.help_out(type_arguments));
1413 }
1414
1415 handler.emit_err(CompileError::TraitConstraintNotSatisfied {
1417 type_id: type_id.index(),
1418 ty: engines.help_out(type_id).to_string(),
1419 trait_name: format!("{}{}", trait_name, type_arguments_string),
1420 span: access_span.clone(),
1421 });
1422 }
1423
1424 Ok(())
1425 })
1426 }
1427
1428 pub fn get_trait_constraints_are_satisfied_for_types(
1429 module: &Module,
1430 _handler: &Handler,
1431 type_id: TypeId,
1432 constraints: &[TraitConstraint],
1433 engines: &Engines,
1434 ) -> Result<Vec<(TypeId, String)>, ErrorEmitted> {
1435 let type_id = engines.te().get_unaliased_type_id(type_id);
1436
1437 let _decl_engine = engines.de();
1438 let unify_check = UnifyCheck::coercion(engines);
1439 let unify_check_equality = UnifyCheck::constraint_subset(engines);
1440
1441 let mut impld_traits_type_ids: Vec<Vec<(TypeId, String)>> = vec![];
1442 let _ = module.walk_scope_chain_early_return(|lexical_scope| {
1443 lexical_scope
1444 .items
1445 .implemented_traits
1446 .for_each_impls(engines, type_id, true, |e| {
1447 let mut traits: Vec<(TypeId, String)> = vec![];
1448
1449 let key = &e.key;
1450 for constraint in constraints {
1451 if key.name.suffix.name == constraint.trait_name.suffix
1452 && key
1453 .name
1454 .suffix
1455 .args
1456 .iter()
1457 .zip(constraint.type_arguments.iter())
1458 .all(|(a1, a2)| {
1459 unify_check_equality.check(a1.type_id(), a2.type_id())
1460 })
1461 && unify_check.check(type_id, key.type_id)
1462 {
1463 let name_type_args = if !key.name.suffix.args.is_empty() {
1464 format!("<{}>", engines.help_out(key.name.suffix.args.clone()))
1465 } else {
1466 "".to_string()
1467 };
1468 let name =
1469 format!("{}{}", key.name.suffix.name.as_str(), name_type_args);
1470 traits.push((key.type_id, name));
1471 break;
1472 }
1473 }
1474 impld_traits_type_ids.push(traits);
1475 });
1476
1477 Ok(None::<()>)
1478 });
1479 Ok(impld_traits_type_ids.concat())
1480 }
1481
1482 fn get_impls_mut(&mut self, engines: &Engines, type_id: TypeId) -> &mut Vec<TraitEntry> {
1483 let type_root_filter = Self::get_type_root_filter(engines, type_id);
1484 if !self.trait_impls.contains_key(&type_root_filter) {
1485 self.trait_impls
1486 .insert(type_root_filter.clone(), Vec::new());
1487 }
1488
1489 self.trait_impls.get_mut(&type_root_filter).unwrap()
1490 }
1491
1492 pub(crate) fn for_each_impls<F>(
1493 &self,
1494 engines: &Engines,
1495 type_id: TypeId,
1496 include_placeholder: bool,
1497 mut callback: F,
1498 ) where
1499 F: FnMut(&TraitEntry),
1500 {
1501 let type_root_filter = Self::get_type_root_filter(engines, type_id);
1502 self.trait_impls
1503 .get(&type_root_filter)
1504 .iter()
1505 .for_each(|vec| vec.iter().for_each(&mut callback));
1506 if include_placeholder && type_root_filter != TypeRootFilter::Placeholder {
1507 self.trait_impls
1508 .get(&TypeRootFilter::Placeholder)
1509 .iter()
1510 .for_each(|vec| vec.iter().for_each(&mut callback));
1511 }
1512 }
1513
1514 fn get_type_root_filter(engines: &Engines, type_id: TypeId) -> TypeRootFilter {
1517 use TypeInfo::*;
1518 match &*engines.te().get(type_id) {
1519 Unknown => TypeRootFilter::Unknown,
1520 Never => TypeRootFilter::Never,
1521 UnknownGeneric { .. } | Placeholder(_) => TypeRootFilter::Placeholder,
1522 TypeParam(_param) => unreachable!(),
1523 StringSlice => TypeRootFilter::StringSlice,
1524 StringArray(x) => TypeRootFilter::StringArray(x.val()),
1525 UnsignedInteger(x) => match x {
1526 IntegerBits::Eight => TypeRootFilter::U8,
1527 IntegerBits::Sixteen => TypeRootFilter::U16,
1528 IntegerBits::ThirtyTwo => TypeRootFilter::U32,
1529 IntegerBits::SixtyFour => TypeRootFilter::U64,
1530 IntegerBits::V256 => TypeRootFilter::U256,
1531 },
1532 Boolean => TypeRootFilter::Bool,
1533 Custom {
1534 qualified_call_path: call_path,
1535 ..
1536 } => TypeRootFilter::Custom(call_path.call_path.suffix.to_string()),
1537 B256 => TypeRootFilter::B256,
1538 Numeric => TypeRootFilter::U64, Contract => TypeRootFilter::Contract,
1540 ErrorRecovery(_) => TypeRootFilter::ErrorRecovery,
1541 Tuple(fields) => TypeRootFilter::Tuple(fields.len()),
1542 UntypedEnum(decl_id) => TypeRootFilter::Enum(*decl_id),
1543 UntypedStruct(decl_id) => TypeRootFilter::Struct(*decl_id),
1544 Enum(decl_id) => {
1545 TypeRootFilter::Enum(engines.de().get_parsed_decl_id(decl_id).unwrap())
1547 }
1548 Struct(decl_id) => {
1549 TypeRootFilter::Struct(engines.de().get_parsed_decl_id(decl_id).unwrap())
1551 }
1552 ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()),
1553 Array(_, _) => TypeRootFilter::Array,
1554 RawUntypedPtr => TypeRootFilter::RawUntypedPtr,
1555 RawUntypedSlice => TypeRootFilter::RawUntypedSlice,
1556 Ptr(_) => TypeRootFilter::Ptr,
1557 Slice(_) => TypeRootFilter::Slice,
1558 Alias { ty, .. } => Self::get_type_root_filter(engines, ty.type_id()),
1559 TraitType { name, .. } => TypeRootFilter::TraitType(name.to_string()),
1560 Ref {
1561 referenced_type, ..
1562 } => Self::get_type_root_filter(engines, referenced_type.type_id()),
1563 }
1564 }
1565}