Skip to content

Commit

Permalink
[red-knot] Port type inference tests to new test framework (#13719)
Browse files Browse the repository at this point in the history
## Summary

Porting infer tests to new markdown tests framework.

Link to the corresponding issue: #13696

---------

Co-authored-by: Carl Meyer <[email protected]>
  • Loading branch information
Lexxxzy and carljm authored Oct 15, 2024
1 parent 5fa82fb commit d774807
Show file tree
Hide file tree
Showing 56 changed files with 2,682 additions and 4,012 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Assignment with annotations

## Annotation only transparent to local inference

```py
x = 1
x: int
y = x

reveal_type(y) # revealed: Literal[1]
```

## Violates own annotation

```py
x: int = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`"

```

## Violates previous annotation

```py
x: int
x = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Multi-target assignment

## Basic

```py
x = y = 1
reveal_type(x) # revealed: Literal[1]
reveal_type(y) # revealed: Literal[1]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Unbound

## Maybe unbound

```py
if flag:
y = 3
x = y
reveal_type(x) # revealed: Unbound | Literal[3]
```

## Unbound

```py
x = foo; foo = 1
reveal_type(x) # revealed: Unbound
```

## Unbound class variable

Class variables can reference global variables unless overridden within the class scope.

```py
x = 1
class C:
y = x
if flag:
x = 2

reveal_type(C.x) # revealed: Unbound | Literal[2]
reveal_type(C.y) # revealed: Literal[1]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Walrus operator

## Basic

```py
x = (y := 1) + 1
reveal_type(x) # revealed: Literal[2]
reveal_type(y) # revealed: Literal[1]
```

## Walrus self-addition

```py
x = 0
(x := x + 1)
reveal_type(x) # revealed: Literal[1]
```
15 changes: 15 additions & 0 deletions crates/red_knot_python_semantic/resources/mdtest/attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Class attributes

## Union of attributes

```py
if flag:
class C:
x = 1
else:
class C:
x = 2

y = C.x
reveal_type(y) # revealed: Literal[1, 2]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Binary operations on integers

## Basic Arithmetic

```py
a = 2 + 1
b = a - 4
c = a * b
d = c // 3
e = c / 3
f = 5 % 3

reveal_type(a) # revealed: Literal[3]
reveal_type(b) # revealed: Literal[-1]
reveal_type(c) # revealed: Literal[-3]
reveal_type(d) # revealed: Literal[-1]
reveal_type(e) # revealed: float
reveal_type(f) # revealed: Literal[2]
```

## Division by Zero

```py
# TODO: `a` should be `int` and `e` should be `float` once we support inference.
a = 1 / 0 # error: "Cannot divide object of type `Literal[1]` by zero"
b = 2 // 0 # error: "Cannot floor divide object of type `Literal[2]` by zero"
c = 3 % 0 # error: "Cannot reduce object of type `Literal[3]` modulo zero"
d = int() / 0 # error: "Cannot divide object of type `int` by zero"
e = 1.0 / 0 # error: "Cannot divide object of type `float` by zero"

reveal_type(a) # revealed: float
reveal_type(b) # revealed: int
reveal_type(c) # revealed: int
reveal_type(d) # revealed: @Todo
reveal_type(e) # revealed: @Todo
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Callable instance

## Dunder call

```py
class Multiplier:
def __init__(self, factor: float):
self.factor = factor

def __call__(self, number: float) -> float:
return number * self.factor

a = Multiplier(2.0)(3.0)

class Unit: ...

b = Unit()(3.0) # error: "Object of type `Unit` is not callable"

reveal_type(a) # revealed: float
reveal_type(b) # revealed: Unknown
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Constructor

```py
class Foo: ...

x = Foo()
reveal_type(x) # revealed: Foo
```
51 changes: 51 additions & 0 deletions crates/red_knot_python_semantic/resources/mdtest/call/function.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Call expression

## Simple

```py
def get_int() -> int:
return 42

x = get_int()
reveal_type(x) # revealed: int
```

## Async

```py
async def get_int_async() -> int:
return 42

x = get_int_async()

# TODO: we don't yet support `types.CoroutineType`, should be generic `Coroutine[Any, Any, int]`
reveal_type(x) # revealed: @Todo
```

## Decorated

```py
from typing import Callable

def foo() -> int:
return 42

def decorator(func) -> Callable[[], int]:
return foo

@decorator
def bar() -> str:
return 'bar'

x = bar()

# TODO: should reveal `int`, as the decorator replaces `bar` with `foo`
reveal_type(x) # revealed: @Todo
```

## Invalid callable

```py
nonsense = 123
x = nonsense() # error: "Object of type `Literal[123]` is not callable"
```
74 changes: 74 additions & 0 deletions crates/red_knot_python_semantic/resources/mdtest/call/union.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Unions in calls

## Union of return types

```py
if flag:
def f() -> int:
return 1
else:
def f() -> str:
return 'foo'

x = f()
reveal_type(x) # revealed: int | str
```

## Calling with an unknown union

```py
from nonexistent import f # error: [unresolved-import] "Cannot resolve import `nonexistent`"

if flag:
def f() -> int:
return 1

x = f()
reveal_type(x) # revealed: Unknown | int
```

## Non-callable elements in a union

Calling a union with a non-callable element should emit a diagnostic.

```py
if flag:
f = 1
else:
def f() -> int:
return 1

x = f() # error: "Object of type `Literal[1] | Literal[f]` is not callable (due to union element `Literal[1]`)"
reveal_type(x) # revealed: Unknown | int
```

## Multiple non-callable elements in a union

Calling a union with multiple non-callable elements should mention all of them in the diagnostic.

```py
if flag:
f = 1
elif flag2:
f = 'foo'
else:
def f() -> int:
return 1

x = f() # error: "Object of type `Literal[1] | Literal["foo"] | Literal[f]` is not callable (due to union elements Literal[1], Literal["foo"])"
reveal_type(x) # revealed: Unknown | int
```

## All non-callable union elements

Calling a union with no callable elements can emit a simpler diagnostic.

```py
if flag:
f = 1
else:
f = 'foo'

x = f() # error: "Object of type `Literal[1] | Literal["foo"]` is not callable"
reveal_type(x) # revealed: Unknown
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Comparing integers

## Integer literals

```py
a = 1 == 1 == True
b = 1 == 1 == 2 == 4
c = False < True <= 2 < 3 != 6
d = 1 < 1
e = 1 > 1
f = 1 is 1
g = 1 is not 1
h = 1 is 2
i = 1 is not 7
j = 1 <= "" and 0 < 1

reveal_type(a) # revealed: Literal[True]
reveal_type(b) # revealed: Literal[False]
reveal_type(c) # revealed: Literal[True]
reveal_type(d) # revealed: Literal[False]
reveal_type(e) # revealed: Literal[False]
reveal_type(f) # revealed: bool
reveal_type(g) # revealed: bool
reveal_type(h) # revealed: Literal[False]
reveal_type(i) # revealed: Literal[True]
reveal_type(j) # revealed: @Todo | Literal[True]
```

## Integer instance

```py
# TODO: implement lookup of `__eq__` on typeshed `int` stub.
def int_instance() -> int: ...
a = 1 == int_instance()
b = 9 < int_instance()
c = int_instance() < int_instance()

reveal_type(a) # revealed: @Todo
reveal_type(b) # revealed: bool
reveal_type(c) # revealed: bool
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Non boolean returns

Walking through examples:

- `a = A() < B() < C()`

1. `A() < B() and B() < C()` - split in N comparison
1. `A()` and `B()` - evaluate outcome types
1. `bool` and `bool` - evaluate truthiness
1. `A | B` - union of "first true" types

- `b = 0 < 1 < A() < 3`

1. `0 < 1 and 1 < A() and A() < 3` - split in N comparison
1. `True` and `bool` and `A` - evaluate outcome types
1. `True` and `bool` and `bool` - evaluate truthiness
1. `bool | A` - union of "true" types

- `c = 10 < 0 < A() < B() < C()` short-circuit to False

```py
from __future__ import annotations
class A:
def __lt__(self, other) -> A: ...
class B:
def __lt__(self, other) -> B: ...
class C:
def __lt__(self, other) -> C: ...

a = A() < B() < C()
b = 0 < 1 < A() < 3
c = 10 < 0 < A() < B() < C()

reveal_type(a) # revealed: A | B
reveal_type(b) # revealed: bool | A
reveal_type(c) # revealed: Literal[False]
```
Loading

0 comments on commit d774807

Please sign in to comment.