feat(checker): handle assignments to attributes
This commit is contained in:
@@ -7,3 +7,5 @@ diff_x = p2.x - p1.x
|
|||||||
diff_y = p2.y - p1.y
|
diff_y = p2.y - p1.y
|
||||||
|
|
||||||
dist = diff_x + diff_y
|
dist = diff_x + diff_y
|
||||||
|
|
||||||
|
p2.x += cast(Meter, 1)
|
||||||
|
|||||||
@@ -437,10 +437,22 @@ class Checker(
|
|||||||
def visit_assign_stmt(self, stmt: p.AssignStmt) -> None:
|
def visit_assign_stmt(self, stmt: p.AssignStmt) -> None:
|
||||||
value_type: Type = self.type_of(stmt.value)
|
value_type: Type = self.type_of(stmt.value)
|
||||||
for target in stmt.targets:
|
for target in stmt.targets:
|
||||||
|
self._assign(stmt.location, target, value_type)
|
||||||
|
|
||||||
|
def _assign(self, location: Location, target: p.Expr, value_type: Type):
|
||||||
|
match target:
|
||||||
|
case p.VariableExpr():
|
||||||
|
self._assign_var(location, target, value_type)
|
||||||
|
|
||||||
|
case p.GetExpr():
|
||||||
|
self._assign_attr(location, target, value_type)
|
||||||
|
|
||||||
|
case _:
|
||||||
if not isinstance(target, p.VariableExpr):
|
if not isinstance(target, p.VariableExpr):
|
||||||
self.logger.warning(f"Unsupported assignment to {target}")
|
self.logger.warning(f"Unsupported assignment to {target}")
|
||||||
self.warning(target.location, f"Unsupported assignment to {target}")
|
self.warning(target.location, f"Unsupported assignment to {target}")
|
||||||
continue
|
|
||||||
|
def _assign_var(self, location: Location, target: p.VariableExpr, value_type: Type):
|
||||||
name: str = target.name
|
name: str = target.name
|
||||||
var_type: Optional[Type] = self.look_up_variable(name, target)
|
var_type: Optional[Type] = self.look_up_variable(name, target)
|
||||||
|
|
||||||
@@ -452,10 +464,38 @@ class Checker(
|
|||||||
# x = v
|
# x = v
|
||||||
if not self.is_subtype(value_type, var_type):
|
if not self.is_subtype(value_type, var_type):
|
||||||
self.error(
|
self.error(
|
||||||
stmt.location,
|
location,
|
||||||
f"Cannot assign {value_type} to {name} of type {var_type}",
|
f"Cannot assign {value_type} to {name} of type {var_type}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _assign_attr(self, location: Location, target: p.GetExpr, value_type: Type):
|
||||||
|
object: Type = self.type_of(target.object)
|
||||||
|
base_object: Type = self.unfold_type(object)
|
||||||
|
match base_object:
|
||||||
|
case ComplexType(properties=properties):
|
||||||
|
if target.name not in properties:
|
||||||
|
self.error(
|
||||||
|
target.location, f"Unknown property '{target.name} on {object}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
prop_type: Type = properties[target.name]
|
||||||
|
if not self.is_subtype(value_type, prop_type):
|
||||||
|
self.error(
|
||||||
|
location,
|
||||||
|
f"Cannot assign {value_type} to property '{target.name}' of type {prop_type} on {object}",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
case UnknownType():
|
||||||
|
pass
|
||||||
|
|
||||||
|
case _:
|
||||||
|
self.error(
|
||||||
|
target.location,
|
||||||
|
f"Cannot assign {value_type} to unknown property '{target.name}' on {object}",
|
||||||
|
)
|
||||||
|
|
||||||
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
|
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
|
||||||
type: Type = stmt.value.accept(self) if stmt.value is not None else UnitType()
|
type: Type = stmt.value.accept(self) if stmt.value is not None else UnitType()
|
||||||
self.env.return_types.append(type)
|
self.env.return_types.append(type)
|
||||||
@@ -580,8 +620,10 @@ class Checker(
|
|||||||
)
|
)
|
||||||
return UnknownType()
|
return UnknownType()
|
||||||
return properties[expr.name]
|
return properties[expr.name]
|
||||||
|
|
||||||
case UnknownType():
|
case UnknownType():
|
||||||
return UnknownType()
|
return UnknownType()
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
self.error(
|
self.error(
|
||||||
expr.location, f"Cannot get property '{expr.name}' on {object}"
|
expr.location, f"Cannot get property '{expr.name}' on {object}"
|
||||||
|
|||||||
@@ -111,9 +111,8 @@ 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(name=name):
|
case p.VariableExpr() | p.GetExpr():
|
||||||
self.resolve_local(target, name)
|
target.accept(self)
|
||||||
# TODO: declare if not found
|
|
||||||
case _:
|
case _:
|
||||||
raise Exception(f"Unsupported assignment to {target}")
|
raise Exception(f"Unsupported assignment to {target}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user