Commit graph

82 commits

Author SHA1 Message Date
Douglas Creager
b39a4ad01d
[red-knot] Rename constraint to predicate (#16382)
In https://github.com/astral-sh/ruff/pull/16306#discussion_r1966290700,
@carljm pointed out that #16306 introduced a terminology problem, with
too many things called a "constraint". This is a follow-up PR that
renames `Constraint` to `Predicate` to hopefully clear things up a bit.
So now we have that:

- a _predicate_ is a Python expression that might influence type
inference
- a _narrowing constraint_ is a list of predicates that constraint the
type of a binding that is visible at a use
- a _visibility constraint_ is a ternary formula of predicates that
define whether a binding is visible or a statement is reachable

This is a pure renaming, with no behavioral changes.
2025-02-25 14:52:40 -05:00
Douglas Creager
fa76f6cbb2
[red-knot] Use arena-allocated association lists for narrowing constraints (#16306)
This PR adds an implementation of [association
lists](https://en.wikipedia.org/wiki/Association_list), and uses them to
replace the previous `BitSet`/`SmallVec` representation for narrowing
constraints.

An association list is a linked list of key/value pairs. We additionally
guarantee that the elements of an association list are sorted (by their
keys), and that they do not contain any entries with duplicate keys.

Association lists have fallen out of favor in recent decades, since you
often need operations that are inefficient on them. In particular,
looking up a random element by index is O(n), just like a linked list;
and looking up an element by key is also O(n), since you must do a
linear scan of the list to find the matching element. Luckily we don't
need either of those operations for narrowing constraints!

The typical implementation also suffers from poor cache locality and
high memory allocation overhead, since individual list cells are
typically allocated separately from the heap. We solve that last problem
by storing the cells of an association list in an `IndexVec` arena.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-02-25 10:58:56 -05:00
Douglas Creager
4dae09ecff
[red-knot] Better handling of visibility constraint copies (#16276)
Two related changes.  For context:

1. We were maintaining two separate arenas of `Constraint`s in each
use-def map. One was used for narrowing constraints, and the other for
visibility constraints. The visibility constraint arena was interned,
ensuring that we always used the same ID for any particular
`Constraint`. The narrowing constraint arena was not interned.

2. The TDD code relies on _all_ TDD nodes being interned and reduced.
This is an important requirement for TDDs to be a canonical form, which
allows us to use a single int comparison to test for "always true/false"
and to compare two TDDs for equivalence. But we also need to support an
individual `Constraint` having multiple values in a TDD evaluation (e.g.
to handle a `while` condition having different values the first time
it's evaluated vs later times). Previously, we handled that by
introducing a "copy" number, which was only there as a disambiguator, to
allow an interned, deduplicated constraint ID to appear in the TDD
formula multiple times.

A better way to handle (2) is to not intern the constraints in the
visibility constraint arena! The caller now gets to decide: if they add
a `Constraint` to the arena more than once, they get distinct
`ScopedConstraintId`s — which the TDD code will treat as distinct
variables, allowing them to take on different values in the ternary
function.

With that in place, we can then consolidate on a single (non-interned)
arena, which is shared for both narrowing and visibility constraints.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-02-21 09:16:25 -05:00
Micha Reiser
470f852f04
[red-knot] Prevent cross-module query dependencies in own_instance_member (#16268) 2025-02-20 18:46:45 +01:00
Douglas Creager
cfc6941d5c
[red-knot] Resolve references in eager nested scopes eagerly (#16079)
We now resolve references in "eager" scopes correctly — using the
bindings and declarations that are visible at the point where the eager
scope is created, not the "public" type of the symbol (typically the
bindings visible at the end of the scope).

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2025-02-19 10:22:30 -05:00
Dhruv Manilawala
60b3ef2c98
[red-knot] Support re-export conventions for stub files (#16073)
This is an alternative implementation to #15848.

## Summary

This PR adds support for re-export conventions for imports for stub
files.

**How does this work?**
* Add a new flag on the `Import` and `ImportFrom` definitions to
indicate whether they're being exported or not
* Add a new enum to indicate whether the symbol lookup is happening
within the same file or is being queried from another file (e.g., an
import statement)
* When a `Symbol` is being queried, we'll skip the definitions that are
(a) coming from a stub file (b) external lookup and (c) check the
re-export flag on the definition

This implementation does not yet support `__all__` and `*` imports as
both are features that needs to be implemented independently.

closes: #14099
closes: #15476 

## Test Plan

Add test cases, update existing ones if required.
2025-02-14 15:17:51 +05:30
David Peter
97e6fc3793
[red-knot] Unpacking and for loop assignments to attributes (#16004)
## Summary

* Support assignments to attributes in more cases:
    - assignments in `for` loops
    - in unpacking assignments
* Add test for multi-target assignments
* Add tests for all other possible assignments to attributes that could
   possibly occur (in decreasing order of likeliness):
    - augmented attribute assignments
    - attribute assignments in `with` statements
    - attribute assignments in comprehensions
- Note: assignments to attributes in named expressions are not
   syntactically allowed

closes #15962

## Test Plan

New Markdown tests
2025-02-07 11:30:51 +01:00
Douglas Creager
0906554357
[red-knot] Combine terminal statement support with statically known branches (#15817)
This example from @sharkdp shows how terminal statements can appear in
statically known branches:
https://github.com/astral-sh/ruff/pull/15676#issuecomment-2618809716

```py
def _(cond: bool):
    x = "a"
    if cond:
        x = "b"
        if True:
            return

    reveal_type(x)  # revealed: "a", "b"; should be "a"
```

We now use visibility constraints to track reachability, which allows us
to model this correctly. There are two related changes as a result:

- New bindings are not assumed to be visible; they inherit the current
"scope start" visibility, which effectively means that new bindings are
visible if/when the current flow is reachable

- When simplifying visibility constraints after branching control flow,
we only simplify if none of the intervening branches included a terminal
statement. That is, earlier unaffected bindings are only _actually_
unaffected if all branches make it to the merge point.
2025-02-05 17:47:49 -05:00
Douglas Creager
0529ad67d7
[red-knot] Internal refactoring of visibility constraints API (#15913)
This extracts some pure refactoring noise from
https://github.com/astral-sh/ruff/pull/15861. This changes the API for
creating and evaluating visibility constraints, but does not change how
they are respresented internally. There should be no behavioral or
performance changes in this PR.

Changes:

- Hide the internal representation isn't changed, so that we can make
changes to it in #15861.
- Add a separate builder type for visibility constraints. (With TDDs, we
will have some additional builder state that we can throw away once
we're done constructing.)
- Remove a layer of helper methods from `UseDefMapBuilder`, making
`SemanticIndexBuilder` responsible for constructing whatever visibility
constraints it needs.
2025-02-03 15:13:09 -05:00
David Peter
102c2eec12
[red-knot] Implicit instance attributes (#15811)
## Summary

Add support for implicitly-defined instance attributes, i.e. support
type inference for cases like this:
```py
class C:
    def __init__(self) -> None:
        self.x: int = 1
        self.y = None

reveal_type(C().x)  # int
reveal_type(C().y)  # Unknown | None
```

## Benchmarks

Codspeed reports no change in a cold-cache benchmark, and a -1%
regression in the incremental benchmark. On `black`'s `src` folder, I
don't see a statistically significant difference between the branches:

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `./red_knot_main check --project /home/shark/black/src` | 133.7 ± 9.5 | 126.7 | 164.7 | 1.01 ± 0.08 |
| `./red_knot_feature check --project /home/shark/black/src` | 132.2 ± 5.1 | 118.1 | 140.9 | 1.00 |

## Test Plan

Updated and new Markdown tests
2025-02-03 19:34:23 +01:00
Alex Waygood
d9a1034db0
Add convenience helper methods for AST nodes representing function parameters (#15871) 2025-02-01 17:16:32 +00:00
Douglas Creager
fab86de3ef
[red-knot] Should A ∧ !A always be false? (#15839)
This mimics a simplification we have on the OR side, where we simplify
`A ∨ !A` to true. This requires changes to how we add `while` statements
to the semantic index, since we now need distinct
`VisibilityConstraint`s if we need to model evaluating a `Constraint`
multiple times at different points in the execution of the program.
2025-01-31 14:06:52 -05:00
Douglas Creager
15d886a502
[red-knot] Consider all definitions after terminal statements unreachable (#15676)
`FlowSnapshot` now tracks a `reachable` bool, which indicates whether we
have encountered a terminal statement on that control flow path. When
merging flow states together, we skip any that have been marked
unreachable. This ensures that bindings that can only be reached through
unreachable paths are not considered visible.

## Test Plan

The new mdtests failed (with incorrect `reveal_type` results, and
spurious `possibly-unresolved-reference` errors) before adding the new
visibility constraints.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-01-29 14:06:57 -05:00
David Peter
792f9e357e
[red-knot] Rename *_ty functions (#15617)
## Summary

General rules:

* Change the `_ty` suffix of all functions to `_type`.
* `_type_and_qualifiers` suffixes seem too long, so we ignore the
existence of qualifiers and still speak of "types"
* Functions only have a `_type` suffix if they return either `Type`,
`Option<Type>`, or `TypeAndQualifiers`

Free functions:

* `binding_ty` => `binding_type`
* `declaration_ty` => `declaration_type`
* `definition_expression_ty` => `definition_expression_type`

Methods:

* `CallDunderResult::return_ty` => `return_type`
* `NotCallableError::return_ty` => `return_type`
* `NotCallableError::called_ty` => `called_type`
* `TypeAndQualifiers::inner_ty` => `inner_type`
* `TypeAliasType::value_ty` => `value_type`
* `TypeInference::expression_ty` => `expression_type`
* `TypeInference::try_expression_ty` => `try_expression_type`
* `TypeInference::binding_ty` => `binding_type`
* `TypeInference::declaration_ty` => `declaration_type` 
* `TypeInferenceBuilder::expression_ty` => `expression_type`
* `TypeInferenceBuilder::file_expression_ty` => `file_expression_type`
* `TypeInferenceBuilder::module_ty_from_name` => `module_type_from_name`
* `ClassBase::try_from_ty` => `try_from_type`
* `Parameter::annotated_ty` => `annotated_type`
* `Parameter::default_ty` => `default_type`
* `CallOutcome::return_ty` => `return_type`
* `CallOutcome::return_ty_result` => `return_type_result`
* `CallBinding::from_return_ty` => `from_return_type`
* `CallBinding::set_return_ty` => `set_return_type`
* `CallBinding::return_ty` => `return_type`
* `CallBinding::parameter_tys` => `parameter_types`
* `CallBinding::one_parameter_ty` => `one_parameter_type`
* `CallBinding::two_parameter_tys` => `two_parameter_types`
* `Unpacker::tuple_ty_elements` => `tuple_type_elements`
* `StringPartsCollector::ty` => `string_type`

Traits

* `HasTy` => `HasType`
* `HasTy::ty` => `inferred_type`

Test functions:

* `assert_public_ty` => `assert_public_type`
* `assert_scope_ty` => `assert_scope_type`

closes #15569

## Test Plan

—
2025-01-22 09:06:56 +01:00
Douglas Creager
b2a0d68d70
Narrowing for class patterns in match statements (#15223)
We now support class patterns in a match statement, adding a narrowing
constraint that within the body of that match arm, we can assume that
the subject is an instance of that class.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-01-07 15:58:12 -05:00
Carl Meyer
2ea63620cf
[red-knot] fix control flow for assignment expressions in elif tests (#15274)
## Summary

The test expression in an `elif` clause is evaluated whether or not we
take the branch. Our control flow model for if/elif chains failed to
reflect this, causing wrong inference in cases where an assignment
expression occurs inside an `elif` test expression. Our "no branch taken
yet" snapshot (which is the starting state for every new elif branch)
can't simply be the pre-if state, it must be updated after visiting each
test expression.

Once we do this, it also means we no longer need to track a vector of
narrowing constraints to reapply for each new branch, since our "branch
not taken" state (which is the initial state for each branch) is
continuously updated to include the negative narrowing constraints of
all previous branches.

Fixes #15033.

## Test Plan

Added mdtests.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-01-05 18:35:29 +00:00
Micha Reiser
0caab81d3d
@no_type_check support (#15122)
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-12-30 09:42:18 +00:00
Dhruv Manilawala
113c804a62
[red-knot] Add support for unpacking for target (#15058)
## Summary

Related to #13773 

This PR adds support for unpacking `for` statement targets.

This involves updating the `value` field in the `Unpack` target to use
an enum which specifies the "where did the value expression came from?".
This is because for an iterable expression, we need to unpack the
iterator type while for assignment statement we need to unpack the value
type itself. And, this needs to be done in the unpack query.

### Question

One of the ways unpacking works in `for` statement is by looking at the
union of the types because if the iterable expression is a tuple then
the iterator type will be union of all the types in the tuple. This
means that the test cases that will test the unpacking in `for`
statement will also implicitly test the unpacking union logic. I was
wondering if it makes sense to merge these cases and only add the ones
that are specific to the union unpacking or for statement unpacking
logic.

## Test Plan

Add test cases involving iterating over a tuple type. I've intentionally
left out certain cases for now and I'm curious to know any thoughts on
the above query.
2024-12-23 06:13:49 +00:00
David Peter
000948ad3b
[red-knot] Statically known branches (#15019)
## Summary

This changeset adds support for precise type-inference and
boundness-handling of definitions inside control-flow branches with
statically-known conditions, i.e. test-expressions whose truthiness we
can unambiguously infer as *always false* or *always true*.

This branch also includes:
- `sys.platform` support
- statically-known branches handling for Boolean expressions and while
  loops
- new `target-version` requirements in some Markdown tests which were
  now required due to the understanding of `sys.version_info` branches.

closes #12700 
closes #15034 

## Performance

### `tomllib`, -7%, needs to resolve one additional module (sys)

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `./red_knot_main --project /home/shark/tomllib` | 22.2 ± 1.3 | 19.1 |
25.6 | 1.00 |
| `./red_knot_feature --project /home/shark/tomllib` | 23.8 ± 1.6 | 20.8
| 28.6 | 1.07 ± 0.09 |

### `black`, -6%

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `./red_knot_main --project /home/shark/black` | 129.3 ± 5.1 | 119.0 |
137.8 | 1.00 |
| `./red_knot_feature --project /home/shark/black` | 136.5 ± 6.8 | 123.8
| 147.5 | 1.06 ± 0.07 |

## Test Plan

- New Markdown tests for the main feature in
  `statically-known-branches.md`
- New Markdown tests for `sys.platform`
- Adapted tests for `EllipsisType`, `Never`, etc
2024-12-21 11:33:10 +01:00
Douglas Creager
4ddf9228f6
Bind top-most parent when importing nested module (#14946)
When importing a nested module, we were correctly creating a binding for
the top-most parent, but we were binding that to the nested module, not
to that parent module. Moreover, we weren't treating those submodules as
members of their containing parents. This PR addresses both issues, so
that nested imports work as expected.

As discussed in ~Slack~ whatever chat app I find myself in these days
😄, this requires keeping track of which modules have been imported
within the current file, so that when we resolve member access on a
module reference, we can see if that member has been imported as a
submodule. If so, we return the submodule reference immediately, instead
of checking whether the parent module's definition defines the symbol.

This is currently done in a flow insensitive manner. The `SemanticIndex`
now tracks all of the modules that are imported (via `import`, not via
`from...import`). The member access logic mentioned above currently only
considers module imports in the file containing the attribute
expression.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-12-16 16:15:40 -05:00
David Peter
d7ce548893
[red-knot] Add narrowing for 'while' loops (#14947)
## Summary

Add type narrowing for `while` loops and corresponding `else` branches.

closes #14861 

## Test Plan

New Markdown tests.
2024-12-13 07:40:14 +01:00
Carl Meyer
3017b3b687
[red-knot] function parameter types (#14802)
## Summary

Inferred and declared types for function parameters, in the function
body scope.

Fixes #13693.

## Test Plan

Added mdtests.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-12-06 12:55:56 -08:00
Samodya Abeysiriwardane
3f6c65e78c
[red-knot] Fix merged type after if-else without explicit else branch (#14621)
## Summary

Closes: https://github.com/astral-sh/ruff/issues/14593

The final type of a variable after if-statement without explicit else
branch should be similar to having an explicit else branch.

## Test Plan

Originally failed test cases from the bug are added.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-28 06:23:55 -08:00
cake-monotone
f98eebdbab
[red-knot] Fix Leaking Narrowing Constraint in ast::ExprIf (#14590)
## Summary

Closes #14588


```py
x: Literal[42, "hello"] = 42 if bool_instance() else "hello"
reveal_type(x)  # revealed: Literal[42] | Literal["hello"]

_ = ... if isinstance(x, str) else ...

# The `isinstance` test incorrectly narrows the type of `x`.
# As a result, `x` is revealed as Literal["hello"], but it should remain Literal[42, "hello"].
reveal_type(x)  # revealed: Literal["hello"]
```

## Test Plan
mdtest included!

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-25 10:36:37 -08:00
David Peter
f6b2cd5588
[red-knot] Semantic index: handle invalid breaks (#14522)
## Summary

This fix addresses panics related to invalid syntax like the following
where a `break` statement is used in a nested definition inside a
loop:

```py
while True:

    def b():
        x: int

        break
```

closes #14342

## Test Plan

* New corpus regression tests.
* New unit test to make sure we handle nested while loops correctly.
This test is passing on `main`, but can easily fail if the
`is_inside_loop` state isn't properly saved/restored.
2024-11-22 13:13:55 +01:00
David Peter
a90e404c3f
[red-knot] PEP 695 type aliases (#14357)
## Summary

Add support for (non-generic) type aliases. The main motivation behind
this was to get rid of panics involving expressions in (generic) type
aliases. But it turned out the best way to fix it was to implement
(partial) support for type aliases.

```py
type IntOrStr = int | str

reveal_type(IntOrStr)  # revealed: typing.TypeAliasType
reveal_type(IntOrStr.__name__)  # revealed: Literal["IntOrStr"]

x: IntOrStr = 1

reveal_type(x)  # revealed: Literal[1]

def f() -> None:
    reveal_type(x)  # revealed: int | str
```

## Test Plan

- Updated corpus test allow list to reflect that we don't panic anymore.
- Added Markdown-based test for type aliases (`type_alias.md`)
2024-11-22 08:47:14 +01:00
Alex Waygood
62d650226b
[red-knot] Derive more Default methods (#14361) 2024-11-15 13:15:41 +00:00
David Peter
5e64863895
[red-knot] Handle invalid assignment targets (#14325)
## Summary

This fixes several panics related to invalid assignment targets. All of
these led to some a crash, previously:
```py
(x.y := 1)  # only name-expressions are valid targets of named expressions
([x, y] := [1, 2])  # same
(x, y): tuple[int, int] = (2, 3)  # tuples are not valid targets for annotated assignments
(x, y) += 2  # tuples are not valid targets for augmented assignments
```

closes #14321
closes #14322

## Test Plan

I symlinked four files from `crates/ruff_python_parser/resources` into
the red knot corpus, as they seemed like ideal test files for this exact
scenario. I think eventually, it might be a good idea to simply include *all*
invalid-syntax examples from the parser tests into red knots corpus (I believe
we're actually not too far from that goal). Or expand the scope of the corpus
test to this directory. Then we can get rid of these symlinks again.
2024-11-13 20:50:39 +01:00
Carl Meyer
645ce7e5ec
[red-knot] infer types for PEP695 typevars (#14182)
## Summary

Create definitions and infer types for PEP 695 type variables.

This just gives us the type of the type variable itself (the type of `T`
as a runtime object in the body of `def f[T](): ...`), with special
handling for its attributes `__name__`, `__bound__`, `__constraints__`,
and `__default__`. Mostly the support for these attributes exists
because it is easy to implement and allows testing that we are
internally representing the typevar correctly.

This PR doesn't yet have support for interpreting a typevar as a type
annotation, which is of course the primary use of a typevar. But the
information we store in the typevar's type in this PR gives us
everything we need to handle it correctly in a future PR when the
typevar appears in an annotation.

## Test Plan

Added mdtest.
2024-11-08 21:23:05 +00:00
Micha Reiser
31681f66c9
Fix duplicate unpack diagnostics (#14125)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-06 11:28:29 +00:00
Dhruv Manilawala
34b6a9b909
Remove unpack field from SemanticIndexBuilder (#14101)
## Summary

Related to
https://github.com/astral-sh/ruff/pull/13979#discussion_r1828305790,
this PR removes the `current_unpack` state field from
`SemanticIndexBuilder` and passes the `Unpack` ingredient via the
`CurrentAssignment` -> `DefinitionNodeRef` conversion to finally store
it on `DefintionNodeKind`.

This involves updating the lifetime of `AnyParameterRef` (parameter to
`declare_parameter`) to use the `'db` lifetime. Currently, all AST nodes
stored on various enums are marked with `'a` lifetime but they're always
utilized using the `'db` lifetime.

This also removes the dedicated `'a` lifetime parameter on
`add_definition` which is currently being used in `DefinitionNodeRef`.
As mentioned, all AST nodes live through the `'db` lifetime so we can
remove the `'a` lifetime parameter from that method and use the `'db`
lifetime instead.
2024-11-06 08:42:58 +05:30
Micha Reiser
05687285fe
fix double inference of standalone expressions (#14107) 2024-11-05 15:50:31 +01:00
Micha Reiser
4323512a65
Remove AST-node dependency from FunctionType and ClassType (#14087)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-05 08:02:38 +00:00
Dhruv Manilawala
e302c2de7c
Cached inference of all definitions in an unpacking (#13979)
## Summary

This PR adds a new salsa query and an ingredient to resolve all the
variables involved in an unpacking assignment like `(a, b) = (1, 2)` at
once. Previously, we'd recursively try to match the correct type for
each definition individually which will result in creating duplicate
diagnostics.

This PR still doesn't solve the duplicate diagnostics issue because that
requires a different solution like using salsa accumulator or
de-duplicating the diagnostics manually.

Related: #13773 

## Test Plan

Make sure that all unpack assignment test cases pass, there are no
panics in the corpus tests.

## Todo

- [x] Look at the performance regression
2024-11-04 17:11:57 +05:30
Micha Reiser
76e4277696
[red-knot] Handle context managers in (sync) with statements (#13998) 2024-10-31 08:18:18 +00:00
Charlie Marsh
c6b82151dd
Add augmented assignment inference for -= operator (#13981)
## Summary

See: https://github.com/astral-sh/ruff/issues/12699
2024-10-29 22:14:27 -04:00
Alex Waygood
d2c9f5e43c
[red-knot] Fallback to attributes on types.ModuleType if a symbol can't be found in locals or globals (#13904) 2024-10-29 10:59:03 +00:00
TomerBin
9a0dade925
[red-knot] Type narrowing inside boolean expressions (#13970)
## Summary

This PR adds type narrowing in `and` and `or` expressions, for example:

```py
class A: ...

x: A | None = A() if bool_instance() else None

isinstance(x, A) or reveal_type(x)  # revealed: None
``` 

## Test Plan
New mdtests 😍
2024-10-28 18:17:48 -07:00
TomerBin
66c3aaa307
[red-knot] - Flow-control for boolean operations (#13940)
## Summary

As python uses short-circuiting boolean operations in runtime, we should
mimic that logic in redknot as well.
For example, we should detect that in the following code `x` might be
undefined inside the block:

```py
if flag or (x := 1):
    print(x) 
```

## Test Plan

Added mdtest suit for boolean expressions.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-27 03:33:01 +00:00
TomerBin
35f007f17f
[red-knot] Type narrow in else clause (#13918)
## Summary

Add support for type narrowing in elif and else scopes as part of
#13694.

## Test Plan

- mdtest
- builder unit test for union negation.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-26 16:22:57 +00:00
Alex Waygood
72adb09bf3
Simplify iteration idioms (#13834)
Remove unnecessary uses of `.as_ref()`, `.iter()`, `&**` and similar, mostly in situations when iterating over variables. Many of these changes are only possible following #13826, when we bumped our MSRV to 1.80: several useful implementations on `&Box<[T]>` were only stabilised in Rust 1.80. Some of these changes we could have done earlier, however.
2024-10-20 22:25:27 +01:00
Alex Waygood
6282402a8c
[red-knot] Add control flow for try/except blocks (#13729) 2024-10-16 13:03:59 +00:00
Raphael Gaschignard
d25673f664
[red-knot] Do not panic if named expressions show up in assignment position (#13711)
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-16 12:42:39 +00:00
Dhruv Manilawala
b16f665a81
[red-knot] Infer target types for unpacked tuple assignment (#13316)
## Summary

This PR adds support for unpacking tuple expression in an assignment
statement where the target expression can be a tuple or a list (the
allowed sequence targets).

The implementation introduces a new `infer_assignment_target` which can
then be used for other targets like the ones in for loops as well. This
delegates it to the `infer_definition`. The final implementation uses a
recursive function that visits the target expression in source order and
compares the variable node that corresponds to the definition. At the
same time, it keeps track of where it is on the assignment value type.

The logic also accounts for the number of elements on both sides such
that it matches even if there's a gap in between. For example, if
there's a starred expression like `(a, *b, c) = (1, 2, 3)`, then the
type of `a` will be `Literal[1]` and the type of `b` will be
`Literal[2]`.

There are a couple of follow-ups that can be done:
* Use this logic for other target positions like `for` loop
* Add diagnostics for mis-match length between LHS and RHS

## Test Plan

Add various test cases using the new markdown test framework.
Validate that existing test cases pass.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-10-15 19:07:11 +00:00
Simon
a8d9104fa3
Fix/#13070 defer annotations when future is active (#13395) 2024-09-19 10:13:37 +02:00
Alex Waygood
f4de49ab37
[red-knot] Clarify how scopes are pushed and popped for comprehensions and generator expressions (#13353) 2024-09-14 13:31:17 -04:00
Carl Meyer
d988204b1b
[red-knot] add Declarations support to semantic indexing (#13334)
Add support for declared types to the semantic index. This involves a
lot of renaming to clarify the distinction between bindings and
declarations. The Definition (or more specifically, the DefinitionKind)
becomes responsible for determining which definitions are bindings,
which are declarations, and which are both, and the symbol table
building is refactored a bit so that the `IS_BOUND` (renamed from
`IS_DEFINED` for consistent terminology) flag is always set when a
binding is added, rather than being set separately (and requiring us to
ensure it is set properly).

The `SymbolState` is split into two parts, `SymbolBindings` and
`SymbolDeclarations`, because we need to store live bindings for every
declaration and live declarations for every binding; the split lets us
do this without storing more than we need.

The massive doc comment in `use_def.rs` is updated to reflect bindings
vs declarations.

The `UseDefMap` gains some new APIs which are allow-unused for now,
since this PR doesn't yet update type inference to take declarations
into account.
2024-09-13 13:55:22 -04:00
Alex Waygood
4dc2c257ef
[red-knot] Fix type inference for except* definitions (#13320) 2024-09-11 15:05:40 -04:00
Alex Waygood
b93d0ab57c
[red-knot] Add control flow for for loops (#13318) 2024-09-10 22:04:35 +00:00
Dhruv Manilawala
62c7d8f6ba
[red-knot] Add control flow support for match statement (#13241)
## Summary

This PR adds support for control flow for match statement.

It also adds the necessary infrastructure required for narrowing
constraints in case blocks and implements the logic for
`PatternMatchSingleton` which is either `None` / `True` / `False`. Even
after this the inferred type doesn't get simplified completely, there's
a TODO for that in the test code.

## Test Plan

Add test cases for control flow for (a) when there's a wildcard pattern
and (b) when there isn't. There's also a test case to verify the
narrowing logic.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-09-10 02:14:19 +05:30