ty_python_core/expression.rs
1use crate::ast_node_ref::AstNodeRef;
2use crate::db::Db;
3use crate::scope::ScopeId;
4use crate::{Program, ProgramFile};
5use ruff_db::PythonFile;
6use ruff_db::files::File;
7use ruff_python_ast as ast;
8use salsa;
9
10/// Whether or not this expression should be inferred as a normal expression or
11/// a type expression. For example, in `self.x: <annotation> = <value>`, the
12/// `<annotation>` is inferred as a type expression, while `<value>` is inferred
13/// as a normal expression.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
15pub enum ExpressionKind {
16 Normal,
17 TypeExpression,
18}
19
20/// An independently type-inferable expression.
21///
22/// Includes constraint expressions (e.g. if tests) and the RHS of an unpacking assignment.
23///
24/// ## Module-local type
25/// This type should not be used as part of any cross-module API because
26/// it holds a reference to the AST node. Range-offset changes
27/// then propagate through all usages, and deserialization requires
28/// reparsing the entire module.
29///
30/// E.g. don't use this type in:
31///
32/// * a return type of a cross-module query
33/// * a field of a type that is a return type of a cross-module query
34/// * an argument of a cross-module query
35#[salsa::tracked(debug, heap_size=ruff_memory_usage::heap_size)]
36pub struct Expression<'db> {
37 /// The scope in which the expression occurs.
38 ///
39 /// Storing the interned scope avoids retaining the file and file-local scope separately, at
40 /// the cost of database lookups when either of those values is needed.
41 #[returns(copy)]
42 pub scope_id: ScopeId<'db>,
43
44 /// The expression node.
45 #[no_eq]
46 #[tracked]
47 #[returns(ref)]
48 pub node_ref: AstNodeRef<ast::Expr>,
49
50 /// An assignment statement, if this expression is immediately used as the rhs of that
51 /// assignment.
52 ///
53 /// (Note that this is the _immediately_ containing assignment — if a complex expression is
54 /// assigned to some target, only the outermost expression node has this set. The inner
55 /// expressions are used to build up the assignment result, and are not "immediately assigned"
56 /// to the target, and so have `None` for this field.)
57 #[no_eq]
58 #[tracked]
59 #[returns(clone)]
60 pub assigned_to: Option<AstNodeRef<ast::StmtAssign>>,
61
62 /// Should this expression be inferred as a normal expression or a type expression?
63 #[returns(copy)]
64 pub kind: ExpressionKind,
65}
66
67// The Salsa heap is tracked separately.
68impl get_size2::GetSize for Expression<'_> {}
69
70impl<'db> Expression<'db> {
71 pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
72 self.scope_id(db)
73 }
74
75 pub fn file(self, db: &'db dyn Db) -> File {
76 self.scope_id(db).file(db)
77 }
78
79 pub fn python_file(self, db: &'db dyn Db) -> PythonFile<'db> {
80 self.scope_id(db).python_file(db)
81 }
82
83 pub fn program_file(self, db: &'db dyn Db) -> ProgramFile<'db> {
84 self.scope_id(db).program_file(db)
85 }
86
87 pub fn program(self, db: &'db dyn Db) -> Program<'db> {
88 self.scope_id(db).program(db)
89 }
90}