Skip to content

Commit

Permalink
Port deferred-annotations tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkdp committed Jan 23, 2025
1 parent d09cd2e commit c513ba8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Deferred annotations

## Basic deferred annotation

```pyi path=mod.pyi
class C(object): ...
```

```py
from mod import C

reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[object]]
```

## Deferred annotations in stubs always resolve

```pyi path=mod.pyi
def get_foo() -> Foo: ...
class Foo: ...
```

```py
from mod import get_foo

reveal_type(get_foo()) # revealed: Foo
```

## Deferred annotations in regular code fail

In (regular) source files, annotations are *not* deferred. This also tests that imports from
`__future__` that are not `annotations` are ignored.

```py
from __future__ import with_statement as annotations

# error: [unresolved-reference]
def get_foo() -> Foo: ...

class Foo: ...

reveal_type(get_foo()) # revealed: Unknown
```

## Deferred annotations in regular code with `__future__.annotations`

If `__future__.annotations` is imported, annotations *are* deferred.

```py
from __future__ import annotations

def get_foo() -> Foo: ...

class Foo: ...

reveal_type(get_foo()) # revealed: Foo
```
73 changes: 0 additions & 73 deletions crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6205,79 +6205,6 @@ mod tests {
Ok(())
}

#[test]
fn deferred_annotation_builtin() -> anyhow::Result<()> {
let mut db = setup_db();
db.write_file("/src/a.pyi", "class C(object): pass")?;
let file = system_path_to_file(&db, "/src/a.pyi").unwrap();
let ty = global_symbol(&db, file, "C").expect_type();
let base = ty
.expect_class_literal()
.class
.iter_mro(&db)
.nth(1)
.unwrap();
assert_eq!(base.display(&db).to_string(), "<class 'object'>");
Ok(())
}

#[test]
fn deferred_annotation_in_stubs_always_resolve() -> anyhow::Result<()> {
let mut db = setup_db();

// Stub files should always resolve deferred annotations
db.write_dedented(
"/src/stub.pyi",
"
def get_foo() -> Foo: ...
class Foo: ...
foo = get_foo()
",
)?;
assert_public_type(&db, "/src/stub.pyi", "foo", "Foo");

Ok(())
}

#[test]
fn deferred_annotations_regular_source_fails() -> anyhow::Result<()> {
let mut db = setup_db();

// In (regular) source files, annotations are *not* deferred
// Also tests imports from `__future__` that are not annotations
db.write_dedented(
"/src/source.py",
"
from __future__ import with_statement as annotations
def get_foo() -> Foo: ...
class Foo: ...
foo = get_foo()
",
)?;
assert_public_type(&db, "/src/source.py", "foo", "Unknown");

Ok(())
}

#[test]
fn deferred_annotation_in_sources_with_future_resolves() -> anyhow::Result<()> {
let mut db = setup_db();

// In source files with `__future__.annotations`, deferred annotations are resolved
db.write_dedented(
"/src/source_with_future.py",
"
from __future__ import annotations
def get_foo() -> Foo: ...
class Foo: ...
foo = get_foo()
",
)?;
assert_public_type(&db, "/src/source_with_future.py", "foo", "Foo");

Ok(())
}

#[test]
fn basic_comprehension() -> anyhow::Result<()> {
let mut db = setup_db();
Expand Down

0 comments on commit c513ba8

Please sign in to comment.