diff --git a/pyre2/conformance/third_party/conformance.exp b/pyre2/conformance/third_party/conformance.exp index 9c2276c8ab..e54311214c 100644 --- a/pyre2/conformance/third_party/conformance.exp +++ b/pyre2/conformance/third_party/conformance.exp @@ -2471,16 +2471,6 @@ } ], "annotations_methods.py": [ - { - "code": -2, - "column": 24, - "concise_description": "untype, got Literal['A']", - "description": "untype, got Literal['A']", - "line": 10, - "name": "PyreError", - "stop_column": 27, - "stop_line": 10 - }, { "code": -2, "column": 16, @@ -11769,16 +11759,6 @@ "stop_column": 24, "stop_line": 63 }, - { - "code": -2, - "column": 32, - "concise_description": "untype, got Literal['Foo2']", - "description": "untype, got Literal['Foo2']", - "line": 78, - "name": "PyreError", - "stop_column": 38, - "stop_line": 78 - }, { "code": -2, "column": 9, @@ -14915,16 +14895,6 @@ } ], "generics_upper_bound.py": [ - { - "code": -2, - "column": 36, - "concise_description": "untype, got Literal['ForwardRef | str']", - "description": "untype, got Literal['ForwardRef | str']", - "line": 12, - "name": "PyreError", - "stop_column": 54, - "stop_line": 12 - }, { "code": -2, "column": 1, @@ -14974,16 +14944,6 @@ "name": "PyreError", "stop_column": 50, "stop_line": 56 - }, - { - "code": -2, - "column": 44, - "concise_description": "untype, got Literal['int']", - "description": "untype, got Literal['int']", - "line": 56, - "name": "PyreError", - "stop_column": 49, - "stop_line": 56 } ], "generics_variance.py": [ @@ -17278,16 +17238,6 @@ "stop_column": 35, "stop_line": 32 }, - { - "code": -2, - "column": 28, - "concise_description": "untype, got Literal['A']", - "description": "untype, got Literal['A']", - "line": 37, - "name": "PyreError", - "stop_column": 31, - "stop_line": 37 - }, { "code": -2, "column": 16, @@ -17660,16 +17610,6 @@ "stop_column": 30, "stop_line": 38 }, - { - "code": -2, - "column": 28, - "concise_description": "untype, got Literal['A']", - "description": "untype, got Literal['A']", - "line": 41, - "name": "PyreError", - "stop_column": 31, - "stop_line": 41 - }, { "code": -2, "column": 16, @@ -19259,26 +19199,6 @@ ], "protocols_runtime_checkable.py": [], "protocols_self.py": [ - { - "code": -2, - "column": 24, - "concise_description": "untype, got Literal['Copyable']", - "description": "untype, got Literal['Copyable']", - "line": 10, - "name": "PyreError", - "stop_column": 34, - "stop_line": 10 - }, - { - "code": -2, - "column": 24, - "concise_description": "untype, got Literal['Other']", - "description": "untype, got Literal['Other']", - "line": 23, - "name": "PyreError", - "stop_column": 31, - "stop_line": 23 - }, { "code": -2, "column": 5, diff --git a/pyre2/conformance/third_party/conformance.result b/pyre2/conformance/third_party/conformance.result index 0ccc8d8b39..b8fba02d23 100644 --- a/pyre2/conformance/third_party/conformance.result +++ b/pyre2/conformance/third_party/conformance.result @@ -180,7 +180,6 @@ "Line 187: Unexpected errors ['EXPECTED None <: AsyncIterator[int]', 'TODO: ExprYield - Answers::expr_infer']" ], "annotations_methods.py": [ - "Line 10: Unexpected errors [\"untype, got Literal['A']\"]", "Line 19: Unexpected errors ['Expected a callable, got type[?_]']", "Line 23: Unexpected errors ['Expected a callable, got type[?_]']", "Line 30: Unexpected errors ['assert_type(Any, A) failed']", @@ -880,7 +879,6 @@ "Line 59: Unexpected errors [\"Missing argument 'flush'\"]", "Line 60: Unexpected errors [\"Missing argument 'flush'\", 'TODO: Answers::expr_infer attribute: `Self`.x']", "Line 63: Unexpected errors ['EXPECTED HasNestedFunction <: Self']", - "Line 78: Unexpected errors [\"untype, got Literal['Foo2']\"]", "Line 93: Unexpected errors ['Object of class `Foo3` has no attribute `child_value`']" ], "generics_syntax_compatibility.py": [], @@ -1071,7 +1069,6 @@ "generics_upper_bound.py": [ "Line 24: Expected 1 errors", "Line 51: Expected 1 errors", - "Line 12: Unexpected errors [\"untype, got Literal['ForwardRef | str']\"]", "Line 37: Unexpected errors ['assert_type(list[Any], list[int]) failed']", "Line 38: Unexpected errors ['assert_type(set[Any], set[int]) failed']" ], @@ -1224,7 +1221,6 @@ "Line 25: Unexpected errors ['EXPECTED bool <: TypeGuard[list[str]]', 'EXPECTED Generator[bool, None, None] <: Iterable[object]', 'EXPECTED type[str] <: UnionType | type | tuple[Unknown, ...]', 'Expected `list.__iter__` to be a callable, got Callable[[_PyreReadOnly_[list[object]]], Iterator[_PyreReadOnly_[object]]] | Callable[[list[object]], Iterator[object]]']", "Line 28: Unexpected errors ['EXPECTED bool <: TypeGuard[set[?_]]', 'EXPECTED Generator[bool, None, None] <: Iterable[object]', 'EXPECTED type[?_] <: UnionType | type | tuple[Unknown, ...]']", "Line 32: Unexpected errors ['assert_type(set[object], set[int]) failed']", - "Line 37: Unexpected errors [\"untype, got Literal['A']\"]", "Line 41: Unexpected errors ['EXPECTED bool <: TypeGuard[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", "Line 45: Unexpected errors ['EXPECTED bool <: TypeGuard[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", "Line 49: Unexpected errors ['EXPECTED bool <: TypeGuard[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", @@ -1256,7 +1252,6 @@ "Line 28: Unexpected errors ['EXPECTED bool <: TypeIs[Awaitable[Any]]', 'EXPECTED type[Awaitable] <: UnionType | type | tuple[Unknown, ...]']", "Line 35: Unexpected errors ['TODO: Await(ExprAwait - Answers::expr_infer']", "Line 38: Unexpected errors ['assert_type(Awaitable[int] | int, int) failed']", - "Line 41: Unexpected errors [\"untype, got Literal['A']\"]", "Line 45: Unexpected errors ['EXPECTED bool <: TypeIs[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", "Line 49: Unexpected errors ['EXPECTED bool <: TypeIs[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", "Line 53: Unexpected errors ['EXPECTED bool <: TypeIs[int]', 'EXPECTED type[int] <: UnionType | type | tuple[Unknown, ...]']", @@ -1387,8 +1382,6 @@ "Line 96: Expected 1 errors" ], "protocols_self.py": [ - "Line 10: Unexpected errors [\"untype, got Literal['Copyable']\"]", - "Line 23: Unexpected errors [\"untype, got Literal['Other']\"]", "Line 32: Unexpected errors ['EXPECTED One <: Copyable']", "Line 33: Unexpected errors ['EXPECTED Other <: Copyable']", "Line 54: Unexpected errors ['EXPECTED C1[str] <: P1Parent[str]']", diff --git a/pyre2/conformance/third_party/results.json b/pyre2/conformance/third_party/results.json index 039e8f6933..4c9daf3f46 100644 --- a/pyre2/conformance/third_party/results.json +++ b/pyre2/conformance/third_party/results.json @@ -3,7 +3,7 @@ "pass": 7, "fail": 126, "pass_rate": 0.05, - "differences": 1496, + "differences": 1489, "passing": [ "directives_no_type_check.py", "directives_type_ignore.py", @@ -24,7 +24,7 @@ "annotations_coroutines.py": 3, "annotations_forward_refs.py": 9, "annotations_generators.py": 32, - "annotations_methods.py": 11, + "annotations_methods.py": 10, "annotations_typeexpr.py": 5, "callables_annotation.py": 26, "callables_kwargs.py": 18, @@ -79,7 +79,7 @@ "generics_self_attributes.py": 2, "generics_self_basic.py": 11, "generics_self_protocols.py": 2, - "generics_self_usage.py": 19, + "generics_self_usage.py": 18, "generics_syntax_declarations.py": 14, "generics_syntax_infer_variance.py": 7, "generics_syntax_scoping.py": 18, @@ -91,7 +91,7 @@ "generics_typevartuple_overloads.py": 6, "generics_typevartuple_specialization.py": 49, "generics_typevartuple_unpack.py": 7, - "generics_upper_bound.py": 5, + "generics_upper_bound.py": 4, "generics_variance.py": 13, "generics_variance_inference.py": 10, "historical_positional.py": 4, @@ -103,8 +103,8 @@ "namedtuples_define_functional.py": 18, "namedtuples_type_compat.py": 4, "namedtuples_usage.py": 13, - "narrowing_typeguard.py": 29, - "narrowing_typeis.py": 33, + "narrowing_typeguard.py": 28, + "narrowing_typeis.py": 32, "overloads_basic.py": 4, "protocols_class_objects.py": 7, "protocols_definition.py": 39, @@ -114,7 +114,7 @@ "protocols_modules.py": 4, "protocols_recursive.py": 4, "protocols_runtime_checkable.py": 6, - "protocols_self.py": 8, + "protocols_self.py": 6, "protocols_subtyping.py": 10, "protocols_variance.py": 7, "qualifiers_annotated.py": 13, diff --git a/pyre2/pyre2/bin/alt/bindings.rs b/pyre2/pyre2/bin/alt/bindings.rs index 6de8071013..4e6de07b6e 100644 --- a/pyre2/pyre2/bin/alt/bindings.rs +++ b/pyre2/pyre2/bin/alt/bindings.rs @@ -20,6 +20,7 @@ use ruff_python_ast::name::Name; use ruff_python_ast::Comprehension; use ruff_python_ast::Expr; use ruff_python_ast::ExprAttribute; +use ruff_python_ast::ExprCall; use ruff_python_ast::ExprName; use ruff_python_ast::ExprNoneLiteral; use ruff_python_ast::ExprSubscript; @@ -1088,12 +1089,40 @@ impl<'a> BindingsBuilder<'a> { } else { None }; - self.ensure_expr(&x.value); + let mut value = *x.value; + // Handle forward references in a TypeVar call. + match &mut value { + Expr::Call(ExprCall { + range: _, + func: box Expr::Name(name), + arguments, + }) if name.id == "TypeVar" && !arguments.is_empty() => { + self.ensure_expr(&Expr::Name(name.clone())); + // The constraints (i.e., any positional arguments after the first) + // and the "bound" keyword argument are types. + for arg in arguments.args[1..].iter_mut() { + self.ensure_type(arg, &mut BindingsBuilder::forward_lookup); + } + for kw in arguments.keywords.iter_mut() { + if let Some(id) = &kw.arg + && id.id == "bound" + { + self.ensure_type( + &mut kw.value, + &mut BindingsBuilder::forward_lookup, + ); + } else { + self.ensure_expr(&kw.value); + } + } + } + _ => self.ensure_expr(&value), + } for target in x.targets.iter() { let make_binding = |k: Option>| { - let b = Binding::Expr(k, *x.value.clone()); + let b = Binding::Expr(k, value.clone()); if let Some(name) = &name { - Binding::NameAssign(name.clone(), k, Box::new(b), x.value.range()) + Binding::NameAssign(name.clone(), k, Box::new(b), value.range()) } else { b } diff --git a/pyre2/pyre2/bin/test/legacy_generic.rs b/pyre2/pyre2/bin/test/legacy_generic.rs index ab0a57f644..54f751b55d 100644 --- a/pyre2/pyre2/bin/test/legacy_generic.rs +++ b/pyre2/pyre2/bin/test/legacy_generic.rs @@ -183,3 +183,28 @@ T2 = TypeVar('T2', covariant=True, contravariant=False) T3 = TypeVar('T3', covariant="lunch") # E: Expected literal True or False "#, ); + +simple_test!( + test_tvar_forward_ref, + r#" +from typing import TypeVar +T1 = TypeVar('T1', bound='A') +T2 = TypeVar('T2', bound='B') # E: Could not find name `B` +T3 = TypeVar('T3', 'A', int) +T4 = TypeVar('T4', 'B', int) # E: Could not find name `B` + +class A: + pass + "#, +); + +simple_test!( + test_tvar_class_constraint, + r#" +from typing import TypeVar +class A: + pass +T1 = TypeVar('T1', int, A) +T2 = TypeVar('T2', int, B) # E: Could not find name `B` + "#, +);