Commit graph

135 commits

Author SHA1 Message Date
Micha Reiser
ad19b3fd0e
[red-knot] Add verbosity argument to CLI (#12404) 2024-07-19 11:38:24 +00:00
Carl Meyer
181e7b3c0d
[red-knot] rename module_global to global (#12385)
Per comments in https://github.com/astral-sh/ruff/pull/12269, "module
global" is kind of long, and arguably redundant.

I tried just using "module" but there were too many cases where I felt
this was ambiguous. I like the way "global" works out better, though it
does require an understanding that in Python "global" generally means
"module global" not "globally global" (though in a sense module globals
are also globally global since modules are singletons).
2024-07-18 13:05:30 -07:00
Micha Reiser
79b535587b
[red-knot] Reload notebook on file change (#12361) 2024-07-17 12:23:48 +00:00
Micha Reiser
91338ae902
[red-knot] Add basic workspace support (#12318) 2024-07-17 11:34:21 +02:00
Carl Meyer
595b1aa4a1
[red-knot] per-definition inference, use-def maps (#12269)
Implements definition-level type inference, with basic control flow
(only if statements and if expressions so far) in Salsa.

There are a couple key ideas here:

1) We can do type inference queries at any of three region
granularities: an entire scope, a single definition, or a single
expression. These are represented by the `InferenceRegion` enum, and the
entry points are the salsa queries `infer_scope_types`,
`infer_definition_types`, and `infer_expression_types`. Generally
per-scope will be used for scopes that we are directly checking and
per-definition will be used anytime we are looking up symbol types from
another module/scope. Per-expression should be uncommon: used only for
the RHS of an unpacking or multi-target assignment (to avoid
re-inferring the RHS once per symbol defined in the assignment) and for
test nodes in type narrowing (e.g. the `test` of an `If` node). All
three queries return a `TypeInference` with a map of types for all
definitions and expressions within their region. If you do e.g.
scope-level inference, when it hits a definition, or an
independently-inferable expression, it should use the relevant query
(which may already be cached) to get all types within the smaller
region. This avoids double-inferring smaller regions, even though larger
regions encompass smaller ones.

2) Instead of building a control-flow graph and lazily traversing it to
find definitions which reach a use of a name (which is O(n^2) in the
worst case), instead semantic indexing builds a use-def map, where every
use of a name knows which definitions can reach that use. We also no
longer track all definitions of a symbol in the symbol itself; instead
the use-def map also records which defs remain visible at the end of the
scope, and considers these the publicly-visible definitions of the
symbol (see below).

Major items left as TODOs in this PR, to be done in follow-up PRs:

1) Free/global references aren't supported yet (only lookup based on
definitions in current scope), which means the override-check example
doesn't currently work. This is the first thing I'll fix as follow-up to
this PR.

2) Control flow outside of if statements and expressions.

3) Type narrowing.

There are also some smaller relevant changes here:

1) Eliminate `Option` in the return type of member lookups; instead
always return `Type::Unbound` for a name we can't find. Also use
`Type::Unbound` for modules we can't resolve (not 100% sure about this
one yet.)

2) Eliminate the use of the terms "public" and "root" to refer to
module-global scope or symbols. Instead consistently use the term
"module-global". It's longer, but it's the clearest, and the most
consistent with typical Python terminology. In particular I don't like
"public" for this use because it has other implications around author
intent (is an underscore-prefixed module-global symbol "public"?). And
"root" is just not commonly used for this in Python.

3) Eliminate the `PublicSymbol` Salsa ingredient. Many non-module-global
symbols can also be seen from other scopes (e.g. by a free var in a
nested scope, or by class attribute access), and thus need to have a
"public type" (that is, the type not as seen from a particular use in
the control flow of the same scope, but the type as seen from some other
scope.) So all symbols need to have a "public type" (here I want to keep
the use of the term "public", unless someone has a better term to
suggest -- since it's "public type of a symbol" and not "public symbol"
the confusion with e.g. initial underscores is less of an issue.) At
least initially, I would like to try not having special handling for
module-global symbols vs other symbols.

4) Switch to using "definitions that reach end of scope" rather than
"all definitions" in determining the public type of a symbol. I'm
convinced that in general this is the right way to go. We may want to
refine this further in future for some free-variable cases, but it can
be changed purely by making changes to the building of the use-def map
(the `public_definitions` index in it), without affecting any other
code. One consequence of combining this with no control-flow support
(just last-definition-wins) is that some inference tests now give more
wrong-looking results; I left TODO comments on these tests to fix them
when control flow is added.

And some potential areas for consideration in the future:

