Refine SemanticModel lifetime bounds (#10221)

## Summary

Corrects/refines some semantic model and related lifetime bounds.

## Test Plan

`cargo check`
This commit is contained in:
Micha Reiser 2024-03-04 09:21:13 +01:00 committed by GitHub
parent 4eac9baf43
commit 64f66cd8fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 46 additions and 40 deletions

View file

@ -110,7 +110,7 @@ impl<'a> Binding<'a> {
/// Return `true` if this binding "redefines" the given binding, as per Pyflake's definition of
/// redefinition.
pub fn redefines(&self, existing: &'a Binding) -> bool {
pub fn redefines(&self, existing: &Binding) -> bool {
match &self.kind {
// Submodule imports are only considered redefinitions if they import the same
// 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`).
pub fn name<'b>(&self, locator: &'b Locator) -> &'b str {
pub fn name<'b>(&self, locator: &Locator<'b>) -> &'b str {
locator.slice(self.range)
}
/// 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
.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 {
BindingKind::Import(import) => Some(AnyImport::Import(import)),
BindingKind::SubmoduleImport(import) => Some(AnyImport::SubmoduleImport(import)),
@ -549,10 +549,10 @@ bitflags! {
/// A trait for imported symbols.
pub trait Imported<'a> {
/// 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.
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
/// 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> {
/// For example, given `import foo`, returns `["foo"]`.
fn call_path(&self) -> &[&str] {
fn call_path(&self) -> &[&'a str] {
self.call_path.as_ref()
}
/// For example, given `import foo`, returns `["foo"]`.
fn module_name(&self) -> &[&str] {
fn module_name(&self) -> &[&'a str] {
&self.call_path[..1]
}
@ -585,12 +585,12 @@ impl<'a> Imported<'a> for Import<'a> {
impl<'a> Imported<'a> for SubmoduleImport<'a> {
/// 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()
}
/// For example, given `import foo.bar`, returns `["foo"]`.
fn module_name(&self) -> &[&str] {
fn module_name(&self) -> &[&'a str] {
&self.call_path[..1]
}
@ -602,12 +602,12 @@ impl<'a> Imported<'a> for SubmoduleImport<'a> {
impl<'a> Imported<'a> for FromImport<'a> {
/// For example, given `from foo import bar`, returns `["foo", "bar"]`.
fn call_path(&self) -> &[&str] {
fn call_path(&self) -> &[&'a str] {
&self.call_path
}
/// 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]
}
@ -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.
#[derive(Debug, Clone, is_macro::Is)]
pub enum AnyImport<'a> {
Import(&'a Import<'a>),
SubmoduleImport(&'a SubmoduleImport<'a>),
FromImport(&'a FromImport<'a>),
pub enum AnyImport<'a, 'ast> {
Import(&'a Import<'ast>),
SubmoduleImport(&'a SubmoduleImport<'ast>),
FromImport(&'a FromImport<'ast>),
}
impl<'a> Imported<'a> for AnyImport<'a> {
fn call_path(&self) -> &[&str] {
impl<'a, 'ast> Imported<'ast> for AnyImport<'a, 'ast> {
fn call_path(&self) -> &[&'ast str] {
match self {
Self::Import(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 {
Self::Import(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 {
Self::Import(import) => import.member_name(),
Self::SubmoduleImport(import) => import.member_name(),

View file

@ -81,7 +81,7 @@ pub struct Member<'a> {
impl<'a> Member<'a> {
/// Return the name of the member.
pub fn name(&self) -> &str {
pub fn name(&self) -> &'a str {
match self.kind {
MemberKind::Class(class) => &class.name,
MemberKind::NestedClass(class) => &class.name,
@ -92,7 +92,7 @@ impl<'a> Member<'a> {
}
/// Return the body of the member.
pub fn body(&self) -> &[Stmt] {
pub fn body(&self) -> &'a [Stmt] {
match self.kind {
MemberKind::Class(class) => &class.body,
MemberKind::NestedClass(class) => &class.body,
@ -123,7 +123,7 @@ pub enum Definition<'a> {
Member(Member<'a>),
}
impl Definition<'_> {
impl<'a> Definition<'a> {
/// Returns `true` if the [`Definition`] is a method definition.
pub const fn is_method(&self) -> bool {
matches!(
@ -136,7 +136,7 @@ impl Definition<'_> {
}
/// Return the name of the definition.
pub fn name(&self) -> Option<&str> {
pub fn name(&self) -> Option<&'a str> {
match self {
Definition::Module(module) => module.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.
pub fn as_function_def(&self) -> Option<&ast::StmtFunctionDef> {
pub fn as_function_def(&self) -> Option<&'a ast::StmtFunctionDef> {
match self {
Definition::Member(Member {
kind:
@ -158,7 +158,7 @@ impl 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 {
Definition::Member(Member {
kind: MemberKind::Class(class) | MemberKind::NestedClass(class),

View file

@ -48,8 +48,8 @@ impl<'a> Globals<'a> {
builder.finish()
}
pub(crate) fn get(&self, name: &str) -> Option<&TextRange> {
self.0.get(name)
pub(crate) fn get(&self, name: &str) -> Option<TextRange> {
self.0.get(name).copied()
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (&&'a str, &TextRange)> + '_ {

View file

@ -131,7 +131,7 @@ pub struct 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 {
typing_modules,
module_path: module.path(),
@ -159,7 +159,7 @@ impl<'a> SemanticModel<'a> {
/// Return the [`Binding`] for the given [`BindingId`].
#[inline]
pub fn binding(&self, id: BindingId) -> &Binding {
pub fn binding(&self, id: BindingId) -> &Binding<'a> {
&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.
pub fn typing_modules(&self) -> impl Iterator<Item = &str> {
pub fn typing_modules(&self) -> impl Iterator<Item = &'a str> {
["typing", "_typeshed", "typing_extensions"]
.iter()
.copied()
@ -567,7 +567,7 @@ impl<'a> SemanticModel<'a> {
/// For example, given `["Class", "method"`], resolve the `BindingKind::ClassDefinition`
/// associated with `Class`, then the `BindingKind::FunctionDefinition` associated with
/// `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)?;
// 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`.
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.
const fn match_head(value: &Expr) -> Option<&ast::ExprName> {
match value {
@ -974,7 +980,7 @@ impl<'a> SemanticModel<'a> {
}
/// 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)
}
@ -1154,7 +1160,7 @@ impl<'a> SemanticModel<'a> {
/// Return the [`TextRange`] at which a name is declared as global in the current [`Scope`].
pub fn global(&self, name: &str) -> Option<TextRange> {
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`]
@ -1998,7 +2004,7 @@ impl ImportedName {
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)
}
}

View file

@ -95,7 +95,7 @@ impl<'a> Scope<'a> {
}
/// 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))
}
@ -238,7 +238,7 @@ impl<'a> Scopes<'a> {
}
/// 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| {
scope.parent.map(|scope_id| &self[scope_id])
})