Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update trait map to track fully resolved impl type parameters. #6963

Merged
merged 10 commits into from
Mar 9, 2025
2 changes: 1 addition & 1 deletion sway-core/src/abi_generation/abi_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl TypeInfo {
Never => "never".into(),
UnknownGeneric { name, .. } => name.to_string(),
Placeholder(_) => "_".to_string(),
TypeParam(n) => format!("typeparam({n})"),
TypeParam(param) => format!("typeparam({})", param.name),
StringSlice => "str".into(),
StringArray(length) => format!("str[{}]", length.val()),
UnsignedInteger(x) => match x {
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/abi_generation/evm_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String {
Never => "never".into(),
UnknownGeneric { name, .. } => name.to_string(),
Placeholder(_) => "_".to_string(),
TypeParam(n) => format!("typeparam({n})"),
TypeParam(param) => format!("typeparam({})", param.name),
StringSlice => "str".into(),
StringArray(x) => format!("str[{}]", x.val()),
UnsignedInteger(x) => match x {
Expand Down
18 changes: 13 additions & 5 deletions sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,19 @@ impl<T: PartialEqWithEngines> PartialEqWithEngines for [T] {
}
impl<T: OrdWithEngines> OrdWithEngines for [T] {
fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
self.iter()
.zip(other.iter())
.map(|(x, y)| x.cmp(y, ctx))
.find(|o| o.is_ne())
.unwrap_or_else(|| self.len().cmp(&other.len()))
let len_cmp = self.len().cmp(&other.len());
if len_cmp != Ordering::Equal {
return len_cmp;
}

for (a, b) in self.iter().zip(other.iter()) {
let cmp = a.cmp(b, ctx);
if cmp != Ordering::Equal {
return cmp;
}
}

Ordering::Equal
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ impl ty::TyAbiDecl {
CallPath::ident_to_fullpath(self.name.clone(), ctx.namespace()),
vec![],
type_id,
vec![],
&all_items,
&self.span,
Some(self.span()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ where
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.implementing_for.type_id,
impl_trait.impl_type_parameters.clone(),
&impl_trait.items,
&impl_trait.span,
impl_trait
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl TyDecl {
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.implementing_for.type_id,
impl_trait.impl_type_parameters.clone(),
&impl_trait.items,
&impl_trait.span,
impl_trait
Expand Down Expand Up @@ -310,6 +311,7 @@ impl TyDecl {
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.implementing_for.type_id,
impl_trait.impl_type_parameters.clone(),
impl_trait_items,
&impl_trait.span,
impl_trait
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ impl TyImplSelfOrTrait {
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.implementing_for.type_id,
impl_trait.impl_type_parameters.clone(),
&impl_trait.items,
&impl_trait.span,
impl_trait
Expand Down Expand Up @@ -820,6 +821,7 @@ fn type_check_trait_implementation(
trait_name.clone(),
trait_type_arguments.to_vec(),
implementing_for,
impl_type_parameters.to_vec(),
&this_supertrait_impld_method_refs
.values()
.cloned()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl TyTraitDecl {
CallPath::ident_to_fullpath(name.clone(), ctx.namespace),
new_type_parameters.iter().map(|x| x.into()).collect(),
self_type,
vec![],
&dummy_interface_surface,
&span,
None,
Expand Down Expand Up @@ -235,6 +236,7 @@ impl TyTraitDecl {
CallPath::ident_to_fullpath(name.clone(), ctx.namespace()),
new_type_parameters.iter().map(|x| x.into()).collect(),
self_type,
vec![],
&dummy_interface_surface,
&span,
None,
Expand Down Expand Up @@ -614,6 +616,7 @@ impl TyTraitDecl {
trait_name.clone(),
type_arguments.to_vec(),
type_id,
vec![],
&all_items,
&trait_name.span(),
Some(self.span()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,7 @@ impl ty::TyExpression {
abi_name.clone(),
vec![],
return_type,
vec![],
&abi_items,
span,
Some(span.clone()),
Expand Down
53 changes: 32 additions & 21 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ impl From<bool> for CodeBlockFirstPass {
}

#[derive(Clone, Debug)]
struct TraitSuffix {
name: Ident,
args: Vec<TypeArgument>,
pub(crate) struct TraitSuffix {
pub(crate) name: Ident,
pub(crate) args: Vec<TypeArgument>,
}
impl PartialEqWithEngines for TraitSuffix {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
Expand Down Expand Up @@ -99,17 +99,20 @@ impl DebugWithEngines for TraitSuffix {
type TraitName = Arc<CallPath<TraitSuffix>>;

#[derive(Clone, Debug)]
struct TraitKey {
name: TraitName,
type_id: TypeId,
trait_decl_span: Option<Span>,
pub(crate) struct TraitKey {
pub(crate) name: TraitName,
pub(crate) type_id: TypeId,
pub(crate) impl_type_parameters: Vec<TypeId>,
pub(crate) trait_decl_span: Option<Span>,
}

impl OrdWithEngines for TraitKey {
fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> std::cmp::Ordering {
self.name
.cmp(&other.name, ctx)
.then_with(|| self.type_id.cmp(&other.type_id))
self.name.cmp(&other.name, ctx).then_with(|| {
self.type_id
.cmp(&other.type_id)
.then_with(|| self.impl_type_parameters.cmp(&other.impl_type_parameters))
})
}
}

Expand Down Expand Up @@ -148,29 +151,28 @@ impl ResolvedTraitImplItem {
type TraitItems = HashMap<String, ResolvedTraitImplItem>;

#[derive(Clone, Debug)]
struct TraitValue {
trait_items: TraitItems,
pub(crate) struct TraitValue {
pub(crate) trait_items: TraitItems,
/// The span of the entire impl block.
impl_span: Span,
pub(crate) impl_span: Span,
}

#[derive(Clone, Debug)]
struct TraitEntry {
key: TraitKey,
value: TraitValue,
pub(crate) struct TraitEntry {
pub(crate) key: TraitKey,
pub(crate) value: TraitValue,
}

/// Map of string of type entry id and vec of [TraitEntry].
/// We are using the HashMap as a wrapper to the vec so the TraitMap algorithms
/// don't need to traverse every TraitEntry.
type TraitImpls = HashMap<TypeRootFilter, Vec<TraitEntry>>;
pub(crate) type TraitImpls = HashMap<TypeRootFilter, Vec<TraitEntry>>;

#[derive(Clone, Hash, Eq, PartialOrd, Ord, PartialEq, Debug)]
enum TypeRootFilter {
pub(crate) enum TypeRootFilter {
Unknown,
Never,
Placeholder,
TypeParam(usize),
StringSlice,
StringArray(usize),
U8,
Expand Down Expand Up @@ -201,7 +203,7 @@ enum TypeRootFilter {
/// [TraitMap].
#[derive(Clone, Debug, Default)]
pub struct TraitMap {
trait_impls: TraitImpls,
pub(crate) trait_impls: TraitImpls,
satisfied_cache: HashSet<u64>,
}

Expand Down Expand Up @@ -230,6 +232,7 @@ impl TraitMap {
trait_name: CallPath,
trait_type_args: Vec<TypeArgument>,
type_id: TypeId,
impl_type_parameters: Vec<TypeId>,
items: &[ResolvedTraitImplItem],
impl_span: &Span,
trait_decl_span: Option<Span>,
Expand Down Expand Up @@ -276,6 +279,7 @@ impl TraitMap {
name: map_trait_name,
type_id: map_type_id,
trait_decl_span: _,
impl_type_parameters: _,
},
value:
TraitValue {
Expand Down Expand Up @@ -443,6 +447,7 @@ impl TraitMap {
impl_span.clone(),
trait_decl_span,
type_id,
impl_type_parameters,
trait_items,
engines,
);
Expand All @@ -451,19 +456,22 @@ impl TraitMap {
})
}

#[allow(clippy::too_many_arguments)]
fn insert_inner(
&mut self,
trait_name: TraitName,
impl_span: Span,
trait_decl_span: Option<Span>,
type_id: TypeId,
impl_type_parameters: Vec<TypeId>,
trait_methods: TraitItems,
engines: &Engines,
) {
let key = TraitKey {
name: trait_name,
type_id,
trait_decl_span,
impl_type_parameters,
};
let value = TraitValue {
trait_items: trait_methods,
Expand Down Expand Up @@ -643,6 +651,7 @@ impl TraitMap {
name: map_trait_name,
type_id: map_type_id,
trait_decl_span: map_trait_decl_span,
impl_type_parameters: map_impl_type_parameters,
},
value:
TraitValue {
Expand All @@ -658,6 +667,7 @@ impl TraitMap {
impl_span.clone(),
map_trait_decl_span.clone(),
*type_id,
map_impl_type_parameters.clone(),
map_trait_items.clone(),
engines,
);
Expand All @@ -667,6 +677,7 @@ impl TraitMap {
impl_span.clone(),
map_trait_decl_span.clone(),
*map_type_id,
map_impl_type_parameters.clone(),
Self::filter_dummy_methods(
map_trait_items.clone(),
*type_id,
Expand Down Expand Up @@ -1478,7 +1489,7 @@ impl TraitMap {
Unknown => TypeRootFilter::Unknown,
Never => TypeRootFilter::Never,
UnknownGeneric { .. } | Placeholder(_) => TypeRootFilter::Placeholder,
TypeParam(n) => TypeRootFilter::TypeParam(*n),
TypeParam(_param) => unreachable!(),
StringSlice => TypeRootFilter::StringSlice,
StringArray(x) => TypeRootFilter::StringArray(x.val()),
UnsignedInteger(x) => match x {
Expand Down
19 changes: 18 additions & 1 deletion sway-core/src/semantic_analysis/type_check_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use crate::{
Namespace,
},
type_system::{SubstTypes, TypeArgument, TypeId, TypeInfo},
EnforceTypeArguments, SubstTypesContext, TraitConstraint, TypeSubstMap, UnifyCheck,
EnforceTypeArguments, SubstTypesContext, TraitConstraint, TypeParameter, TypeSubstMap,
UnifyCheck,
};
use sway_error::{
error::CompileError,
Expand Down Expand Up @@ -1289,13 +1290,28 @@ impl<'a> TypeCheckContext<'a> {
trait_name: CallPath,
trait_type_args: Vec<TypeArgument>,
type_id: TypeId,
mut impl_type_parameters: Vec<TypeParameter>,
items: &[ty::TyImplItem],
impl_span: &Span,
trait_decl_span: Option<Span>,
is_impl_self: IsImplSelf,
is_extending_existing_impl: IsExtendingExistingImpl,
) -> Result<(), ErrorEmitted> {
let engines = self.engines;

// Use trait name with full path, improves consistency between
// this inserting and getting in `get_methods_for_type_and_trait_name`.
impl_type_parameters.iter_mut().for_each(|tp| {
tp.trait_constraints.iter_mut().for_each(|tc| {
tc.trait_name = tc.trait_name.to_fullpath(self.engines(), self.namespace())
})
});

let impl_type_parameters_ids = impl_type_parameters
.iter()
.map(|type_parameter| engines.te().new_type_param(type_parameter.clone()))
.collect::<Vec<_>>();

// CallPath::to_fullpath gives a resolvable path, but is not guaranteed to provide the path
// to the actual trait declaration. Since the path of the trait declaration is used as a key
// in the trait map, we need to find the actual declaration path.
Expand All @@ -1314,6 +1330,7 @@ impl<'a> TypeCheckContext<'a> {
canonical_trait_path,
trait_type_args,
type_id,
impl_type_parameters_ids,
&items,
impl_span,
trait_decl_span,
Expand Down
20 changes: 9 additions & 11 deletions sway-core/src/type_system/ast_elements/type_parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ impl OrdWithEngines for TypeParameter {
fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
let TypeParameter {
type_id: lti,
name: ln,
name: lname,
trait_constraints: ltc,
// these fields are not compared because they aren't relevant/a
// reliable source of obj v. obj distinction
trait_constraints_span: _,
initial_type_id: _,
is_from_parent: _,
} = self;
} = &self;
let TypeParameter {
type_id: rti,
name: rn,
Expand All @@ -108,15 +108,13 @@ impl OrdWithEngines for TypeParameter {
trait_constraints_span: _,
initial_type_id: _,
is_from_parent: _,
} = other;
ln.cmp(rn)
.then_with(|| {
ctx.engines()
.te()
.get(*lti)
.cmp(&ctx.engines().te().get(*rti), ctx)
})
.then_with(|| ltc.cmp(rtc, ctx))
} = &other;
let type_engine = ctx.engines().te();
let ltype = type_engine.get(*lti);
let rtype = type_engine.get(*rti);
ltype
.cmp(&rtype, ctx)
.then_with(|| lname.cmp(rn).then_with(|| ltc.cmp(rtc, ctx)))
}
}

Expand Down
Loading
Loading