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

Implement OrdWithEngines for some types #4082

Merged
merged 4 commits into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ impl<T: PartialEqWithEngines> PartialEq for WithEngines<'_, T> {

impl<T: EqWithEngines> Eq for WithEngines<'_, T> {}

impl<T: OrdWithEngines> PartialOrd for WithEngines<'_, T>
where
T: PartialEqWithEngines,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.thing.cmp(&other.thing, self.engines.te()))
}
}

impl<T: OrdWithEngines> Ord for WithEngines<'_, T>
where
T: EqWithEngines,
{
fn cmp(&self, other: &Self) -> Ordering {
self.thing.cmp(&other.thing, self.engines.te())
}
}

pub(crate) trait DisplayWithEngines {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: Engines<'_>) -> fmt::Result;
}
Expand Down Expand Up @@ -141,7 +159,7 @@ pub trait PartialEqWithEngines {
}

pub trait OrdWithEngines {
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering;
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering;
}

impl<T: EqWithEngines + ?Sized> EqWithEngines for &T {}
Expand All @@ -151,8 +169,19 @@ impl<T: PartialEqWithEngines + ?Sized> PartialEqWithEngines for &T {
}
}
impl<T: OrdWithEngines + ?Sized> OrdWithEngines for &T {
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering {
(*self).cmp(*rhs, type_engine)
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
(*self).cmp(*other, type_engine)
}
}

impl<T: OrdWithEngines> OrdWithEngines for Option<T> {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
match (self, other) {
(Some(x), Some(y)) => x.cmp(y, type_engine),
(Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater,
(None, None) => Ordering::Equal,
}
emilyaherbert marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -174,11 +203,11 @@ impl<T: PartialEqWithEngines> PartialEqWithEngines for [T] {
}
}
impl<T: OrdWithEngines> OrdWithEngines for [T] {
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
self.iter()
.zip(rhs.iter())
.zip(other.iter())
.map(|(x, y)| x.cmp(y, type_engine))
.find(|o| o.is_ne())
.unwrap_or_else(|| self.len().cmp(&rhs.len()))
.unwrap_or_else(|| self.len().cmp(&other.len()))
}
}
31 changes: 30 additions & 1 deletion sway-core/src/language/ty/declaration/enum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::hash::{Hash, Hasher};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
};

use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};
Expand Down Expand Up @@ -154,6 +157,32 @@ impl PartialEqWithEngines for TyEnumVariant {
}
}

impl OrdWithEngines for TyEnumVariant {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
let TyEnumVariant {
name: ln,
type_argument: lta,
tag: lt,
// these fields are not compared because they aren't relevant/a
// reliable source of obj v. obj distinction
span: _,
attributes: _,
} = self;
let TyEnumVariant {
name: rn,
type_argument: rta,
tag: rt,
// these fields are not compared because they aren't relevant/a
// reliable source of obj v. obj distinction
span: _,
attributes: _,
} = other;
ln.cmp(rn)
.then_with(|| lta.cmp(rta, type_engine))
.then_with(|| lt.cmp(rt))
}
}

impl SubstTypes for TyEnumVariant {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
self.type_argument.subst_inner(type_mapping, engines);
Expand Down
27 changes: 26 additions & 1 deletion sway-core/src/language/ty/declaration/struct.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::hash::{Hash, Hasher};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
};

use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};
Expand Down Expand Up @@ -161,6 +164,28 @@ impl PartialEqWithEngines for TyStructField {
}
}

impl OrdWithEngines for TyStructField {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
let TyStructField {
name: ln,
type_argument: lta,
// these fields are not compared because they aren't relevant/a
// reliable source of obj v. obj distinction
span: _,
attributes: _,
} = self;
let TyStructField {
name: rn,
type_argument: rta,
// these fields are not compared because they aren't relevant/a
// reliable source of obj v. obj distinction
span: _,
attributes: _,
} = other;
ln.cmp(rn).then_with(|| lta.cmp(rta, type_engine))
}
}

impl SubstTypes for TyStructField {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
self.type_argument.subst_inner(type_mapping, engines);
Expand Down
25 changes: 14 additions & 11 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use std::{
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
};

use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};
Expand All @@ -23,10 +26,10 @@ impl PartialEqWithEngines for TraitSuffix {
}
}
impl OrdWithEngines for TraitSuffix {
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
self.name
.cmp(&rhs.name)
.then_with(|| self.args.cmp(&rhs.args, type_engine))
.cmp(&other.name)
.then_with(|| self.args.cmp(&other.args, type_engine))
}
}

Expand All @@ -38,11 +41,11 @@ impl<T: PartialEqWithEngines> PartialEqWithEngines for CallPath<T> {
}
}
impl<T: OrdWithEngines> OrdWithEngines for CallPath<T> {
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
self.prefixes
.cmp(&rhs.prefixes)
.then_with(|| self.suffix.cmp(&rhs.suffix, type_engine))
.then_with(|| self.is_absolute.cmp(&rhs.is_absolute))
.cmp(&other.prefixes)
.then_with(|| self.suffix.cmp(&other.suffix, type_engine))
.then_with(|| self.is_absolute.cmp(&other.is_absolute))
}
}

