Skip to content

Commit ba377f2

Browse files
committed
Document #[tracked] recommendation for AstNodeRef
1 parent 1dfe37d commit ba377f2

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

crates/red_knot_python_semantic/src/ast_node_ref.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@ use ruff_db::parsed::ParsedModule;
1313
///
1414
/// ## Equality
1515
/// Two `AstNodeRef` are considered equal if their pointer addresses are equal.
16+
///
17+
/// ## Usage in salsa tracked structs
18+
/// It's important that [`AstNodeRef`] fields in salsa tracked structs are tracked fields
19+
/// (attributed with `#[tracked`]). It prevents that the tracked struct gets a new ID
20+
/// everytime the AST changes, which in turn, invalidates the result of any query
21+
/// that takes said tracked struct as a query argument or returns the tracked struct as part of its result.
22+
///
23+
/// For example, marking the [`AstNodeRef`] as tracked on `Expression`
24+
/// has the effect that salsa will consider the expression as "unchanged" for as long as it:
25+
///
26+
/// * belongs to the same file
27+
/// * belongs to the same scope
28+
/// * has the same kind
29+
/// * was created in the same order
30+
///
31+
/// This means that changes to expressions in other scopes don't invalidate the expression's id, giving
32+
/// us some form of scope-stable identity for expressions. Only queries accessing the node field
33+
/// run on every AST change. All other queries only run when the expression's identity changes.
34+
///
35+
/// The one exception to this is if it is known that all queries tacking the tracked struct
36+
/// as argument or returning it as part of their result are known to access the node field.
37+
/// Marking the field tracked is then unnecessary.
1638
#[derive(Clone)]
1739
pub struct AstNodeRef<T> {
1840
/// Owned reference to the node's [`ParsedModule`].

crates/red_knot_python_semantic/src/semantic_index/definition.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,13 @@ impl DefinitionCategory {
432432
}
433433
}
434434

435+
/// The kind of a definition.
436+
///
437+
/// ## Usage in salsa tracked structs
438+
///
439+
/// [`DefinitionKind`] fields in salsa tracked structs should be tracked (attributed with `#[tracked]`)
440+
/// because the kind is a thin wrapper around [`AstNodeRef`]. See the [`AstNodeRef`] documentation
441+
/// for an in-depth explanation of why this is necessary.
435442
#[derive(Clone, Debug, Hash)]
436443
pub enum DefinitionKind<'db> {
437444
Import(AstNodeRef<ast::Alias>),

crates/red_knot_python_semantic/src/semantic_index/expression.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ pub(crate) struct Expression<'db> {
3939
pub(crate) file_scope: FileScopeId,
4040

4141
/// The expression node.
42-
#[return_ref]
42+
#[no_eq]
4343
#[tracked]
44+
#[return_ref]
4445
pub(crate) node_ref: AstNodeRef<ast::Expr>,
4546

4647
/// Should this expression be inferred as a normal expression or a type expression?

0 commit comments

Comments
 (0)