Skip to content

Commit

Permalink
Add HashWithEngines impls for more types (FuelLabs#4014)
Browse files Browse the repository at this point in the history
## Description

This PR is a subset of FuelLabs#3744. It adds a `HashWithEngines` 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 😄

This PR also makes a few corrections to some of the existing
implementations for `HashWithEngines` which were incorrectly comparing
`TypeId`s.

## Checklist

- [x] I have linked to any relevant issues.
- [ ] 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.
- [ ] 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.

---------

Co-authored-by: emilyaherbert <[email protected]>
  • Loading branch information
emilyaherbert and emilyaherbert authored Feb 9, 2023
1 parent d77cafd commit 1e37122
Showing 40 changed files with 877 additions and 207 deletions.
2 changes: 1 addition & 1 deletion sway-ast/src/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

#[derive(Eq, PartialEq, Debug, Clone)]
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum Intrinsic {
GetStorageKey,
IsReferenceType,
13 changes: 10 additions & 3 deletions sway-core/src/decl_engine/id.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::Hasher;

use sway_types::{Ident, Span, Spanned};

use crate::{engine_threading::*, language::ty, type_system::*};
@@ -28,9 +30,6 @@ impl Clone for DeclId {
}
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl EqWithEngines for DeclId {}
impl PartialEqWithEngines for DeclId {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
@@ -41,6 +40,14 @@ impl PartialEqWithEngines for DeclId {
}
}

impl HashWithEngines for DeclId {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let decl_engine = engines.de();
let decl = decl_engine.get(self.clone());
decl.hash(state, engines);
}
}

impl std::ops::Deref for DeclId {
type Target = usize;
fn deref(&self) -> &Self::Target {
45 changes: 41 additions & 4 deletions sway-core/src/decl_engine/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt;
use std::{
fmt,
hash::{Hash, Hasher},
};

use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};
@@ -35,9 +38,6 @@ impl Default for DeclWrapper {
}
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl PartialEqWithEngines for DeclWrapper {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
match (self, other) {
@@ -56,6 +56,43 @@ impl PartialEqWithEngines for DeclWrapper {
}
}

impl HashWithEngines for DeclWrapper {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
use DeclWrapper::*;
std::mem::discriminant(self).hash(state);
match self {
Unknown => {}
Function(decl) => {
decl.hash(state, engines);
}
Trait(decl) => {
decl.hash(state, engines);
}
TraitFn(decl) => {
decl.hash(state, engines);
}
ImplTrait(decl) => {
decl.hash(state, engines);
}
Struct(decl) => {
decl.hash(state, engines);
}
Storage(decl) => {
decl.hash(state, engines);
}
Abi(decl) => {
decl.hash(state, engines);
}
Constant(decl) => {
decl.hash(state, engines);
}
Enum(decl) => {
decl.hash(state, engines);
}
}
}
}

impl fmt::Display for DeclWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "decl({})", self.friendly_name())
16 changes: 8 additions & 8 deletions sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
@@ -75,7 +75,7 @@ impl<T: DebugWithEngines> fmt::Debug for WithEngines<'_, T> {

impl<T: HashWithEngines> Hash for WithEngines<'_, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.thing.hash(state, self.engines.te())
self.thing.hash(state, self.engines)
}
}

@@ -108,28 +108,28 @@ impl<T: DebugWithEngines> DebugWithEngines for &T {
}

pub trait HashWithEngines {
fn hash<H: Hasher>(&self, state: &mut H, type_engine: &TypeEngine);
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>);
}

impl<T: HashWithEngines + ?Sized> HashWithEngines for &T {
fn hash<H: Hasher>(&self, state: &mut H, type_engine: &TypeEngine) {
(*self).hash(state, type_engine)
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
(*self).hash(state, engines)
}
}

impl<T: HashWithEngines> HashWithEngines for Option<T> {
fn hash<H: Hasher>(&self, state: &mut H, type_engine: &TypeEngine) {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
match self {
None => state.write_u8(0),
Some(x) => x.hash(state, type_engine),
Some(x) => x.hash(state, engines),
}
}
}

