Skip to content

Commit 3f3557b

Browse files
davidfstrclaude
andcommitted
TypeForm: Early-reject functions and modules in try_parse_as_type_expression()
Add a second fast-rejection filter: a string literal that is an identifier naming a FuncDef, OverloadedFuncDef, or MypyFile is a function or module, never a type expression. Reject it before the expensive full-parse block. On mypy's self-check this rejects 48 of the identifier-string literals that reach the full-parse block (e.g. builtin functions like "classmethod", "staticmethod", "hash"; user functions; module names like "platform"), all of which were failing full parses. Unlike the Var-value filter, this check is a single isinstance with no expensive follow-on work, and FuncDef/OverloadedFuncDef/MypyFile are mutually exclusive with the other early-reject node kinds, so it is freely positionable and its rejection count is order-independent. It is placed by descending rejection frequency: after the Var-value filter (~157) and before the placeholder check (~23), i.e. the final order is unbound type variable (~951) -> value Var (~157) -> function/module (~48) -> placeholder (~23) No companion guard is needed (a function or module name is never a valid type, so nothing valid is rejected; check-typeform and testsemanal unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1125b30 commit 3f3557b

1 file changed

Lines changed: 11 additions & 7 deletions

File tree

mypy/semanal.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8100,13 +8100,13 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> None:
81008100
return
81018101
else: # sym is not None
81028102
node = sym.node # cache
8103-
# The following early-reject checks are mutually exclusive
8104-
# (a node is at most one of an unbound type variable, a value
8105-
# Var, or a placeholder), so their order never affects which
8106-
# expressions are rejected. They are ordered by descending
8107-
# rejection frequency (measured on mypy's self-check) so the
8108-
# commonest rejections exit first: unbound type variables
8109-
# (~951) >> value Vars (~157) > placeholders (~23).
8103+
# The following early-reject checks are mutually exclusive,
8104+
# ordered by decreasing rejection frequency (measured on
8105+
# mypy's self-check) so the commonest rejections exit first.
8106+
# - TypeVarExpr, TypeVarTupleExpr, ParamSpecExpr (~951)
8107+
# - Var (~157)
8108+
# - FuncDef, OverloadedFuncDef, MypyFile (~48)
8109+
# - PlaceholderNode (~23)
81108110
unbound_tvar_or_paramspec = (
81118111
isinstance(node, (TypeVarExpr, TypeVarTupleExpr, ParamSpecExpr))
81128112
and self.tvar_scope.get_binding(sym) is None
@@ -8127,6 +8127,10 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> None:
81278127
# not a type expression.
81288128
maybe_type_expr.as_type = None
81298129
return
8130+
if isinstance(node, (FuncDef, OverloadedFuncDef, MypyFile)):
8131+
# Functions and modules are never type expressions.
8132+
maybe_type_expr.as_type = None
8133+
return
81308134
if isinstance(node, PlaceholderNode) and not node.becomes_typeinfo:
81318135
# Either:
81328136
# 1. f'Cannot resolve name "{t.name}" (possible cyclic definition)'

0 commit comments

Comments
 (0)