Compare commits
3
Commits
0a748a36a3
...
b8bb8190c4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8bb8190c4
|
||
|
|
a4f5db7ece
|
||
|
|
fc67f01f34
|
+8
-25
@@ -204,13 +204,13 @@ class PythonTyper(
|
|||||||
inferred_return: Type = UnknownType()
|
inferred_return: Type = UnknownType()
|
||||||
if not returned:
|
if not returned:
|
||||||
env.return_types.append(UnitType())
|
env.return_types.append(UnitType())
|
||||||
return_types: set[Type] = set(env.return_types)
|
return_types: list[Type] = self.types.reduce_types(env.return_types)
|
||||||
if len(return_types) == 1:
|
if len(return_types) == 1:
|
||||||
inferred_return = list(return_types)[0]
|
inferred_return = return_types[0]
|
||||||
elif len(return_types) > 1:
|
elif len(return_types) > 1:
|
||||||
self.reporter.error(
|
self.reporter.error(
|
||||||
stmt.location,
|
stmt.location,
|
||||||
f"Mixed return types: {env.return_types}",
|
f"Mixed return types: {return_types}",
|
||||||
)
|
)
|
||||||
|
|
||||||
returns: Type = UnknownType()
|
returns: Type = UnknownType()
|
||||||
@@ -502,34 +502,17 @@ class PythonTyper(
|
|||||||
def visit_list_expr(self, expr: p.ListExpr) -> Type:
|
def visit_list_expr(self, expr: p.ListExpr) -> Type:
|
||||||
list_type: Type = self.types.get_type("list")
|
list_type: Type = self.types.get_type("list")
|
||||||
item_types: list[Type] = [self.type_of(item) for item in expr.items]
|
item_types: list[Type] = [self.type_of(item) for item in expr.items]
|
||||||
|
item_types = self.types.reduce_types(item_types)
|
||||||
|
|
||||||
# Try to reduce types with subsumption
|
if len(item_types) == 0:
|
||||||
reduced: bool = True
|
|
||||||
keep: list[int] = list(range(len(item_types)))
|
|
||||||
while reduced:
|
|
||||||
reduced = False
|
|
||||||
for i, i1 in enumerate(keep):
|
|
||||||
type1: Type = item_types[i1]
|
|
||||||
for i2 in keep[i + 1 :]:
|
|
||||||
type2 = item_types[i2]
|
|
||||||
if self.types.is_subtype(type1, type2):
|
|
||||||
keep.remove(i1)
|
|
||||||
elif self.types.is_subtype(type2, type1):
|
|
||||||
keep.remove(i2)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
reduced = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if len(keep) == 0:
|
|
||||||
return list_type
|
return list_type
|
||||||
|
|
||||||
if len(keep) == 1:
|
if len(item_types) == 1:
|
||||||
item_type: Type = item_types[keep[0]]
|
item_type: Type = item_types[0]
|
||||||
return self.types.apply_generic(list_type, [item_type])
|
return self.types.apply_generic(list_type, [item_type])
|
||||||
self.reporter.error(
|
self.reporter.error(
|
||||||
expr.location,
|
expr.location,
|
||||||
f"Heterogeneous list items: {[item_types[i] for i in keep]}",
|
f"Heterogeneous list items: {item_types}",
|
||||||
)
|
)
|
||||||
return self.types.apply_generic(list_type, [UnknownType()])
|
return self.types.apply_generic(list_type, [UnknownType()])
|
||||||
|
|
||||||
|
|||||||
@@ -283,3 +283,31 @@ class TypesRegistry:
|
|||||||
|
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"{type} is not a generic type")
|
raise ValueError(f"{type} is not a generic type")
|
||||||
|
|
||||||
|
def reduce_types(self, types: list[Type]) -> list[Type]:
|
||||||
|
"""Reduce a list of types to remove subtypes and only keep the highest types
|
||||||
|
|
||||||
|
Args:
|
||||||
|
types (list[Type]): the types to reduce
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[Type]: the reduced list of types
|
||||||
|
"""
|
||||||
|
|
||||||
|
reduced: bool = True
|
||||||
|
keep: list[int] = list(range(len(types)))
|
||||||
|
while reduced:
|
||||||
|
reduced = False
|
||||||
|
for i, i1 in enumerate(keep):
|
||||||
|
type1: Type = types[i1]
|
||||||
|
for i2 in keep[i + 1 :]:
|
||||||
|
type2 = types[i2]
|
||||||
|
if self.is_subtype(type1, type2):
|
||||||
|
keep.remove(i1)
|
||||||
|
elif self.is_subtype(type2, type1):
|
||||||
|
keep.remove(i2)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
reduced = True
|
||||||
|
break
|
||||||
|
return [types[i] for i in keep]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.locals: dict[p.Expr, int] = {}
|
self.locals: dict[p.Expr, int] = {}
|
||||||
self.scopes: list[dict[str, bool]] = []
|
self.scopes: list[dict[str, bool]] = [{}]
|
||||||
|
|
||||||
def resolve(self, *objects: p.Stmt | p.Expr) -> None:
|
def resolve(self, *objects: p.Stmt | p.Expr) -> None:
|
||||||
"""Resolve the given statements or expressions"""
|
"""Resolve the given statements or expressions"""
|
||||||
@@ -77,6 +77,12 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
self.locals[expr] = i
|
self.locals[expr] = i
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def is_defined(self, name: str) -> bool:
|
||||||
|
for scope in self.scopes:
|
||||||
|
if name in scope:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def resolve_function(self, function: p.Function) -> None:
|
def resolve_function(self, function: p.Function) -> None:
|
||||||
"""Resolve a function definition
|
"""Resolve a function definition
|
||||||
|
|
||||||
@@ -111,7 +117,13 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
self.resolve(stmt.value)
|
self.resolve(stmt.value)
|
||||||
for target in stmt.targets:
|
for target in stmt.targets:
|
||||||
match target:
|
match target:
|
||||||
case p.VariableExpr() | p.GetExpr():
|
case p.VariableExpr(name=name):
|
||||||
|
if not self.is_defined(name):
|
||||||
|
self.declare(name)
|
||||||
|
self.define(name)
|
||||||
|
target.accept(self)
|
||||||
|
|
||||||
|
case p.GetExpr():
|
||||||
target.accept(self)
|
target.accept(self)
|
||||||
case _:
|
case _:
|
||||||
raise Exception(f"Unsupported assignment to {target}")
|
raise Exception(f"Unsupported assignment to {target}")
|
||||||
|
|||||||
Reference in New Issue
Block a user