Skip to content

Commit

Permalink
Fixes method Eq not found when used with where clause. (FuelLabs#3348)
Browse files Browse the repository at this point in the history
The problem was that although two `TypeInfo::UnknownGeneric` were
unified they were not regarded as equals by
`are_equal_minus_dynamic_types`.

Solution was to change how `TypeInfo::UnknownGeneric` are compared in
`are_equal_minus_dynamic_types`. Which can now check if two
`TypeInfo::UnknownGeneric` were previously unified. This was
accomplished by adding two methods to the type engine
`insert_unified_type` and `get_unified_types`.

Closes FuelLabs#3324
  • Loading branch information
esdrubal authored Nov 22, 2022
1 parent fe6b76e commit f581909
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 3 deletions.
6 changes: 5 additions & 1 deletion sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,6 @@ fn are_equal_minus_dynamic_types(type_engine: &TypeEngine, left: TypeId, right:
(TypeInfo::Unknown, TypeInfo::Unknown) => false,
(TypeInfo::SelfType, TypeInfo::SelfType) => false,
(TypeInfo::Numeric, TypeInfo::Numeric) => false,
(TypeInfo::UnknownGeneric { .. }, TypeInfo::UnknownGeneric { .. }) => false,
(TypeInfo::Contract, TypeInfo::Contract) => false,
(TypeInfo::Storage { .. }, TypeInfo::Storage { .. }) => false,

Expand All @@ -785,6 +784,11 @@ fn are_equal_minus_dynamic_types(type_engine: &TypeEngine, left: TypeId, right:
(TypeInfo::UnsignedInteger(l), TypeInfo::UnsignedInteger(r)) => l == r,
(TypeInfo::RawUntypedPtr, TypeInfo::RawUntypedPtr) => true,
(TypeInfo::RawUntypedSlice, TypeInfo::RawUntypedSlice) => true,
(TypeInfo::UnknownGeneric { .. }, TypeInfo::UnknownGeneric { .. }) => {
// return true if left and right were unified previously
type_engine.get_unified_types(left).contains(&right)
|| type_engine.get_unified_types(right).contains(&left)
}

// these cases may contain dynamic types
(
Expand Down
35 changes: 35 additions & 0 deletions sway-core/src/type_system/type_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub struct TypeEngine {
pub(super) slab: ConcurrentSlab<TypeInfo>,
storage_only_types: ConcurrentSlab<TypeInfo>,
id_map: RwLock<HashMap<TypeInfo, TypeId>>,
unify_map: RwLock<HashMap<TypeId, Vec<TypeId>>>,
}

impl fmt::Display for TypeEngine {
Expand Down Expand Up @@ -69,6 +70,40 @@ impl TypeEngine {
}
}

pub(crate) fn insert_unified_type(&self, received: TypeId, expected: TypeId) {
let mut unify_map = self.unify_map.write().unwrap();
if let Some(type_ids) = unify_map.get(&received) {
if type_ids.contains(&expected) {
return;
}
let mut type_ids = type_ids.clone();
type_ids.push(expected);
unify_map.insert(received, type_ids);
return;
}

unify_map.insert(received, vec![expected]);
}

pub(crate) fn get_unified_types(&self, type_id: TypeId) -> Vec<TypeId> {
let mut final_unify_ids: Vec<TypeId> = vec![];
self.get_unified_types_rec(type_id, &mut final_unify_ids);
final_unify_ids
}

fn get_unified_types_rec(&self, type_id: TypeId, final_unify_ids: &mut Vec<TypeId>) {
let unify_map = self.unify_map.read().unwrap();
if let Some(unify_ids) = unify_map.get(&type_id) {
for unify_id in unify_ids {
if final_unify_ids.contains(unify_id) {
continue;
}
final_unify_ids.push(*unify_id);
self.get_unified_types_rec(*unify_id, final_unify_ids);
}
}
}

/// Currently the [TypeEngine] is a lazy static object, so when we run
/// cargo tests, we can either choose to use a local [TypeEngine] and bypass
/// all of the global methods or we can use the lazy static [TypeEngine].
Expand Down
12 changes: 10 additions & 2 deletions sway-core/src/type_system/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ pub(super) fn unify(
name: en,
trait_constraints: etc,
},
) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => (vec![], vec![]),
) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => {
type_engine.insert_unified_type(received, expected);
type_engine.insert_unified_type(expected, received);
(vec![], vec![])
}
(ref r @ UnknownGeneric { .. }, e) => {
match type_engine.slab.replace(received, r, e, type_engine) {
None => (vec![], vec![]),
Expand Down Expand Up @@ -444,8 +448,12 @@ pub(super) fn unify_right(
name: en,
trait_constraints: etc,
},
) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => (vec![], vec![]),
) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => {
type_engine.insert_unified_type(received, expected);
(vec![], vec![])
}
(r, ref e @ UnknownGeneric { .. }) => {
type_engine.insert_unified_type(received, expected);
match type_engine.slab.replace(expected, e, r, type_engine) {
None => (vec![], vec![]),
Some(_) => unify_right(type_engine, received, expected, span, help_text),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[package]]
name = 'core'
source = 'path+from-root-D8A8CF23B4069FF9'

[[package]]
name = 'eq_generic'
source = 'member'
dependencies = ['std']

[[package]]
name = 'std'
source = 'path+from-root-D8A8CF23B4069FF9'
dependencies = ['core']
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "eq_generic"

[dependencies]
std = { path = "../../../../../../../sway-lib-std" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"functions": [
{
"inputs": [],
"name": "main",
"output": {
"name": "",
"type": 0,
"typeArguments": null
}
}
],
"loggedTypes": [],
"types": [
{
"components": [],
"type": "()",
"typeId": 0,
"typeParameters": null
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
script;

use core::ops::*;

impl<T> Option<T> {
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Option::Some(v) => Result::Ok(v),
Option::None => Result::Err(err),
}
}
}

fn test_ok_or<T, E>(val: T, default: E) where T: Eq {
match Option::Some(val).ok_or(default) {
Result::Ok(inner) => assert(inner == val),
Result::Err(_) => revert(0),
};
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
category = "run"
expected_result = { action = "return", value = 0 }
validate_abi = true

0 comments on commit f581909

Please sign in to comment.