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

feat(lsp): goto type reference for Struct #4091

Merged
merged 5 commits into from
Jan 22, 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
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 @@
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 Expand Up @@ -1408,7 +1408,7 @@
Type::NamedGeneric(binding, _) | Type::TypeVariable(binding, _) => {
substitute_binding(binding)
}
// Do not substitute_helper fields, it ca, substitute_bound_typevarsn lead to infinite recursion

Check warning on line 1411 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsn)
// and we should not match fields when type checking anyway.
Type::Struct(fields, args) => {
let args = vecmap(args, |arg| {
Expand All @@ -1423,7 +1423,7 @@
Type::Tuple(fields)
}
Type::Forall(typevars, typ) => {
// Trying to substitute_helper a variable de, substitute_bound_typevarsfined within a nested Forall

Check warning on line 1426 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsfined)
// is usually impossible and indicative of an error in the type checker somewhere.
for var in typevars {
assert!(!type_bindings.contains_key(&var.id()));
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 @@
.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 @@ -171,7 +172,7 @@
///
/// ### Example:
/// ```nr
/// trait Fieldable {

Check warning on line 175 in compiler/noirc_frontend/src/resolve_locations.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Fieldable)
/// fn to_field(self) -> Field;
/// ^------------------------------\
/// } |
Expand All @@ -196,7 +197,17 @@
})
}

#[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