Skip to content

Commit

Permalink
feat(lsp): goto type reference for Struct (#4091)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves <!-- Link to GitHub Issue -->

feat(lsp): goto type reference #4090

## Summary\*

Allows to go to type reference from symbol representing struct, ie.
function return.

## Additional Context



## Documentation\*

Check one:
- [x] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist\*

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
kobyhallx authored Jan 22, 2024
1 parent 80f7e29 commit d56cac2
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 4 deletions.
14 changes: 13 additions & 1 deletion compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ impl<'a> Resolver<'a> {
fn resolve_type_inner(&mut self, typ: UnresolvedType, new_variables: &mut Generics) -> Type {
use UnresolvedTypeData::*;

match typ.typ {
let resolved_type = match typ.typ {
FieldElement => Type::FieldElement,
Array(size, elem) => {
let elem = Box::new(self.resolve_type_inner(*elem, new_variables));
Expand Down Expand Up @@ -510,7 +510,18 @@ impl<'a> Resolver<'a> {
Type::MutableReference(Box::new(self.resolve_type_inner(*element, new_variables)))
}
Parenthesized(typ) => self.resolve_type_inner(*typ, new_variables),
};

if let Type::Struct(_, _) = 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),
);
}
}
resolved_type
}

fn find_generic(&self, target_name: &str) -> Option<&(Rc<String>, TypeVariable, Span)> {
Expand Down Expand Up @@ -714,6 +725,7 @@ impl<'a> Resolver<'a> {
if resolved_type.is_nested_slice() {
self.errors.push(ResolverError::NestedSlices { span: span.unwrap() });
}

resolved_type
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub enum Type {
TypeVariable(TypeVariable, TypeVariableKind),

/// `impl Trait` when used in a type position.
/// These are only matched based on the TraitId. The trait name paramer is only
/// These are only matched based on the TraitId. The trait name parameter is only
/// used for displaying error messages using the name of the trait.
TraitAsType(TraitId, /*name:*/ Rc<String>, /*generics:*/ Vec<Type>),

Expand Down
10 changes: 9 additions & 1 deletion compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ pub struct NodeInterner {
/// A list of all type aliases that are referenced in the program.
/// Searched by LSP to resolve [Location]s of [TypeAliasType]s
pub(crate) type_alias_ref: Vec<(TypeAliasId, Location)>,

/// Stores the [Location] of a [Type] reference
pub(crate) type_ref_locations: Vec<(Type, Location)>,
}

/// A trait implementation is either a normal implementation that is present in the source
Expand Down Expand Up @@ -455,6 +458,7 @@ impl Default for NodeInterner {
struct_methods: HashMap::new(),
primitive_methods: HashMap::new(),
type_alias_ref: Vec::new(),
type_ref_locations: Vec::new(),
};

// An empty block expression is used often, we add this into the `node` on startup
Expand Down Expand Up @@ -607,6 +611,11 @@ impl NodeInterner {
self.id_to_type.insert(definition_id.into(), typ);
}

/// Store [Location] of [Type] reference
pub fn push_type_ref_location(&mut self, typ: Type, location: Location) {
self.type_ref_locations.push((typ, location));
}

pub fn push_global(&mut self, stmt_id: StmtId, ident: Ident, local_id: LocalModuleId) {
self.globals.insert(stmt_id, GlobalInfo { ident, local_id });
}
Expand Down Expand Up @@ -1186,7 +1195,6 @@ impl NodeInterner {
}

/// Adds a trait implementation to the list of known implementations.
#[tracing::instrument(skip(self))]
pub fn add_trait_implementation(
&mut self,
object_type: Type,
Expand Down
13 changes: 12 additions & 1 deletion compiler/noirc_frontend/src/resolve_locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl NodeInterner {
.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))
}

Expand Down Expand Up @@ -196,7 +197,17 @@ impl NodeInterner {
})
}

#[tracing::instrument(skip(self), ret)]
/// Attempts to resolve [Location] of [Type] based on [Location] of reference in code
pub(crate) fn try_resolve_type_ref(&self, location: Location) -> Option<Location> {
self.type_ref_locations
.iter()
.find(|(_typ, type_ref_location)| type_ref_location.contains(&location))
.and_then(|(typ, _)| match typ {
Type::Struct(struct_typ, _) => Some(struct_typ.borrow().location),
_ => None,
})
}

fn try_resolve_type_alias(&self, location: Location) -> Option<Location> {
self.type_alias_ref
.iter()
Expand Down

0 comments on commit d56cac2

Please sign in to comment.