Move reference-resolution into Context (#4510)

This commit is contained in:
Charlie Marsh 2023-05-19 22:47:15 -04:00 committed by GitHub
parent b42ff08612
commit bb4e674415
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 141 additions and 96 deletions

View file

@ -3,6 +3,7 @@ use std::path::Path;
use bitflags::bitflags;
use nohash_hasher::{BuildNoHashHasher, IntMap};
use ruff_text_size::TextRange;
use rustpython_parser::ast::{Expr, Stmt};
use smallvec::smallvec;
@ -113,6 +114,54 @@ impl<'a> Context<'a> {
.map_or(false, |binding| binding.kind.is_builtin())
}
/// Resolve a reference to the given symbol.
pub fn resolve_reference(&mut self, symbol: &str, range: TextRange) -> ResolvedReference {
let mut import_starred = false;
for (index, scope_id) in self.scopes.ancestor_ids(self.scope_id).enumerate() {
let scope = &self.scopes[scope_id];
if scope.kind.is_class() {
if symbol == "__class__" {
return ResolvedReference::ImplicitGlobal;
}
if index > 0 {
continue;
}
}
if let Some(binding_id) = scope.get(symbol) {
// Mark the binding as used.
let context = self.execution_context();
self.bindings[*binding_id].mark_used(self.scope_id, range, context);
// But if it's a type annotation, don't treat it as resolved, unless we're in a
// forward reference. For example, given:
//
// ```python
// name: str
// print(name)
// ```
//
// The `name` in `print(name)` should be treated as unresolved, but the `name` in
// `name: str` should be treated as used.
if !self.in_deferred_type_definition()
&& self.bindings[*binding_id].kind.is_annotation()
{
continue;
}
return ResolvedReference::Resolved(scope_id, *binding_id);
}
import_starred = import_starred || scope.uses_star_imports();
}
if import_starred {
ResolvedReference::StarImport
} else {
ResolvedReference::NotFound
}
}
/// Resolves the [`Expr`] to a fully-qualified symbol-name, if `value` resolves to an imported
/// or builtin symbol.
///
@ -708,3 +757,17 @@ pub struct Snapshot {
definition_id: DefinitionId,
flags: ContextFlags,
}
#[derive(Debug)]
pub enum ResolvedReference {
/// The reference is resolved to a specific binding.
Resolved(ScopeId, BindingId),
/// The reference is resolved to a context-specific, implicit global (e.g., `__class__` within
/// a class scope).
ImplicitGlobal,
/// The reference is unresolved, but at least one of the containing scopes contains a star
/// import.
StarImport,
/// The reference is definitively unresolved.
NotFound,
}