Skip to content

Commit d3d6d33

Browse files
Implement OrdWithEngines for some types (#4082)
## Description This PR is a subset of #3744. It adds a `OrdWithEngines` for the types required in #3744. Note---this isn't a necessary change into master right at this current moment, just simply a way of breaking up #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.
1 parent b0b0d86 commit d3d6d33

File tree

9 files changed

+299
-28
lines changed

9 files changed

+299
-28
lines changed

sway-core/src/engine_threading.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,24 @@ impl<T: PartialEqWithEngines> PartialEq for WithEngines<'_, T> {
8787

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

90+
impl<T: OrdWithEngines> PartialOrd for WithEngines<'_, T>
91+
where
92+
T: PartialEqWithEngines,
93+
{
94+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
95+
Some(self.thing.cmp(&other.thing, self.engines.te()))
96+
}
97+
}
98+
99+
impl<T: OrdWithEngines> Ord for WithEngines<'_, T>
100+
where
101+
T: EqWithEngines,
102+
{
103+
fn cmp(&self, other: &Self) -> Ordering {
104+
self.thing.cmp(&other.thing, self.engines.te())
105+
}
106+
}
107+
90108
pub(crate) trait DisplayWithEngines {
91109
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: Engines<'_>) -> fmt::Result;
92110
}
@@ -141,7 +159,7 @@ pub trait PartialEqWithEngines {
141159
}
142160

143161
pub trait OrdWithEngines {
144-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering;
162+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering;
145163
}
146164

147165
impl<T: EqWithEngines + ?Sized> EqWithEngines for &T {}
@@ -151,8 +169,19 @@ impl<T: PartialEqWithEngines + ?Sized> PartialEqWithEngines for &T {
151169
}
152170
}
153171
impl<T: OrdWithEngines + ?Sized> OrdWithEngines for &T {
154-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering {
155-
(*self).cmp(*rhs, type_engine)
172+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
173+
(*self).cmp(*other, type_engine)
174+
}
175+
}
176+
177+
impl<T: OrdWithEngines> OrdWithEngines for Option<T> {
178+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
179+
match (self, other) {
180+
(Some(x), Some(y)) => x.cmp(y, type_engine),
181+
(Some(_), None) => Ordering::Less,
182+
(None, Some(_)) => Ordering::Greater,
183+
(None, None) => Ordering::Equal,
184+
}
156185
}
157186
}
158187

@@ -174,11 +203,11 @@ impl<T: PartialEqWithEngines> PartialEqWithEngines for [T] {
174203
}
175204
}
176205
impl<T: OrdWithEngines> OrdWithEngines for [T] {
177-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering {
206+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
178207
self.iter()
179-
.zip(rhs.iter())
208+
.zip(other.iter())
180209
.map(|(x, y)| x.cmp(y, type_engine))
181210
.find(|o| o.is_ne())
182-
.unwrap_or_else(|| self.len().cmp(&rhs.len()))
211+
.unwrap_or_else(|| self.len().cmp(&other.len()))
183212
}
184213
}

sway-core/src/language/ty/declaration/enum.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::hash::{Hash, Hasher};
1+
use std::{
2+
cmp::Ordering,
3+
hash::{Hash, Hasher},
4+
};
25

36
use sway_error::error::CompileError;
47
use sway_types::{Ident, Span, Spanned};
@@ -154,6 +157,32 @@ impl PartialEqWithEngines for TyEnumVariant {
154157
}
155158
}
156159

160+
impl OrdWithEngines for TyEnumVariant {
161+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
162+
let TyEnumVariant {
163+
name: ln,
164+
type_argument: lta,
165+
tag: lt,
166+
// these fields are not compared because they aren't relevant/a
167+
// reliable source of obj v. obj distinction
168+
span: _,
169+
attributes: _,
170+
} = self;
171+
let TyEnumVariant {
172+
name: rn,
173+
type_argument: rta,
174+
tag: rt,
175+
// these fields are not compared because they aren't relevant/a
176+
// reliable source of obj v. obj distinction
177+
span: _,
178+
attributes: _,
179+
} = other;
180+
ln.cmp(rn)
181+
.then_with(|| lta.cmp(rta, type_engine))
182+
.then_with(|| lt.cmp(rt))
183+
}
184+
}
185+
157186
impl SubstTypes for TyEnumVariant {
158187
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
159188
self.type_argument.subst_inner(type_mapping, engines);

sway-core/src/language/ty/declaration/struct.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::hash::{Hash, Hasher};
1+
use std::{
2+
cmp::Ordering,
3+
hash::{Hash, Hasher},
4+
};
25

36
use sway_error::error::CompileError;
47
use sway_types::{Ident, Span, Spanned};
@@ -161,6 +164,28 @@ impl PartialEqWithEngines for TyStructField {
161164
}
162165
}
163166

