From 52d8040b9bf1cc6293aace4afe4b6c499d515200 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sun, 12 Jan 2025 00:04:55 +0000 Subject: [PATCH 1/8] [red-knot] Extend `knot_extensions` with a few more symbols --- .../resources/mdtest/type_api.md | 55 +++++++++++++++++++ crates/red_knot_python_semantic/src/types.rs | 35 ++++++++++-- .../src/types/class_base.rs | 5 +- .../src/types/infer.rs | 51 ++++++++++++++++- .../knot_extensions/knot_extensions.pyi | 3 + 5 files changed, 143 insertions(+), 6 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index c4e7aa1a1685a..06dae8c4e871c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -94,6 +94,27 @@ reveal_type(C.__mro__) u: Unknown[str] ``` +### `AlwaysTruthy` and `AlwaysFalsy` + +`AlwaysTruthy` and `AlwaysFalsy` represent the sets of all types whose truthiness is always truthy +or falsy, respectively. + +```py +from typing_extensions import Literal + +from knot_extensions import AlwaysFalsy, AlwaysTruthy, is_subtype_of, static_assert + +static_assert(is_subtype_of(Literal[True], AlwaysTruthy)) +static_assert(is_subtype_of(Literal[False], AlwaysFalsy)) + +static_assert(not is_subtype_of(int, AlwaysFalsy)) +static_assert(not is_subtype_of(str, AlwaysFalsy)) + +def _(t: AlwaysTruthy, f: AlwaysFalsy): + reveal_type(t) # revealed: AlwaysTruthy + reveal_type(f) # revealed: AlwaysFalsy +``` + ## Static assertions ### Basics @@ -350,3 +371,37 @@ def type_of_annotation() -> None: # error: "Special form `knot_extensions.TypeOf` expected exactly one type parameter" t: TypeOf[int, str, bytes] ``` + +## `LiteralExt` + +`LiteralExt` creates (unions of) class, function or slice types. + +It cannot be nested and does not mix with `Literal`. + +```py +from typing_extensions import Literal + +from knot_extensions import LiteralExt, static_assert, is_subtype_of + +class C: ... +class D: ... +def f(): ... +def g(): ... + +def _(a: LiteralExt[C], b: LiteralExt[f], c: LiteralExt[1:2:3], flag: bool): + reveal_type(a) # revealed: Literal[C] + reveal_type(b) # revealed: Literal[f] + reveal_type(c) # revealed: slice[Literal[1], Literal[2], Literal[3]] + +def _(a: LiteralExt[C, D], b: LiteralExt[C, f, g], c: LiteralExt[D, g, ::4]): + reveal_type(a) # revealed: Literal[C, D] + reveal_type(b) # revealed: Literal[C] | Literal[f, g] + reveal_type(c) # revealed: Literal[D] | Literal[g] | slice[None, None, Literal[4]] + +# error: [invalid-type-form] +d: LiteralExt[LiteralExt[f]] +# error: [invalid-type-form] +d: LiteralExt[4] +# error: [invalid-type-form] +d: LiteralExt[Literal["5"]] +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 6606cb3640641..758bd47a9c9ce 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -2278,6 +2278,8 @@ impl<'db> Type<'db> { fallback_type: Type::unknown(), }), Type::KnownInstance(KnownInstanceType::Unknown) => Ok(Type::unknown()), + Type::KnownInstance(KnownInstanceType::AlwaysTruthy) => Ok(Type::AlwaysTruthy), + Type::KnownInstance(KnownInstanceType::AlwaysFalsy) => Ok(Type::AlwaysFalsy), _ => Ok(todo_type!( "Unsupported or invalid type in a type expression" )), @@ -2813,12 +2815,18 @@ pub enum KnownInstanceType<'db> { TypeAliasType(TypeAliasType<'db>), /// The symbol `knot_extensions.Unknown` Unknown, + /// The symbol `knot_extensions.AlwaysTruthy` + AlwaysTruthy, + /// The symbol `knot_extensions.AlwaysFalsy` + AlwaysFalsy, /// The symbol `knot_extensions.Not` Not, /// The symbol `knot_extensions.Intersection` Intersection, /// The symbol `knot_extensions.TypeOf` TypeOf, + /// The symbol `knot_extensions.LiteralExt` + LiteralExt, // Various special forms, special aliases and type qualifiers that we don't yet understand // (all currently inferred as TODO in most contexts): @@ -2874,9 +2882,12 @@ impl<'db> KnownInstanceType<'db> { Self::OrderedDict => "OrderedDict", Self::ReadOnly => "ReadOnly", Self::Unknown => "Unknown", + Self::AlwaysTruthy => "AlwaysTruthy", + Self::AlwaysFalsy => "AlwaysFalsy", Self::Not => "Not", Self::Intersection => "Intersection", Self::TypeOf => "TypeOf", + Self::LiteralExt => "LiteralExt", } } @@ -2917,9 +2928,12 @@ impl<'db> KnownInstanceType<'db> { | Self::ReadOnly | Self::TypeAliasType(_) | Self::Unknown + | Self::AlwaysTruthy + | Self::AlwaysFalsy | Self::Not | Self::Intersection - | Self::TypeOf => Truthiness::AlwaysTrue, + | Self::TypeOf + | Self::LiteralExt => Truthiness::AlwaysTrue, } } @@ -2960,9 +2974,12 @@ impl<'db> KnownInstanceType<'db> { Self::TypeVar(typevar) => typevar.name(db), Self::TypeAliasType(_) => "typing.TypeAliasType", Self::Unknown => "knot_extensions.Unknown", + Self::AlwaysTruthy => "knot_extensions.AlwaysTruthy", + Self::AlwaysFalsy => "knot_extensions.AlwaysFalsy", Self::Not => "knot_extensions.Not", Self::Intersection => "knot_extensions.Intersection", Self::TypeOf => "knot_extensions.TypeOf", + Self::LiteralExt => "knot_extensions.LiteralExt", } } @@ -3005,7 +3022,10 @@ impl<'db> KnownInstanceType<'db> { Self::TypeOf => KnownClass::SpecialForm, Self::Not => KnownClass::SpecialForm, Self::Intersection => KnownClass::SpecialForm, + Self::LiteralExt => KnownClass::SpecialForm, Self::Unknown => KnownClass::Object, + Self::AlwaysTruthy => KnownClass::Object, + Self::AlwaysFalsy => KnownClass::Object, } } @@ -3057,9 +3077,12 @@ impl<'db> KnownInstanceType<'db> { "NotRequired" => Self::NotRequired, "LiteralString" => Self::LiteralString, "Unknown" => Self::Unknown, + "AlwaysTruthy" => Self::AlwaysTruthy, + "AlwaysFalsy" => Self::AlwaysFalsy, "Not" => Self::Not, "Intersection" => Self::Intersection, "TypeOf" => Self::TypeOf, + "LiteralExt" => Self::LiteralExt, _ => return None, }; @@ -3109,9 +3132,13 @@ impl<'db> KnownInstanceType<'db> { | Self::TypeVar(_) => { matches!(module, KnownModule::Typing | KnownModule::TypingExtensions) } - Self::Unknown | Self::Not | Self::Intersection | Self::TypeOf => { - module.is_knot_extensions() - } + Self::Unknown + | Self::AlwaysTruthy + | Self::AlwaysFalsy + | Self::Not + | Self::Intersection + | Self::TypeOf + | Self::LiteralExt => module.is_knot_extensions(), } } diff --git a/crates/red_knot_python_semantic/src/types/class_base.rs b/crates/red_knot_python_semantic/src/types/class_base.rs index 1b4a35791453d..fc4e2f3c6f21e 100644 --- a/crates/red_knot_python_semantic/src/types/class_base.rs +++ b/crates/red_knot_python_semantic/src/types/class_base.rs @@ -105,7 +105,10 @@ impl<'db> ClassBase<'db> { | KnownInstanceType::Optional | KnownInstanceType::Not | KnownInstanceType::Intersection - | KnownInstanceType::TypeOf => None, + | KnownInstanceType::TypeOf + | KnownInstanceType::LiteralExt + | KnownInstanceType::AlwaysTruthy + | KnownInstanceType::AlwaysFalsy => None, KnownInstanceType::Unknown => Some(Self::unknown()), KnownInstanceType::Any => Some(Self::any()), // TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 4923285adb587..7ea87fa3afa2e 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -4539,7 +4539,7 @@ impl<'db> TypeInferenceBuilder<'db> { return dunder_getitem_method .call(self.db(), &CallArguments::positional([value_ty, slice_ty])) - .return_ty_result( &self.context, value_node.into()) + .return_ty_result(&self.context, value_node.into()) .unwrap_or_else(|err| { self.context.report_lint( &CALL_NON_CALLABLE, @@ -5298,6 +5298,39 @@ impl<'db> TypeInferenceBuilder<'db> { argument_type } }, + KnownInstanceType::LiteralExt => { + let elements = match arguments_slice { + ast::Expr::Tuple(tuple) => Either::Left(tuple.iter()), + element => Either::Right(std::iter::once(element)), + }; + + elements + .fold(UnionBuilder::new(self.db()), |builder, element| { + let argument_type = self.infer_expression(element); + + match argument_type { + Type::ClassLiteral(_) + | Type::FunctionLiteral(_) + | Type::SliceLiteral(_) => { + builder.add(argument_type) + } + + _ => { + self.context.report_lint( + &INVALID_TYPE_FORM, + element.into(), + format_args!( + "Special form `{}` expected class, function or slice literals as arguments, got `{}`", + known_instance.repr(self.db()), + argument_type.display(self.db()), + ), + ); + builder.add(Type::unknown()) + } + } + }) + .build() + } // TODO: Generics KnownInstanceType::ChainMap => { @@ -5397,6 +5430,22 @@ impl<'db> TypeInferenceBuilder<'db> { ); Type::unknown() } + KnownInstanceType::AlwaysTruthy | KnownInstanceType::AlwaysFalsy => { + self.context.report_lint( + &INVALID_TYPE_FORM, + subscript.into(), + format_args!( + "Special form `{}` expected no type parameter", + known_instance.repr(self.db()) + ), + ); + + if matches!(known_instance, KnownInstanceType::AlwaysTruthy) { + Type::AlwaysTruthy + } else { + Type::AlwaysFalsy + } + } KnownInstanceType::LiteralString => { self.context.report_lint( &INVALID_TYPE_FORM, diff --git a/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi b/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi index 581b2a3d29717..b3e518a235266 100644 --- a/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi +++ b/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi @@ -5,11 +5,14 @@ def static_assert(condition: object, msg: LiteralString | None = None) -> None: # Types Unknown = object() +AlwaysTruthy = object() +AlwaysFalsy = object() # Special forms Not: _SpecialForm Intersection: _SpecialForm TypeOf: _SpecialForm +LiteralExt: _SpecialForm # Predicates on types # From 9f73911164be5fec6928bb44a795627cac71efc3 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sun, 12 Jan 2025 00:22:39 +0000 Subject: [PATCH 2/8] Formatting --- crates/red_knot_python_semantic/resources/mdtest/type_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index 06dae8c4e871c..e8f83c0e24a16 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -385,9 +385,9 @@ from knot_extensions import LiteralExt, static_assert, is_subtype_of class C: ... class D: ... + def f(): ... def g(): ... - def _(a: LiteralExt[C], b: LiteralExt[f], c: LiteralExt[1:2:3], flag: bool): reveal_type(a) # revealed: Literal[C] reveal_type(b) # revealed: Literal[f] From e4251c4f86580ab503ecf1a532f99c5c688e1f31 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sun, 12 Jan 2025 09:55:30 +0000 Subject: [PATCH 3/8] Slightly better formatting --- .../red_knot_python_semantic/resources/mdtest/type_api.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index e8f83c0e24a16..1fc7997b6998e 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -381,13 +381,14 @@ It cannot be nested and does not mix with `Literal`. ```py from typing_extensions import Literal -from knot_extensions import LiteralExt, static_assert, is_subtype_of +from knot_extensions import LiteralExt, TypeOf, static_assert, is_subtype_of + +def f(): ... +def g(): ... class C: ... class D: ... -def f(): ... -def g(): ... def _(a: LiteralExt[C], b: LiteralExt[f], c: LiteralExt[1:2:3], flag: bool): reveal_type(a) # revealed: Literal[C] reveal_type(b) # revealed: Literal[f] From 129637a1acee0cbc16deed3a257352379aef7ecc Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sun, 12 Jan 2025 11:25:17 +0000 Subject: [PATCH 4/8] Remove `LiteralExt` in favor of `TypeOf` --- .../resources/mdtest/type_api.md | 35 ------------------- crates/red_knot_python_semantic/src/types.rs | 12 ++----- .../src/types/class_base.rs | 1 - .../src/types/infer.rs | 33 ----------------- .../knot_extensions/knot_extensions.pyi | 1 - 5 files changed, 2 insertions(+), 80 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index 1fc7997b6998e..c8764ee9a90b4 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -371,38 +371,3 @@ def type_of_annotation() -> None: # error: "Special form `knot_extensions.TypeOf` expected exactly one type parameter" t: TypeOf[int, str, bytes] ``` - -## `LiteralExt` - -`LiteralExt` creates (unions of) class, function or slice types. - -It cannot be nested and does not mix with `Literal`. - -```py -from typing_extensions import Literal - -from knot_extensions import LiteralExt, TypeOf, static_assert, is_subtype_of - -def f(): ... -def g(): ... - -class C: ... -class D: ... - -def _(a: LiteralExt[C], b: LiteralExt[f], c: LiteralExt[1:2:3], flag: bool): - reveal_type(a) # revealed: Literal[C] - reveal_type(b) # revealed: Literal[f] - reveal_type(c) # revealed: slice[Literal[1], Literal[2], Literal[3]] - -def _(a: LiteralExt[C, D], b: LiteralExt[C, f, g], c: LiteralExt[D, g, ::4]): - reveal_type(a) # revealed: Literal[C, D] - reveal_type(b) # revealed: Literal[C] | Literal[f, g] - reveal_type(c) # revealed: Literal[D] | Literal[g] | slice[None, None, Literal[4]] - -# error: [invalid-type-form] -d: LiteralExt[LiteralExt[f]] -# error: [invalid-type-form] -d: LiteralExt[4] -# error: [invalid-type-form] -d: LiteralExt[Literal["5"]] -``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 758bd47a9c9ce..aaf35d2d379d7 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -2825,8 +2825,6 @@ pub enum KnownInstanceType<'db> { Intersection, /// The symbol `knot_extensions.TypeOf` TypeOf, - /// The symbol `knot_extensions.LiteralExt` - LiteralExt, // Various special forms, special aliases and type qualifiers that we don't yet understand // (all currently inferred as TODO in most contexts): @@ -2887,7 +2885,6 @@ impl<'db> KnownInstanceType<'db> { Self::Not => "Not", Self::Intersection => "Intersection", Self::TypeOf => "TypeOf", - Self::LiteralExt => "LiteralExt", } } @@ -2932,8 +2929,7 @@ impl<'db> KnownInstanceType<'db> { | Self::AlwaysFalsy | Self::Not | Self::Intersection - | Self::TypeOf - | Self::LiteralExt => Truthiness::AlwaysTrue, + | Self::TypeOf => Truthiness::AlwaysTrue, } } @@ -2979,7 +2975,6 @@ impl<'db> KnownInstanceType<'db> { Self::Not => "knot_extensions.Not", Self::Intersection => "knot_extensions.Intersection", Self::TypeOf => "knot_extensions.TypeOf", - Self::LiteralExt => "knot_extensions.LiteralExt", } } @@ -3022,7 +3017,6 @@ impl<'db> KnownInstanceType<'db> { Self::TypeOf => KnownClass::SpecialForm, Self::Not => KnownClass::SpecialForm, Self::Intersection => KnownClass::SpecialForm, - Self::LiteralExt => KnownClass::SpecialForm, Self::Unknown => KnownClass::Object, Self::AlwaysTruthy => KnownClass::Object, Self::AlwaysFalsy => KnownClass::Object, @@ -3082,7 +3076,6 @@ impl<'db> KnownInstanceType<'db> { "Not" => Self::Not, "Intersection" => Self::Intersection, "TypeOf" => Self::TypeOf, - "LiteralExt" => Self::LiteralExt, _ => return None, }; @@ -3137,8 +3130,7 @@ impl<'db> KnownInstanceType<'db> { | Self::AlwaysFalsy | Self::Not | Self::Intersection - | Self::TypeOf - | Self::LiteralExt => module.is_knot_extensions(), + | Self::TypeOf => module.is_knot_extensions(), } } diff --git a/crates/red_knot_python_semantic/src/types/class_base.rs b/crates/red_knot_python_semantic/src/types/class_base.rs index fc4e2f3c6f21e..18f0605b0d0d3 100644 --- a/crates/red_knot_python_semantic/src/types/class_base.rs +++ b/crates/red_knot_python_semantic/src/types/class_base.rs @@ -106,7 +106,6 @@ impl<'db> ClassBase<'db> { | KnownInstanceType::Not | KnownInstanceType::Intersection | KnownInstanceType::TypeOf - | KnownInstanceType::LiteralExt | KnownInstanceType::AlwaysTruthy | KnownInstanceType::AlwaysFalsy => None, KnownInstanceType::Unknown => Some(Self::unknown()), diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 7ea87fa3afa2e..fee35fb933af7 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -5298,39 +5298,6 @@ impl<'db> TypeInferenceBuilder<'db> { argument_type } }, - KnownInstanceType::LiteralExt => { - let elements = match arguments_slice { - ast::Expr::Tuple(tuple) => Either::Left(tuple.iter()), - element => Either::Right(std::iter::once(element)), - }; - - elements - .fold(UnionBuilder::new(self.db()), |builder, element| { - let argument_type = self.infer_expression(element); - - match argument_type { - Type::ClassLiteral(_) - | Type::FunctionLiteral(_) - | Type::SliceLiteral(_) => { - builder.add(argument_type) - } - - _ => { - self.context.report_lint( - &INVALID_TYPE_FORM, - element.into(), - format_args!( - "Special form `{}` expected class, function or slice literals as arguments, got `{}`", - known_instance.repr(self.db()), - argument_type.display(self.db()), - ), - ); - builder.add(Type::unknown()) - } - } - }) - .build() - } // TODO: Generics KnownInstanceType::ChainMap => { diff --git a/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi b/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi index b3e518a235266..e2695caa97392 100644 --- a/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi +++ b/crates/red_knot_vendored/knot_extensions/knot_extensions.pyi @@ -12,7 +12,6 @@ AlwaysFalsy = object() Not: _SpecialForm Intersection: _SpecialForm TypeOf: _SpecialForm -LiteralExt: _SpecialForm # Predicates on types # From fbbe74006f97741f0b7891ca3350c6b709eb8a72 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sun, 12 Jan 2025 15:23:41 +0000 Subject: [PATCH 5/8] Per review --- .../resources/mdtest/type_api.md | 7 ++++++ .../src/types/infer.rs | 22 +++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index c8764ee9a90b4..af8244071f5f8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -99,6 +99,8 @@ u: Unknown[str] `AlwaysTruthy` and `AlwaysFalsy` represent the sets of all types whose truthiness is always truthy or falsy, respectively. +They do not accept any type arguments. + ```py from typing_extensions import Literal @@ -113,6 +115,11 @@ static_assert(not is_subtype_of(str, AlwaysFalsy)) def _(t: AlwaysTruthy, f: AlwaysFalsy): reveal_type(t) # revealed: AlwaysTruthy reveal_type(f) # revealed: AlwaysFalsy + +# error: [invalid-type-form] +a: AlwaysTruthy[int] +# error: [invalid-type-form] +b: AlwaysFalsy[str] ``` ## Static assertions diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index fee35fb933af7..194ce6c634748 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -5373,7 +5373,11 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_type_expression(arguments_slice); todo_type!("`Unpack[]` special form") } - KnownInstanceType::NoReturn | KnownInstanceType::Never | KnownInstanceType::Any => { + KnownInstanceType::NoReturn + | KnownInstanceType::Never + | KnownInstanceType::Any + | KnownInstanceType::AlwaysTruthy + | KnownInstanceType::AlwaysFalsy => { self.context.report_lint( &INVALID_TYPE_FORM, subscript.into(), @@ -5397,22 +5401,6 @@ impl<'db> TypeInferenceBuilder<'db> { ); Type::unknown() } - KnownInstanceType::AlwaysTruthy | KnownInstanceType::AlwaysFalsy => { - self.context.report_lint( - &INVALID_TYPE_FORM, - subscript.into(), - format_args!( - "Special form `{}` expected no type parameter", - known_instance.repr(self.db()) - ), - ); - - if matches!(known_instance, KnownInstanceType::AlwaysTruthy) { - Type::AlwaysTruthy - } else { - Type::AlwaysFalsy - } - } KnownInstanceType::LiteralString => { self.context.report_lint( &INVALID_TYPE_FORM, From 076dbb2beee0180cc09fca0e726995320c068757 Mon Sep 17 00:00:00 2001 From: InSync Date: Sun, 12 Jan 2025 15:33:46 +0000 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Alex Waygood --- crates/red_knot_python_semantic/resources/mdtest/type_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index af8244071f5f8..9f3ab7de5df24 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -96,7 +96,7 @@ u: Unknown[str] ### `AlwaysTruthy` and `AlwaysFalsy` -`AlwaysTruthy` and `AlwaysFalsy` represent the sets of all types whose truthiness is always truthy +`AlwaysTruthy` and `AlwaysFalsy` represent the sets of all possible objects whose truthiness is always truthy or falsy, respectively. They do not accept any type arguments. From baaa2b66fad72d384e198e84e19937a53d3df110 Mon Sep 17 00:00:00 2001 From: InSync Date: Sun, 12 Jan 2025 22:51:58 +0700 Subject: [PATCH 7/8] Formatting --- crates/red_knot_python_semantic/resources/mdtest/type_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index 9f3ab7de5df24..f2d80bf97de9b 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -96,8 +96,8 @@ u: Unknown[str] ### `AlwaysTruthy` and `AlwaysFalsy` -`AlwaysTruthy` and `AlwaysFalsy` represent the sets of all possible objects whose truthiness is always truthy -or falsy, respectively. +`AlwaysTruthy` and `AlwaysFalsy` represent the sets of all possible objects whose truthiness is +always truthy or falsy, respectively. They do not accept any type arguments. From eac6e0a695d2045f95e380f92308ee81b9866d12 Mon Sep 17 00:00:00 2001 From: InSync Date: Sun, 12 Jan 2025 16:39:39 +0000 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Alex Waygood --- .../resources/mdtest/type_api.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_api.md b/crates/red_knot_python_semantic/resources/mdtest/type_api.md index f2d80bf97de9b..715ceef584d41 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_api.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_api.md @@ -116,10 +116,12 @@ def _(t: AlwaysTruthy, f: AlwaysFalsy): reveal_type(t) # revealed: AlwaysTruthy reveal_type(f) # revealed: AlwaysFalsy -# error: [invalid-type-form] -a: AlwaysTruthy[int] -# error: [invalid-type-form] -b: AlwaysFalsy[str] +def f( + a: AlwaysTruthy[int], # error: [invalid-type-form] + b: AlwaysFalsy[str], # error: [invalid-type-form] +): + reveal_type(a) # revealed: Unknown + reveal_type(b) # revealed: Unknown ``` ## Static assertions