Skip to content

Commit

Permalink
Enables where clauses for traits.
Browse files Browse the repository at this point in the history
With these changes where clauses are enabled for traits.
This commit also adds error handling when an `impl` is created for a generic
trait with where clause.

Generic traits are not supported yet on super traits or where clauses,
when the support is added we should also perform the bounds check there.

Fixes #4560
Fixes #970
  • Loading branch information
esdrubal committed May 24, 2023
1 parent e5d3185 commit 4f18e94
Show file tree
Hide file tree
Showing 20 changed files with 175 additions and 24 deletions.
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
29 changes: 24 additions & 5 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
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,23 @@ fn type_check_trait_implementation(
errors
);

for (type_arg, type_param) in trait_type_arguments
.clone()
.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(decl_engine, 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,30 @@
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){
let s = S1{s1: self};
s.method();
}
}

impl<T> MyTraitGeneric<T> for u32 {
fn method(self){
let s = S1{s1: self};
s.method();
}
}

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

0 comments on commit 4f18e94

Please sign in to comment.