From 6f0b66278fc80755d988ec0aa7cc327302caf763 Mon Sep 17 00:00:00 2001 From: InSync Date: Thu, 16 Jan 2025 22:40:41 +0700 Subject: [PATCH] [red-knot] Migrate `is_fully_static`/`is_single_valued`/`is_singleton` unit tests to Markdown tests (#15533) ## Summary Part of #15397. ## Test Plan Markdown tests. --------- Co-authored-by: Alex Waygood --- .../mdtest/type_properties/is_fully_static.md | 54 ++++++++++++ .../type_properties/is_single_valued.md | 25 ++++++ .../mdtest/type_properties/is_singleton.md | 56 ++++++++++++ crates/red_knot_python_semantic/src/types.rs | 87 ------------------- 4 files changed, 135 insertions(+), 87 deletions(-) create mode 100644 crates/red_knot_python_semantic/resources/mdtest/type_properties/is_fully_static.md create mode 100644 crates/red_knot_python_semantic/resources/mdtest/type_properties/is_single_valued.md create mode 100644 crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_fully_static.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_fully_static.md new file mode 100644 index 0000000000000..d7e9828e7adab --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_fully_static.md @@ -0,0 +1,54 @@ +# Fully-static types + +A type is fully static iff it does not contain any gradual forms. + +## Fully-static + +```py +from typing_extensions import Literal, LiteralString, Never +from knot_extensions import Intersection, Not, TypeOf, is_fully_static, static_assert + +static_assert(is_fully_static(Never)) +static_assert(is_fully_static(None)) + +static_assert(is_fully_static(Literal[1])) +static_assert(is_fully_static(Literal[True])) +static_assert(is_fully_static(Literal["abc"])) +static_assert(is_fully_static(Literal[b"abc"])) + +static_assert(is_fully_static(LiteralString)) + +static_assert(is_fully_static(str)) +static_assert(is_fully_static(object)) +static_assert(is_fully_static(type)) + +static_assert(is_fully_static(TypeOf[str])) +static_assert(is_fully_static(TypeOf[Literal])) + +static_assert(is_fully_static(str | None)) +static_assert(is_fully_static(Intersection[str, Not[LiteralString]])) + +static_assert(is_fully_static(tuple[()])) +static_assert(is_fully_static(tuple[int, object])) + +static_assert(is_fully_static(type[str])) +static_assert(is_fully_static(type[object])) +``` + +## Non-fully-static + +```py +from typing_extensions import Any, Literal, LiteralString +from knot_extensions import Intersection, Not, TypeOf, Unknown, is_fully_static, static_assert + +static_assert(not is_fully_static(Any)) +static_assert(not is_fully_static(Unknown)) + +static_assert(not is_fully_static(Any | str)) +static_assert(not is_fully_static(str | Unknown)) +static_assert(not is_fully_static(Intersection[Any, Not[LiteralString]])) + +static_assert(not is_fully_static(tuple[Any, ...])) +static_assert(not is_fully_static(tuple[int, Any])) +static_assert(not is_fully_static(type[Any])) +``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_single_valued.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_single_valued.md new file mode 100644 index 0000000000000..c5709b4ddfa77 --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_single_valued.md @@ -0,0 +1,25 @@ +## Single-valued types + +A type is single-valued iff it is not empty and all inhabitants of it compare equal. + +```py +from typing_extensions import Any, Literal, LiteralString, Never +from knot_extensions import is_single_valued, static_assert + +static_assert(is_single_valued(None)) +static_assert(is_single_valued(Literal[True])) +static_assert(is_single_valued(Literal[1])) +static_assert(is_single_valued(Literal["abc"])) +static_assert(is_single_valued(Literal[b"abc"])) + +static_assert(is_single_valued(tuple[()])) +static_assert(is_single_valued(tuple[Literal[True], Literal[1]])) + +static_assert(not is_single_valued(str)) +static_assert(not is_single_valued(Never)) +static_assert(not is_single_valued(Any)) + +static_assert(not is_single_valued(Literal[1, 2])) + +static_assert(not is_single_valued(tuple[None, int])) +``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md new file mode 100644 index 0000000000000..a3e1ed9a969fd --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_singleton.md @@ -0,0 +1,56 @@ +# Singleton types + +A type is a singleton type iff it has exactly one inhabitant. + +## Basic + +```py +from typing_extensions import Literal, Never +from knot_extensions import is_singleton, static_assert + +static_assert(is_singleton(None)) +static_assert(is_singleton(Literal[True])) +static_assert(is_singleton(Literal[False])) + +static_assert(is_singleton(type[bool])) + +static_assert(not is_singleton(Never)) +static_assert(not is_singleton(str)) + +static_assert(not is_singleton(Literal[345])) +static_assert(not is_singleton(Literal[1, 2])) + +static_assert(not is_singleton(tuple[()])) +static_assert(not is_singleton(tuple[None])) +static_assert(not is_singleton(tuple[None, Literal[True]])) +``` + +## `NoDefault` + +### 3.12 + +```toml +[environment] +python-version = "3.12" +``` + +```py +from typing_extensions import _NoDefaultType +from knot_extensions import is_singleton, static_assert + +static_assert(is_singleton(_NoDefaultType)) +``` + +### 3.13 + +```toml +[environment] +python-version = "3.13" +``` + +```py +from typing import _NoDefaultType +from knot_extensions import is_singleton, static_assert + +static_assert(is_singleton(_NoDefaultType)) +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index aaf770b52f30b..4e0c7a2e36bf8 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -4533,16 +4533,6 @@ pub(crate) mod tests { )); } - #[test_case(Ty::None)] - #[test_case(Ty::BooleanLiteral(true))] - #[test_case(Ty::BooleanLiteral(false))] - #[test_case(Ty::SubclassOfBuiltinClass("bool"))] // a `@final` class - fn is_singleton(from: Ty) { - let db = setup_db(); - - assert!(from.into_type(&db).is_singleton(&db)); - } - /// Explicitly test for Python version <3.13 and >=3.13, to ensure that /// the fallback to `typing_extensions` is working correctly. /// See [`KnownClass::canonical_module`] for more information. @@ -4559,83 +4549,6 @@ pub(crate) mod tests { assert!(no_default.is_singleton(&db)); } - #[test_case(Ty::None)] - #[test_case(Ty::BooleanLiteral(true))] - #[test_case(Ty::IntLiteral(1))] - #[test_case(Ty::StringLiteral("abc"))] - #[test_case(Ty::BytesLiteral("abc"))] - #[test_case(Ty::Tuple(vec![]))] - #[test_case(Ty::Tuple(vec![Ty::BooleanLiteral(true), Ty::IntLiteral(1)]))] - fn is_single_valued(from: Ty) { - let db = setup_db(); - - assert!(from.into_type(&db).is_single_valued(&db)); - } - - #[test_case(Ty::Never)] - #[test_case(Ty::Any)] - #[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]))] - #[test_case(Ty::Tuple(vec![Ty::None, Ty::BuiltinInstance("int")]))] - #[test_case(Ty::BuiltinInstance("str"))] - #[test_case(Ty::LiteralString)] - fn is_not_single_valued(from: Ty) { - let db = setup_db(); - - assert!(!from.into_type(&db).is_single_valued(&db)); - } - - #[test_case(Ty::Never)] - #[test_case(Ty::IntLiteral(345))] - #[test_case(Ty::BuiltinInstance("str"))] - #[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]))] - #[test_case(Ty::Tuple(vec![]))] - #[test_case(Ty::Tuple(vec![Ty::None]))] - #[test_case(Ty::Tuple(vec![Ty::None, Ty::BooleanLiteral(true)]))] - fn is_not_singleton(from: Ty) { - let db = setup_db(); - - assert!(!from.into_type(&db).is_singleton(&db)); - } - - #[test_case(Ty::Never)] - #[test_case(Ty::None)] - #[test_case(Ty::IntLiteral(1))] - #[test_case(Ty::BooleanLiteral(true))] - #[test_case(Ty::StringLiteral("abc"))] - #[test_case(Ty::LiteralString)] - #[test_case(Ty::BytesLiteral("abc"))] - #[test_case(Ty::KnownClassInstance(KnownClass::Str))] - #[test_case(Ty::KnownClassInstance(KnownClass::Object))] - #[test_case(Ty::KnownClassInstance(KnownClass::Type))] - #[test_case(Ty::BuiltinClassLiteral("str"))] - #[test_case(Ty::TypingLiteral)] - #[test_case(Ty::Union(vec![Ty::KnownClassInstance(KnownClass::Str), Ty::None]))] - #[test_case(Ty::Intersection{pos: vec![Ty::KnownClassInstance(KnownClass::Str)], neg: vec![Ty::LiteralString]})] - #[test_case(Ty::Tuple(vec![]))] - #[test_case(Ty::Tuple(vec![Ty::KnownClassInstance(KnownClass::Int), Ty::KnownClassInstance(KnownClass::Object)]))] - #[test_case(Ty::BuiltinInstance("type"))] - #[test_case(Ty::SubclassOfBuiltinClass("object"))] - #[test_case(Ty::SubclassOfBuiltinClass("str"))] - fn is_fully_static(from: Ty) { - let db = setup_db(); - - assert!(from.into_type(&db).is_fully_static(&db)); - } - - #[test_case(Ty::Any)] - #[test_case(Ty::Unknown)] - #[test_case(Ty::Todo)] - #[test_case(Ty::Union(vec![Ty::Any, Ty::KnownClassInstance(KnownClass::Str)]))] - #[test_case(Ty::Union(vec![Ty::KnownClassInstance(KnownClass::Str), Ty::Unknown]))] - #[test_case(Ty::Intersection{pos: vec![Ty::Any], neg: vec![Ty::LiteralString]})] - #[test_case(Ty::Tuple(vec![Ty::KnownClassInstance(KnownClass::Int), Ty::Any]))] - #[test_case(Ty::SubclassOfAny)] - fn is_not_fully_static(from: Ty) { - let db = setup_db(); - - assert!(!from.into_type(&db).is_fully_static(&db)); - } - #[test_case(Ty::Todo, Ty::Todo)] #[test_case(Ty::Any, Ty::Any)] #[test_case(Ty::Unknown, Ty::Unknown)]