diff --git a/conformance/third_party/conformance.exp b/conformance/third_party/conformance.exp index 2e31af72fc..023fcbed03 100644 --- a/conformance/third_party/conformance.exp +++ b/conformance/third_party/conformance.exp @@ -9862,39 +9862,6 @@ "stop_column": 26, "stop_line": 76 }, - { - "code": -2, - "column": 16, - "concise_description": "assert_type(type, type[Any]) failed", - "description": "assert_type(type, type[Any]) failed", - "line": 84, - "name": "assert-type", - "severity": "error", - "stop_column": 30, - "stop_line": 84 - }, - { - "code": -2, - "column": 17, - "concise_description": "Object of class `type` has no attribute `unknown`", - "description": "Object of class `type` has no attribute `unknown`", - "line": 99, - "name": "missing-attribute", - "severity": "error", - "stop_column": 26, - "stop_line": 99 - }, - { - "code": -2, - "column": 17, - "concise_description": "Object of class `type` has no attribute `unknown`", - "description": "Object of class `type` has no attribute `unknown`", - "line": 100, - "name": "missing-attribute", - "severity": "error", - "stop_column": 26, - "stop_line": 100 - }, { "code": -2, "column": 5, @@ -9917,22 +9884,11 @@ "stop_column": 14, "stop_line": 120 }, - { - "code": -2, - "column": 16, - "concise_description": "assert_type(type, type[Any]) failed", - "description": "assert_type(type, type[Any]) failed", - "line": 139, - "name": "assert-type", - "severity": "error", - "stop_column": 30, - "stop_line": 139 - }, { "code": -2, "column": 1, - "concise_description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA1, type[type[Unknown]]] (trying to access unknown)", - "description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA1, type[type[Unknown]]] (trying to access unknown)", + "concise_description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA1, type[type]] (trying to access unknown)", + "description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA1, type[type]] (trying to access unknown)", "line": 143, "name": "missing-attribute", "severity": "error", @@ -9953,8 +9909,8 @@ { "code": -2, "column": 1, - "concise_description": "Class `type` has no class attribute `unknown`", - "description": "Class `type` has no class attribute `unknown`", + "concise_description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA3, type[type]] (trying to access unknown)", + "description": "TODO: Expr::attr_infer_for_type attribute base undefined for type: TypeAlias[TA3, type[type]] (trying to access unknown)", "line": 145, "name": "missing-attribute", "severity": "error", @@ -10579,8 +10535,8 @@ { "code": -2, "column": 7, - "concise_description": "Typed dictionary definitions may not specify a metaclass", - "description": "Typed dictionary definitions may not specify a metaclass", + "concise_description": "Metaclass of `BadTypedDict2` has type `type` that is not a simple class type", + "description": "Metaclass of `BadTypedDict2` has type `type` that is not a simple class type", "line": 44, "name": "invalid-inheritance", "severity": "error", diff --git a/conformance/third_party/conformance.result b/conformance/third_party/conformance.result index e4683f7ddb..e329be6707 100644 --- a/conformance/third_party/conformance.result +++ b/conformance/third_party/conformance.result @@ -280,11 +280,7 @@ "specialtypes_none.py": [], "specialtypes_promotions.py": [], "specialtypes_type.py": [ - "Line 70: Expected 1 errors", - "Line 84: Unexpected errors ['assert_type(type, type[Any]) failed']", - "Line 99: Unexpected errors ['Object of class `type` has no attribute `unknown`']", - "Line 100: Unexpected errors ['Object of class `type` has no attribute `unknown`']", - "Line 139: Unexpected errors ['assert_type(type, type[Any]) failed']" + "Line 70: Expected 1 errors" ], "tuples_type_compat.py": [], "tuples_type_form.py": [], diff --git a/conformance/third_party/results.json b/conformance/third_party/results.json index 0e32cf245c..dcde3d39b6 100644 --- a/conformance/third_party/results.json +++ b/conformance/third_party/results.json @@ -3,7 +3,7 @@ "pass": 106, "fail": 32, "pass_rate": 0.77, - "differences": 133, + "differences": 129, "passing": [ "aliases_explicit.py", "aliases_newtype.py", @@ -144,7 +144,7 @@ "qualifiers_annotated.py": 6, "qualifiers_final_annotation.py": 7, "specialtypes_never.py": 1, - "specialtypes_type.py": 5 + "specialtypes_type.py": 1 }, "comment": "@generated" } \ No newline at end of file diff --git a/crates/pyrefly_types/src/display.rs b/crates/pyrefly_types/src/display.rs index 756c2233b0..e3860542de 100644 --- a/crates/pyrefly_types/src/display.rs +++ b/crates/pyrefly_types/src/display.rs @@ -708,6 +708,7 @@ impl<'a> TypeDisplayContext<'a> { output.write_str(ta.name.as_str()) } } + Type::Type(box Type::Any(AnyStyle::Implicit)) => output.write_str("type"), Type::Type(ty) => { output.write_str("type[")?; self.fmt_helper_generic(ty, false, output)?; diff --git a/pyrefly/lib/alt/class/class_metadata.rs b/pyrefly/lib/alt/class/class_metadata.rs index 2a9a9b01d6..71dc5e02ce 100644 --- a/pyrefly/lib/alt/class/class_metadata.rs +++ b/pyrefly/lib/alt/class/class_metadata.rs @@ -19,6 +19,7 @@ use pyrefly_types::type_var::Restriction; use pyrefly_types::typed_dict::ExtraItem; use pyrefly_types::typed_dict::ExtraItems; use pyrefly_types::typed_dict::TypedDict; +use pyrefly_types::types::AnyStyle; use pyrefly_types::types::Forallable; use pyrefly_util::display::DisplayWithCtx; use pyrefly_util::prelude::SliceExt; @@ -914,6 +915,18 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { } } } + Type::Type(box Type::Any(AnyStyle::Implicit)) => { + // `type[Any]` is canoicalized from `type` or `Type` + let type_obj = self.stdlib.builtins_type().class_object(); + let metadata = self.get_metadata_for_class(type_obj); + BaseClassParseResult::Parsed({ + ParsedBaseClass { + class_object: type_obj.dupe(), + range, + metadata, + } + }) + } _ => { if is_new_type || !ty.is_any() { BaseClassParseResult::InvalidType(ty, range) diff --git a/pyrefly/lib/alt/expr.rs b/pyrefly/lib/alt/expr.rs index 98c7ffa906..c8407c5915 100644 --- a/pyrefly/lib/alt/expr.rs +++ b/pyrefly/lib/alt/expr.rs @@ -1289,12 +1289,18 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { Type::ClassDef(cls) => { if cls.is_builtin("tuple") { *ty = Type::type_form(Type::unbounded_tuple(Type::Any(AnyStyle::Implicit))); + } else if cls.is_builtin("type") { + // type is equivalent to type[Any] + *ty = Type::type_form(Type::type_form(Type::Any(AnyStyle::Implicit))); } else if cls.has_toplevel_qname("typing", "Any") { *ty = Type::type_form(Type::any_explicit()) } else { *ty = Type::type_form(self.promote(cls, range, errors)); } } + Type::ClassType(cls) if cls.is_builtin("type") => { + *ty = Type::type_form(Type::Any(AnyStyle::Implicit)); + } _ => {} }) } diff --git a/pyrefly/lib/alt/types/class_bases.rs b/pyrefly/lib/alt/types/class_bases.rs index 5cbd8520e4..ddbd2bc944 100644 --- a/pyrefly/lib/alt/types/class_bases.rs +++ b/pyrefly/lib/alt/types/class_bases.rs @@ -15,6 +15,7 @@ use pyrefly_python::short_identifier::ShortIdentifier; use pyrefly_types::class::ClassType; use pyrefly_types::special_form::SpecialForm; use pyrefly_types::typed_dict::TypedDict; +use pyrefly_types::types::AnyStyle; use pyrefly_util::display::commas_iter; use ruff_python_ast::Expr; use ruff_text_size::Ranged; @@ -299,6 +300,13 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { } } } + (Type::Type(box Type::Any(AnyStyle::Implicit)), range) => { + // `type` is canonicalized to `Type[Any]`, so we need to handle it here. + let class = self.stdlib.builtins_type().clone(); + let bases = self + .get_base_types_for_class(self.stdlib.builtins_type().class_object()); + Some((class, bases, range)) + } (_, _) => None, } }) diff --git a/pyrefly/lib/test/simple.rs b/pyrefly/lib/test/simple.rs index a0ea13377f..875063cdcd 100644 --- a/pyrefly/lib/test/simple.rs +++ b/pyrefly/lib/test/simple.rs @@ -844,6 +844,19 @@ c2: type[C, C] = C # E: Expected 1 type argument for `type`, got 2 "#, ); +testcase!( + test_type_without_argument_is_equivalent_to_type_any, + r#" +from typing import assert_type, Any +def f(x: type) -> None: + g(x) + assert_type(x, type[Any]) +def g(x: type[Any]) -> None: + f(x) + assert_type(x, type) +"#, +); + testcase!( test_annotated, r#" @@ -1402,7 +1415,7 @@ def g(x: type) -> None: ... f(int) f(Type) f(type) -f(42) # E: not assignable to parameter `x` with type `type[Unknown]` +f(42) # E: not assignable to parameter `x` with type `type` g(int) g(Type)