Skip to content

Commit

Permalink
[red-knot] Add typing.Any as a spelling for the Any type
Browse files Browse the repository at this point in the history
We already had a representation for the Any type, which we would use
e.g. for expressions without type annotations.  We now recognize
`typing.Any` as a way to refer to this type explicitly.  Like other
special forms, this is tracked correctly through aliasing, and isn't
confused with local definitions that happen to have the same name.
  • Loading branch information
dcreager committed Dec 2, 2024
1 parent 83651de commit 59e9670
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Any

## Annotation

`typing.Any` is a way to name the Any type.

```py
from typing import Any

x: Any = 1
x = "foo"

def f():
reveal_type(x) # revealed: Any
```

## Aliased to a different name

If you alias `typing.Any` to another name, we still recognize that as a spelling
of the Any type.

```py
from typing import Any as RenamedAny

x: RenamedAny = 1
x = "foo"

def f():
reveal_type(x) # revealed: Any
```

## Shadowed class

If you define your own class named `Any`, using that in a type expression refers
to your class, and isn't a spelling of the Any type.

> Note that the real name of the class shouldn't be `Any`, so that we can
> distinguish it from the Any type in the assertion below.
```py
class LocalAny:
pass

Any = LocalAny

x: Any = Any()

def f():
reveal_type(x) # revealed: LocalAny
```
8 changes: 8 additions & 0 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,7 @@ impl<'db> Type<'db> {
Type::KnownInstance(KnownInstanceType::Never | KnownInstanceType::NoReturn) => {
Type::Never
}
Type::KnownInstance(KnownInstanceType::Any) => Type::Any,
_ => todo_type!(),
}
}
Expand Down Expand Up @@ -1896,6 +1897,8 @@ pub enum KnownInstanceType<'db> {
NoReturn,
/// The symbol `typing.Never` available since 3.11 (which can also be found as `typing_extensions.Never`)
Never,
/// The symbol `typing.Any` (which can also be found as `typing_extensions.Any`)
Any,
/// A single instance of `typing.TypeVar`
TypeVar(TypeVarInstance<'db>),
/// A single instance of `typing.TypeAliasType` (PEP 695 type alias)
Expand All @@ -1912,6 +1915,7 @@ impl<'db> KnownInstanceType<'db> {
Self::TypeVar(_) => "TypeVar",
Self::NoReturn => "NoReturn",
Self::Never => "Never",
Self::Any => "Any",
Self::TypeAliasType(_) => "TypeAliasType",
}
}
Expand All @@ -1925,6 +1929,7 @@ impl<'db> KnownInstanceType<'db> {
| Self::Union
| Self::NoReturn
| Self::Never
| Self::Any
| Self::TypeAliasType(_) => Truthiness::AlwaysTrue,
}
}
Expand All @@ -1937,6 +1942,7 @@ impl<'db> KnownInstanceType<'db> {
Self::Union => "typing.Union",
Self::NoReturn => "typing.NoReturn",
Self::Never => "typing.Never",
Self::Any => "typing.Any",
Self::TypeVar(typevar) => typevar.name(db),
Self::TypeAliasType(_) => "typing.TypeAliasType",
}
Expand All @@ -1950,6 +1956,7 @@ impl<'db> KnownInstanceType<'db> {
Self::Union => KnownClass::SpecialForm,
Self::NoReturn => KnownClass::SpecialForm,
Self::Never => KnownClass::SpecialForm,
Self::Any => KnownClass::SpecialForm,
Self::TypeVar(_) => KnownClass::TypeVar,
Self::TypeAliasType(_) => KnownClass::TypeAliasType,
}
Expand All @@ -1969,6 +1976,7 @@ impl<'db> KnownInstanceType<'db> {
return None;
}
match (module.name().as_str(), instance_name) {
("typing" | "typing_extensions", "Any") => Some(Self::Any),
("typing" | "typing_extensions", "Literal") => Some(Self::Literal),
("typing" | "typing_extensions", "Optional") => Some(Self::Optional),
("typing" | "typing_extensions", "Union") => Some(Self::Union),
Expand Down
1 change: 1 addition & 0 deletions crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4642,6 +4642,7 @@ impl<'db> TypeInferenceBuilder<'db> {
);
Type::Unknown
}
KnownInstanceType::Any => Type::Any,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/red_knot_python_semantic/src/types/mro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ impl<'db> ClassBase<'db> {
| KnownInstanceType::Union
| KnownInstanceType::NoReturn
| KnownInstanceType::Never
| KnownInstanceType::Any
| KnownInstanceType::Optional => None,
},
}
Expand Down
3 changes: 1 addition & 2 deletions crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,6 @@ if sys.version_info >= (3, 12):
if sys.version_info >= (3, 13):
__all__ += ["get_protocol_members", "is_protocol", "NoDefault", "TypeIs", "ReadOnly"]

Any = object()

class _Final: ...

def final(f: _T) -> _T: ...
Expand Down Expand Up @@ -199,6 +197,7 @@ class _SpecialForm(_Final):
def __or__(self, other: Any) -> _SpecialForm: ...
def __ror__(self, other: Any) -> _SpecialForm: ...

Any: _SpecialForm
Union: _SpecialForm
Generic: _SpecialForm
# Protocol is only present in 3.8 and later, but mypy needs it unconditionally
Expand Down

0 comments on commit 59e9670

Please sign in to comment.