Skip to content

[ty] Tighten up validation of subscripts and attributes in type expressions#24329

Merged
AlexWaygood merged 2 commits intomainfrom
alex/stricter-subscript-validation
Apr 1, 2026
Merged

[ty] Tighten up validation of subscripts and attributes in type expressions#24329
AlexWaygood merged 2 commits intomainfrom
alex/stricter-subscript-validation

Conversation

@AlexWaygood
Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood commented Mar 31, 2026

Summary

According to the type-expression grammar in the typing spec, only simple names and dotted names can be subscripted in type expressions. More complex expressions, such as list[T][int], constitute invalid type expressions. This PR adds the missing validation for this rule.

Test Plan

mdtests

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Mar 31, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 31, 2026

Typing conformance results

The percentage of diagnostics emitted that were expected errors held steady at 86.76%. The percentage of expected errors that received a diagnostic held steady at 81.53%. The number of fully passing files held steady at 70/132.

Summary

How are test cases classified?

Each test case represents one expected error annotation or a group of annotations sharing a tag. Counts are per test case, not per diagnostic — multiple diagnostics on the same line count as one. Required annotations (E) are true positives when ty flags the expected location and false negatives when it does not. Optional annotations (E?) are true positives when flagged but true negatives (not false negatives) when not. Tagged annotations (E[tag]) require ty to flag exactly one of the tagged lines; tagged multi-annotations (E[tag+]) allow any number up to the tag count. Flagging unexpected locations counts as a false positive.

Metric Old New Diff Outcome
True Positives 865 865 +0
False Positives 132 132 +0
False Negatives 196 196 +0
Total Diagnostics 1050 1050 +0
Precision 86.76% 86.76% +0.00%
Recall 81.53% 81.53% +0.00%
Passing Files 70/132 70/132 +0

True positives changed (5)

5 diagnostics
Test case Diff

aliases_type_statement.py:43

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
+error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

aliases_typealiastype.py:58

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
+error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

annotations_forward_refs.py:47

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
+error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

annotations_typeexpr.py:94

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
+error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

qualifiers_annotated.py:43

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
+error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 31, 2026

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 31, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-type-form 0 0 5
Total 0 0 5

Raw diff:

egglog-python (https://github.com/egraphs-good/egglog-python)
- python/egglog/builtins.py:542:79 error[invalid-type-form] Invalid subscript of object of type `tuple[type, ...]` in type expression
+ python/egglog/builtins.py:542:79 error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions
- python/egglog/builtins.py:666:89 error[invalid-type-form] Invalid subscript of object of type `tuple[type, ...]` in type expression
+ python/egglog/builtins.py:666:89 error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions
- python/egglog/builtins.py:1060:83 error[invalid-type-form] Invalid subscript of object of type `tuple[type, ...]` in type expression
+ python/egglog/builtins.py:1060:83 error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions
- python/tests/test_convert.py:117:35 error[invalid-type-form] Invalid subscript of object of type `tuple[type, ...]` in type expression
+ python/tests/test_convert.py:117:35 error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions
- python/tests/test_convert.py:140:33 error[invalid-type-form] Invalid subscript of object of type `tuple[type, ...]` in type expression
+ python/tests/test_convert.py:140:33 error[invalid-type-form] Only simple names and dotted names can be subscripted in type expressions

Full report with detailed diff (timing results)

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 31, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@AlexWaygood AlexWaygood force-pushed the alex/stricter-subscript-validation branch from 11e34ab to 4e832cc Compare April 1, 2026 13:59
@AlexWaygood AlexWaygood changed the base branch from alex/invalid-expr-messages to main April 1, 2026 14:00
@AlexWaygood AlexWaygood closed this Apr 1, 2026
@AlexWaygood AlexWaygood reopened this Apr 1, 2026
@AlexWaygood AlexWaygood marked this pull request as ready for review April 1, 2026 16:14
Copy link
Copy Markdown
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is what is specified (though it took me a few minutes to notice the extra clarification underneath the grammar table about name being allowed to be a qualified dotted name). It's perhaps worth noting that currently only mypy enforces this rule, so this PR puts us into the strictest tier with mypy (and zuban). Pyright and pyrefly and pycroscope are all fine with this, for example:

class C[T]:
    class Inner: pass
    
x: C[int].Inner = C.Inner()

Ecosystem results suggest it's not a problem in practice to be strict about this, though if someone proposed that the above should be allowed by the spec, I would not argue against allowing it. Which I guess suggests that my initial inclination is that it ought to be allowed.

# error: [invalid-type-form] "Invalid subscript"
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
o: "[1, 2, 3][1:2]",
# error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in type expressions"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wording of this message is a bit confusing, because the expression below could reasonably be said to contain only "simple names, dotted names, and subscripts". The subtlety is that "dotted names" can't include a subscript. Not sure how to make that subtlety clearer, though...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well... the expression below might contain only "simple names, dotted names and subscripts", but it is nonetheless not a simple name, dotted name or subscript itself! (It's a non-dotted-name attribute expression where the value is a subscript.)

But, uh, yeah, possibly not my finest error message... I also don't really have any better ideas, though. We do link to the typing spec grammar in a subdiagnostic, so that's something at least

@AlexWaygood
Copy link
Copy Markdown
Member Author

Pyright and pyrefly and pycroscope are all fine with this, for example:

class C[T]:
    class Inner: pass
    
x: C[int].Inner = C.Inner()

Sure, but is that actually useful? It "means" exactly the same thing as C.Inner -- the specialization of C here has no bearing on the meaning of Inner in a type expression. And it's impossible to construct an example where the specialization of C would have a bearing on that, because the typing spec mandates that type checkers must forbid type variables used in outer scopes from being shadowed in inner scopes.

The rules in the typing spec make sense to me here; I'm in favour of strictly enforcing them.

@AlexWaygood AlexWaygood merged commit 298d1ce into main Apr 1, 2026
51 checks passed
@AlexWaygood AlexWaygood deleted the alex/stricter-subscript-validation branch April 1, 2026 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants