From b8cb2b42734686a2de5c8de1e3730b8b988b3074 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sun, 7 Jun 2026 15:07:24 +0200 Subject: [PATCH] feat(checker): handle attribute getter --- .../04_complex_types.midas | 11 ++++++++ .../04_complex_types.py | 9 +++++++ midas/checker/checker.py | 26 ++++++++++++++++++- midas/resolver/midas.py | 10 ++++--- 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 examples/01_simple_type_checking/04_complex_types.midas create mode 100644 examples/01_simple_type_checking/04_complex_types.py diff --git a/examples/01_simple_type_checking/04_complex_types.midas b/examples/01_simple_type_checking/04_complex_types.midas new file mode 100644 index 0000000..b920c37 --- /dev/null +++ b/examples/01_simple_type_checking/04_complex_types.midas @@ -0,0 +1,11 @@ +type Meter = float + +extend Meter { + op __add__(Meter) -> Meter + op __sub__(Meter) -> Meter +} + +type Coordinate = { + x: Meter + y: Meter +} \ No newline at end of file diff --git a/examples/01_simple_type_checking/04_complex_types.py b/examples/01_simple_type_checking/04_complex_types.py new file mode 100644 index 0000000..476cb90 --- /dev/null +++ b/examples/01_simple_type_checking/04_complex_types.py @@ -0,0 +1,9 @@ +# type: ignore +# ruff: disable [F821] +p1: Coordinate +p2: Coordinate + +diff_x = p2.x - p1.x +diff_y = p2.y - p1.y + +dist = diff_x + diff_y diff --git a/midas/checker/checker.py b/midas/checker/checker.py index 57fa5e9..ad06b9c 100644 --- a/midas/checker/checker.py +++ b/midas/checker/checker.py @@ -178,6 +178,13 @@ class Checker( stmts: list[m.Stmt] = parser.parse() self.ctx.resolve(stmts) + def unfold_type(self, type: Type) -> Type: + match type: + case AliasType(type=ref_type): + return self.unfold_type(ref_type) + case _: + return type + def is_subtype(self, type1: Type, type2: Type) -> bool: """Check whether `type1` is a subtype of `type2` @@ -562,7 +569,24 @@ class Checker( ) return function.returns - def visit_get_expr(self, expr: p.GetExpr) -> Type: ... + def visit_get_expr(self, expr: p.GetExpr) -> Type: + object: Type = self.type_of(expr.object) + base_object: Type = self.unfold_type(object) + match base_object: + case ComplexType(properties=properties): + if expr.name not in properties: + self.error( + expr.location, f"Unknown property '{expr.name} on {object}" + ) + return UnknownType() + return properties[expr.name] + case UnknownType(): + return UnknownType() + case _: + self.error( + expr.location, f"Cannot get property '{expr.name}' on {object}" + ) + return UnknownType() def visit_literal_expr(self, expr: p.LiteralExpr) -> Type: match expr.value: diff --git a/midas/resolver/midas.py b/midas/resolver/midas.py index 2962b09..468f59a 100644 --- a/midas/resolver/midas.py +++ b/midas/resolver/midas.py @@ -3,6 +3,7 @@ from typing import Optional import midas.ast.midas as m from midas.checker.types import ( AliasType, + ComplexType, Operation, Type, UnknownType, @@ -178,7 +179,8 @@ class MidasResolver(m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[T return UnknownType() def visit_complex_type(self, type: m.ComplexType) -> Type: - for prop in type.properties: - prop.accept(self) - # TODO - return UnknownType() + return ComplexType( + properties={ + prop.name.lexeme: prop.type.accept(self) for prop in type.properties + } + )