Skip to content

Commit

Permalink
Some fixes, and adds get_method_safe_to_unify
Browse files Browse the repository at this point in the history
  • Loading branch information
esdrubal committed Feb 13, 2025
1 parent 695f87f commit e50e270
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ where
&handler,
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.impl_type_parameters.clone(),
impl_trait.implementing_for.type_id,
&impl_trait.items,
&impl_trait.span,
Expand Down
130 changes: 10 additions & 120 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,36 +200,6 @@ enum TypeRootFilter {
TraitType(String),
}

#[derive(Clone, Hash, Eq, PartialEq, Debug)]
enum TypeFilter {
Unknown,
Never,
Placeholder,
TypeParam(usize),
StringSlice,
StringArray(usize),
U8,
U16,
U32,
U64,
U256,
Bool,
Custom(String),
B256,
Contract,
ErrorRecovery,
Tuple(usize, Vec<TypeFilter>),
Enum(ParsedDeclId<EnumDeclaration>, Vec<TypeFilter>),
Struct(ParsedDeclId<StructDeclaration>, Vec<TypeFilter>),
ContractCaller(String),
Array(usize, Box<TypeFilter>),
RawUntypedPtr,
RawUntypedSlice,
Ptr(Box<TypeFilter>),
Slice(Box<TypeFilter>),
TraitType(String),
}

