Skip to content

Commit

Permalink
Improve parsing of trait constraints (FuelLabs#3143)
Browse files Browse the repository at this point in the history
  • Loading branch information
emilyaherbert authored Oct 25, 2022
1 parent d084bc1 commit 457beff
Show file tree
Hide file tree
Showing 27 changed files with 404 additions and 33 deletions.
2 changes: 1 addition & 1 deletion sway-core/src/language/ty/expression/intrinsic_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use itertools::Itertools;
use sway_ast::Intrinsic;
use sway_types::Span;

#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TyIntrinsicFunctionKind {
pub kind: Intrinsic,
pub arguments: Vec<TyExpression>,
Expand Down
8 changes: 8 additions & 0 deletions sway-core/src/semantic_analysis/ast_node/declaration/enum.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use sway_error::error::CompileError;

use crate::{
error::*,
language::{parsed::*, ty},
Expand Down Expand Up @@ -28,6 +30,12 @@ impl ty::TyEnumDeclaration {
// insert them into the namespace
let mut new_type_parameters = vec![];
for type_parameter in type_parameters.into_iter() {
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.trait_constraints_span,
});
return err(warnings, errors);
}
new_type_parameters.push(check!(
TypeParameter::type_check(ctx.by_ref(), type_parameter),
return err(warnings, errors),
Expand Down
11 changes: 10 additions & 1 deletion sway-core/src/semantic_analysis/ast_node/declaration/function.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
mod function_parameter;

pub use function_parameter::*;
use sway_error::warning::{CompileWarning, Warning};
use sway_error::{
error::CompileError,
warning::{CompileWarning, Warning},
};

use crate::{
error::*,
Expand Down Expand Up @@ -49,6 +52,12 @@ impl ty::TyFunctionDeclaration {
// insert them into the namespace
let mut new_type_parameters = vec![];
for type_parameter in type_parameters.into_iter() {
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.trait_constraints_span,
});
return err(warnings, errors);
}
new_type_parameters.push(check!(
TypeParameter::type_check(fn_ctx.by_ref(), type_parameter),
return err(warnings, errors),
Expand Down
12 changes: 12 additions & 0 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ impl ty::TyImplTrait {
// TODO: eventually when we support generic traits, we will want to use this
let mut new_impl_type_parameters = vec![];
for type_parameter in impl_type_parameters.into_iter() {
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.trait_constraints_span,
});
return err(warnings, errors);
}
new_impl_type_parameters.push(check!(
TypeParameter::type_check(impl_ctx.by_ref(), type_parameter),
return err(warnings, errors),
Expand Down Expand Up @@ -398,6 +404,12 @@ impl ty::TyImplTrait {
// insert them into the namespace
let mut new_type_parameters = vec![];
for type_parameter in impl_type_parameters.into_iter() {
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.trait_constraints_span,
});
return err(warnings, errors);
}
new_type_parameters.push(check!(
TypeParameter::type_check(ctx.by_ref(), type_parameter),
return err(warnings, errors),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use sway_error::error::CompileError;

use crate::{
error::*,
language::{parsed::*, ty},
Expand Down Expand Up @@ -31,6 +33,12 @@ impl ty::TyStructDeclaration {
// insert them into the namespace
let mut new_type_parameters = vec![];
for type_parameter in type_parameters.into_iter() {
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.trait_constraints_span,
});
return err(warnings, errors);
}
new_type_parameters.push(check!(
TypeParameter::type_check(ctx.by_ref(), type_parameter),
return err(warnings, errors),
Expand Down
8 changes: 2 additions & 6 deletions sway-core/src/semantic_analysis/ast_node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,8 @@ impl ty::TyAstNode {
Declaration::FunctionDeclaration(fn_decl) => {
let mut ctx = ctx.with_type_annotation(insert_type(TypeInfo::Unknown));
let fn_decl = check!(
ty::TyFunctionDeclaration::type_check(
ctx.by_ref(),
fn_decl.clone(),
false
),
ty::TyFunctionDeclaration::error(fn_decl),
ty::TyFunctionDeclaration::type_check(ctx.by_ref(), fn_decl, false),
return err(warnings, errors),
warnings,
errors
);
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/semantic_analysis/node_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ impl Dependencies {
self.gather_from_iter(type_parameters.iter(), |deps, type_parameter| {
deps.gather_from_iter(
type_parameter.trait_constraints.iter(),
|deps, constraint| deps.gather_from_call_path(&constraint.call_path, false, false),
|deps, constraint| deps.gather_from_call_path(&constraint.trait_name, false, false),
)
})
}
Expand Down
38 changes: 24 additions & 14 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ fn generic_params_opt_to_type_parameters(
initial_type_id: custom_type,
name_ident: ident,
trait_constraints: Vec::new(),
trait_constraints_span: Span::dummy(),
}
})
.collect::<Vec<_>>(),
Expand All @@ -764,15 +765,16 @@ fn generic_params_opt_to_type_parameters(
}
};

param_to_edit
.trait_constraints
.extend(
traits_to_call_paths(handler, bounds)?
.iter()
.map(|call_path| TraitConstraint {
call_path: call_path.clone(),
}),
);
param_to_edit.trait_constraints_span = Span::join(ty_name.span(), bounds.span());

param_to_edit.trait_constraints.extend(
traits_to_call_paths(handler, bounds)?.into_iter().map(
|(trait_name, type_arguments)| TraitConstraint {
trait_name,
type_arguments,
},
),
);
}
if let Some(errors) = emit_all(handler, errors) {
return Err(errors);
Expand Down Expand Up @@ -964,13 +966,19 @@ fn fn_signature_to_trait_fn(
Ok(trait_fn)
}

fn traits_to_call_paths(handler: &Handler, traits: Traits) -> Result<Vec<CallPath>, ErrorEmitted> {
let mut call_paths = vec![path_type_to_call_path(handler, traits.prefix)?];
fn traits_to_call_paths(
handler: &Handler,
traits: Traits,
) -> Result<Vec<(CallPath, Vec<TypeArgument>)>, ErrorEmitted> {
let mut parsed_traits = vec![path_type_to_call_path_and_type_arguments(
handler,
traits.prefix,
)?];
for (_add_token, suffix) in traits.suffixes {
let supertrait = path_type_to_call_path(handler, suffix)?;
call_paths.push(supertrait);
let supertrait = path_type_to_call_path_and_type_arguments(handler, suffix)?;
parsed_traits.push(supertrait);
}
Ok(call_paths)
Ok(parsed_traits)
}

fn traits_to_supertraits(
Expand Down Expand Up @@ -2882,6 +2890,7 @@ fn ty_to_type_parameter(handler: &Handler, ty: Ty) -> Result<TypeParameter, Erro
initial_type_id: unknown_type,
name_ident: underscore_token.into(),
trait_constraints: Default::default(),
trait_constraints_span: Span::dummy(),
});
}
Ty::Tuple(..) => panic!("tuple types are not allowed in this position"),
Expand All @@ -2897,6 +2906,7 @@ fn ty_to_type_parameter(handler: &Handler, ty: Ty) -> Result<TypeParameter, Erro
initial_type_id: custom_type,
name_ident,
trait_constraints: Vec::new(),
trait_constraints_span: Span::dummy(),
})
}

Expand Down
13 changes: 11 additions & 2 deletions sway-core/src/type_system/trait_constraint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use crate::language::CallPath;
use sway_types::Spanned;

use crate::{language::CallPath, TypeArgument};

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub(crate) struct TraitConstraint {
pub(crate) call_path: CallPath,
pub(crate) trait_name: CallPath,
pub(crate) type_arguments: Vec<TypeArgument>,
}

impl Spanned for TraitConstraint {
fn span(&self) -> sway_types::Span {
self.trait_name.span()
}
}
2 changes: 1 addition & 1 deletion sway-core/src/type_system/type_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{
};
use sway_types::{Span, Spanned};

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq)]
pub struct TypeArgument {
pub type_id: TypeId,
pub initial_type_id: TypeId,
Expand Down
9 changes: 2 additions & 7 deletions sway-core/src/type_system/type_parameter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{error::*, language::ty, semantic_analysis::*, type_system::*};

use sway_error::error::CompileError;
use sway_types::{ident::Ident, span::Span, JsonTypeDeclaration, Spanned};

use std::{
Expand All @@ -14,6 +13,7 @@ pub struct TypeParameter {
pub(crate) initial_type_id: TypeId,
pub name_ident: Ident,
pub(crate) trait_constraints: Vec<TraitConstraint>,
pub(crate) trait_constraints_span: Span,
}

// NOTE: Hash and PartialEq must uphold the invariant:
Expand Down Expand Up @@ -69,12 +69,6 @@ impl TypeParameter {
) -> CompileResult<Self> {
let mut warnings = vec![];
let mut errors = vec![];
if !type_parameter.trait_constraints.is_empty() {
errors.push(CompileError::WhereClauseNotYetSupported {
span: type_parameter.name_ident.span(),
});
return err(warnings, errors);
}
// TODO: add check here to see if the type parameter has a valid name and does not have type parameters
let type_id = insert_type(TypeInfo::UnknownGeneric {
name: type_parameter.name_ident.clone(),
Expand All @@ -91,6 +85,7 @@ impl TypeParameter {
type_id,
initial_type_id: type_parameter.initial_type_id,
trait_constraints: type_parameter.trait_constraints,
trait_constraints_span: type_parameter.trait_constraints_span,
};
ok(type_parameter, warnings, errors)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = 'core'
source = 'path+from-root-9C8BB63A0EAABF66'

[[package]]
name = 'where_clause_adts'
source = 'root'
dependencies = ['core']
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[project]
name = "where_clause_adts"
authors = ["Fuel Labs <[email protected]>"]
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,46 @@
script;

trait MyAdd {
fn my_add(a: Self, b: Self) -> Self;
}

struct MyU32 {
value: u32
}

struct MyU64 {
value: u64
}

impl MyAdd for MyU32 {
fn my_add(a: MyU32, b: MyU32) -> MyU32 {
MyU32 {
value: a.value + b.value
}
}
}

impl MyAdd for MyU64 {
fn my_add(a: MyU64, b: MyU64) -> MyU64 {
MyU64 {
value: a.value + b.value
}
}
}

struct MyPoint<T> where T: MyAdd {
x: T,
y: T,
}

fn main() -> u8 {
let foo = MyPoint {
x: 1u32,
y: 2u64,
};
let bar = MyPoint {
x: 3u32,
y: 4u64,
};
0u8
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
category = "fail"

# check: $()struct MyPoint<T> where T: MyAdd {
# nextln:$()"where" clauses are not yet supported

# check: $()let foo = MyPoint {
# nextln: $()Could not find symbol "MyPoint" in this scope.

# check: $()MyPoint {
# nextln: $()Unknown type name "MyPoint".

# check: $()MyPoint {
# nextln: $()Unknown type name "MyPoint".
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = 'core'
source = 'path+from-root-7DE2C09CF8DCCAB3'

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

[dependencies]
core = { path = "../../../../../../sway-lib-core" }
Loading

0 comments on commit 457beff

Please sign in to comment.