diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 791cb8913d6..e013cf7b4f1 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -27,7 +27,7 @@ use crate::{ HirLiteral, HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression, MethodCallExpression, PrefixExpression, }, - node_interner::{DefinitionKind, DependencyId, ExprId, FuncId}, + node_interner::{DefinitionKind, ExprId, FuncId, ReferenceId}, token::Tokens, Kind, QuotedType, Shared, StructType, Type, }; @@ -432,8 +432,8 @@ impl<'context> Elaborator<'context> { struct_generics, }); - let referenced = DependencyId::Struct(struct_type.borrow().id); - let reference = DependencyId::Variable(Location::new(span, self.file)); + let referenced = ReferenceId::Struct(struct_type.borrow().id); + let reference = ReferenceId::Variable(Location::new(span, self.file)); self.interner.add_reference(referenced, reference); (expr, Type::Struct(struct_type, generics)) diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index d7087a5ab07..7c780838163 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -534,7 +534,7 @@ impl<'context> Elaborator<'context> { fn resolve_trait_by_path(&mut self, path: Path) -> Option { let path_resolver = StandardPathResolver::new(self.module_id()); - let error = match path_resolver.resolve(self.def_maps, path.clone()) { + let error = match path_resolver.resolve(self.def_maps, path.clone(), &mut None) { Ok(PathResolution { module_def_id: ModuleDefId::TraitId(trait_id), error }) => { if let Some(error) = error { self.push_err(error); diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 61d30a915fc..e3c854d615d 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -15,7 +15,7 @@ use crate::{ stmt::HirPattern, }, macros_api::{HirExpression, Ident, Path, Pattern}, - node_interner::{DefinitionId, DefinitionKind, DependencyId, ExprId, GlobalId, TraitImplKind}, + node_interner::{DefinitionId, DefinitionKind, ExprId, GlobalId, ReferenceId, TraitImplKind}, Shared, StructType, Type, TypeBindings, }; @@ -199,8 +199,8 @@ impl<'context> Elaborator<'context> { new_definitions, ); - let referenced = DependencyId::Struct(struct_type.borrow().id); - let reference = DependencyId::Variable(Location::new(name_span, self.file)); + let referenced = ReferenceId::Struct(struct_type.borrow().id); + let reference = ReferenceId::Variable(Location::new(name_span, self.file)); self.interner.add_reference(referenced, reference); HirPattern::Struct(expected_type, fields, location) @@ -446,8 +446,8 @@ impl<'context> Elaborator<'context> { self.interner.add_function_dependency(current_item, func_id); } - let variable = DependencyId::Variable(hir_ident.location); - let function = DependencyId::Function(func_id); + let variable = ReferenceId::Variable(hir_ident.location); + let function = ReferenceId::Function(func_id); self.interner.add_reference(function, variable); } DefinitionKind::Global(global_id) => { @@ -458,8 +458,8 @@ impl<'context> Elaborator<'context> { self.interner.add_global_dependency(current_item, global_id); } - let variable = DependencyId::Variable(hir_ident.location); - let global = DependencyId::Global(global_id); + let variable = ReferenceId::Variable(hir_ident.location); + let global = ReferenceId::Global(global_id); self.interner.add_reference(global, variable); } DefinitionKind::GenericType(_) => { diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index 9fd3be0a354..c13ea5a2e40 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -1,4 +1,4 @@ -use noirc_errors::Spanned; +use noirc_errors::{Location, Spanned}; use crate::ast::ERROR_IDENT; use crate::hir::def_map::{LocalModuleId, ModuleId}; @@ -6,6 +6,7 @@ use crate::hir::resolution::path_resolver::{PathResolver, StandardPathResolver}; use crate::hir::resolution::resolver::SELF_TYPE_NAME; use crate::hir::scope::{Scope as GenericScope, ScopeTree as GenericScopeTree}; use crate::macros_api::Ident; +use crate::node_interner::ReferenceId; use crate::{ hir::{ def_map::{ModuleDefId, TryFromModuleDefId}, @@ -44,7 +45,20 @@ impl<'context> Elaborator<'context> { pub(super) fn resolve_path(&mut self, path: Path) -> Result { let resolver = StandardPathResolver::new(self.module_id()); - let path_resolution = resolver.resolve(self.def_maps, path)?; + let path_resolution; + + if self.interner.track_references { + let mut dependencies: Vec = Vec::new(); + path_resolution = + resolver.resolve(self.def_maps, path.clone(), &mut Some(&mut dependencies))?; + + for (referenced, ident) in dependencies.iter().zip(path.segments) { + let reference = ReferenceId::Variable(Location::new(ident.span(), self.file)); + self.interner.add_reference(*referenced, reference); + } + } else { + path_resolution = resolver.resolve(self.def_maps, path, &mut None)?; + } if let Some(error) = path_resolution.error { self.push_err(error); diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index d27e150d649..b6212abb4a2 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -31,7 +31,8 @@ use crate::{ UnaryOp, UnresolvedType, UnresolvedTypeData, }, node_interner::{ - DefinitionKind, DependencyId, ExprId, GlobalId, TraitId, TraitImplKind, TraitMethodId, + DefinitionKind, DependencyId, ExprId, GlobalId, ReferenceId, TraitId, TraitImplKind, + TraitMethodId, }, Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeVariable, TypeVariableKind, }; @@ -146,13 +147,17 @@ impl<'context> Elaborator<'context> { Resolved(id) => self.interner.get_quoted_type(id).clone(), }; - if let Type::Struct(_, _) = resolved_type { + if let Type::Struct(ref struct_type, _) = resolved_type { if let Some(unresolved_span) = typ.span { // Record the location of the type reference self.interner.push_type_ref_location( resolved_type.clone(), Location::new(unresolved_span, self.file), ); + + let referenced = ReferenceId::Struct(struct_type.borrow().id); + let reference = ReferenceId::Variable(Location::new(unresolved_span, self.file)); + self.interner.add_reference(referenced, reference); } } @@ -244,8 +249,6 @@ 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) { @@ -283,11 +286,6 @@ 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, diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index cd670167d2c..668dbf33d52 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -20,7 +20,7 @@ use crate::hir::Context; use crate::macros_api::{MacroError, MacroProcessor}; use crate::node_interner::{ - DependencyId, FuncId, GlobalId, NodeInterner, StructId, TraitId, TraitImplId, TypeAliasId, + FuncId, GlobalId, NodeInterner, ReferenceId, StructId, TraitId, TraitImplId, TypeAliasId, }; use crate::ast::{ @@ -330,7 +330,7 @@ impl DefCollector { // Resolve unresolved imports collected from the crate, one by one. for collected_import in std::mem::take(&mut def_collector.imports) { let module_id = collected_import.module_id; - match resolve_import(crate_id, &collected_import, &context.def_maps) { + match resolve_import(crate_id, &collected_import, &context.def_maps, &mut None) { Ok(resolved_import) => { if let Some(error) = resolved_import.error { errors.push(( @@ -491,12 +491,12 @@ fn add_import_reference( 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); + let variable = ReferenceId::Variable(Location::new(name.span(), file_id)); + interner.add_reference(ReferenceId::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); + let variable = ReferenceId::Variable(Location::new(name.span(), file_id)); + interner.add_reference(ReferenceId::Struct(struct_id), variable); } _ => (), } @@ -524,6 +524,7 @@ fn inject_prelude( &context.def_maps, ModuleId { krate: crate_id, local_id: crate_root }, path, + &mut None, ) { assert!(error.is_none(), "Tried to add private item to prelude"); let module_id = module_def_id.as_module().expect("std::prelude should be a module"); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index e908f5c1545..9077f13abe1 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -14,7 +14,7 @@ use crate::ast::{ TypeImpl, }; use crate::macros_api::NodeInterner; -use crate::node_interner::DependencyId; +use crate::node_interner::ReferenceId; use crate::{ graph::CrateId, hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait}, @@ -314,7 +314,7 @@ impl<'a> ModCollector<'a> { 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)); + context.def_interner.add_definition_location(ReferenceId::Struct(id)); } definition_errors } diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index d73130411e4..710c12a91bf 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -3,6 +3,7 @@ use thiserror::Error; use crate::graph::CrateId; use crate::hir::def_collector::dc_crate::CompilationError; +use crate::node_interner::ReferenceId; use std::collections::BTreeMap; use crate::ast::{Ident, ItemVisibility, Path, PathKind}; @@ -80,13 +81,14 @@ pub fn resolve_import( crate_id: CrateId, import_directive: &ImportDirective, def_maps: &BTreeMap, + path_references: &mut Option<&mut Vec>, ) -> Result { let module_scope = import_directive.module_id; let NamespaceResolution { module_id: resolved_module, namespace: resolved_namespace, mut error, - } = resolve_path_to_ns(import_directive, crate_id, crate_id, def_maps)?; + } = resolve_path_to_ns(import_directive, crate_id, crate_id, def_maps, path_references)?; let name = resolve_path_name(import_directive); @@ -124,6 +126,7 @@ fn resolve_path_to_ns( crate_id: CrateId, importing_crate: CrateId, def_maps: &BTreeMap, + path_references: &mut Option<&mut Vec>, ) -> NamespaceResolutionResult { let import_path = &import_directive.path.segments; let def_map = &def_maps[&crate_id]; @@ -131,7 +134,13 @@ fn resolve_path_to_ns( match import_directive.path.kind { crate::ast::PathKind::Crate => { // Resolve from the root of the crate - resolve_path_from_crate_root(crate_id, importing_crate, import_path, def_maps) + resolve_path_from_crate_root( + crate_id, + importing_crate, + import_path, + def_maps, + path_references, + ) } crate::ast::PathKind::Plain => { // There is a possibility that the import path is empty @@ -143,6 +152,7 @@ fn resolve_path_to_ns( import_path, import_directive.module_id, def_maps, + path_references, ); } @@ -151,7 +161,13 @@ fn resolve_path_to_ns( let first_segment = import_path.first().expect("ice: could not fetch first segment"); if current_mod.find_name(first_segment).is_none() { // Resolve externally when first segment is unresolved - return resolve_external_dep(def_map, import_directive, def_maps, importing_crate); + return resolve_external_dep( + def_map, + import_directive, + def_maps, + path_references, + importing_crate, + ); } resolve_name_in_module( @@ -160,12 +176,17 @@ fn resolve_path_to_ns( import_path, import_directive.module_id, def_maps, + path_references, ) } - crate::ast::PathKind::Dep => { - resolve_external_dep(def_map, import_directive, def_maps, importing_crate) - } + crate::ast::PathKind::Dep => resolve_external_dep( + def_map, + import_directive, + def_maps, + path_references, + importing_crate, + ), } } @@ -175,6 +196,7 @@ fn resolve_path_from_crate_root( import_path: &[Ident], def_maps: &BTreeMap, + path_references: &mut Option<&mut Vec>, ) -> NamespaceResolutionResult { resolve_name_in_module( crate_id, @@ -182,6 +204,7 @@ fn resolve_path_from_crate_root( import_path, def_maps[&crate_id].root, def_maps, + path_references, ) } @@ -191,6 +214,7 @@ fn resolve_name_in_module( import_path: &[Ident], starting_mod: LocalModuleId, def_maps: &BTreeMap, + path_references: &mut Option<&mut Vec>, ) -> NamespaceResolutionResult { let def_map = &def_maps[&krate]; let mut current_mod_id = ModuleId { krate, local_id: starting_mod }; @@ -221,12 +245,27 @@ fn resolve_name_in_module( // In the type namespace, only Mod can be used in a path. current_mod_id = match typ { - ModuleDefId::ModuleId(id) => id, + ModuleDefId::ModuleId(id) => { + if let Some(path_references) = path_references { + path_references.push(ReferenceId::Module(id)); + } + id + } ModuleDefId::FunctionId(_) => panic!("functions cannot be in the type namespace"), // TODO: If impls are ever implemented, types can be used in a path - ModuleDefId::TypeId(id) => id.module_id(), + ModuleDefId::TypeId(id) => { + if let Some(path_references) = path_references { + path_references.push(ReferenceId::Struct(id)); + } + id.module_id() + } ModuleDefId::TypeAliasId(_) => panic!("type aliases cannot be used in type namespace"), - ModuleDefId::TraitId(id) => id.0, + ModuleDefId::TraitId(id) => { + if let Some(path_references) = path_references { + path_references.push(ReferenceId::Trait(id)); + } + id.0 + } ModuleDefId::GlobalId(_) => panic!("globals cannot be in the type namespace"), }; @@ -270,6 +309,7 @@ fn resolve_external_dep( current_def_map: &CrateDefMap, directive: &ImportDirective, def_maps: &BTreeMap, + path_references: &mut Option<&mut Vec>, importing_crate: CrateId, ) -> NamespaceResolutionResult { // Use extern_prelude to get the dep @@ -299,7 +339,7 @@ fn resolve_external_dep( is_prelude: false, }; - resolve_path_to_ns(&dep_directive, dep_module.krate, importing_crate, def_maps) + resolve_path_to_ns(&dep_directive, dep_module.krate, importing_crate, def_maps, path_references) } // Issue an error if the given private function is being called from a non-child module, or diff --git a/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs b/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs index e423e10b712..c3dc76b635f 100644 --- a/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs @@ -1,5 +1,6 @@ use super::import::{resolve_import, ImportDirective, PathResolution, PathResolutionResult}; use crate::ast::Path; +use crate::node_interner::ReferenceId; use std::collections::BTreeMap; use crate::graph::CrateId; @@ -7,10 +8,13 @@ use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; pub trait PathResolver { /// Resolve the given path returning the resolved ModuleDefId. + /// If `path_references` is `Some`, a `ReferenceId` for each segment in `path` + /// will be resolved and pushed. fn resolve( &self, def_maps: &BTreeMap, path: Path, + path_references: &mut Option<&mut Vec>, ) -> PathResolutionResult; fn local_module_id(&self) -> LocalModuleId; @@ -34,8 +38,9 @@ impl PathResolver for StandardPathResolver { &self, def_maps: &BTreeMap, path: Path, + path_references: &mut Option<&mut Vec>, ) -> PathResolutionResult { - resolve_path(def_maps, self.module_id, path) + resolve_path(def_maps, self.module_id, path, path_references) } fn local_module_id(&self) -> LocalModuleId { @@ -53,11 +58,12 @@ pub fn resolve_path( def_maps: &BTreeMap, module_id: ModuleId, path: Path, + path_references: &mut Option<&mut Vec>, ) -> PathResolutionResult { // lets package up the path into an ImportDirective and resolve it using that let import = ImportDirective { module_id: module_id.local_id, path, alias: None, is_prelude: false }; - let resolved_import = resolve_import(module_id.krate, &import, def_maps)?; + let resolved_import = resolve_import(module_id.krate, &import, def_maps, path_references)?; let namespace = resolved_import.resolved_namespace; let id = diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index c97de6d3e05..364d694462b 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -765,7 +765,7 @@ impl<'a> Resolver<'a> { } // If we cannot find a local generic of the same name, try to look up a global - match self.path_resolver.resolve(self.def_maps, path.clone()) { + match self.path_resolver.resolve(self.def_maps, path.clone(), &mut None) { Ok(PathResolution { module_def_id: ModuleDefId::GlobalId(id), error }) => { if let Some(current_item) = self.current_item { self.interner.add_global_dependency(current_item, id); @@ -2017,7 +2017,7 @@ impl<'a> Resolver<'a> { } fn resolve_path(&mut self, path: Path) -> Result { - let path_resolution = self.path_resolver.resolve(self.def_maps, path)?; + let path_resolution = self.path_resolver.resolve(self.def_maps, path, &mut None)?; if let Some(error) = path_resolution.error { self.push_err(error.into()); diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index e674a48e779..6781c2833c4 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -388,7 +388,7 @@ pub(crate) fn resolve_trait_by_path( ) -> Result<(TraitId, Option), DefCollectorErrorKind> { let path_resolver = StandardPathResolver::new(module); - match path_resolver.resolve(def_maps, path.clone()) { + match path_resolver.resolve(def_maps, path.clone(), &mut None) { Ok(PathResolution { module_def_id: ModuleDefId::TraitId(trait_id), error }) => { Ok((trait_id, error)) } diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 3f1678f4dba..a9a51b636a8 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -461,7 +461,9 @@ pub mod test { function::{FuncMeta, HirFunction}, stmt::HirStatement, }; - use crate::node_interner::{DefinitionKind, FuncId, NodeInterner, TraitId, TraitMethodId}; + use crate::node_interner::{ + DefinitionKind, FuncId, NodeInterner, ReferenceId, TraitId, TraitMethodId, + }; use crate::{ hir::{ def_map::{CrateDefMap, LocalModuleId, ModuleDefId}, @@ -692,6 +694,7 @@ pub mod test { &self, _def_maps: &BTreeMap, path: Path, + _path_references: &mut Option<&mut Vec>, ) -> PathResolutionResult { // Not here that foo::bar and hello::foo::bar would fetch the same thing let name = path.segments.last().unwrap(); diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index e38e8e2fcc9..79927b03041 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -3,7 +3,7 @@ use noirc_errors::Location; use rangemap::RangeMap; use rustc_hash::FxHashMap; -use crate::{macros_api::NodeInterner, node_interner::DependencyId}; +use crate::{macros_api::NodeInterner, node_interner::ReferenceId}; use petgraph::prelude::NodeIndex as PetGraphIndex; #[derive(Debug, Default)] @@ -29,41 +29,43 @@ impl LocationIndices { } 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.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 fn reference_location(&self, reference: ReferenceId) -> Location { + match reference { + ReferenceId::Module(_) => todo!(), + ReferenceId::Function(id) => self.function_modifiers(&id).name_location, + ReferenceId::Struct(id) => self.struct_location(&id), + ReferenceId::Trait(_) => todo!(), + ReferenceId::Global(id) => self.get_global(id).location, + ReferenceId::Alias(id) => self.get_type_alias(id).borrow().location, + ReferenceId::Variable(location) => location, } } - pub(crate) fn add_reference(&mut self, referenced: DependencyId, reference: DependencyId) { + pub(crate) fn add_reference(&mut self, referenced: ReferenceId, reference: ReferenceId) { if !self.track_references { return; } let referenced_index = self.get_or_insert_reference(referenced); - let reference_location = self.dependency_location(reference); + let reference_location = self.reference_location(reference); let reference_index = self.reference_graph.add_node(reference); 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) { + pub(crate) fn add_definition_location(&mut self, referenced: ReferenceId) { if !self.track_references { return; } let referenced_index = self.get_or_insert_reference(referenced); - let referenced_location = self.dependency_location(referenced); + let referenced_location = self.reference_location(referenced); self.location_indices.add_location(referenced_location, referenced_index); } #[tracing::instrument(skip(self), ret)] - pub(crate) fn get_or_insert_reference(&mut self, id: DependencyId) -> PetGraphIndex { + pub(crate) fn get_or_insert_reference(&mut self, id: ReferenceId) -> PetGraphIndex { if let Some(index) = self.reference_graph_indices.get(&id) { return *index; } @@ -78,7 +80,7 @@ impl NodeInterner { 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])) + .map(|node_index| self.reference_location(self.reference_graph[node_index])) } // Is the given location known to this interner? @@ -99,12 +101,15 @@ impl NodeInterner { let reference_node = self.reference_graph[node_index]; let found_locations: Vec = match reference_node { - DependencyId::Alias(_) | DependencyId::Global(_) => todo!(), - DependencyId::Function(_) | DependencyId::Struct(_) => { + ReferenceId::Alias(_) + | ReferenceId::Global(_) + | ReferenceId::Module(_) + | ReferenceId::Trait(_) => todo!(), + ReferenceId::Function(_) | ReferenceId::Struct(_) => { self.find_all_references_for_index(node_index, include_reference) } - DependencyId::Variable(_) => { + ReferenceId::Variable(_) => { let referenced_node_index = self.referenced_index(node_index)?; self.find_all_references_for_index(referenced_node_index, include_reference) } @@ -122,14 +127,14 @@ impl NodeInterner { let id = self.reference_graph[referenced_node_index]; let mut edit_locations = Vec::new(); if include_reference { - edit_locations.push(self.dependency_location(id)); + edit_locations.push(self.reference_location(id)); } self.reference_graph .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.push(self.reference_location(id)); }); edit_locations } diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 7c30ccf5b8f..95a6a56ac60 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -207,10 +207,10 @@ pub struct NodeInterner { /// // | | /// // +------+ /// ``` - pub(crate) reference_graph: DiGraph, + pub(crate) reference_graph: DiGraph, /// Tracks the index of the references in the graph - pub(crate) reference_graph_indices: HashMap, + pub(crate) reference_graph_indices: HashMap, /// Store the location of the references in the graph pub(crate) location_indices: LocationIndices, @@ -235,6 +235,19 @@ pub enum DependencyId { Variable(Location), } +/// A reference to a module, struct, trait, etc., mainly used by the LSP code +/// to keep track of how symbols reference each other. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum ReferenceId { + Module(ModuleId), + Struct(StructId), + Trait(TraitId), + Global(GlobalId), + Function(FuncId), + Alias(TypeAliasId), + Variable(Location), +} + /// A trait implementation is either a normal implementation that is present in the source /// program via an `impl` block, or it is assumed to exist from a `where` clause or similar. #[derive(Debug, Clone)] @@ -858,7 +871,7 @@ impl NodeInterner { // This needs to be done after pushing the definition since it will reference the // location that was stored - self.add_definition_location(DependencyId::Function(id)); + self.add_definition_location(ReferenceId::Function(id)); definition_id } diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 66d5095f797..6dd3cc3fda7 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -102,7 +102,7 @@ mod rename_tests { let changes = response.changes.expect("Expected to find rename changes"); let mut changes: Vec = changes.values().flatten().map(|edit| edit.range).collect(); - changes.sort_by_key(|range| range.start.line); + changes.sort_by_key(|range| (range.start.line, range.start.character)); assert_eq!(changes, ranges); } } diff --git a/tooling/lsp/src/test_utils.rs b/tooling/lsp/src/test_utils.rs index fd1a9090965..c0505107842 100644 --- a/tooling/lsp/src/test_utils.rs +++ b/tooling/lsp/src/test_utils.rs @@ -46,9 +46,8 @@ pub(crate) fn search_in_file(filename: &str, search_string: &str) -> Vec file_lines .iter() .enumerate() - .filter_map(|(line_num, line)| { - // Note: this only finds the first instance of `search_string` on this line. - line.find(search_string).map(|index| { + .flat_map(|(line_num, line)| { + line.match_indices(search_string).map(move |(index, _)| { let start = Position { line: line_num as u32, character: index as u32 }; let end = Position { line: line_num as u32, diff --git a/tooling/lsp/test_programs/rename_struct/src/main.nr b/tooling/lsp/test_programs/rename_struct/src/main.nr index 96cccb4d72a..93a0779cf3b 100644 --- a/tooling/lsp/test_programs/rename_struct/src/main.nr +++ b/tooling/lsp/test_programs/rename_struct/src/main.nr @@ -3,6 +3,10 @@ mod foo { struct Foo { field: Field, } + + impl Foo { + fn foo() {} + } } } @@ -12,7 +16,10 @@ fn main(x: Field) -> pub Field { let foo1 = Foo { field: 1 }; let foo2 = Foo { field: 2 }; let Foo { field } = foo1; + Foo::foo(); x } -fn foo(foo: Foo) {} +fn foo(foo: Foo) -> Foo { + foo +}