feat[next]: friendly errors for more invalid DSL programs#2661
Closed
havogt wants to merge 11 commits into
Closed
Conversation
'global x' inside a field operator crashed SingleAssignTargetPass with
AttributeError ('str' object has no attribute '_fields') because the
pass visited the plain-string 'names' field of the statement. Skip
non-AST field values in NodeYielder.generic_visit so the statement
reaches the dialect parser, and register friendly names + hints for
'global'/'nonlocal' there.
Attribute accesses like 'a.T', 'a.transpose()' or 'np.sin(a)' leaked raw AttributeError/ValueError from FOAST type deduction. Guard visit_Attribute: report nonexistent attributes (with a NumPy-specific note for fields/scalars and 'did you mean' for named collections), nonexistent namespace members, and namespace members whose value has no DSL type (with a hint towards GT4Py built-ins). Also publish the did_you_mean helper for reuse.
Three crashes in FOAST type deduction become diagnostics:
- 'field[3]' leaked AttributeError ('ScalarType' has no 'dim'); now
explains that absolute indexing is unavailable and points to field
offsets / local-dimension indices.
- 'tuple[5]' on a 2-tuple leaked IndexError; now reports the index and
the tuple size.
- 'IDim(3)' on a non-local dimension crashed an assert; now explains
that only local-dimension indices can be constructed.
Three annotation failure modes leaked raw Python exceptions:
- annotations that typing.get_type_hints cannot resolve (invalid
forward-reference strings, undefined names) raised SyntaxError or
NameError; now wrapped into a DSLError pointing at the function.
- parameter annotations that have no GT4Py type (e.g. 'a: list',
'inp: gtx.Field' without arguments) raised ValueError from type
translation; now InvalidParameterAnnotationError, with the underlying
reason as a note and a hint showing valid annotations.
- annotated assignments inside an operator ('b: gtx.Field[...] = a')
raised NameError when the annotation used names not visible inside
the function; now a DSLError explaining what names are available.
Three program-level crashes become diagnostics:
- a bare expression statement ('a + a') leaked a TypeError from IR node
validation; now explains that program statements must be operator
calls.
- calling a '@program' from another program crashed with an
AssertionError; now a DSLError suggesting to call the field operators
directly or compose programs in Python.
- referencing a plain (undecorated) Python function leaked a ValueError
from type translation; now a DSLTypeError hinting at
'@field_operator'/'@scan_operator'. Other non-translatable closure
variables in programs get the same wrapping as in field operators.
DSLTypeError now forwards the structured diagnostic payload
(label/notes/hints) to DSLError.
The message started with a newline and embedded a multi-line code block, which rendered awkwardly; the replacement suggestion is now a hint in the structured diagnostics format.
'value in (None, type(None))' invokes '__eq__', which fails for values
with non-boolean equality such as NumPy arrays ('The truth value of an
array ... is ambiguous'). Compare by identity instead.
Direct calls to field operators and scan operators ('as program') now
validate their arguments the same way program calls do, instead of
crashing deep inside the embedded execution or backend:
- non-GT4Py argument types (e.g. raw NumPy arrays) report which
argument is wrong and hint at 'gtx.as_field' (also when calling
programs, where this previously crashed in type inference);
- wrong dimensions/dtypes/argument counts raise 'Invalid argument
types in call to ...' listing the mismatches;
- a wrong 'out' argument reports the expected vs actual type;
- an invalid 'domain' argument explains the expected mapping form.
Also turned into diagnostics: missing/invalid offset-provider entries
when applying a field offset (was KeyError/NotImplementedError),
unsupported scan-operator attributes like 'init=np.zeros(...)' (was a
crash in fingerprinting), string keys in 'domain' dicts (was an IR
validation TypeError), nested tuple unpacking (was AttributeError) and
invalid literals in type constructors like 'int32("abc")' (was a
ValueError at execution time).
…vity misuse - Unsupported parameter-list features (keyword-only, positional-only, '*args', '**kwargs', defaults) were silently dropped, leading to misleading 'Undeclared symbol' errors; they now raise UnsupportedPythonFeatureError pointing at the parameter. - Out-of-range integer literals reported 'Constants of type <class 'int'> are not permitted'; the underlying reason is now a note. - Calling a '@program' inside a field operator dumped the whole 'ProgramType(...)' spec; now a one-line explanation with a hint. - Unstructured offsets: a missing offset-provider entry leaked KeyError and a raw neighbor-table (NumPy array) entry leaked NotImplementedError from 'as_connectivity_field'; both are now diagnostics, the latter hinting at 'gtx.as_connectivity'.
…tructor misuse - 'offset_provider' arguments that are not a mapping (e.g. a list of pairs or a plain string) were silently accepted and only crashed (or worse, went unnoticed) when an offset was looked up; programs and direct operator calls now reject them upfront with a DSLTypeError. - 'as_field' with an unsupported dtype (e.g. float16) crashed an assert; now a ValueError naming the dtype. - 'as_field' with string dimensions (e.g. ['IDim']) failed with a baffling "''D'' cannot be interpreted as 'UnitRange'"; now a TypeError explaining dimensions must be 'Dimension' objects. - 'as_connectivity' with a non-integral neighbor table crashed an assert; now a ValueError naming the dtype. - 'with_backend' with a non-backend object failed later with AttributeError; now a TypeError at the call.
ruff (imports, noqa for deliberately-dead DSL test code, raw regex patterns), ruff-format, and mypy annotations for the new diagnostics code paths.
This was referenced Jun 16, 2026
Contributor
Author
|
Superseded by a split into three smaller PRs (converted to draft; will close once those land):
Together #2663 + #2664 + #2662 reproduce this branch's src exactly. Please review the splits instead of this PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2655. Extends the structured DSLError diagnostics to more
invalid DSL programs, turning a range of internal crashes into actionable
user-facing errors and improving several existing messages.
New or clearer diagnostics for:
with an AttributeError)
suggestions
dtypes, and constructors
Other changes:
ambiguous truth-value error on array-like values
Notes:
errors.did_you_mean so the attribute-access diagnostic can reuse it