diff --git a/midas/checker/builtins.py b/midas/checker/builtins.py index ce97d9c..017f158 100644 --- a/midas/checker/builtins.py +++ b/midas/checker/builtins.py @@ -14,6 +14,8 @@ if TYPE_CHECKING: from midas.checker.registry import TypesRegistry +# Hard-coded subtype relationships between builtin types +# Circular dependencies and diamond inheritance MUST be avoided BUILTIN_SUBTYPES: dict[str, set[str]] = { "object": {"float", "list", "dict", "str", "bytes", "tuple"}, "float": {"int"}, diff --git a/midas/checker/registry.py b/midas/checker/registry.py index 02c96c3..d1074a7 100644 --- a/midas/checker/registry.py +++ b/midas/checker/registry.py @@ -113,6 +113,15 @@ class TypesRegistry: raise ValueError(f"Predicate {name} already defined") self._predicates[name] = predicate + def is_builtin_subtype(self, name1: str, name2: str) -> bool: + subtypes: set[str] = BUILTIN_SUBTYPES.get(name2, set()) + if name1 in subtypes: + return True + for subtype in subtypes: + if self.is_builtin_subtype(name1, subtype): + return True + return False + def is_subtype(self, type1: Type, type2: Type) -> bool: """Check whether `type1` is a subtype of `type2` @@ -150,7 +159,7 @@ class TypesRegistry: return self.is_subtype(base1, type2) case (BaseType(name=name1), BaseType(name=name2)): - return name1 in BUILTIN_SUBTYPES.get(name2, set()) + return self.is_builtin_subtype(name1, name2) case (ComplexType(properties=props1), ComplexType(properties=props2)): for k, t in props2.items():