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

#615 Add an optional type system to Bend #631

Merged
merged 30 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0b468c2
Add type syntax
developedby Jul 14, 2024
1333bfb
Fix resolution of type vars to type constructors
developedby Jul 15, 2024
b164389
Make types work with imports, fix nested fatal passes
developedby Jul 19, 2024
f700642
Removed unused atan2 and log adt nodes
developedby Aug 6, 2024
8a06134
Add type checking by compiling to kindc
developedby Aug 8, 2024
dd6d8f8
Update builtins for typechecker
developedby Aug 21, 2024
43ce0d9
Implement a basic hindley-milner type system for bend
developedby Aug 21, 2024
4d8739f
Implement type inference for the remaining types + checking
developedby Aug 23, 2024
05f5729
Add hole type syntax, fix infer for dup, tup elim and match
developedby Aug 26, 2024
cc8e1c2
Fix typing for builting functions
developedby Aug 27, 2024
74d200f
Check that checked functions don't have untyped terms
developedby Aug 28, 2024
1ae3289
Improve type errs, add unchecked fn syntax
developedby Aug 29, 2024
4754445
Fix parsing of unchecked fun functions
developedby Aug 29, 2024
e8687f4
Add infer for switches with more than 2 arms, fix specialization
developedby Aug 29, 2024
5394399
Add typing to examples
developedby Aug 29, 2024
ad3556a
Fix after rebase, optimize type inference
developedby Sep 2, 2024
5027fc3
Optimize unbound var check
developedby Sep 2, 2024
433a5f6
Small improvements
developedby Sep 3, 2024
0b82461
Update snapshots for types
developedby Sep 3, 2024
66e454b
fix parsing of unchecked imp functions
developedby Sep 4, 2024
e6010e9
Slightly improve err messages with location info
developedby Sep 5, 2024
6882d30
Update simplify_matches and encode_pattern_match tests for local defs
developedby Sep 5, 2024
c964274
Update all snapshots for type system branch
developedby Sep 5, 2024
1fe7de9
Fix renaming of imported types in with blocks
developedby Sep 5, 2024
dbba1dd
Rename cast operations
developedby Sep 5, 2024
f59d088
Merge remote-tracking branch 'origin/main' into 615-add-progressive-t…
developedby Sep 5, 2024
617527b
clean
developedby Sep 5, 2024
eaa2809
WIP add documentation on type checking
imaqtkatt Sep 5, 2024
538f9f0
Improve type-check docs
developedby Sep 9, 2024
55f8d87
Update changelog for type checker PR
developedby Sep 9, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project does not currently adhere to a particular versioning scheme.

### Added

