fixed variable freshness bug
This commit is contained in:
parent
c0a44756e3
commit
4577d0cc12
|
@ -52,7 +52,7 @@ doing unification.
|
||||||
|
|
||||||
Consider the following example:
|
Consider the following example:
|
||||||
|
|
||||||
```py
|
```python
|
||||||
X = TypeVar('X')
|
X = TypeVar('X')
|
||||||
|
|
||||||
def head(a: list[X]) -> X:
|
def head(a: list[X]) -> X:
|
||||||
|
@ -68,7 +68,7 @@ algorithm tries to fit `(list[int32])` into `(list[X])`, giving a substitution
|
||||||
Substitution can also substitute variables into another variable. Consider the
|
Substitution can also substitute variables into another variable. Consider the
|
||||||
following example:
|
following example:
|
||||||
|
|
||||||
```
|
```python
|
||||||
X = TypeVar('X')
|
X = TypeVar('X')
|
||||||
Y = TypeVar('Y', int32, int64)
|
Y = TypeVar('Y', int32, int64)
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ So the function is well typed.
|
||||||
|
|
||||||
Note that variables are fresh in every invocation. Consider the following
|
Note that variables are fresh in every invocation. Consider the following
|
||||||
example:
|
example:
|
||||||
```
|
```python
|
||||||
I = TypeVar('I', int32, list[int32])
|
I = TypeVar('I', int32, list[int32])
|
||||||
|
|
||||||
def add(a: int32, b: I) -> int32:
|
def add(a: int32, b: I) -> int32:
|
||||||
|
@ -102,7 +102,7 @@ def add(a: int32, b: I) -> int32:
|
||||||
|
|
||||||
add(1, [1, 2, 3])
|
add(1, [1, 2, 3])
|
||||||
```
|
```
|
||||||
This one should type check (bug now). `I -> list[int32]` only affects 1 call,
|
This one should type check. `I -> list[int32]` only affects 1 call,
|
||||||
and the recursion inside could substitute `I -> int32`.
|
and the recursion inside could substitute `I -> int32`.
|
||||||
|
|
||||||
## Variable Scoping
|
## Variable Scoping
|
||||||
|
|
|
@ -14,3 +14,14 @@ class Vec:
|
||||||
return Vec([self.v[i] + other.v[i] for i in range(len(self.v))])
|
return Vec([self.v[i] + other.v[i] for i in range(len(self.v))])
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar('T', int32, list[int32])
|
||||||
|
|
||||||
|
def add(a: int32, b: T) -> int32:
|
||||||
|
if type(b) == int32:
|
||||||
|
return a + b
|
||||||
|
else:
|
||||||
|
for x in b:
|
||||||
|
a = add(a, x)
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ast
|
import ast
|
||||||
import sys
|
import sys
|
||||||
|
import copy
|
||||||
from helper import CustomError
|
from helper import CustomError
|
||||||
from type_def import SelfType, ClassType
|
from type_def import SelfType, ClassType
|
||||||
from parse_stmt import parse_stmts
|
from parse_stmt import parse_stmts
|
||||||
|
@ -24,9 +25,11 @@ try:
|
||||||
|
|
||||||
for c, name, fn in fns:
|
for c, name, fn in fns:
|
||||||
if c is None:
|
if c is None:
|
||||||
params, result, _ = ctx.functions[name]
|
params, result, var = ctx.functions[name]
|
||||||
else:
|
else:
|
||||||
params, result, _ = ctx.types[c].methods[name]
|
params, result, var = ctx.types[c].methods[name]
|
||||||
|
# create substitution for type variables
|
||||||
|
subst = {k: copy.deepcopy(ctx.variables[k]) for k in var}
|
||||||
# check if fully annotated all params
|
# check if fully annotated all params
|
||||||
sym_table = {}
|
sym_table = {}
|
||||||
for n, ty in zip(fn.args.args, params):
|
for n, ty in zip(fn.args.args, params):
|
||||||
|
@ -36,7 +39,7 @@ try:
|
||||||
fn)
|
fn)
|
||||||
if isinstance(ty, SelfType):
|
if isinstance(ty, SelfType):
|
||||||
ty = ctx.types[c]
|
ty = ctx.types[c]
|
||||||
sym_table[n.arg] = ty
|
sym_table[n.arg] = ty.subst(subst)
|
||||||
_, _, returned = parse_stmts(ctx, sym_table, sym_table, result, fn.body)
|
_, _, returned = parse_stmts(ctx, sym_table, sym_table, result, fn.body)
|
||||||
if result is not None and not returned:
|
if result is not None and not returned:
|
||||||
raise CustomError('Function may have no return value', fn)
|
raise CustomError('Function may have no return value', fn)
|
||||||
|
|
Loading…
Reference in New Issue