|
172 | 172 | TypeAliasStmt,
|
173 | 173 | TypeApplication,
|
174 | 174 | TypedDictExpr,
|
| 175 | + TypeFormExpr, |
175 | 176 | TypeInfo,
|
176 | 177 | TypeParam,
|
177 | 178 | TypeVarExpr,
|
|
191 | 192 | type_aliases_source_versions,
|
192 | 193 | typing_extensions_aliases,
|
193 | 194 | )
|
194 |
| -from mypy.options import Options |
| 195 | +from mypy.options import Options, TYPE_FORM |
195 | 196 | from mypy.patterns import (
|
196 | 197 | AsPattern,
|
197 | 198 | ClassPattern,
|
@@ -3209,6 +3210,7 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
|
3209 | 3210 | self.store_final_status(s)
|
3210 | 3211 | self.check_classvar(s)
|
3211 | 3212 | self.process_type_annotation(s)
|
| 3213 | + self.analyze_rvalue_as_type_form(s) |
3212 | 3214 | self.apply_dynamic_class_hook(s)
|
3213 | 3215 | if not s.type:
|
3214 | 3216 | self.process_module_assignment(s.lvalues, s.rvalue, s)
|
@@ -3537,6 +3539,10 @@ def analyze_lvalues(self, s: AssignmentStmt) -> None:
|
3537 | 3539 | has_explicit_value=has_explicit_value,
|
3538 | 3540 | )
|
3539 | 3541 |
|
| 3542 | + def analyze_rvalue_as_type_form(self, s: AssignmentStmt) -> None: |
| 3543 | + if TYPE_FORM in self.options.enable_incomplete_feature: |
| 3544 | + s.rvalue.as_type = self.try_parse_as_type_expression(s.rvalue) |
| 3545 | + |
3540 | 3546 | def apply_dynamic_class_hook(self, s: AssignmentStmt) -> None:
|
3541 | 3547 | if not isinstance(s.rvalue, CallExpr):
|
3542 | 3548 | return
|
@@ -5271,6 +5277,8 @@ def visit_return_stmt(self, s: ReturnStmt) -> None:
|
5271 | 5277 | self.fail('"return" not allowed in except* block', s, serious=True)
|
5272 | 5278 | if s.expr:
|
5273 | 5279 | s.expr.accept(self)
|
| 5280 | + if TYPE_FORM in self.options.enable_incomplete_feature: |
| 5281 | + s.expr.as_type = self.try_parse_as_type_expression(s.expr) |
5274 | 5282 |
|
5275 | 5283 | def visit_raise_stmt(self, s: RaiseStmt) -> None:
|
5276 | 5284 | self.statement = s
|
@@ -5791,10 +5799,33 @@ def visit_call_expr(self, expr: CallExpr) -> None:
|
5791 | 5799 | with self.allow_unbound_tvars_set():
|
5792 | 5800 | for a in expr.args:
|
5793 | 5801 | a.accept(self)
|
| 5802 | + elif refers_to_fullname( |
| 5803 | + expr.callee, ("typing.TypeForm", "typing_extensions.TypeForm") |
| 5804 | + ): |
| 5805 | + # Special form TypeForm(...). |
| 5806 | + if not self.check_fixed_args(expr, 1, "TypeForm"): |
| 5807 | + return |
| 5808 | + # Translate first argument to an unanalyzed type. |
| 5809 | + try: |
| 5810 | + typ = self.expr_to_unanalyzed_type(expr.args[0]) |
| 5811 | + except TypeTranslationError: |
| 5812 | + self.fail("TypeForm argument is not a type", expr) |
| 5813 | + # Suppress future error: "<typing special form>" not callable |
| 5814 | + expr.analyzed = CastExpr(expr.args[0], AnyType(TypeOfAny.from_error)) |
| 5815 | + return |
| 5816 | + # Piggyback TypeFormExpr object to the CallExpr object; it takes |
| 5817 | + # precedence over the CallExpr semantics. |
| 5818 | + expr.analyzed = TypeFormExpr(typ) |
| 5819 | + expr.analyzed.line = expr.line |
| 5820 | + expr.analyzed.column = expr.column |
| 5821 | + expr.analyzed.accept(self) |
5794 | 5822 | else:
|
5795 | 5823 | # Normal call expression.
|
| 5824 | + calculate_type_forms = TYPE_FORM in self.options.enable_incomplete_feature |
5796 | 5825 | for a in expr.args:
|
5797 | 5826 | a.accept(self)
|
| 5827 | + if calculate_type_forms: |
| 5828 | + a.as_type = self.try_parse_as_type_expression(a) |
5798 | 5829 |
|
5799 | 5830 | if (
|
5800 | 5831 | isinstance(expr.callee, MemberExpr)
|
@@ -6063,6 +6094,11 @@ def visit_cast_expr(self, expr: CastExpr) -> None:
|
6063 | 6094 | if analyzed is not None:
|
6064 | 6095 | expr.type = analyzed
|
6065 | 6096 |
|
| 6097 | + def visit_type_form_expr(self, expr: TypeFormExpr) -> None: |
| 6098 | + analyzed = self.anal_type(expr.type) |
| 6099 | + if analyzed is not None: |
| 6100 | + expr.type = analyzed |
| 6101 | + |
6066 | 6102 | def visit_assert_type_expr(self, expr: AssertTypeExpr) -> None:
|
6067 | 6103 | expr.expr.accept(self)
|
6068 | 6104 | analyzed = self.anal_type(expr.type)
|
@@ -7584,6 +7620,34 @@ def visit_pass_stmt(self, o: PassStmt, /) -> None:
|
7584 | 7620 | def visit_singleton_pattern(self, o: SingletonPattern, /) -> None:
|
7585 | 7621 | return None
|
7586 | 7622 |
|
| 7623 | + def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> Type|None: |
| 7624 | + """Try to parse maybe_type_expr as a type expression. |
| 7625 | + If parsing fails return None and emit no errors.""" |
| 7626 | + # Save SemanticAnalyzer state |
| 7627 | + original_errors = self.errors # altered by fail() |
| 7628 | + original_num_incomplete_refs = self.num_incomplete_refs # altered by record_incomplete_ref() |
| 7629 | + original_progress = self.progress # altered by defer() |
| 7630 | + original_deferred = self.deferred # altered by defer() |
| 7631 | + original_deferral_debug_context_len = len(self.deferral_debug_context) # altered by defer() |
| 7632 | + |
| 7633 | + self.errors = Errors(Options()) |
| 7634 | + try: |
| 7635 | + t = self.expr_to_analyzed_type(maybe_type_expr) |
| 7636 | + if self.errors.is_errors(): |
| 7637 | + raise TypeTranslationError |
| 7638 | + if isinstance(t, (UnboundType, PlaceholderType)): # type: ignore[misc] |
| 7639 | + raise TypeTranslationError |
| 7640 | + except TypeTranslationError: |
| 7641 | + # Not a type expression. It must be a value expression. |
| 7642 | + t = None |
| 7643 | + finally: |
| 7644 | + # Restore SemanticAnalyzer state |
| 7645 | + self.errors = original_errors |
| 7646 | + self.num_incomplete_refs = original_num_incomplete_refs |
| 7647 | + self.progress = original_progress |
| 7648 | + self.deferred = original_deferred |
| 7649 | + del self.deferral_debug_context[original_deferral_debug_context_len:] |
| 7650 | + return t |
7587 | 7651 |
|
7588 | 7652 | def replace_implicit_first_type(sig: FunctionLike, new: Type) -> FunctionLike:
|
7589 | 7653 | if isinstance(sig, CallableType):
|
|
0 commit comments