Expand All @@ -55,10 +58,10 @@ struct TraitKey {
}

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

Expand Down
124 changes: 121 additions & 3 deletions sway-core/src/type_system/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ use sway_error::error::CompileError;
use sway_types::{integer_bits::IntegerBits, span::Span, Spanned};

use std::{
cmp::Ordering,
collections::HashSet,
fmt,
hash::{Hash, Hasher},
};

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub enum AbiName {
Deferred,
Known(CallPath),
Expand Down Expand Up @@ -146,7 +147,7 @@ pub enum TypeInfo {

impl HashWithEngines for TypeInfo {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
std::mem::discriminant(self).hash(state);
self.discriminant_value().hash(state);
match self {
TypeInfo::Str(len) => {
len.hash(state);
Expand Down Expand Up @@ -313,7 +314,95 @@ impl PartialEqWithEngines for TypeInfo {
(TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => {
l_fields.eq(r_fields, engines)
}
(l, r) => std::mem::discriminant(l) == std::mem::discriminant(r),
(l, r) => l.discriminant_value() == r.discriminant_value(),
}
}
}

impl OrdWithEngines for TypeInfo {
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
match (self, other) {
(
Self::UnknownGeneric {
name: l,
trait_constraints: ltc,
},
Self::UnknownGeneric {
name: r,
trait_constraints: rtc,
},
) => l.cmp(r).then_with(|| ltc.cmp(rtc, type_engine)),
(Self::Placeholder(l), Self::Placeholder(r)) => l.cmp(r, type_engine),
(
Self::Custom {
call_path: l_call_path,
type_arguments: l_type_args,
},
Self::Custom {
call_path: r_call_path,
type_arguments: r_type_args,
},
) => l_call_path.suffix.cmp(&r_call_path.suffix).then_with(|| {
l_type_args
.as_deref()
.cmp(&r_type_args.as_deref(), type_engine)
}),
(Self::Str(l), Self::Str(r)) => l.val().cmp(&r.val()),
(Self::UnsignedInteger(l), Self::UnsignedInteger(r)) => l.cmp(r),
(
Self::Enum {
call_path: l_call_path,
type_parameters: ltp,
variant_types: lvt,
},
Self::Enum {
call_path: r_call_path,
type_parameters: rtp,
variant_types: rvt,
},
) => l_call_path
.suffix
.cmp(&r_call_path.suffix)
.then_with(|| ltp.cmp(rtp, type_engine))
.then_with(|| lvt.cmp(rvt, type_engine)),
(
Self::Struct {
call_path: l_call_path,
type_parameters: ltp,
fields: lf,
},
Self::Struct {
call_path: r_call_path,
type_parameters: rtp,
fields: rf,
},
) => l_call_path
.suffix
.cmp(&r_call_path.suffix)
.then_with(|| ltp.cmp(rtp, type_engine))
.then_with(|| lf.cmp(rf, type_engine)),
(Self::Tuple(l), Self::Tuple(r)) => l.cmp(r, type_engine),
(
Self::ContractCaller {
abi_name: l_abi_name,
address: _,
},
Self::ContractCaller {
abi_name: r_abi_name,
address: _,
},
) => {
// NOTE: we assume all contract callers are unique
l_abi_name.cmp(r_abi_name)
}
(Self::Array(l0, l1), Self::Array(r0, r1)) => type_engine
.get(l0.type_id)
.cmp(&type_engine.get(r0.type_id), type_engine)
.then_with(|| l1.val().cmp(&r1.val())),
(TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => {
l_fields.cmp(r_fields, type_engine)
}
(l, r) => l.discriminant_value().cmp(&r.discriminant_value()),
}
}
}
Expand Down Expand Up @@ -505,6 +594,35 @@ impl UnconstrainedTypeParameters for TypeInfo {
}

impl TypeInfo {
/// Returns a discriminant for the variant.
// NOTE: This is approach is not the most straightforward, but is needed
// because of this missing feature on Rust's `Discriminant` type:
// https://github.com/rust-lang/rust/pull/106418
fn discriminant_value(&self) -> u8 {
match self {
TypeInfo::Unknown => 0,
TypeInfo::UnknownGeneric { .. } => 1,
TypeInfo::Placeholder(_) => 2,
TypeInfo::Str(_) => 3,
TypeInfo::UnsignedInteger(_) => 4,
TypeInfo::Enum { .. } => 5,
TypeInfo::Struct { .. } => 6,
TypeInfo::Boolean => 7,
TypeInfo::Tuple(_) => 8,
TypeInfo::ContractCaller { .. } => 9,
TypeInfo::Custom { .. } => 10,
TypeInfo::SelfType => 11,
TypeInfo::B256 => 12,
TypeInfo::Numeric => 13,
TypeInfo::Contract => 14,
TypeInfo::ErrorRecovery => 15,
TypeInfo::Array(_, _) => 16,
TypeInfo::Storage { .. } => 17,
TypeInfo::RawUntypedPtr => 18,
TypeInfo::RawUntypedSlice => 19,
}
}

/// maps a type to a name that is used when constructing function selectors
pub(crate) fn to_selector_name(
&self,
Expand Down
Loading