From 90051c7981f8c5fbe759324ccee562bf0e866987 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 25 Jun 2026 21:09:14 +0200 Subject: [PATCH] feat(checker): add structural subtyping rule for dataframes --- midas/checker/registry.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/midas/checker/registry.py b/midas/checker/registry.py index bbd3d85..8e816ac 100644 --- a/midas/checker/registry.py +++ b/midas/checker/registry.py @@ -8,8 +8,10 @@ from midas.checker.types import ( AliasType, AppliedType, BaseType, + ColumnType, ComplexType, ConstraintType, + DataFrameType, ExtensionType, Function, GenericType, @@ -157,6 +159,24 @@ class TypesRegistry: return False return True + case (DataFrameType(columns=columns1), DataFrameType(columns=columns2)): + # TODO: check order? + by_name1: dict[str, DataFrameType.Column] = { + col.name: col for col in columns1 if col.name is not None + } + for col2 in columns2: + if col2.name not in by_name1: + return False + if not self.is_subtype(by_name1[col2.name].type, col2.type): + return False + return True + + case (ColumnType(type=inner1), ColumnType(type=inner2)): + # TODO: invariant, replace ColumnType with simple GenericType + if not self.are_equivalent(inner1, inner2): + return False + return True + case (Function(), Function()): return self.is_func_subtype(type1, type2) @@ -187,6 +207,9 @@ class TypesRegistry: return False + def are_equivalent(self, type1: Type, type2: Type) -> bool: + return self.is_subtype(type1, type2) and self.is_subtype(type2, type1) + # TODO: verify the logic in here def is_func_subtype(self, func1: Function, func2: Function) -> bool: """Check whether a function is a subtype of another