167+
impl OrdWithEngines for TyStructField {
168+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
169+
let TyStructField {
170+
name: ln,
171+
type_argument: lta,
172+
// these fields are not compared because they aren't relevant/a
173+
// reliable source of obj v. obj distinction
174+
span: _,
175+
attributes: _,
176+
} = self;
177+
let TyStructField {
178+
name: rn,
179+
type_argument: rta,
180+
// these fields are not compared because they aren't relevant/a
181+
// reliable source of obj v. obj distinction
182+
span: _,
183+
attributes: _,
184+
} = other;
185+
ln.cmp(rn).then_with(|| lta.cmp(rta, type_engine))
186+
}
187+
}
188+
164189
impl SubstTypes for TyStructField {
165190
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
166191
self.type_argument.subst_inner(type_mapping, engines);

sway-core/src/semantic_analysis/namespace/trait_map.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::collections::{BTreeMap, BTreeSet};
1+
use std::{
2+
cmp::Ordering,
3+
collections::{BTreeMap, BTreeSet},
4+
};
25

36
use sway_error::error::CompileError;
47
use sway_types::{Ident, Span, Spanned};
@@ -23,10 +26,10 @@ impl PartialEqWithEngines for TraitSuffix {
2326
}
2427
}
2528
impl OrdWithEngines for TraitSuffix {
26-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
29+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
2730
self.name
28-
.cmp(&rhs.name)
29-
.then_with(|| self.args.cmp(&rhs.args, type_engine))
31+
.cmp(&other.name)
32+
.then_with(|| self.args.cmp(&other.args, type_engine))
3033
}
3134
}
3235

@@ -38,11 +41,11 @@ impl<T: PartialEqWithEngines> PartialEqWithEngines for CallPath<T> {
3841
}
3942
}
4043
impl<T: OrdWithEngines> OrdWithEngines for CallPath<T> {
41-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
44+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
4245
self.prefixes
43-
.cmp(&rhs.prefixes)
44-
.then_with(|| self.suffix.cmp(&rhs.suffix, type_engine))
45-
.then_with(|| self.is_absolute.cmp(&rhs.is_absolute))
46+
.cmp(&other.prefixes)
47+
.then_with(|| self.suffix.cmp(&other.suffix, type_engine))
48+
.then_with(|| self.is_absolute.cmp(&other.is_absolute))
4649
}
4750
}
4851

@@ -55,10 +58,10 @@ struct TraitKey {
5558
}
5659

5760
impl OrdWithEngines for TraitKey {
58-
fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
61+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering {
5962
self.name
60-
.cmp(&rhs.name, type_engine)
61-
.then_with(|| self.type_id.cmp(&rhs.type_id))
63+
.cmp(&other.name, type_engine)
64+
.then_with(|| self.type_id.cmp(&other.type_id))
6265
}
6366
}
6467

sway-core/src/type_system/info.rs

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use sway_error::error::CompileError;
88
use sway_types::{integer_bits::IntegerBits, span::Span, Spanned};
99

1010
use std::{
11+
cmp::Ordering,
1112
collections::HashSet,
1213
fmt,
1314
hash::{Hash, Hasher},
1415
};
1516

