Skip to content

Commit

Permalink
Where clauses on impl blocks (#3731)
Browse files Browse the repository at this point in the history
Closes #1162

---------

Co-authored-by: emilyaherbert <[email protected]>
Co-authored-by: Marcos Henrich <[email protected]>
Co-authored-by: IGI-111 <[email protected]>
  • Loading branch information
4 people authored Apr 28, 2023
1 parent 6a3fba1 commit e95e052
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 46 deletions.
56 changes: 15 additions & 41 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use crate::{
},
semantic_analysis::{Mode, TypeCheckContext},
type_system::*,
types::*,
};

impl ty::TyImplTrait {
Expand Down Expand Up @@ -45,7 +44,7 @@ impl ty::TyImplTrait {
// Type check the type parameters. This will also insert them into the
// current namespace.
let new_impl_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters, true),
TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters, false),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -803,52 +802,27 @@ fn type_check_impl_method(
return err(warnings, errors);
}

// if this method uses a type parameter from its parent's impl type
// parameters that is not constrained by the type that we are
// implementing for, then we need to add that type parameter to the
// method's type parameters so that in-line monomorphization can
// complete.
// We need to add impl type parameters to the method's type parameters
// so that in-line monomorphization can complete.
//
// We also need to add impl type parameters to the method's type
// parameters so the type constraints are correctly applied to the method.
//
// NOTE: this is a semi-hack that is used to force monomorphization of
// trait methods that contain a generic defined in the parent impl...
// without stuffing the generic into the method's type parameters, its
// not currently possible to monomorphize on that generic at function
// application time.
//
// *This will change* when either https://github.com/FuelLabs/sway/issues/1267
// or https://github.com/FuelLabs/sway/issues/2814 goes in.
let unconstrained_type_parameters_in_this_function: HashSet<WithEngines<'_, TypeParameter>> =
impl_method
.unconstrained_type_parameters(engines, impl_type_parameters)
.into_iter()
.cloned()
.map(|x| WithEngines::new(x, engines))
.collect();
let constrained_type_parameters_in_the_type: HashSet<WithEngines<'_, TypeParameter>> =
self_type
.unconstrained_type_parameters(engines, impl_type_parameters)
.into_iter()
.cloned()
.map(|x| WithEngines::new(x, engines))
.collect::<HashSet<_>>();
let mut unconstrained_type_parameters_to_be_added =
unconstrained_type_parameters_in_this_function
.difference(&constrained_type_parameters_in_the_type)
.cloned()
.collect::<HashSet<_>>()
.intersection(
&impl_type_parameters
.iter()
.cloned()
.map(|x| engines.help_out(x))
.collect::<HashSet<_>>(),
)
impl_method.type_parameters.append(
&mut impl_type_parameters
.iter()
.cloned()
.map(|x| x.thing)
.collect::<Vec<_>>();
impl_method
.type_parameters
.append(&mut unconstrained_type_parameters_to_be_added);
.map(|mut t| {
t.is_from_parent = true;
t
})
.collect::<Vec<_>>(),
);

if errors.is_empty() {
ok(impl_method, warnings, errors)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ struct MyPoint<T> {
y: T,
}

impl<T> MyAdd for MyPoint<T> where T: MyAdd {
// Missing where T: MyAdd
impl<T> MyAdd for MyPoint<T> {
fn my_add(a: MyPoint<T>, b: MyPoint<T>) -> MyPoint<T> {
MyPoint {
x: a.x.my_add(b.x),
Expand All @@ -53,4 +54,4 @@ fn main() -> u8 {
};
let baz = foo.my_add(bar);
baz.y
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
category = "fail"

# check: $()impl<T> MyAdd for MyPoint<T> where T: MyAdd {
# check: $()"where" clauses are not yet supported
# check: $()x: a.x.my_add(b.x),
# nextln: $()No method named "my_add" found for type "T".
# check: $()y: a.y.my_add(b.y),

# check: $()y: a.y.my_add(b.y),
# nextln: $()No method named "my_add" found for type "T".

# check: $()let baz = foo.my_add(bar);
# check: $()No method named "my_add" found for type "MyPoint<u32>".
# nextln: $()No method named "my_add" found for type "MyPoint<u32>".
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[package]]
name = 'core'
source = 'path+from-root-7FCA9B4231E4DA1F'

[[package]]
name = 'std'
source = 'path+from-root-7FCA9B4231E4DA1F'
dependencies = ['core']

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

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

use std::{
assert::assert,
logging::log,
};

pub trait MyAdd {
fn my_add(self, other: Self) -> Self;
}

impl MyAdd for u8 {
fn my_add(self, other: Self) -> Self {
self + other
}
}

impl MyAdd for u16 {
fn my_add(self, other: Self) -> Self {
self + other
}
}

impl MyAdd for u32 {
fn my_add(self, other: Self) -> Self {
self + other
}
}

impl MyAdd for u64 {
fn my_add(self, other: Self) -> Self {
self + other
}
}

pub trait MyMul {
fn my_mul(self, other: Self) -> Self;
}

impl MyMul for u8 {
fn my_mul(self, other: Self) -> Self {
self * other
}
}

impl MyMul for u16 {
fn my_mul(self, other: Self) -> Self {
self * other
}
}

impl MyMul for u32 {
fn my_mul(self, other: Self) -> Self {
self * other
}
}

impl MyMul for u64 {
fn my_mul(self, other: Self) -> Self {
self * other
}
}

pub trait MyMath: MyAdd + MyMul {

} {
fn my_double(self) -> Self {
self.my_add(self)
}

fn my_pow_2(self) -> Self {
self.my_mul(self)
}
}

impl MyMath for u8 {}

impl MyMath for u16 {}

impl MyMath for u32 {}

impl MyMath for u64 {}

pub struct MyPoint<T> {
x: T,
y: T,
}

impl<T> MyPoint<T> {
pub fn new(x: T, y: T) -> MyPoint<T> {
MyPoint {
x,
y,
}
}
}

impl<T> MyAdd for MyPoint<T> where T: MyAdd {
fn my_add(self, other: Self) -> Self {
MyPoint {
x: self.x.my_add(other.x),
y: self.y.my_add(other.y),
}
}
}

impl<T> MyMul for MyPoint<T> where T: MyMul {
fn my_mul(self, other: Self) -> Self {
MyPoint {
x: self.x.my_mul(other.x),
y: self.y.my_mul(other.y),
}
}
}

impl<T> MyMath for MyPoint<T> where T: MyMath { }

pub fn basic_unit_tests() {
assert(100.my_add(99) == 199);
assert(3.my_mul(4) == 12);
assert(5.my_double() == 10);
assert(5.my_pow_2() == 25);
}

pub fn basic_point_tests() {
let a = MyPoint::new(1, 2);
let b = MyPoint::new(3, 4);

let c = a.my_add(b);
assert(c.x == 4);
assert(c.y == 6);
}

fn main() -> u64 {
basic_unit_tests();
basic_point_tests();

42
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
category = "run"
expected_result = { action = "return", value = 42 }
validate_abi = true

expected_warnings = 8

0 comments on commit e95e052

Please sign in to comment.