Skip to content
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
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
32029f91f6aae4d2f6b08b4ea40481f5837e50bc
f35614a43cf8c5cfb244d9f6ffc9d63282a63e6d
2 changes: 1 addition & 1 deletion noir/noir-repo/.github/workflows/publish-nargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ jobs:
strategy:
fail-fast: false
matrix:
target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl]
target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, aarch64-unknown-linux-gnu]
timeout-minutes: 30

steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
HirLiteral, HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression,
MethodCallExpression, PrefixExpression,
},
node_interner::{DefinitionKind, ExprId, FuncId},
node_interner::{DefinitionKind, DependencyId, ExprId, FuncId},
token::Tokens,
Kind, QuotedType, Shared, StructType, Type,
};
Expand Down Expand Up @@ -431,6 +431,11 @@ impl<'context> Elaborator<'context> {
r#type,
struct_generics,
});

let referenced = DependencyId::Struct(struct_type.borrow().id);
let reference = DependencyId::Variable(Location::new(span, self.file));
self.interner.add_reference(referenced, reference);

(expr, Type::Struct(struct_type, generics))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ impl<'context> Elaborator<'context> {
mutable: Option<Span>,
new_definitions: &mut Vec<HirIdent>,
) -> HirPattern {
let name_span = name.last_segment().span();

let error_identifier = |this: &mut Self| {
// Must create a name here to return a HirPattern::Identifier. Allowing
// shadowing here lets us avoid further errors if we define ERROR_IDENT
Expand Down Expand Up @@ -196,6 +198,10 @@ impl<'context> Elaborator<'context> {
new_definitions,
);

let referenced = DependencyId::Struct(struct_type.borrow().id);
let reference = DependencyId::Variable(Location::new(name_span, self.file));
self.interner.add_reference(referenced, reference);

HirPattern::Struct(expected_type, fields, location)
}

Expand Down Expand Up @@ -584,10 +590,7 @@ impl<'context> Elaborator<'context> {
}

pub fn get_ident_from_path(&mut self, path: Path) -> (HirIdent, usize) {
let location = Location::new(
path.segments.last().expect("ice: path without segments").span(),
self.file,
);
let location = Location::new(path.last_segment().span(), self.file);

let error = match path.as_ident().map(|ident| self.use_variable(ident)) {
Some(Ok(found)) => return found,
Expand Down
11 changes: 10 additions & 1 deletion noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ use crate::{
HirExpression, HirLiteral, HirStatement, Path, PathKind, SecondaryAttribute, Signedness,
UnaryOp, UnresolvedType, UnresolvedTypeData,
},
node_interner::{DefinitionKind, ExprId, GlobalId, TraitId, TraitImplKind, TraitMethodId},
node_interner::{
DefinitionKind, DependencyId, ExprId, GlobalId, TraitId, TraitImplKind, TraitMethodId,
},
Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeVariable, TypeVariableKind,
};

Expand Down Expand Up @@ -242,6 +244,8 @@ impl<'context> Elaborator<'context> {
return Type::Alias(alias, args);
}

let last_segment = path.last_segment();

match self.lookup_struct_or_error(path) {
Some(struct_type) => {
if self.resolving_ids.contains(&struct_type.borrow().id) {
Expand Down Expand Up @@ -279,6 +283,11 @@ impl<'context> Elaborator<'context> {
self.interner.add_type_dependency(current_item, dependency_id);
}

let referenced = DependencyId::Struct(struct_type.borrow().id);
let reference =
DependencyId::Variable(Location::new(last_segment.span(), self.file));
self.interner.add_reference(referenced, reference);

Type::Struct(struct_type, args)
}
None => Type::Error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,17 @@ fn add_import_reference(
// We ignore empty spans at 0 location, this must be Stdlib
return;
}
if let crate::macros_api::ModuleDefId::FunctionId(func_id) = def_id {
let variable = DependencyId::Variable(Location::new(name.span(), file_id));
interner.add_reference_for(DependencyId::Function(func_id), variable);

match def_id {
crate::macros_api::ModuleDefId::FunctionId(func_id) => {
let variable = DependencyId::Variable(Location::new(name.span(), file_id));
interner.add_reference(DependencyId::Function(func_id), variable);
}
crate::macros_api::ModuleDefId::TypeId(struct_id) => {
let variable = DependencyId::Variable(Location::new(name.span(), file_id));
interner.add_reference(DependencyId::Struct(struct_id), variable);
}
_ => (),
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::ast::{
TypeImpl,
};
use crate::macros_api::NodeInterner;
use crate::node_interner::DependencyId;
use crate::{
graph::CrateId,
hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait},
Expand Down Expand Up @@ -267,6 +268,7 @@ impl<'a> ModCollector<'a> {
let mut definition_errors = vec![];
for struct_definition in types {
let name = struct_definition.name.clone();
let name_location = Location::new(name.span(), self.file_id);

let unresolved = UnresolvedStruct {
file_id: self.file_id,
Expand Down Expand Up @@ -310,6 +312,9 @@ impl<'a> ModCollector<'a> {

// And store the TypeId -> StructType mapping somewhere it is reachable
self.def_collector.items.types.insert(id, unresolved);

context.def_interner.add_struct_location(id, name_location);
context.def_interner.add_definition_location(DependencyId::Struct(id));
}
definition_errors
}
Expand Down
5 changes: 5 additions & 0 deletions noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,9 @@ impl Context<'_, '_> {
ResolvedGeneric { name, type_var, kind, span }
})
}

// Enables reference tracking (useful for tools like LSP).
pub fn track_references(&mut self) {
self.def_interner.track_references = true;
}
}
76 changes: 43 additions & 33 deletions noir/noir-repo/compiler/noirc_frontend/src/locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,31 @@ impl NodeInterner {
pub fn dependency_location(&self, dependency: DependencyId) -> Location {
match dependency {
DependencyId::Function(id) => self.function_modifiers(&id).name_location,
DependencyId::Struct(id) => self.get_struct(id).borrow().location,
DependencyId::Struct(id) => self.struct_location(&id),
DependencyId::Global(id) => self.get_global(id).location,
DependencyId::Alias(id) => self.get_type_alias(id).borrow().location,
DependencyId::Variable(location) => location,
}
}

pub(crate) fn add_reference(&mut self, referenced: DependencyId, reference: DependencyId) {
let referenced_index = self.get_or_insert_reference(referenced);
let reference_index = self.reference_graph.add_node(reference);

let referenced_location = self.dependency_location(referenced);
let reference_location = self.dependency_location(reference);

self.reference_graph.add_edge(referenced_index, reference_index, ());
self.location_indices.add_location(referenced_location, referenced_index);
self.location_indices.add_location(reference_location, reference_index);
}

pub(crate) fn add_reference_for(
&mut self,
referenced_id: DependencyId,
reference: DependencyId,
) {
let Some(referenced_index) = self.reference_graph_indices.get(&referenced_id) else {
panic!("Compiler Error: Referenced index not found")
};
if !self.track_references {
return;
}

let referenced_index = self.get_or_insert_reference(referenced);
let reference_location = self.dependency_location(reference);
let reference_index = self.reference_graph.add_node(reference);
self.reference_graph.add_edge(*referenced_index, reference_index, ());

self.reference_graph.add_edge(reference_index, referenced_index, ());
self.location_indices.add_location(reference_location, reference_index);
}

pub(crate) fn add_definition_location(&mut self, referenced: DependencyId) {
if !self.track_references {
return;
}

let referenced_index = self.get_or_insert_reference(referenced);
let referenced_location = self.dependency_location(referenced);
self.location_indices.add_location(referenced_location, referenced_index);
Expand All @@ -83,40 +73,60 @@ impl NodeInterner {
index
}

pub fn check_rename_possible(&self, location: Location) -> bool {
// Given a reference location, find the location of the referenced node.
pub fn find_referenced_location(&self, reference_location: Location) -> Option<Location> {
self.location_indices
.get_node_from_location(reference_location)
.and_then(|node_index| self.referenced_index(node_index))
.map(|node_index| self.dependency_location(self.reference_graph[node_index]))
}

// Is the given location known to this interner?
pub fn is_location_known(&self, location: Location) -> bool {
self.location_indices.get_node_from_location(location).is_some()
}

pub fn find_rename_symbols_at(&self, location: Location) -> Option<Vec<Location>> {
// Starting at the given location, find the node referenced by it. Then, gather
// all locations that reference that node, and return all of them
// (the referenced node and the references).
// Returns `None` if the location is not known to this interner.
pub fn find_all_references(&self, location: Location) -> Option<Vec<Location>> {
let node_index = self.location_indices.get_node_from_location(location)?;

let reference_node = self.reference_graph[node_index];
let found_locations: Vec<Location> = match reference_node {
DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(),
DependencyId::Function(_) => self.get_edit_locations(node_index),
DependencyId::Alias(_) | DependencyId::Global(_) => todo!(),
DependencyId::Function(_) | DependencyId::Struct(_) => {
self.find_all_references_for_index(node_index)
}

DependencyId::Variable(_) => {
let referenced_node_index = self
.reference_graph
.neighbors_directed(node_index, petgraph::Direction::Incoming)
.next()?;

self.get_edit_locations(referenced_node_index)
let referenced_node_index = self.referenced_index(node_index)?;
self.find_all_references_for_index(referenced_node_index)
}
};
Some(found_locations)
}

fn get_edit_locations(&self, referenced_node_index: PetGraphIndex) -> Vec<Location> {
// Given a referenced node index, find all references to it and return their locations, together
// with the reference node's location.
fn find_all_references_for_index(&self, referenced_node_index: PetGraphIndex) -> Vec<Location> {
let id = self.reference_graph[referenced_node_index];
let mut edit_locations = vec![self.dependency_location(id)];

self.reference_graph
.neighbors_directed(referenced_node_index, petgraph::Direction::Outgoing)
.neighbors_directed(referenced_node_index, petgraph::Direction::Incoming)
.for_each(|reference_node_index| {
let id = self.reference_graph[reference_node_index];
edit_locations.push(self.dependency_location(id));
});
edit_locations
}

// Given a reference index, returns the referenced index, if any.
fn referenced_index(&self, reference_index: PetGraphIndex) -> Option<PetGraphIndex> {
self.reference_graph
.neighbors_directed(reference_index, petgraph::Direction::Outgoing)
.next()
}
}
34 changes: 33 additions & 1 deletion noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;

use fm::FileId;
Expand Down Expand Up @@ -64,6 +65,9 @@ pub struct NodeInterner {
// Contains the source module each function was defined in
function_modules: HashMap<FuncId, ModuleId>,

// The location of each struct name
struct_name_locations: HashMap<StructId, Location>,

/// This graph tracks dependencies between different global definitions.
/// This is used to ensure the absence of dependency cycles for globals and types.
dependency_graph: DiGraph<DependencyId, ()>,
Expand Down Expand Up @@ -184,7 +188,25 @@ pub struct NodeInterner {
/// the actual type since types do not implement Send or Sync.
quoted_types: noirc_arena::Arena<Type>,

/// Store the location of the references in the graph
/// Whether to track references. In regular compilations this is false, but tools set it to true.
pub(crate) track_references: bool,

/// Store the location of the references in the graph.
/// Edges are directed from reference nodes to referenced nodes.
/// For example:
///
/// ```
/// let foo = 3;
/// // referenced
/// // ^
/// // |
/// // +------------+
/// let bar = foo; |
/// // reference |
/// // v |
/// // | |
/// // +------+
/// ```
pub(crate) reference_graph: DiGraph<DependencyId, ()>,

/// Tracks the index of the references in the graph
Expand Down Expand Up @@ -504,6 +526,7 @@ impl Default for NodeInterner {
function_definition_ids: HashMap::new(),
function_modifiers: HashMap::new(),
function_modules: HashMap::new(),
struct_name_locations: HashMap::new(),
func_id_to_trait: HashMap::new(),
dependency_graph: petgraph::graph::DiGraph::new(),
dependency_graph_indices: HashMap::new(),
Expand Down Expand Up @@ -531,6 +554,7 @@ impl Default for NodeInterner {
type_alias_ref: Vec::new(),
type_ref_locations: Vec::new(),
quoted_types: Default::default(),
track_references: false,
location_indices: LocationIndices::default(),
reference_graph: petgraph::graph::DiGraph::new(),
reference_graph_indices: HashMap::new(),
Expand Down Expand Up @@ -928,6 +952,14 @@ impl NodeInterner {
&self.struct_attributes[struct_id]
}

pub fn add_struct_location(&mut self, struct_id: StructId, location: Location) {
self.struct_name_locations.insert(struct_id, location);
}

pub fn struct_location(&self, struct_id: &StructId) -> Location {
self.struct_name_locations[struct_id]
}

pub fn global_attributes(&self, global_id: &GlobalId) -> &[SecondaryAttribute] {
&self.global_attributes[global_id]
}
Expand Down
16 changes: 10 additions & 6 deletions noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ impl NodeInterner {
location: Location,
return_type_location_instead: bool,
) -> Option<Location> {
self.find_location_index(location)
.and_then(|index| self.resolve_location(index, return_type_location_instead))
.or_else(|| self.try_resolve_trait_impl_location(location))
.or_else(|| self.try_resolve_trait_method_declaration(location))
.or_else(|| self.try_resolve_type_ref(location))
.or_else(|| self.try_resolve_type_alias(location))
// First try to find the location in the reference graph
self.find_referenced_location(location).or_else(|| {
// Otherwise fallback to the location indices
self.find_location_index(location)
.and_then(|index| self.resolve_location(index, return_type_location_instead))
.or_else(|| self.try_resolve_trait_impl_location(location))
.or_else(|| self.try_resolve_trait_method_declaration(location))
.or_else(|| self.try_resolve_type_ref(location))
.or_else(|| self.try_resolve_type_alias(location))
})
}

pub fn get_declaration_location_from(&self, location: Location) -> Option<Location> {
Expand Down
Loading