16-
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
17+
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
1718
pub enum AbiName {
1819
Deferred,
1920
Known(CallPath),
@@ -146,7 +147,7 @@ pub enum TypeInfo {
146147

147148
impl HashWithEngines for TypeInfo {
148149
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
149-
std::mem::discriminant(self).hash(state);
150+
self.discriminant_value().hash(state);
150151
match self {
151152
TypeInfo::Str(len) => {
152153
len.hash(state);
@@ -313,7 +314,95 @@ impl PartialEqWithEngines for TypeInfo {
313314
(TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => {
314315
l_fields.eq(r_fields, engines)
315316
}
316-
(l, r) => std::mem::discriminant(l) == std::mem::discriminant(r),
317+
(l, r) => l.discriminant_value() == r.discriminant_value(),
318+
}
319+
}
320+
}
321+
322+
impl OrdWithEngines for TypeInfo {
323+
fn cmp(&self, other: &Self, type_engine: &TypeEngine) -> Ordering {
324+
match (self, other) {
325+
(
326+
Self::UnknownGeneric {
327+
name: l,
328+
trait_constraints: ltc,
329+
},
330+
Self::UnknownGeneric {
331+
name: r,
332+
trait_constraints: rtc,
333+
},
334+
) => l.cmp(r).then_with(|| ltc.cmp(rtc, type_engine)),
335+
(Self::Placeholder(l), Self::Placeholder(r)) => l.cmp(r, type_engine),
336+
(
337+
Self::Custom {
338+
call_path: l_call_path,
339+
type_arguments: l_type_args,
340+
},
341+
Self::Custom {
342+
call_path: r_call_path,
343+
type_arguments: r_type_args,
344+
},
345+
) => l_call_path.suffix.cmp(&r_call_path.suffix).then_with(|| {
346+
l_type_args
347+
.as_deref()
348+
.cmp(&r_type_args.as_deref(), type_engine)
349+
}),
350+
(Self::Str(l), Self::Str(r)) => l.val().cmp(&r.val()),
351+
(Self::UnsignedInteger(l), Self::UnsignedInteger(r)) => l.cmp(r),
352+
(
353+
Self::Enum {
354+
call_path: l_call_path,
355+
type_parameters: ltp,
356+
variant_types: lvt,
357+
},
358+
Self::Enum {
359+
call_path: r_call_path,
360+
type_parameters: rtp,
361+
variant_types: rvt,
362+
},
363+
) => l_call_path
364+
.suffix
365+
.cmp(&r_call_path.suffix)
366+
.then_with(|| ltp.cmp(rtp, type_engine))
367+
.then_with(|| lvt.cmp(rvt, type_engine)),
368+
(
369+
Self::Struct {
370+
call_path: l_call_path,
371+
type_parameters: ltp,
372+
fields: lf,
373+
},
374+
Self::Struct {
375+
call_path: r_call_path,
376+
type_parameters: rtp,
377+
fields: rf,
378+
},
379+
) => l_call_path
380+
.suffix
381+
.cmp(&r_call_path.suffix)
382+
.then_with(|| ltp.cmp(rtp, type_engine))
383+
.then_with(|| lf.cmp(rf, type_engine)),
384+
(Self::Tuple(l), Self::Tuple(r)) => l.cmp(r, type_engine),
385+
(
386+
Self::ContractCaller {
387+
abi_name: l_abi_name,
388+
address: _,
389+
},
390+
Self::ContractCaller {
391+
abi_name: r_abi_name,
392+
address: _,
393+
},
394+
) => {
395+
// NOTE: we assume all contract callers are unique
396+
l_abi_name.cmp(r_abi_name)
397+
}
398+
(Self::Array(l0, l1), Self::Array(r0, r1)) => type_engine
399+
.get(l0.type_id)
400+
.cmp(&type_engine.get(r0.type_id), type_engine)
401+
.then_with(|| l1.val().cmp(&r1.val())),
402+
(TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => {
403+
l_fields.cmp(r_fields, type_engine)
404+
}
405+
(l, r) => l.discriminant_value().cmp(&r.discriminant_value()),
317406
}
318407
}
319408
}
@@ -505,6 +594,35 @@ impl UnconstrainedTypeParameters for TypeInfo {
505594
}
506595

507596
impl TypeInfo {
597+
/// Returns a discriminant for the variant.
598+
// NOTE: This is approach is not the most straightforward, but is needed
599+
// because of this missing feature on Rust's `Discriminant` type:
600+
// https://github.com/rust-lang/rust/pull/106418
601+
fn discriminant_value(&self) -> u8 {
602+
match self {
603+
TypeInfo::Unknown => 0,
604+
TypeInfo::UnknownGeneric { .. } => 1,
605+
TypeInfo::Placeholder(_) => 2,
606+
TypeInfo::Str(_) => 3,
607+
TypeInfo::UnsignedInteger(_) => 4,
608+
TypeInfo::Enum { .. } => 5,
609+
TypeInfo::Struct { .. } => 6,
610+
TypeInfo::Boolean => 7,
611+
TypeInfo::Tuple(_) => 8,
612+
TypeInfo::ContractCaller { .. } => 9,
613+
TypeInfo::Custom { .. } => 10,
614+
TypeInfo::SelfType => 11,
615+
TypeInfo::B256 => 12,
616+
TypeInfo::Numeric => 13,
617+
TypeInfo::Contract => 14,
618+
TypeInfo::ErrorRecovery => 15,
619+
TypeInfo::Array(_, _) => 16,
620+
TypeInfo::Storage { .. } => 17,
621+
TypeInfo::RawUntypedPtr => 18,
622+
TypeInfo::RawUntypedSlice => 19,
623+
}
624+
}
625+
508626
/// maps a type to a name that is used when constructing function selectors
509627
pub(crate) fn to_selector_name(
510628
&self,

0 commit comments

Comments
 (0)