Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(js_semantic): wrap scope id for niche optimization and clarity #3408

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions crates/biome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use std::collections::VecDeque;
use std::mem;
use JsSyntaxKind::*;

use crate::ScopeId;

/// Events emitted by the [SemanticEventExtractor].
/// These events are later made into the Semantic Model.
#[derive(Debug, Eq, PartialEq)]
Expand All @@ -25,8 +27,8 @@ pub enum SemanticEvent {
/// - Type parameters
DeclarationFound {
range: TextRange,
scope_id: u32,
hoisted_scope_id: Option<u32>,
scope_id: ScopeId,
hoisted_scope_id: Option<ScopeId>,
},

/// Tracks where a symbol is read, but only if its declaration is before this reference.
Expand All @@ -35,7 +37,7 @@ pub enum SemanticEvent {
Read {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is read, but only if its declaration was hoisted.
Expand All @@ -44,7 +46,7 @@ pub enum SemanticEvent {
HoistedRead {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is written, but only if its declaration is before this reference.
Expand All @@ -53,7 +55,7 @@ pub enum SemanticEvent {
Write {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is written, but only if its declaration was hoisted.
Expand All @@ -63,7 +65,7 @@ pub enum SemanticEvent {
HoistedWrite {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks references that do no have any matching binding
Expand All @@ -78,8 +80,7 @@ pub enum SemanticEvent {
ScopeStarted {
/// Scope range
range: TextRange,
scope_id: u32,
parent_scope_id: Option<u32>,
parent_scope_id: Option<ScopeId>,
is_closure: bool,
},

Expand All @@ -90,7 +91,7 @@ pub enum SemanticEvent {
ScopeEnded {
/// Scope range
range: TextRange,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is exported.
Expand Down Expand Up @@ -156,7 +157,7 @@ pub struct SemanticEventExtractor {
scopes: Vec<Scope>,
/// Number of generated scopes
/// This allows assigning a unique id to every scope.
scope_count: u32,
scope_count: usize,
/// At any point this is the set of available bindings and their range in the current scope
bindings: FxHashMap<BindingName, BindingInfo>,
/// Type parameters bound in a `infer T` clause.
Expand Down Expand Up @@ -274,7 +275,7 @@ enum ScopeHoisting {

#[derive(Debug)]
struct Scope {
scope_id: u32,
scope_id: ScopeId,
/// All bindings declared inside this scope
bindings: Vec<BindingName>,
/// References that still needs to be bound and will be solved at the end of the scope
Expand Down Expand Up @@ -780,11 +781,10 @@ impl SemanticEventExtractor {
}

fn push_scope(&mut self, range: TextRange, hoisting: ScopeHoisting, is_closure: bool) {
let scope_id = self.scope_count;
let scope_id = ScopeId::new(self.scope_count);
self.scope_count += 1;
self.stash.push_back(SemanticEvent::ScopeStarted {
range,
scope_id,
parent_scope_id: self.scopes.iter().last().map(|x| x.scope_id),
is_closure,
});
Expand Down Expand Up @@ -913,13 +913,13 @@ impl SemanticEventExtractor {
SemanticEvent::Read {
range,
declaration_at,
scope_id: 0,
scope_id: ScopeId::new(0),
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
scope_id: 0,
scope_id: ScopeId::new(0),
}
};
self.stash.push_back(event);
Expand Down Expand Up @@ -979,7 +979,7 @@ impl SemanticEventExtractor {
///
/// This method when called inside the `f` scope will return
/// the `f` scope index.
fn scope_index_to_hoist_declarations(&mut self, skip: u32) -> Option<u32> {
fn scope_index_to_hoist_declarations(&mut self, skip: u32) -> Option<ScopeId> {
debug_assert!(self.scopes.len() > (skip as usize));
// We should at least have the global scope
// that do not hoist
Expand All @@ -999,7 +999,7 @@ impl SemanticEventExtractor {
/// Push the binding `binding` into the hoisted scope if it exists, or into the current scope.
fn push_binding(
&mut self,
hoisted_scope_id: Option<u32>,
hoisted_scope_id: Option<ScopeId>,
binding_name: BindingName,
binding_info: BindingInfo,
) {
Expand Down
23 changes: 10 additions & 13 deletions crates/biome_js_semantic/src/semantic_model/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub struct SemanticModelBuilder {
globals: Vec<SemanticModelGlobalBindingData>,
globals_by_name: FxHashMap<String, Option<u32>>,
scopes: Vec<SemanticModelScopeData>,
scope_range_by_start: FxHashMap<TextSize, BTreeSet<Interval<u32, u32>>>,
scope_hoisted_to_by_range: FxHashMap<TextSize, u32>,
scope_range_by_start: FxHashMap<TextSize, BTreeSet<Interval<u32, ScopeId>>>,
scope_hoisted_to_by_range: FxHashMap<TextSize, ScopeId>,
bindings: Vec<SemanticModelBindingData>,
/// maps a binding range start to its index inside SemanticModelBuilder::bindings vec
bindings_by_start: FxHashMap<TextSize, u32>,
Expand Down Expand Up @@ -128,11 +128,10 @@ impl SemanticModelBuilder {
ScopeStarted {
range,
parent_scope_id,
scope_id,
is_closure,
} => {
// Scopes will be raised in order
debug_assert!((scope_id as usize) == self.scopes.len());
let scope_id = ScopeId::new(self.scopes.len());

self.scopes.push(SemanticModelScopeData {
range,
Expand All @@ -146,9 +145,7 @@ impl SemanticModelBuilder {
});

if let Some(parent_scope_id) = parent_scope_id {
self.scopes[parent_scope_id as usize]
.children
.push(scope_id);
self.scopes[parent_scope_id.index()].children.push(scope_id);
}

let start = range.start();
Expand All @@ -171,7 +168,7 @@ impl SemanticModelBuilder {

// SAFETY: this scope id is guaranteed to exist because they were generated by the
// event extractor
debug_assert!((binding_scope_id as usize) < self.scopes.len());
debug_assert!((binding_scope_id.index()) < self.scopes.len());

let binding_id = self.bindings.len() as u32;
self.bindings.push(SemanticModelBindingData {
Expand All @@ -181,7 +178,7 @@ impl SemanticModelBuilder {
});
self.bindings_by_start.insert(range.start(), binding_id);

let scope = &mut self.scopes[binding_scope_id as usize];
let scope = &mut self.scopes[binding_scope_id.index()];

scope.bindings.push(binding_id);
// Handle bindings with a bogus name
Expand Down Expand Up @@ -214,7 +211,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Read { hoisted: false },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -237,7 +234,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Read { hoisted: true },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -260,7 +257,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Write { hoisted: false },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -283,7 +280,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Write { hoisted: true },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand Down
24 changes: 12 additions & 12 deletions crates/biome_js_semantic/src/semantic_model/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl Capture {
pub struct AllCapturesIter {
data: Rc<SemanticModelData>,
closure_range: TextRange,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
references: Vec<SemanticModelScopeReference>,
}

Expand All @@ -143,7 +143,7 @@ impl Iterator for AllCapturesIter {
}

'scopes: while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];

if scope.is_closure {
continue 'scopes;
Expand All @@ -167,15 +167,15 @@ impl FusedIterator for AllCapturesIter {}
/// Iterate all immediate children closures of a specific closure
pub struct ChildrenIter {
data: Rc<SemanticModelData>,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
}

impl Iterator for ChildrenIter {
type Item = Closure;

fn next(&mut self) -> Option<Self::Item> {
while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];
if scope.is_closure {
return Some(Closure {
data: self.data.clone(),
Expand All @@ -195,15 +195,15 @@ impl FusedIterator for ChildrenIter {}
/// Iterate all descendents closures of a specific closure
pub struct DescendentsIter {
data: Rc<SemanticModelData>,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
}

impl Iterator for DescendentsIter {
type Item = Closure;

fn next(&mut self) -> Option<Self::Item> {
while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];
self.scopes.extend(scope.children.iter());
if scope.is_closure {
return Some(Closure {
Expand All @@ -223,7 +223,7 @@ impl FusedIterator for DescendentsIter {}
#[derive(Clone)]
pub struct Closure {
data: Rc<SemanticModelData>,
scope_id: u32,
scope_id: ScopeId,
}

impl Closure {
Expand All @@ -234,8 +234,8 @@ impl Closure {
Closure { data, scope_id }
}

pub(super) fn from_scope(data: Rc<SemanticModelData>, scope_id: u32) -> Option<Closure> {
let node = &data.scope_node_by_range[&data.scopes[scope_id as usize].range];
pub(super) fn from_scope(data: Rc<SemanticModelData>, scope_id: ScopeId) -> Option<Closure> {
let node = &data.scope_node_by_range[&data.scopes[scope_id.index()].range];
match node.kind() {
JsSyntaxKind::JS_FUNCTION_DECLARATION
| JsSyntaxKind::JS_FUNCTION_EXPRESSION
Expand All @@ -246,7 +246,7 @@ impl Closure {

/// Range of this [Closure]
pub fn closure_range(&self) -> &TextRange {
&self.data.scopes[self.scope_id as usize].range
&self.data.scopes[self.scope_id.index()].range
}

/// Return all [Reference] this closure captures, not taking into
Expand All @@ -263,7 +263,7 @@ impl Closure {
/// assert!(model.closure(function_f).all_captures(), &["a"]);
/// ```
pub fn all_captures(&self) -> impl Iterator<Item = Capture> {
let scope = &self.data.scopes[self.scope_id as usize];
let scope = &self.data.scopes[self.scope_id.index()];

let scopes = scope.children.clone();

Expand Down Expand Up @@ -293,7 +293,7 @@ impl Closure {
/// assert!(model.closure(function_f).children(), &["g"]);
/// ```
pub fn children(&self) -> impl Iterator<Item = Closure> {
let scope = &self.data.scopes[self.scope_id as usize];
let scope = &self.data.scopes[self.scope_id.index()];
ChildrenIter {
data: self.data.clone(),
scopes: scope.children.clone(),
Expand Down
Loading
Loading