1) Should `symbol_ty` be a Salsa query? This would require making all
symbols a Salsa ingredient, and tracking even more dependencies. But it
would save some repeated reconstruction of unions, for symbols with
multiple public definitions. For now I'm not making it a query, but open
to changing this in future with actual perf evidence that it's better.
2024-07-16 11:02:30 -07:00
Micha Reiser
85ae02d62e
[red-knot] Add walk_directories to System (#12297) 2024-07-16 06:40:10 +00:00
Micha Reiser
abcf07c8c5
Change File::touch_path to only take a SystemPath (#12273) 2024-07-10 12:15:14 +00:00
Alex Waygood
000dabcd88
[red-knot] Allow module-resolution options to be specified via the CLI (#12246) 2024-07-09 09:16:28 +00:00
Micha Reiser
f8ff42a13d
[red-knot] Prevent salsa cancellation from aborting the program (#12183) 2024-07-09 08:26:15 +00:00
Micha Reiser
b5834d57af
[red-knot] Only store absolute paths in Files (#12215) 2024-07-09 09:52:13 +02:00
Micha Reiser
ac04380f36
[red-knot] Rename FileSystem to System (#12214) 2024-07-09 07:20:51 +00:00
Micha Reiser
64855c5f06
Remove default-run from 'red_knot' crate (#12241) 2024-07-08 09:31:45 +00:00
Alex Waygood
a62a432a48
[red-knot] Respect typeshed's VERSIONS file when resolving stdlib modules (#12141) 2024-07-05 22:43:31 +00:00
Carl Meyer
0e44235981
[red-knot] intern types using Salsa (#12061)
Intern types using Salsa interning instead of in the `TypeInference`
result.

This eliminates the need for `TypingContext`, and also paves the way for
finer-grained type inference queries.
2024-07-05 12:16:37 -07:00
Micha Reiser
e2e0889a30
[red-knot] Add very basic benchmark (#12182) 2024-07-04 15:29:00 +00:00
Micha Reiser
4d385b60c8
[red-knot] Migrate CLI to Salsa (#11972) 2024-07-04 07:23:45 +00:00
renovate[bot]
aaa6cabf3a
Update Rust crate dashmap to v6 (#12126)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-07-01 08:48:26 +00:00
Micha Reiser
4cb6a09fc0
Use CompactString for ModuleName (#12131) 2024-07-01 10:22:34 +02:00
Micha Reiser
5109b50bb3
Use CompactString for Identifier (#12101) 2024-07-01 10:06:02 +02:00
Micha Reiser
692309ebd7
[red-knot] Fix tests in release builds (#12022) 2024-06-25 06:34:35 +00:00
Alex Waygood
8de0cd6565
[red-knot] Move typeshed VERSIONS parser to the module resolver crate (#11967) 2024-06-21 16:41:08 +01:00
Alex Waygood
3277d031f8
[red-knot] Move the vendored typeshed stubs to the module resolver crate (#11966) 2024-06-21 13:47:54 +00:00
Alex Waygood
736a4ead14
[red-knot] Move module-resolution logic to its own crate (#11964) 2024-06-21 13:25:44 +00:00
Micha Reiser
2dfbf118d7
[red-knot] Extract red_knot_python_semantic crate (#11926) 2024-06-20 13:24:24 +02:00
Micha Reiser
1f654ee729
Upgrade to Rust 1.79 (#11875) 2024-06-17 07:15:10 +01:00
github-actions[bot]
e7c4d28c5e
Sync vendored typeshed stubs (#11885) 2024-06-15 02:15:19 +01:00
Alex Waygood
bcbddac21c
Fix Display implementation for typeshed VERSIONS parser (#11848) 2024-06-12 19:56:52 +00:00
Alex Waygood
4ed3aed8d3
[red-knot] Add a parser for typeshed's VERSIONS file (#11836) 2024-06-12 11:44:45 +00:00
Carl Meyer
5c0df7a150
[red-knot] add type narrowing (#11790)
## Summary

Add Constraint nodes to flow graph, and narrow types based on that (only
`is None` and `is not None` narrowing supported for now, to prototype
the structure.)

Also add simplification of zero- and one-element unions and
intersections, and flattening of intersections.

There's a lot more normalization logic needed for unions and
intersections (as is obvious from the inferred type in the added
`narrow_none` test), but this will be non-trivial and I'd rather do it
in a separate PR.

Here's a flowchart diagram for the code in the added `narrow_none` test:

![Screenshot 2024-06-07 at 2 58
00 PM](5152a400-739c-41ff-8bbf-3c19d16bd083)

The top branch is for the `if` expression in the initial assignment to
`x`; that `Constraint` node would only affect the type of `flag`, which
we don't care about in this test.

The second branch is for the `if` statement, with `Constraint` node
affecting the type of `x`.

## Test Plan

Added tests.
2024-06-12 04:38:50 +00:00
Micha Reiser
32ca704956
Rename PreorderVisitor to SourceOrderVisitor (#11798)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-06-07 17:01:58 +00:00
Alex Waygood
37d8de3316
[red-knot] Include vendored typeshed stubs as a zipfile in the Ruff binary (#11779)
Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-06-07 15:00:36 +00:00
Carl Meyer
4157c8635b
[red-knot] add None type (#11788)
Add type for None.
2024-06-07 08:40:22 -06:00
Carl Meyer
540d76892f
[red-knot] remove duplicate test from bad merge (#11787)
Somehow a merge of a PR that had all-green CI duplicated this test when
it merged into main, breaking the build.
2024-06-06 22:40:19 +00:00
Carl Meyer
cd101c83ae
[red-knot] condense int literals (#11784)
Display `(Literal[1] | Literal[2])` as `Literal[1, 2]`, and `(Literal[1]
| Literal[2] | OtherType)` as `(Literal[1, 2] | OtherType)`.

Fixes #11782

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-06-06 16:30:40 -06:00
Carl Meyer
b2fc0df6db
[red-knot] flatten unions (#11783)
Flatten union types. Fixes #11781
2024-06-06 16:13:40 -06:00
Alex Waygood
93eefb1417
[red-knot] Cleanup module-resolution logic in module.rs (#11777) 2024-06-06 17:33:02 +01:00
Alex Waygood
303ef02f93
[red-knot] Encapsulate module resolution logic in module.rs (#11767) 2024-06-06 14:31:09 +00:00
Carl Meyer
fcaa62f0d9
[red-knot] support if-expressions in type inference and CFG (#11765) 2024-06-06 04:40:44 -06:00
Carl Meyer
084e5464fb
[red-knot] support walrus expressions in type inference (#11762)
## Summary

Add support for walrus expressions, both in expression type inference
and in symbol definition type inference.

## Test Plan

Added test.
2024-06-05 15:13:10 -06:00
Carl Meyer
31f97329c0
[red-knot] refactor Definitions out of symbol table (#11761)
## Summary

Definitions are used in symbol table and in flow graph, and aren't
inherently owned by one or the other; move them into their own
submodule.

## Test Plan

Existing tests.
2024-06-05 14:35:01 -06:00
Carl Meyer
b46e9e825a
[red-knot] arithmetic on int literals (#11760)
## Summary

Add support for inferring int literal types from basic arithmetic on int
literals. Just to begin showing examples of resolving more complex
expression types, and because this will be useful in testing walrus
expressions.

## Test Plan

Added test.
2024-06-05 14:10:37 -06:00
Carl Meyer
9b2cf569b2
[red-knot] rename Definition::None to Definition::Unbound (#11758)
## Summary

After looking at this a bit, I think it does make sense to have
`Unbound` as part of the `Definition` enum; if we are modeling `Unbound`
as a type (which currently we are), then every symbol implicitly starts
each scope with a "definition" as unbound, and the cleanest way to model
that is as a real `Definition`. We should be able to handle a definition
of "unbound" anywhere we handle definitions.

But the name `None` wasn't clear enough; changing the name to `Unbound`
and adding a doc comment.

Also change `[first].into_iter()` to `std::iter::once(first)`, from
post-land code review on a prior PR.

## Test Plan

Existing tests.
2024-06-05 11:32:26 -06:00
Micha Reiser
b0b4706e2d
Red-knot: Track scopes per expression (#11754) 2024-06-05 17:53:26 +02:00
Carl Meyer
895eb3ef48
[red-knot] refactor CFG outside of symbol table (#11746) 2024-06-05 06:23:43 -06:00
Carl Meyer
d056d09547
[red-knot] add if-statement support to FlowGraph (#11673)
## Summary

Add if-statement support to FlowGraph. This introduces branches and
joins in the graph for the first time.

## Test Plan

Added tests.
2024-06-04 15:09:39 -06:00
Micha Reiser
6ffb96171a
red-knot: Change resolve_global_symbol to take Module as an argument (#11723) 2024-06-04 06:20:50 +00:00
Micha Reiser
64165bee43
red-knot: Use parse_unchecked to get all parse errors (#11725) 2024-06-04 06:04:48 +00:00
Charlie Marsh
2f8ac1e9b3
Fix red-knot compilation (#11727)
## Summary

Perhaps a result of a bad rebase, but `cargo clippy --fix --workspace
--all-targets -- -D warnings` does not pass on main as-is.
2024-06-04 03:03:38 +00:00
Carl Meyer
3fb2028506
[red-knot] extract helper functions in inference tests (#11671)
There's a lot of repeat boilerplate in the type inference tests; this
cuts it down a lot.
2024-06-03 17:46:04 -06:00
Carl Meyer
3f9ee31efb
[red-knot] use reachable definitions in infer_expression_type (#11670)
## Summary

Switch name resolution in `infer_expression_type` from resolving the
public type of a symbol, to resolving the reachable definitions of that
symbol from the reference point, using the flow graph.

This surfaced a bug in the flow graph implementation and a bug in symbol
table building, both of which are also fixed here.

The bug in flow graph implementation was that when we pushed and popped
scopes, we didn't maintain a stack of "current flow nodes" in all
stacked scopes, to be restored when we returned to that scope. Now we
do.

The bug in symbol table building that we didn't visit the parts of
functions and class definitions in the correct scopes. E.g. decorators
should be visited in the outer scope, arguments should be visited inside
the type-params scope (if any) but not inside the function body scope,
and only the body itself should actually be visited inside the body
scope. Fixing this requires that we no longer use `walk_stmt` here,
instead we have to visit each individual component.

## Test Plan

Added test.
2024-06-03 17:45:31 -06:00