impl<T: HashWithEngines> HashWithEngines for [T] {
fn hash<H: Hasher>(&self, state: &mut H, type_engine: &TypeEngine) {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
for x in self {
x.hash(state, type_engine)
x.hash(state, engines)
}
}
}
6 changes: 0 additions & 6 deletions sway-core/src/language/asm.rs
Original file line number Diff line number Diff line change
@@ -10,9 +10,6 @@ pub struct AsmOp {
pub(crate) immediate: Option<Ident>,
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl Hash for AsmOp {
fn hash<H: Hasher>(&self, state: &mut H) {
self.op_name.hash(state);
@@ -23,9 +20,6 @@ impl Hash for AsmOp {
}
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl PartialEq for AsmOp {
fn eq(&self, other: &Self) -> bool {
self.op_name == other.op_name
6 changes: 0 additions & 6 deletions sway-core/src/language/literal.rs
Original file line number Diff line number Diff line change
@@ -21,9 +21,6 @@ pub enum Literal {
B256([u8; 32]),
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl Hash for Literal {
fn hash<H: Hasher>(&self, state: &mut H) {
use Literal::*;
@@ -64,9 +61,6 @@ impl Hash for Literal {
}
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl PartialEq for Literal {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
13 changes: 10 additions & 3 deletions sway-core/src/language/parsed/declaration/trait.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::{Hash, Hasher};

use super::{FunctionDeclaration, FunctionParameter};

use crate::{decl_engine::DeclId, engine_threading::*, language::*, transform, type_system::*};
@@ -27,16 +29,21 @@ impl Spanned for Supertrait {
}
}

// NOTE: Hash and PartialEq must uphold the invariant:
// k1 == k2 -> hash(k1) == hash(k2)
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
impl EqWithEngines for Supertrait {}
impl PartialEqWithEngines for Supertrait {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
self.name == other.name && self.decl_id.eq(&other.decl_id, engines)
}
}

impl HashWithEngines for Supertrait {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let Supertrait { name, decl_id } = self;
name.hash(state);
decl_id.hash(state, engines);
}
}

#[derive(Debug, Clone)]
pub struct TraitFn {
pub name: Ident,
4 changes: 2 additions & 2 deletions sway-core/src/language/parsed/use_statement.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use crate::parsed::Span;
use sway_types::ident::Ident;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ImportType {
Star,
SelfImport(Span),
Item(Ident),
}

/// A [UseStatement] is a statement that imports something from a module into the local namespace.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UseStatement {
pub call_path: Vec<Ident>,
pub import_type: ImportType,
35 changes: 34 additions & 1 deletion sway-core/src/language/ty/ast_node.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt::{self, Debug};
use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
};

use sway_error::error::CompileError;
use sway_types::{Ident, Span, Spanned};
@@ -34,6 +37,18 @@ impl PartialEqWithEngines for TyAstNode {
}
}

impl HashWithEngines for TyAstNode {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let TyAstNode {
content,
// the span is not hashed because it isn't relevant/a reliable
// source of obj v. obj distinction
span: _,
} = self;
content.hash(state, engines);
}
}

impl DisplayWithEngines for TyAstNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: Engines<'_>) -> fmt::Result {
use TyAstNodeContent::*;
@@ -306,6 +321,24 @@ impl PartialEqWithEngines for TyAstNodeContent {
}
}

impl HashWithEngines for TyAstNodeContent {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
use TyAstNodeContent::*;
std::mem::discriminant(self).hash(state);
match self {
Declaration(decl) => {
decl.hash(state, engines);
}
Expression(exp) | ImplicitReturnExpression(exp) => {
exp.hash(state, engines);
}
SideEffect(effect) => {
effect.hash(state);
}
}
}
}

impl CollectTypesMetadata for TyAstNodeContent {
fn collect_types_metadata(
&self,
9 changes: 9 additions & 0 deletions sway-core/src/language/ty/code_block.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::Hasher;

use crate::{
decl_engine::*, engine_threading::*, language::ty::*, type_system::*,
types::DeterministicallyAborts,
@@ -15,6 +17,13 @@ impl PartialEqWithEngines for TyCodeBlock {
}
}

impl HashWithEngines for TyCodeBlock {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let TyCodeBlock { contents } = self;
contents.hash(state, engines);
}
}

impl SubstTypes for TyCodeBlock {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: Engines<'_>) {
self.contents
25 changes: 21 additions & 4 deletions sway-core/src/language/ty/declaration/abi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::{Hash, Hasher};

use sway_types::{Ident, Span};

use crate::{decl_engine::DeclId, engine_threading::*, transform, type_system::*};
@@ -18,10 +20,25 @@ impl EqWithEngines for TyAbiDeclaration {}
impl PartialEqWithEngines for TyAbiDeclaration {
fn eq(&self, other: &Self, engines: Engines<'_>) -> bool {
self.name == other.name
&& self.interface_surface.eq(&other.interface_surface, engines)
&& self.methods.eq(&other.methods, engines)
// span ignored
&& self.attributes == other.attributes
&& self.interface_surface.eq(&other.interface_surface, engines)
&& self.methods.eq(&other.methods, engines)
}
}

impl HashWithEngines for TyAbiDeclaration {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let TyAbiDeclaration {
name,
interface_surface,
methods,
// these fields are not hashed because they aren't relevant/a
// reliable source of obj v. obj distinction
attributes: _,
span: _,
} = self;
name.hash(state);
interface_surface.hash(state, engines);
methods.hash(state, engines);
}
}

28 changes: 26 additions & 2 deletions sway-core/src/language/ty/declaration/constant.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::{Hash, Hasher};

use sway_types::{Ident, Span};

use crate::{
@@ -29,7 +31,29 @@ impl PartialEqWithEngines for TyConstantDeclaration {
&& type_engine
.get(self.return_type)
.eq(&type_engine.get(other.return_type), engines)
&& self.attributes == other.attributes
&& self.span == other.span
&& self.is_configurable == other.is_configurable
}
}

impl HashWithEngines for TyConstantDeclaration {
fn hash<H: Hasher>(&self, state: &mut H, engines: Engines<'_>) {
let TyConstantDeclaration {
name,
value,
visibility,
return_type,
is_configurable,
// these fields are not hashed because they aren't relevant/a
// reliable source of obj v. obj distinction
attributes: _,
type_ascription_span: _,
span: _,
} = self;
let type_engine = engines.te();
name.hash(state);
value.hash(state, engines);
visibility.hash(state);
type_engine.get(*return_type).hash(state, engines);
is_configurable.hash(state);
}
}
Loading

0 comments on commit 1e37122

Please sign in to comment.