Add debug-only type checking
diff --git a/compiler/util/ir_data.py b/compiler/util/ir_data.py
index 55f12a7..fa284c4 100644
--- a/compiler/util/ir_data.py
+++ b/compiler/util/ir_data.py
@@ -58,6 +58,33 @@
copy_val.shallow_copy(cur_val)
setattr(self, spec.name, copy_val)
+ # This hook adds a 15% overhead to end-to-end code generation in some cases
+ # so we guard it in a `__debug__` block. Users can opt-out of this check by
+ # running python with the `-O` flag, ie: `python3 -O ./embossc`.
+ if __debug__:
+ def __setattr__(self, name: str, value) -> None:
+ """Debug-only hook that adds basic type checking for ir_data fields."""
+ if spec := self.field_specs.all_field_specs.get(name):
+ if (
+ # Check if it's the expected type
+ not isinstance(value, spec.data_type) and
+ # Oneof fields are a special case
+ not spec.is_oneof and
+ # Optional fields can be set to None
+ not (spec.container is ir_data_fields.FieldContainer.OPTIONAL and
+ value is None) and
+ # Sequences can be a few variants of lists
+ not (spec.is_sequence and
+ isinstance(value, (
+ list, ir_data_fields.TemporaryCopyValuesList,
+ ir_data_fields.CopyValuesList))) and
+ # An enum value can be an int
+ not (spec.is_enum and isinstance(value, int))):
+ raise AttributeError(
+ f"Cannot set {value} (type {value.__class__}) for type"
+ "{spec.data_type}")
+ object.__setattr__(self, name, value)
+
# Non-PEP8 name to mimic the Google Protobuf interface.
def HasField(self, name): # pylint:disable=invalid-name
"""Indicates if this class has the given field defined and it is set."""