Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,18 @@ from ty_extensions import reveal_mro

class C(Annotated[int, "foo"]): ...

reveal_mro(C) # revealed: (<class 'C'>, <class 'int'>, <class 'object'>)
# revealed: (<class 'C'>, <class 'int'>, <class 'object'>)
reveal_mro(C)

class D(Annotated[list[str], "foo"]): ...

# revealed: (<class 'D'>, <class 'list[str]'>, <class 'MutableSequence[str]'>, <class 'Sequence[str]'>, <class 'Reversible[str]'>, <class 'Collection[str]'>, <class 'Iterable[str]'>, <class 'Container[str]'>, typing.Protocol, typing.Generic, <class 'object'>)
reveal_mro(D)

class E(Annotated[list["E"], "metadata"]): ...

# error: [revealed-type] "Revealed MRO: (<class 'E'>, <class 'list[E]'>, <class 'MutableSequence[E]'>, <class 'Sequence[E]'>, <class 'Reversible[E]'>, <class 'Collection[E]'>, <class 'Iterable[E]'>, <class 'Container[E]'>, typing.Protocol, typing.Generic, <class 'object'>)"
reveal_mro(E)
```

### Not parameterized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -974,13 +974,14 @@ We *do* support stringified annotations if they appear in a position where a typ
syntactically expected:

```py
from typing import Union, List, Dict
from typing import Union, List, Dict, Annotated

ListOfInts1 = list["int"]
ListOfInts2 = List["int"]
StrOrStyle = Union[str, "Style"]
SubclassOfStyle = type["Style"]
DictStrToStyle = Dict[str, "Style"]
AnnotatedStyle = Annotated["Style", "metadata"]

class Style: ...

Expand All @@ -990,12 +991,14 @@ def _(
str_or_style: StrOrStyle,
subclass_of_style: SubclassOfStyle,
dict_str_to_style: DictStrToStyle,
annotated_style: AnnotatedStyle,
):
reveal_type(list_of_ints1) # revealed: list[int]
reveal_type(list_of_ints2) # revealed: list[int]
reveal_type(str_or_style) # revealed: str | Style
reveal_type(subclass_of_style) # revealed: type[Style]
reveal_type(dict_str_to_style) # revealed: dict[str, Style]
reveal_type(annotated_style) # revealed: Style
```

## Recursive
Expand Down
6 changes: 1 addition & 5 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6602,11 +6602,7 @@ impl<'db> Type<'db> {
Ok(builder.build())
}
KnownInstanceType::Literal(ty) => Ok(ty.inner(db)),
KnownInstanceType::Annotated(ty) => {
Ok(ty
.inner(db)
.in_type_expression(db, scope_id, typevar_binding_context)?)
}
KnownInstanceType::Annotated(ty) => Ok(ty.inner(db)),
KnownInstanceType::TypeGenericAlias(ty) => {
// When `type[…]` appears in a value position (e.g. in an implicit type alias),
// we infer its argument as a type expression. This ensures that we can emit
Expand Down
11 changes: 10 additions & 1 deletion crates/ty_python_semantic/src/types/class_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,16 @@ impl<'db> ClassBase<'db> {
KnownInstanceType::TypeGenericAlias(_) => {
Self::try_from_type(db, KnownClass::Type.to_class_literal(db), subclass)
}
KnownInstanceType::Annotated(ty) => Self::try_from_type(db, ty.inner(db), subclass),
KnownInstanceType::Annotated(ty) => {
// Unions are not supported in this position, so we only need to support
// something like `class C(Annotated[Base, "metadata"]): ...`, which we
// can do by turning the instance type (`Base` in this example) back into
// a class.
let annotated_ty = ty.inner(db);
let instance_ty = annotated_ty.as_nominal_instance()?;

Some(Self::Class(instance_ty.class(db)))
}
Comment on lines +186 to +195
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmmm I feel like there's probably going to be some edge case someone will come up with at some point where this lossy conversion will come back to bite us... but I'm not sure what they are, and this seems fine for now 😆

},

Type::SpecialForm(special_form) => match special_form {
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_python_semantic/src/types/infer/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10708,7 +10708,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
self.infer_expression(element, TypeContext::default());
}

let ty = self.infer_expression(type_expr, TypeContext::default());
let ty = self.infer_type_expression(type_expr);

return Type::KnownInstance(KnownInstanceType::Annotated(InternedType::new(
self.db(),
Expand Down
Loading