Skip to content

Commit

Permalink
Implement OrdWithEngines for some types (FuelLabs#4082)
Browse files Browse the repository at this point in the history
## Description

This PR is a subset of FuelLabs#3744. It adds a `OrdWithEngines` for the types
required in FuelLabs#3744. Note---this isn't a necessary change into master
right at this current moment, just simply a way of breaking up FuelLabs#3744 😄

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
emilyaherbert authored Feb 15, 2023
1 parent b0b0d86 commit d3d6d33
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 28 deletions.
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,
}
}
}

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

0 comments on commit d3d6d33

Please sign in to comment.