- Add type system for Bend. ([#615][gh-615], [#679][gh-679], see [Type Checking](docs/type-checking.md))
- Add import system. ([#544][gh-544])
- Add multi line comment `#{ ... #}` syntax. ([#595][gh-595])
- Add error message when input file is not found. ([#513][gh-513])
Expand Down
3 changes: 3 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"foldl",
"hasher",
"hexdigit",
"Hindley",
"hvm's",
"indexmap",
"inet",
Expand All @@ -57,6 +58,7 @@
"lnil",
"lpthread",
"mant",
"Milner",
"miscompilation",
"mult",
"namegen",
Expand Down Expand Up @@ -109,6 +111,7 @@
"succ",
"supercombinator",
"supercombinators",
"Tarjan's",
"tlsv",
"TSPL",
"tunr",
Expand Down
277 changes: 270 additions & 7 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Click [here](#import-syntax) to see the import syntax.

Click [here](#comments) to see the syntax for commenting code.

Click [here](#imp-type-syntax) to see the imperative type syntax.

Click [here](#fun-type-syntax) to see the functional type syntax.

Both syntaxes can be mixed in the same file like the example below:

```python
Expand Down Expand Up @@ -44,12 +48,15 @@ main =
Defines a top level function.

```python
def add(x, y):
def add(x: u24, y: u24) -> u24:
result = x + y
return result

def unchecked two() -> u24:
return 2

def main:
return add(40, 2)
return add(40, two)
```

A function definition is composed by a name, a sequence of parameters and a body.
Expand All @@ -59,6 +66,10 @@ A top-level name can be anything matching the regex `[A-Za-z0-9_.-/]+`, except i
The last statement of each function must either be a `return` or a selection statement (`if`, `switch`, `match`, `fold`)
where all branches `return`.

Each parameter of the function can receive a type annotation with `param_name: type` and the return value of the function can also be annotated with `def fn_name(args) -> return_type:`.

We can force the type-checker to run or not on a specific function by adding `checked` or `unchecked` between `def` and the function name.

### Type

Defines an algebraic data type.
Expand All @@ -68,14 +79,16 @@ type Option:
Some { value }
None

type Tree:
Node { value, ~left, ~right }
type Tree(T):
Node { value: T, ~left: Tree(T), ~right: Tree(T) }
Leaf
```

Type names must be unique, and should have at least one constructor.

Each constructor is defined by a name followed by its fields.
For a generic or polymorphic type, all type variables used in the constructors must be declared first in the type definition with `type Name(type_var1, ...):`

Each constructor is defined by a name followed by its fields. The fields can be annotated with types that will be checked when creating values of that type.

The `~` notation indicates a recursive field. To use `fold` statements with a type its recursive fields must be correctly marked with `~`.

Expand All @@ -89,9 +102,9 @@ Read [defining data types](./defining-data-types.md) to know more.
Defines a type with a single constructor (like a struct, a record or a class).

```python
object Pair { fst, snd }
object Pair(A, B) { fst: A, snd: B }

object Function { name, args, body }
object Function(T) { name: String, args, body: T }

object Vec { len, data }
```
Expand Down Expand Up @@ -1256,6 +1269,11 @@ hvm link_ports:
(a (b *))
& (c a) ~ (d e)
& (e b) ~ (d c)

# Casts a `u24` to itself.
# We can give type annotations to HVM definitions.
hvm u24_to_u24 -> (u24 -> u24):
($([u24] ret) ret)
```

It's also possible to define functions using HVM syntax. This can be
Expand Down Expand Up @@ -1338,3 +1356,248 @@ Multi-line commenting should also be used to document code.
def second(x, y):
return y
```

<div id="imp-type-syntax"></div>

# Imp Type Syntax

## Variable

Any name represents a type variable.

Used in generic or polymorphic type definitions.

```python
# T is a type variable
type Option(T):
Some { value: T }
None

# A is a type variable
def id(x: A) -> A:
return x
```

## Constructor

`Ctr(...)` represents a constructor type.

Used for defining custom data types or algebraic data types.
Can contain other types as parameters.

```python
def head(list: List(T)) -> Option(T)
match list:
case List/Nil:
return Option/None
case List/Cons:
return Option/Some(list.head)
```

## Any

`Any` represents the untyped type.

It accepts values of alls type and will forcefully cast any type to `Any`.

Can be used for values that can't be statically typed, either because
they are unknown (like in raw IO calls), because they contain untypable
expressions (like unscoped variables), or because the expression cannot
be typed with the current type system (like the self application `lambda x: x(x)`).

```python
def main -> Any:
return 24
```

## None

`None` represents the eraser `*` or absence of a value.

Often used to indicate that a function doesn't return anything.

```python
def none -> None:
return *
```

## Hole

`_` represents a hole type.

This will let the type checker infer the most general type for an argument or return value.

```python
def increment(x: _) -> _:
return x + 1
```

## u24

`u24` represents an unsigned 24-bit integer.

```python
def zero -> u24:
return 0
```

## i24

`i24` represents a signed 24-bit integer.

```python
def random_integer -> i24:
return -42
```

## f24

`f24` represents a 24-bit floating-point number.

```python
def PI -> f24:
return 3.14
```

## Tuple

`(_, _, ...)` represents a tuple type.

Can contain two or more types separated by commas.

```python
def make_tuple(fst: A, snd: B) -> (A, B):
return (fst, snd)
```

## Function

`a -> b` represents a function type.

`a` is the input type, and `b` is the output type.

```python
def apply(f: A -> B, arg: A) -> B:
return f(arg)
```

<div id="fun-type-syntax"></div>

# Fun Type Syntax

## Variable

Any name represents a type variable.

Used in generic or polymorphic type definitions.

```python
# T is a type variable
type (Option T)
= (Some T)
| None

# A is a type variable
id : A -> A
id x = x
```

## Constructor

`(Ctr ...)` represents a constructor type.

Used for defining custom data types or algebraic data types.
Can contain other types as parameters.

```python
head : (List T) -> (Option T)
head [] = Option/None
head (List/Cons head _) = (Option/Some head)
```

## Any

`Any` represents the untyped type.

It accepts values of alls type and will forcefully cast any type to `Any`.

Can be used for values that can't be statically typed, either because
they are unknown (like in raw IO calls), because they contain untypable
expressions (like unscoped variables), or because the expression cannot
be typed with the current type system (like the self application `λx (x x)`).

```python
main : Any
main = @x x
```

## None

`None` represents the eraser `*` or absence of a value.

Often used to indicate that a function doesn't return anything.

```python
none : None
none = *
```

## Hole

`_` represents a hole type.

This will let the type checker infer the most general type for an argument or return value.

```python
increment : _ -> _
increment x = (+ x 1)
```

## u24

`u24` represents an unsigned 24-bit integer.

```python
zero : u24
zero = 0
```

## i24

`i24` represents a signed 24-bit integer.

```python
random_integer : i24
random_integer = -24
```

## f24

`f24` represents a 24-bit floating-point number.

```python
PI : f24
PI = 3.14
```

## Tuple

`(_, _, ...)` represents a tuple type.

Can contain two or more types separated by commas.

```python
make_tuple : A -> B -> (A, B)
make_tuple fst snd = (fst, snd)
```

## Function

`a -> b` represents a function type.

`a` is the input type, and `b` is the output type.

```python
apply : (A -> B) -> A -> B
apply f arg = (f arg)
```
Loading
Loading