mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
Refine SemanticModel lifetime bounds (#10221)
## Summary Corrects/refines some semantic model and related lifetime bounds. ## Test Plan `cargo check`
This commit is contained in:
parent
4eac9baf43
commit
64f66cd8fe
7 changed files with 46 additions and 40 deletions
|
@ -4,7 +4,7 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
/// An import with its surrounding context.
|
/// An import with its surrounding context.
|
||||||
pub(crate) struct ImportBinding<'a> {
|
pub(crate) struct ImportBinding<'a> {
|
||||||
/// The qualified name of the import (e.g., `typing.List` for `from typing import List`).
|
/// The qualified name of the import (e.g., `typing.List` for `from typing import List`).
|
||||||
pub(crate) import: AnyImport<'a>,
|
pub(crate) import: AnyImport<'a, 'a>,
|
||||||
/// The binding for the imported symbol.
|
/// The binding for the imported symbol.
|
||||||
pub(crate) binding: &'a Binding<'a>,
|
pub(crate) binding: &'a Binding<'a>,
|
||||||
/// The first reference to the imported symbol.
|
/// The first reference to the imported symbol.
|
||||||
|
|
|
@ -229,7 +229,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ImportBinding<'a> {
|
struct ImportBinding<'a> {
|
||||||
/// The qualified name of the import (e.g., `typing.List` for `from typing import List`).
|
/// The qualified name of the import (e.g., `typing.List` for `from typing import List`).
|
||||||
import: AnyImport<'a>,
|
import: AnyImport<'a, 'a>,
|
||||||
/// The trimmed range of the import (e.g., `List` in `from typing import List`).
|
/// The trimmed range of the import (e.g., `List` in `from typing import List`).
|
||||||
range: TextRange,
|
range: TextRange,
|
||||||
/// The range of the import's parent statement.
|
/// The range of the import's parent statement.
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl<'a> Binding<'a> {
|
||||||
|
|
||||||
/// Return `true` if this binding "redefines" the given binding, as per Pyflake's definition of
|
/// Return `true` if this binding "redefines" the given binding, as per Pyflake's definition of
|
||||||
/// redefinition.
|
/// redefinition.
|
||||||
pub fn redefines(&self, existing: &'a Binding) -> bool {
|
pub fn redefines(&self, existing: &Binding) -> bool {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
// Submodule imports are only considered redefinitions if they import the same
|
// Submodule imports are only considered redefinitions if they import the same
|
||||||
// submodule. For example, this is a redefinition:
|
// submodule. For example, this is a redefinition:
|
||||||
|
@ -184,12 +184,12 @@ impl<'a> Binding<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the binding (e.g., `x` in `x = 1`).
|
/// Returns the name of the binding (e.g., `x` in `x = 1`).
|
||||||
pub fn name<'b>(&self, locator: &'b Locator) -> &'b str {
|
pub fn name<'b>(&self, locator: &Locator<'b>) -> &'b str {
|
||||||
locator.slice(self.range)
|
locator.slice(self.range)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the statement in which the binding was defined.
|
/// Returns the statement in which the binding was defined.
|
||||||
pub fn statement<'b>(&self, semantic: &'b SemanticModel) -> Option<&'b Stmt> {
|
pub fn statement<'b>(&self, semantic: &SemanticModel<'b>) -> Option<&'b Stmt> {
|
||||||
self.source
|
self.source
|
||||||
.map(|statement_id| semantic.statement(statement_id))
|
.map(|statement_id| semantic.statement(statement_id))
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ impl<'a> Binding<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_any_import(&'a self) -> Option<AnyImport<'a>> {
|
pub fn as_any_import(&self) -> Option<AnyImport<'_, 'a>> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
BindingKind::Import(import) => Some(AnyImport::Import(import)),
|
BindingKind::Import(import) => Some(AnyImport::Import(import)),
|
||||||
BindingKind::SubmoduleImport(import) => Some(AnyImport::SubmoduleImport(import)),
|
BindingKind::SubmoduleImport(import) => Some(AnyImport::SubmoduleImport(import)),
|
||||||
|
@ -549,10 +549,10 @@ bitflags! {
|
||||||
/// A trait for imported symbols.
|
/// A trait for imported symbols.
|
||||||
pub trait Imported<'a> {
|
pub trait Imported<'a> {
|
||||||
/// Returns the call path to the imported symbol.
|
/// Returns the call path to the imported symbol.
|
||||||
fn call_path(&self) -> &[&str];
|
fn call_path(&self) -> &[&'a str];
|
||||||
|
|
||||||
/// Returns the module name of the imported symbol.
|
/// Returns the module name of the imported symbol.
|
||||||
fn module_name(&self) -> &[&str];
|
fn module_name(&self) -> &[&'a str];
|
||||||
|
|
||||||
/// Returns the member name of the imported symbol. For a straight import, this is equivalent
|
/// Returns the member name of the imported symbol. For a straight import, this is equivalent
|
||||||
/// to the qualified name; for a `from` import, this is the name of the imported symbol.
|
/// to the qualified name; for a `from` import, this is the name of the imported symbol.
|
||||||
|
@ -568,12 +568,12 @@ pub trait Imported<'a> {
|
||||||
|
|
||||||
impl<'a> Imported<'a> for Import<'a> {
|
impl<'a> Imported<'a> for Import<'a> {
|
||||||
/// For example, given `import foo`, returns `["foo"]`.
|
/// For example, given `import foo`, returns `["foo"]`.
|
||||||
fn call_path(&self) -> &[&str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
self.call_path.as_ref()
|
self.call_path.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo`, returns `["foo"]`.
|
/// For example, given `import foo`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.call_path[..1]
|
&self.call_path[..1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,12 +585,12 @@ impl<'a> Imported<'a> for Import<'a> {
|
||||||
|
|
||||||
impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
||||||
/// For example, given `import foo.bar`, returns `["foo", "bar"]`.
|
/// For example, given `import foo.bar`, returns `["foo", "bar"]`.
|
||||||
fn call_path(&self) -> &[&str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
self.call_path.as_ref()
|
self.call_path.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `import foo.bar`, returns `["foo"]`.
|
/// For example, given `import foo.bar`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.call_path[..1]
|
&self.call_path[..1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,12 +602,12 @@ impl<'a> Imported<'a> for SubmoduleImport<'a> {
|
||||||
|
|
||||||
impl<'a> Imported<'a> for FromImport<'a> {
|
impl<'a> Imported<'a> for FromImport<'a> {
|
||||||
/// For example, given `from foo import bar`, returns `["foo", "bar"]`.
|
/// For example, given `from foo import bar`, returns `["foo", "bar"]`.
|
||||||
fn call_path(&self) -> &[&str] {
|
fn call_path(&self) -> &[&'a str] {
|
||||||
&self.call_path
|
&self.call_path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For example, given `from foo import bar`, returns `["foo"]`.
|
/// For example, given `from foo import bar`, returns `["foo"]`.
|
||||||
fn module_name(&self) -> &[&str] {
|
fn module_name(&self) -> &[&'a str] {
|
||||||
&self.call_path[..self.call_path.len() - 1]
|
&self.call_path[..self.call_path.len() - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,14 +619,14 @@ impl<'a> Imported<'a> for FromImport<'a> {
|
||||||
|
|
||||||
/// A wrapper around an import [`BindingKind`] that can be any of the three types of imports.
|
/// A wrapper around an import [`BindingKind`] that can be any of the three types of imports.
|
||||||
#[derive(Debug, Clone, is_macro::Is)]
|
#[derive(Debug, Clone, is_macro::Is)]
|
||||||
pub enum AnyImport<'a> {
|
pub enum AnyImport<'a, 'ast> {
|
||||||
Import(&'a Import<'a>),
|
Import(&'a Import<'ast>),
|
||||||
SubmoduleImport(&'a SubmoduleImport<'a>),
|
SubmoduleImport(&'a SubmoduleImport<'ast>),
|
||||||
FromImport(&'a FromImport<'a>),
|
FromImport(&'a FromImport<'ast>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Imported<'a> for AnyImport<'a> {
|
impl<'a, 'ast> Imported<'ast> for AnyImport<'a, 'ast> {
|
||||||
fn call_path(&self) -> &[&str] {
|
fn call_path(&self) -> &[&'ast str] {
|
||||||
match self {
|
match self {
|
||||||
Self::Import(import) => import.call_path(),
|
Self::Import(import) => import.call_path(),
|
||||||
Self::SubmoduleImport(import) => import.call_path(),
|
Self::SubmoduleImport(import) => import.call_path(),
|
||||||
|
@ -634,7 +634,7 @@ impl<'a> Imported<'a> for AnyImport<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_name(&self) -> &[&str] {
|
fn module_name(&self) -> &[&'ast str] {
|
||||||
match self {
|
match self {
|
||||||
Self::Import(import) => import.module_name(),
|
Self::Import(import) => import.module_name(),
|
||||||
Self::SubmoduleImport(import) => import.module_name(),
|
Self::SubmoduleImport(import) => import.module_name(),
|
||||||
|
@ -642,7 +642,7 @@ impl<'a> Imported<'a> for AnyImport<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn member_name(&self) -> Cow<'a, str> {
|
fn member_name(&self) -> Cow<'ast, str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Import(import) => import.member_name(),
|
Self::Import(import) => import.member_name(),
|
||||||
Self::SubmoduleImport(import) => import.member_name(),
|
Self::SubmoduleImport(import) => import.member_name(),
|
||||||
|
|
|
@ -81,7 +81,7 @@ pub struct Member<'a> {
|
||||||
|
|
||||||
impl<'a> Member<'a> {
|
impl<'a> Member<'a> {
|
||||||
/// Return the name of the member.
|
/// Return the name of the member.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &'a str {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
MemberKind::Class(class) => &class.name,
|
MemberKind::Class(class) => &class.name,
|
||||||
MemberKind::NestedClass(class) => &class.name,
|
MemberKind::NestedClass(class) => &class.name,
|
||||||
|
@ -92,7 +92,7 @@ impl<'a> Member<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the body of the member.
|
/// Return the body of the member.
|
||||||
pub fn body(&self) -> &[Stmt] {
|
pub fn body(&self) -> &'a [Stmt] {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
MemberKind::Class(class) => &class.body,
|
MemberKind::Class(class) => &class.body,
|
||||||
MemberKind::NestedClass(class) => &class.body,
|
MemberKind::NestedClass(class) => &class.body,
|
||||||
|
@ -123,7 +123,7 @@ pub enum Definition<'a> {
|
||||||
Member(Member<'a>),
|
Member(Member<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Definition<'_> {
|
impl<'a> Definition<'a> {
|
||||||
/// Returns `true` if the [`Definition`] is a method definition.
|
/// Returns `true` if the [`Definition`] is a method definition.
|
||||||
pub const fn is_method(&self) -> bool {
|
pub const fn is_method(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
|
@ -136,7 +136,7 @@ impl Definition<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the name of the definition.
|
/// Return the name of the definition.
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<&'a str> {
|
||||||
match self {
|
match self {
|
||||||
Definition::Module(module) => module.name(),
|
Definition::Module(module) => module.name(),
|
||||||
Definition::Member(member) => Some(member.name()),
|
Definition::Member(member) => Some(member.name()),
|
||||||
|
@ -144,7 +144,7 @@ impl Definition<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`ast::StmtFunctionDef`] of the definition, if it's a function definition.
|
/// Return the [`ast::StmtFunctionDef`] of the definition, if it's a function definition.
|
||||||
pub fn as_function_def(&self) -> Option<&ast::StmtFunctionDef> {
|
pub fn as_function_def(&self) -> Option<&'a ast::StmtFunctionDef> {
|
||||||
match self {
|
match self {
|
||||||
Definition::Member(Member {
|
Definition::Member(Member {
|
||||||
kind:
|
kind:
|
||||||
|
@ -158,7 +158,7 @@ impl Definition<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`ast::StmtClassDef`] of the definition, if it's a class definition.
|
/// Return the [`ast::StmtClassDef`] of the definition, if it's a class definition.
|
||||||
pub fn as_class_def(&self) -> Option<&ast::StmtClassDef> {
|
pub fn as_class_def(&self) -> Option<&'a ast::StmtClassDef> {
|
||||||
match self {
|
match self {
|
||||||
Definition::Member(Member {
|
Definition::Member(Member {
|
||||||
kind: MemberKind::Class(class) | MemberKind::NestedClass(class),
|
kind: MemberKind::Class(class) | MemberKind::NestedClass(class),
|
||||||
|
|
|
@ -48,8 +48,8 @@ impl<'a> Globals<'a> {
|
||||||
builder.finish()
|
builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(&self, name: &str) -> Option<&TextRange> {
|
pub(crate) fn get(&self, name: &str) -> Option<TextRange> {
|
||||||
self.0.get(name)
|
self.0.get(name).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (&&'a str, &TextRange)> + '_ {
|
pub(crate) fn iter(&self) -> impl Iterator<Item = (&&'a str, &TextRange)> + '_ {
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub struct SemanticModel<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SemanticModel<'a> {
|
impl<'a> SemanticModel<'a> {
|
||||||
pub fn new(typing_modules: &'a [String], path: &'a Path, module: Module<'a>) -> Self {
|
pub fn new(typing_modules: &'a [String], path: &Path, module: Module<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
typing_modules,
|
typing_modules,
|
||||||
module_path: module.path(),
|
module_path: module.path(),
|
||||||
|
@ -159,7 +159,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
|
|
||||||
/// Return the [`Binding`] for the given [`BindingId`].
|
/// Return the [`Binding`] for the given [`BindingId`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn binding(&self, id: BindingId) -> &Binding {
|
pub fn binding(&self, id: BindingId) -> &Binding<'a> {
|
||||||
&self.bindings[id]
|
&self.bindings[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the set of `typing` modules allowed in the semantic model.
|
/// Return an iterator over the set of `typing` modules allowed in the semantic model.
|
||||||
pub fn typing_modules(&self) -> impl Iterator<Item = &str> {
|
pub fn typing_modules(&self) -> impl Iterator<Item = &'a str> {
|
||||||
["typing", "_typeshed", "typing_extensions"]
|
["typing", "_typeshed", "typing_extensions"]
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
@ -567,7 +567,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
/// For example, given `["Class", "method"`], resolve the `BindingKind::ClassDefinition`
|
/// For example, given `["Class", "method"`], resolve the `BindingKind::ClassDefinition`
|
||||||
/// associated with `Class`, then the `BindingKind::FunctionDefinition` associated with
|
/// associated with `Class`, then the `BindingKind::FunctionDefinition` associated with
|
||||||
/// `Class.method`.
|
/// `Class.method`.
|
||||||
pub fn lookup_attribute(&'a self, value: &'a Expr) -> Option<BindingId> {
|
pub fn lookup_attribute(&self, value: &Expr) -> Option<BindingId> {
|
||||||
let call_path = CallPath::from_expr(value)?;
|
let call_path = CallPath::from_expr(value)?;
|
||||||
|
|
||||||
// Find the symbol in the current scope.
|
// Find the symbol in the current scope.
|
||||||
|
@ -659,7 +659,13 @@ impl<'a> SemanticModel<'a> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ...then `resolve_call_path(${python_version})` will resolve to `sys.version_info`.
|
/// ...then `resolve_call_path(${python_version})` will resolve to `sys.version_info`.
|
||||||
pub fn resolve_call_path(&'a self, value: &'a Expr) -> Option<CallPath<'a>> {
|
pub fn resolve_call_path<'name, 'expr: 'name>(
|
||||||
|
&self,
|
||||||
|
value: &'expr Expr,
|
||||||
|
) -> Option<CallPath<'name>>
|
||||||
|
where
|
||||||
|
'a: 'name,
|
||||||
|
{
|
||||||
/// Return the [`ast::ExprName`] at the head of the expression, if any.
|
/// Return the [`ast::ExprName`] at the head of the expression, if any.
|
||||||
const fn match_head(value: &Expr) -> Option<&ast::ExprName> {
|
const fn match_head(value: &Expr) -> Option<&ast::ExprName> {
|
||||||
match value {
|
match value {
|
||||||
|
@ -974,7 +980,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all scopes, starting from the current [`Scope`].
|
/// Returns an iterator over all scopes, starting from the current [`Scope`].
|
||||||
pub fn current_scopes(&self) -> impl Iterator<Item = &Scope> {
|
pub fn current_scopes(&self) -> impl Iterator<Item = &Scope<'a>> {
|
||||||
self.scopes.ancestors(self.scope_id)
|
self.scopes.ancestors(self.scope_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,7 +1160,7 @@ impl<'a> SemanticModel<'a> {
|
||||||
/// Return the [`TextRange`] at which a name is declared as global in the current [`Scope`].
|
/// Return the [`TextRange`] at which a name is declared as global in the current [`Scope`].
|
||||||
pub fn global(&self, name: &str) -> Option<TextRange> {
|
pub fn global(&self, name: &str) -> Option<TextRange> {
|
||||||
let global_id = self.scopes[self.scope_id].globals_id()?;
|
let global_id = self.scopes[self.scope_id].globals_id()?;
|
||||||
self.globals[global_id].get(name).copied()
|
self.globals[global_id].get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a `name` that has been declared `nonlocal`, return the [`ScopeId`] and [`BindingId`]
|
/// Given a `name` that has been declared `nonlocal`, return the [`ScopeId`] and [`BindingId`]
|
||||||
|
@ -1998,7 +2004,7 @@ impl ImportedName {
|
||||||
self.context
|
self.context
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn statement<'a>(&self, semantic: &'a SemanticModel) -> &'a Stmt {
|
pub fn statement<'a>(&self, semantic: &SemanticModel<'a>) -> &'a Stmt {
|
||||||
semantic.statement(self.source)
|
semantic.statement(self.source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl<'a> Scope<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a tuple of the name and ID of all bindings defined in this scope.
|
/// Returns a tuple of the name and ID of all bindings defined in this scope.
|
||||||
pub fn bindings(&self) -> impl Iterator<Item = (&str, BindingId)> + '_ {
|
pub fn bindings(&self) -> impl Iterator<Item = (&'a str, BindingId)> + '_ {
|
||||||
self.bindings.iter().map(|(&name, &id)| (name, id))
|
self.bindings.iter().map(|(&name, &id)| (name, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ impl<'a> Scopes<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all [`Scope`] ancestors, starting from the given [`ScopeId`].
|
/// Returns an iterator over all [`Scope`] ancestors, starting from the given [`ScopeId`].
|
||||||
pub fn ancestors(&self, scope_id: ScopeId) -> impl Iterator<Item = &Scope> + '_ {
|
pub fn ancestors(&self, scope_id: ScopeId) -> impl Iterator<Item = &Scope<'a>> + '_ {
|
||||||
std::iter::successors(Some(&self[scope_id]), |&scope| {
|
std::iter::successors(Some(&self[scope_id]), |&scope| {
|
||||||
scope.parent.map(|scope_id| &self[scope_id])
|
scope.parent.map(|scope_id| &self[scope_id])
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue