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

Properly reject circular dependency when using create/create2 #363

Merged
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
21 changes: 15 additions & 6 deletions analyzer/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@ use fe_parser::node::Span;
/// Errors for things that may arise in a valid Fe AST.
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
AlreadyDefined,
BreakWithoutLoop,
CannotMove,
CircularDependency,
ContinueWithoutLoop,
EventInvocationExpected,
KeyWordArgsRequired,
MissingEventDefinition,
MissingReturn,
MoreThanThreeIndexedParams,
NotCallable,
NotSubscriptable,
NumericCapacityMismatch,
NumericLiteralExpected,
SignedExponentNotAllowed,
StringCapacityMismatch,
TypeError,
UndefinedValue,
UnexpectedReturn,
TypeError,
CannotMove,
NotCallable,
NumericLiteralExpected,
MoreThanThreeIndexedParams,
WrongNumberOfParams,
AlreadyDefined,
}

#[derive(Debug, PartialEq)]
Expand All @@ -44,6 +45,14 @@ impl SemanticError {
}
}

/// Create a new error with kind `CircularDependency`
pub fn circular_dependency() -> Self {
SemanticError {
kind: ErrorKind::CircularDependency,
context: vec![],
}
}

/// Create a new error with kind `ContinueWithoutLoop`
pub fn continue_without_loop() -> Self {
SemanticError {
Expand Down
9 changes: 9 additions & 0 deletions analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,13 +713,18 @@ fn expr_call_type_attribute(
args: &Node<Vec<Node<fe::CallArg>>>,
) -> Result<ExpressionAttributes, SemanticError> {
let arg_attributes = expr_call_args(Rc::clone(&scope), context, args)?;
let contract_name = scope.borrow().contract_scope().borrow().name.clone();

match (typ, ContractTypeMethod::from_str(func_name)) {
(Type::Contract(contract), Ok(ContractTypeMethod::Create2)) => {
if arg_attributes.len() != 2 {
return Err(SemanticError::wrong_number_of_params());
}

if contract_name == contract.name {
return Err(SemanticError::circular_dependency());
}

if matches!(
(&arg_attributes[0].typ, &arg_attributes[1].typ),
(Type::Base(Base::Numeric(_)), Type::Base(Base::Numeric(_)))
Expand All @@ -743,6 +748,10 @@ fn expr_call_type_attribute(
return Err(SemanticError::wrong_number_of_params());
}

if contract_name == contract.name {
return Err(SemanticError::circular_dependency());
}

if matches!(&arg_attributes[0].typ, Type::Base(Base::Numeric(_))) {
scope
.borrow()
Expand Down
2 changes: 2 additions & 0 deletions compiler/tests/compile_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use std::fs;
case("call_undefined_function_on_external_contract.fe", "UndefinedValue"),
case("call_undefined_function_on_memory_struct.fe", "UndefinedValue"),
case("call_undefined_function_on_storage_struct.fe", "UndefinedValue"),
case("circular_dependency_create.fe", "CircularDependency"),
case("circular_dependency_create2.fe", "CircularDependency"),
case("continue_without_loop_2.fe", "ContinueWithoutLoop"),
case("continue_without_loop.fe", "ContinueWithoutLoop"),
case("duplicate_contract_in_module.fe", "AlreadyDefined"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
contract Foo:
pub def bar() -> address:
foo: Foo = Foo.create(0)

return address(foo)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
contract Foo:
pub def bar() -> address:
foo: Foo = Foo.create2(2, 0)

return address(foo)
12 changes: 12 additions & 0 deletions newsfragments/362.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Properly reject code that creates a circular dependency when using `create` or `create2`.

Example, the follwing code is now rightfully rejected because it tries to create an
instance of `Foo` from within the `Foo` contract itself.

```
contract Foo:
pub def bar()->address:
foo:Foo=Foo.create(0)

return address(foo)
```