Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enables where clauses for traits. #4584

Merged
merged 4 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl ty::TyEnumDecl {
// Type check the type parameters. This will also insert them into the
// current namespace.
let new_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters, false),
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl ty::TyFunctionDecl {
// Type check the type parameters. This will also insert them into the
// current namespace.
let new_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters, false),
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -149,7 +149,7 @@ impl ty::TyFunctionDecl {
check!(
return_type
.type_id
.check_type_parameter_bounds(&ctx, &return_type.span),
.check_type_parameter_bounds(&ctx, &return_type.span, vec![]),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl ty::TyFunctionParameter {
check!(
type_argument
.type_id
.check_type_parameter_bounds(&ctx, &type_argument.span),
.check_type_parameter_bounds(&ctx, &type_argument.span, vec![]),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,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, false),
TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -262,7 +262,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, false),
TypeParameter::type_check_type_params(ctx.by_ref(), impl_type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -300,9 +300,11 @@ impl ty::TyImplTrait {
);

check!(
implementing_for
.type_id
.check_type_parameter_bounds(&ctx, &implementing_for.span),
implementing_for.type_id.check_type_parameter_bounds(
&ctx,
&implementing_for.span,
vec![]
),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -421,6 +423,19 @@ fn type_check_trait_implementation(
errors
);

for (type_arg, type_param) in trait_type_arguments.iter().zip(trait_type_parameters) {
check!(
type_arg.type_id.check_type_parameter_bounds(
&ctx,
&type_arg.span(),
type_param.trait_constraints.clone()
),
return err(warnings, errors),
warnings,
errors
);
}

// This map keeps track of the remaining functions in the interface surface
// that still need to be implemented for the trait to be fully implemented.
let mut method_checklist: BTreeMap<Ident, ty::TyTraitFn> = BTreeMap::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl ty::TyStructDecl {
// Type check the type parameters. This will also insert them into the
// current namespace.
let new_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters, false),
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl ty::TyTraitDecl {
// Type check the type parameters. This will also insert them into the
// current namespace.
let new_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters, true),
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub(crate) fn instantiate_enum(
let type_id = type_engine.insert(engines, TypeInfo::Enum(enum_ref.clone()));

check!(
type_id.check_type_parameter_bounds(&ctx, &enum_variant_name.span()),
type_id.check_type_parameter_bounds(&ctx, &enum_variant_name.span(), vec![]),
return err(warnings, errors),
warnings,
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub(crate) fn struct_instantiation(
}

check!(
type_id.check_type_parameter_bounds(&ctx, &span),
type_id.check_type_parameter_bounds(&ctx, &span, vec![]),
return err(warnings, errors),
warnings,
errors
Expand Down
7 changes: 0 additions & 7 deletions sway-core/src/type_system/ast_elements/type_parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,13 @@ impl TypeParameter {
pub(crate) fn type_check_type_params(
mut ctx: TypeCheckContext,
type_params: Vec<TypeParameter>,
disallow_trait_constraints: bool,
) -> CompileResult<Vec<TypeParameter>> {
let mut warnings = vec![];
let mut errors = vec![];

let mut new_type_params: Vec<TypeParameter> = vec![];

for type_param in type_params.into_iter() {
if disallow_trait_constraints && !type_param.trait_constraints.is_empty() {
let errors = vec![CompileError::WhereClauseNotYetSupported {
span: type_param.trait_constraints_span,
}];
return err(vec![], errors);
}
new_type_params.push(check!(
TypeParameter::type_check(ctx.by_ref(), type_param),
continue,
Expand Down
7 changes: 6 additions & 1 deletion sway-core/src/type_system/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,16 +363,21 @@ impl TypeId {
&self,
ctx: &TypeCheckContext,
span: &Span,
trait_constraints: Vec<TraitConstraint>,
) -> CompileResult<()> {
let warnings = vec![];
let mut errors = vec![];
let engines = ctx.engines();

let structure_generics = engines
let mut structure_generics = engines
.te()
.get(*self)
.extract_inner_types_with_trait_constraints(engines);

if !trait_constraints.is_empty() {
structure_generics.insert(*self, trait_constraints);
}

for (structure_type_id, structure_trait_constraints) in &structure_generics {
if structure_trait_constraints.is_empty() {
continue;
Expand Down
3 changes: 0 additions & 3 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,8 +564,6 @@ pub enum CompileError {
Lex { error: LexError },
#[error("{}", error)]
Parse { error: ParseError },
#[error("\"where\" clauses are not yet supported")]
WhereClauseNotYetSupported { span: Span },
#[error("Could not evaluate initializer to a const declaration.")]
NonConstantDeclValue { span: Span },
#[error("Declaring storage in a {program_kind} is not allowed.")]
Expand Down Expand Up @@ -787,7 +785,6 @@ impl Spanned for CompileError {
UnexpectedDeclaration { span, .. } => span.clone(),
ContractAddressMustBeKnown { span, .. } => span.clone(),
ConvertParseTree { error } => error.span(),
WhereClauseNotYetSupported { span, .. } => span.clone(),
Lex { error } => error.span(),
Parse { error } => error.span.clone(),
EnumNotFound { span, .. } => span.clone(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = 'core'
source = 'path+from-root-8E4C78460FB62C32'

[[package]]
name = 'where_clause_traits'
source = 'member'
dependencies = ['core']
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[project]
name = "where_clause_traits"
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
implicit-std = false

[dependencies]
core = { path = "../../../../../../sway-lib-core" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
script;

trait MyTrait {
fn method(self);
}

trait MyTraitGeneric<T> where T : MyTrait {
fn method(self);
}

struct S1 {
s1: u64
}

impl MyTraitGeneric<S1> for u64 {
fn method(self){
}
}

impl<T> MyTraitGeneric<T> for u32 {
fn method(self){
}
}

fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
category = "fail"

# check: $()impl MyTraitGeneric<S1> for u64 {
# nextln:$()Trait "MyTrait" is not implemented for type "S1".

# check: $()impl<T> MyTraitGeneric<T> for u32 {
# nextln: $()Expects trait constraint "T: MyTrait" which is missing from type parameter "T".

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[package]]
name = 'core'
source = 'path+from-root-8E4C78460FB62C32'

[[package]]
name = 'std'
source = 'path+from-root-8E4C78460FB62C32'
dependencies = ['core']

[[package]]
name = 'where_clause_traits'
source = 'member'
dependencies = ['std']
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
name = "where_clause_traits"
authors = ["Fuel Labs <contact@fuel.sh>"]
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": "u8",
"typeId": 0,
"typeParameters": null
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
script;

trait MyTrait {
fn new() -> Self;
}

trait MyTraitGeneric<T> where T : MyTrait {
fn get_value(self) -> T;
}

struct S1 {
s1: u64
}

impl MyTrait for S1 {
fn new() -> Self {
S1 {s1: 0}
}
}

impl MyTraitGeneric<S1> for u64 {
fn get_value(self) -> S1 {
S1::new()
}
}

fn main() -> u8 {
let _s0: S1 = 42u64.get_value();

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

expected_warnings = 1