/// Map holding trait implementations for types.
///
/// Note: "impl self" blocks are considered traits and are stored in the
Expand All @@ -238,7 +208,6 @@ enum TypeFilter {
pub struct TraitMap {
trait_impls: TraitImpls,
satisfied_cache: HashSet<u64>,
insert_for_type_cache: HashMap<TypeFilter, im::Vector<TypeId>>,
}

pub(crate) enum IsImplSelf {
Expand Down Expand Up @@ -275,7 +244,6 @@ impl TraitMap {
engines: &Engines,
) -> Result<(), ErrorEmitted> {
let type_id = engines.te().get_unaliased_type_id(type_id);
let trait_map = &mut module.current_items_mut().implemented_traits;

let mut type_id_type_parameters = match &*engines.te().get(type_id) {
TypeInfo::Enum(decl_id) => engines.de().get_enum(decl_id).type_parameters.clone(),
Expand Down Expand Up @@ -324,7 +292,11 @@ impl TraitMap {
}
}

let trait_impls = trait_map.get_impls_mut(engines, type_id).clone();
let trait_impls = module
.current_items_mut()
.implemented_traits
.get_impls_mut(engines, type_id)
.clone();

// check to see if adding this trait will produce a conflicting definition
for TraitEntry {
Expand Down Expand Up @@ -428,7 +400,7 @@ impl TraitMap {
if type_id_type_parameter
.type_id
.is_concrete(engines, crate::TreatNumericAs::Abstract)
&& TraitMap::check_if_trait_constraints_are_satisfied_for_type(
&& Self::check_if_trait_constraints_are_satisfied_for_type(
&Handler::default(),
module,
type_id_type_parameter.type_id,
Expand Down Expand Up @@ -524,7 +496,7 @@ impl TraitMap {
});

// even if there is a conflicting definition, add the trait anyway
trait_map.insert_inner(
module.current_items_mut().implemented_traits.insert_inner(
trait_name,
impl_span.clone(),
trait_decl_span,
Expand Down Expand Up @@ -569,7 +541,6 @@ impl TraitMap {
let trait_map = TraitMap {
trait_impls,
satisfied_cache: HashSet::default(),
insert_for_type_cache: HashMap::<TypeRootFilter, im::Vector<TypeId>>::new(),
};

self.extend(trait_map, engines);
Expand Down Expand Up @@ -602,7 +573,10 @@ impl TraitMap {
// If we have the same method in: impl<T> FromBytes for T
// and: impl FromBytes for DataPoint
// We keep the second implementation.
// We don't care for the order this is checked
#[allow(clippy::iter_over_hash_type)]
for (name, item) in oe.value.trait_items.iter() {
#[allow(clippy::iter_over_hash_type)]
for (existing_name, existing_item) in
self_vec[pos].value.trait_items.iter()
{
Expand Down Expand Up @@ -1654,88 +1628,4 @@ impl TraitMap {
} => Self::get_type_root_filter(engines, referenced_type.type_id),
}
}

// This is used by the trait map to filter the entries into a HashMap with the return type string as key.
fn get_type_filter(engines: &Engines, type_id: TypeId) -> TypeFilter {
use TypeInfo::*;
match &*engines.te().get(type_id) {
Unknown => TypeFilter::Unknown,
Never => TypeFilter::Never,
UnknownGeneric { .. } | Placeholder(_) => TypeFilter::Placeholder,
TypeParam(n) => TypeFilter::TypeParam(*n),
StringSlice => TypeFilter::StringSlice,
StringArray(x) => TypeFilter::StringArray(x.val()),
UnsignedInteger(x) => match x {
IntegerBits::Eight => TypeFilter::U8,
IntegerBits::Sixteen => TypeFilter::U16,
IntegerBits::ThirtyTwo => TypeFilter::U32,
IntegerBits::SixtyFour => TypeFilter::U64,
IntegerBits::V256 => TypeFilter::U256,
},
Boolean => TypeFilter::Bool,
Custom {
qualified_call_path: call_path,
..
} => TypeFilter::Custom(call_path.call_path.suffix.to_string()),
B256 => TypeFilter::B256,
Numeric => TypeFilter::U64, // u64 is the default
Contract => TypeFilter::Contract,
ErrorRecovery(_) => TypeFilter::ErrorRecovery,
Tuple(fields) => TypeFilter::Tuple(
fields.len(),
fields
.iter()
.map(|f| Self::get_type_filter(engines, f.type_id))
.collect::<Vec<_>>(),
),
UntypedEnum(_) => unreachable!(),
UntypedStruct(_) => unreachable!(),
Enum(decl_id) => {
// TODO Remove unwrap once #6475 is fixed
TypeFilter::Enum(
engines.de().get_parsed_decl_id(decl_id).unwrap(),
engines
.de()
.get_enum(decl_id)
.type_parameters
.iter()
.map(|f| Self::get_type_filter(engines, f.type_id))
.collect::<Vec<_>>(),
)
}
Struct(decl_id) => {
// TODO Remove unwrap once #6475 is fixed
TypeFilter::Struct(
engines.de().get_parsed_decl_id(decl_id).unwrap(),
engines
.de()
.get_struct(decl_id)
.type_parameters
.iter()
.map(|f| Self::get_type_filter(engines, f.type_id))
.collect::<Vec<_>>(),
)
}
ContractCaller { abi_name, .. } => TypeFilter::ContractCaller(abi_name.to_string()),
Array(type_argument, length) => TypeFilter::Array(
length.val(),
Box::new(Self::get_type_filter(engines, type_argument.type_id)),
),
RawUntypedPtr => TypeFilter::RawUntypedPtr,
RawUntypedSlice => TypeFilter::RawUntypedSlice,
Ptr(type_argument) => TypeFilter::Ptr(Box::new(Self::get_type_filter(
engines,
type_argument.type_id,
))),
Slice(type_argument) => TypeFilter::Slice(Box::new(Self::get_type_filter(
engines,
type_argument.type_id,
))),
Alias { ty, .. } => Self::get_type_filter(engines, ty.type_id),
TraitType { name, .. } => TypeFilter::TraitType(name.to_string()),
Ref {
referenced_type, ..
} => Self::get_type_filter(engines, referenced_type.type_id),
}
}
}
88 changes: 31 additions & 57 deletions sway-core/src/semantic_analysis/type_check_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
use std::collections::{HashMap, HashSet, VecDeque};

use crate::{
decl_engine::{DeclEngineGet, DeclId, DeclRefFunction},
decl_engine::{
DeclEngineGet, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef,
DeclRefFunction,
},
engine_threading::*,
language::{
parsed::TreeType,
Expand Down Expand Up @@ -31,7 +34,6 @@ use sway_features::ExperimentalFeatures;
use sway_types::{span::Span, Ident, IdentUnique, Spanned};

use super::{
namespace::CodeBlockFirstPass,
namespace::{Items, LexicalScopeId},
symbol_collection_context::SymbolCollectionContext,
type_resolve::{resolve_call_path, resolve_qualified_call_path, resolve_type, VisibilityCheck},
Expand Down Expand Up @@ -828,9 +830,6 @@ impl<'a> TypeCheckContext<'a> {
type_engine.decay_numeric(handler, self.engines, type_id, &method_name.span())?;
}

// Retrieve the implemented traits for the type and insert them in the namespace.
self.insert_trait_implementation_for_type(type_id);

let mut matching_item_decl_refs =
self.find_items_for_type(handler, type_id, method_prefix, method_name)?;

Expand Down Expand Up @@ -962,21 +961,15 @@ impl<'a> TypeCheckContext<'a> {
.zip(method_type_id_type_parameters.iter())
{
let handler = Handler::default();
if self
.namespace_mut()
.module_mut(engines)
.current_items_mut()
.implemented_traits
.check_if_trait_constraints_are_satisfied_for_type(
&handler,
type_id_type_parameter.type_id,
&method_type_id_type_parameter.trait_constraints,
&method.span(),
engines,
TryInsertingTraitImplOnFailure::Yes,
CodeBlockFirstPass::No,
)
.is_err()
if TraitMap::check_if_trait_constraints_are_satisfied_for_type(
&handler,
self.namespace_mut().current_module_mut(),
type_id_type_parameter.type_id,
&method_type_id_type_parameter.trait_constraints,
&method.span(),
engines,
)
.is_err()
{
let (errors, _) = handler.consume();
let mut errors_strings = vec![];
Expand Down Expand Up @@ -1117,6 +1110,8 @@ impl<'a> TypeCheckContext<'a> {
method.implementing_for_typeid.map(|t| {
self.engines.help_out((*self.engines.te().get(t)).clone())
}),
method.name.clone().into(),
trait_decl.trait_decl_ref.is_none(),
);

if !skip_insert {
Expand All @@ -1130,25 +1125,6 @@ impl<'a> TypeCheckContext<'a> {
}
}

// If we have: impl<T> FromBytes for T
// and: impl FromBytes for DataPoint
// We pick the second implementation.
let mut non_blanket_impl_exists = false;
let mut impls_with_type_params = vec![];
let trait_method_clone = trait_methods.clone();
let existing_values = trait_method_clone.values().collect::<Vec<_>>();
for existing_value in existing_values.iter() {
let existing_method = decl_engine.get_function(*existing_value);
if !existing_method.is_from_blanket_impl(engines) {
non_blanket_impl_exists = true;
} else {
impls_with_type_params.push(existing_value.id());
}
}
if non_blanket_impl_exists {
trait_methods.retain(|_, v| !impls_with_type_params.contains(&v.id()));
}

// If we have: impl<T> FromBytes for T
// and: impl FromBytes for DataPoint
// We pick the second implementation.
Expand Down Expand Up @@ -1189,7 +1165,7 @@ impl<'a> TypeCheckContext<'a> {
if let Some(implementing_for_type) = method.implementing_for_typeid {
if eq_check
.with_unify_ref_mut(false)
.check(implementing_for_type, type_id)
.check(type_id, implementing_for_type)
{
exact_matching_methods.push(*trait_method_ref);
}
Expand Down Expand Up @@ -1514,23 +1490,21 @@ impl<'a> TypeCheckContext<'a> {
.iter()
.map(|item| ResolvedTraitImplItem::Typed(item.clone()))
.collect::<Vec<_>>();
self.namespace_mut()
.current_module_mut()
.current_items_mut()
.implemented_traits
.insert(
handler,
canonical_trait_path,
trait_type_args,
trait_type_parameters,
type_id,
&items,
impl_span,
trait_decl_span,
is_impl_self,
is_extending_existing_impl,
engines,
)

TraitMap::insert(
handler,
self.namespace_mut().current_module_mut(),
canonical_trait_path,
trait_type_args,
trait_type_parameters,
type_id,
&items,
impl_span,
trait_decl_span,
is_impl_self,
is_extending_existing_impl,
engines,
)
}

pub(crate) fn get_items_for_type_and_trait_name(
Expand Down
9 changes: 5 additions & 4 deletions sway-types/src/span.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::SourceId;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};

use crate::{SourceEngine, SourceId};

use {
lazy_static::lazy_static,
std::{cmp, fmt, hash::Hash, sync::Arc},
use std::{
cmp,
fmt::{self, Display},
hash::Hash,
sync::Arc,
};

lazy_static! {
Expand Down

0 comments on commit e50e270

Please sign in to comment.