Skip to content

Commit

Permalink
Typechecker: support decorator declarations (#559)
Browse files Browse the repository at this point in the history
This involves rudimentary typechecking of fields, and adding the backing
struct of the decorator into the scope like any ordinary `type`
declaration. Also, in order to get things to typecheck properly, I added
decorator declarations for the existing usages of decorators in the
compiler: `@noreturn`, `@external`, and `@intrinsic`.
  • Loading branch information
kengorab authored Feb 13, 2025
1 parent cee505b commit de54761
Show file tree
Hide file tree
Showing 21 changed files with 725 additions and 71 deletions.
5 changes: 5 additions & 0 deletions projects/compiler/example.abra
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
decorator bar {
a: String
}

@bar(a: "a")
func foo(): Int {
val a = 1 + []
val (a, b) = foobar
Expand Down
190 changes: 132 additions & 58 deletions projects/compiler/src/typechecker.abra

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions projects/compiler/test/run-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,14 @@ const TYPECHECKER_TESTS = [
{ test: "typechecker/enumdecl/error_invalid_tostring_signature.abra", assertions: "typechecker/enumdecl/error_invalid_tostring_signature.out" },
{ test: "typechecker/enumdecl/error_method_bad_self_position.abra", assertions: "typechecker/enumdecl/error_method_bad_self_position.out" },
{ test: "typechecker/enumdecl/error_variant_field_initializer_type_mismatch.abra", assertions: "typechecker/enumdecl/error_variant_field_initializer_type_mismatch.out" },
// Decorator declaration
{ test: "typechecker/decorators/error_enum_as_decorator.abra", assertions: "typechecker/decorators/error_enum_as_decorator.out" },
{ test: "typechecker/decorators/error_noncomptime_field.abra", assertions: "typechecker/decorators/error_noncomptime_field.out" },
{ test: "typechecker/decorators/error_too_few_args.abra", assertions: "typechecker/decorators/error_too_few_args.out" },
{ test: "typechecker/decorators/error_too_many_args.abra", assertions: "typechecker/decorators/error_too_many_args.out" },
{ test: "typechecker/decorators/error_type_as_decorator.abra", assertions: "typechecker/decorators/error_type_as_decorator.out" },
{ test: "typechecker/decorators/error_unlabeled_args.abra", assertions: "typechecker/decorators/error_unlabeled_args.out" },
{ test: "typechecker/decorators/function_decorator.abra", assertions: "typechecker/decorators/function_decorator.out.json" },

// Returns
{ test: "typechecker/return/return.1.abra", assertions: "typechecker/return/return.1.out.json" },
Expand Down
8 changes: 8 additions & 0 deletions projects/compiler/test/typechecker/decorators/_exports.abra
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pub decorator FromOtherModule1 {
pub a: Int
pub b: Int
}

pub decorator FromOtherModule2 {
pub a: Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
enum Foo {
Bar
}

@Foo.Bar(b: "asdf")
func foo() {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Error at %TEST_DIR%/typechecker/decorators/error_enum_as_decorator.abra:5:5
Unexpected token '.', expected one of 'val', 'var', 'func', 'type', 'enum', 'decorator', '@', 'pub':
| @Foo.Bar(b: "asdf")
^
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
decorator Bar {
p: Person
}

type Person { name: String }
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Error at %TEST_DIR%/typechecker/decorators/error_noncomptime_field.abra:2:3
Forbidden field type for decorator 'Bar'
| p: Person
^
This field has type 'Person', which is not allowed for fields of decorators.
Decorators' fields must be one of: Int, Float, Bool, String
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
decorator Bar {
a: String
}

@Bar
func foo() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Error at %TEST_DIR%/typechecker/decorators/error_too_few_args.abra:5:2
Invalid instantiation
| @Bar
^
The following required fields are missing: 'a'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
decorator Bar {
a: String
}

@Bar("asdf", 123)
func foo() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Error at %TEST_DIR%/typechecker/decorators/error_too_many_args.abra:5:14
Too many arguments for invocation
| @Bar("asdf", 123)
^
Expected no more than 1 argument, but 2 were passed
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type Foo {
a: String
}

@Foo(b: "asdf")
func foo() {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Error at %TEST_DIR%/typechecker/decorators/error_type_as_decorator.abra:5:2
Cannot use non-decorator type as a decorator
| @Foo(b: "asdf")
^
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
decorator Bar {
a: String
b: Int
}

@Bar("asdf", 123)
func foo() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Error at %TEST_DIR%/typechecker/decorators/error_unlabeled_args.abra:6:6
Invalid instantiation
| @Bar("asdf", 123)
^
Calls of type constructors must include argument labels
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import FromOtherModule1, FromOtherModule2 from "./_exports"

decorator Bar {
a: String
}

// no necessary label if only one argument
@Bar("asdf")
func f1() {}

@Bar(a: "asdf")
func f2() {}

@FromOtherModule1(a: 3, b: 1)
func f3() {}

@FromOtherModule2(4)
func f4() {}
Loading

0 comments on commit de54761

Please sign in to comment.