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
3 changes: 1 addition & 2 deletions crates/ty_python_semantic/resources/mdtest/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2741,8 +2741,7 @@ class ManyCycles2:
self.x3 = [1]

def f1(self: "ManyCycles2"):
# TODO: should be Unknown | list[int] | list[Divergent]
reveal_type(self.x3) # revealed: Unknown | list[int] | list[Divergent] | list[Unknown]
reveal_type(self.x3) # revealed: Unknown | list[int] | list[Divergent]

self.x1 = [self.x2] + [self.x3]
self.x2 = [self.x1] + [self.x3]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,10 +583,17 @@ def foo(a: int, b: int) -> RecursiveT:

```py
from typing_extensions import TypeGuard, TypeIs
from collections.abc import Callable

type RecursiveIs = TypeIs[RecursiveIs] # error: [cyclic-type-alias-definition]
type RecursiveGuard = TypeGuard[RecursiveGuard]

type AliasIs = RecursiveIs # error: [cyclic-type-alias-definition]
type AliasGuard = RecursiveGuard

type CallableIs = TypeIs[Callable[[], CallableIs]]
type CallableGuard = TypeGuard[Callable[[], CallableGuard]]

reveal_type(CallableIs) # revealed: TypeAliasType
reveal_type(CallableGuard) # revealed: TypeAliasType
```
14 changes: 11 additions & 3 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5586,9 +5586,17 @@ impl<'db> Type<'db> {
TypeMapping::ReplaceParameterDefaults |
TypeMapping::EagerExpansion |
TypeMapping::RescopeReturnCallables(_) => self,
TypeMapping::Materialize(materialization_kind) => match materialization_kind {
MaterializationKind::Top => Type::object(),
MaterializationKind::Bottom => Type::Never,
TypeMapping::Materialize(materialization_kind) => match self {
// `Divergent` is an internal cycle marker rather than a gradual type like
// `Any` or `Unknown`. Materializing it away would destroy the marker we rely
// on for recursive alias convergence.
// TODO: We elsewhere treat `Divergent` as a dynamic type, so failing to
// materialize it away here could lead to odd behavior.
Type::Dynamic(DynamicType::Divergent(_)) => self,
Comment on lines +5590 to +5595
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we need a TODO here for the fact that we elsewhere treat Divergent as a dynamic type, so it could result in odd behavior to fail to materialize it away. I suspect that odd behavior is less bad than a stack overflow, so I'm ok going ahead with the fix and leaving this as TODO.

One option could be to have variants of Divergent that behave as Never or as object, rather than as a dynamic type, but still are marked as Divergent for cycle normalization purposes, and return those variants here.

I think solving this will almost certainly mean making Divergent a top level Type variant rather than a sub-variant of Type::Dynamic.

_ => match materialization_kind {
MaterializationKind::Top => Type::object(),
MaterializationKind::Bottom => Type::Never,
},
}
}

Expand Down
Loading