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 rename/find-all-references for struct members #5443

Merged
merged 30 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5617aa0
fix: lsp struct reference in return position
asterite Jul 3, 2024
e1ebd06
fix: lsp struct reference in Path
asterite Jul 3, 2024
c3e9c30
Introduce `ReferenceId` as an enum exclusive to the reference graph
asterite Jul 3, 2024
668bc86
feat: lsp "go to definition" for module in call path
asterite Jul 3, 2024
6923fec
feat: lsp "go to" inline module from call path
asterite Jul 3, 2024
c6af4c6
feat: lsp "go to" on `use` module path
asterite Jul 3, 2024
5f8f9b4
feat: lsp "go to" by clicking on module definition ("mod foo")
asterite Jul 3, 2024
9930c11
clippy
asterite Jul 3, 2024
76995b1
feat: lsp rename/find-all-references for traits
asterite Jul 4, 2024
30d0ee4
fix: (lsp) don't rename `self` pointing to struct
asterite Jul 4, 2024
3530c4e
Make sure `Self` isn't renamed but found as a reference
asterite Jul 4, 2024
65a5ad0
Disallow renaming "Self"
asterite Jul 4, 2024
c2d2183
Merge branch 'master' into ab/lsp-struct-more-fixes
asterite Jul 4, 2024
afd6626
clippy
asterite Jul 4, 2024
e68d25a
WIP
asterite Jul 4, 2024
3ff7b2c
feat: lsp rename/find-all-references for type aliases
asterite Jul 4, 2024
c97464a
No need to separately keep track of struct name locations
asterite Jul 4, 2024
5465f6a
No need to separately keep track of alias name locations
asterite Jul 4, 2024
d164f52
No need to separately keep track of trait locations
asterite Jul 4, 2024
b914df0
Merge branch 'master' into ab/lsp-struct-more-fixes
asterite Jul 4, 2024
ab97382
Merge branch 'master' into ab/lsp-struct-more-fixes
asterite Jul 4, 2024
ab3a9a9
Merge branch 'ab/lsp-struct-more-fixes' into ab/lsp-alias-references
asterite Jul 4, 2024
9e097aa
feat: lsp rename/find-all-references for globals
asterite Jul 4, 2024
4968178
Rename ReferenceId::Variable to ReferenceId::Reference
asterite Jul 8, 2024
56b7ea6
lsp rename/find-all-references for local variables
asterite Jul 8, 2024
37b763e
feat: lsp rename/find-all-references for struct members
asterite Jul 8, 2024
1abfd18
Merge branch 'master' into ab/lsp-local-variables
asterite Jul 9, 2024
0a8890b
Merge branch 'ab/lsp-local-variables' into ab/lsp-struct-member
asterite Jul 9, 2024
7a6f7a3
Merge branch 'master' into ab/lsp-struct-member
asterite Jul 9, 2024
5e54385
Move struct_id definition closer to its usage
asterite Jul 10, 2024
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
20 changes: 17 additions & 3 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,11 +437,17 @@ impl<'context> Elaborator<'context> {
) -> Vec<(Ident, ExprId)> {
let mut ret = Vec::with_capacity(fields.len());
let mut seen_fields = HashSet::default();
let struct_id = struct_type.borrow().id;
vezenovm marked this conversation as resolved.
Show resolved Hide resolved
let mut unseen_fields = struct_type.borrow().field_names();

for (field_name, field) in fields {
let expected_type = field_types.iter().find(|(name, _)| name == &field_name.0.contents);
let expected_type = expected_type.map(|(_, typ)| typ).unwrap_or(&Type::Error);
let expected_field_with_index = field_types
.iter()
.enumerate()
.find(|(_, (name, _))| name == &field_name.0.contents);
let expected_index = expected_field_with_index.map(|(index, _)| index);
let expected_type =
expected_field_with_index.map(|(_, (_, typ))| typ).unwrap_or(&Type::Error);

let field_span = field.span;
let (resolved, field_type) = self.elaborate_expression(field);
Expand All @@ -468,6 +474,13 @@ impl<'context> Elaborator<'context> {
});
}

if let Some(expected_index) = expected_index {
let referenced = ReferenceId::StructMember(struct_id, expected_index);
let reference =
ReferenceId::Reference(Location::new(field_name.span(), self.file), false);
self.interner.add_reference(referenced, reference);
}

ret.push((field_name, resolved));
}

Expand All @@ -489,10 +502,11 @@ impl<'context> Elaborator<'context> {
) -> (ExprId, Type) {
let (lhs, lhs_type) = self.elaborate_expression(access.lhs);
let rhs = access.rhs;
let rhs_span = rhs.span();
// `is_offset` is only used when lhs is a reference and we want to return a reference to rhs
let access = HirMemberAccess { lhs, rhs, is_offset: false };
let expr_id = self.intern_expr(HirExpression::MemberAccess(access.clone()), span);
let typ = self.type_check_member_access(access, expr_id, lhs_type, span);
let typ = self.type_check_member_access(access, expr_id, lhs_type, rhs_span);
self.interner.push_expr_type(expr_id, typ.clone());
(expr_id, typ)
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ impl<'context> Elaborator<'context> {
let span = typ.struct_def.span;

let fields = self.resolve_struct_fields(typ.struct_def, type_id);
let fields_len = fields.len();
self.interner.update_struct(type_id, |struct_def| {
struct_def.set_fields(fields);

Expand All @@ -1217,6 +1218,11 @@ impl<'context> Elaborator<'context> {
}
});

for field_index in 0..fields_len {
self.interner
.add_definition_location(ReferenceId::StructMember(type_id, field_index));
}

self.run_comptime_attributes_on_struct(attributes, type_id, span, &mut generated_items);
}

Expand Down
10 changes: 9 additions & 1 deletion compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,18 @@ impl<'context> Elaborator<'context> {
new_definitions,
);

let referenced = ReferenceId::Struct(struct_type.borrow().id);
let struct_id = struct_type.borrow().id;

let referenced = ReferenceId::Struct(struct_id);
let reference = ReferenceId::Reference(Location::new(name_span, self.file), is_self_type);
self.interner.add_reference(referenced, reference);

for (field_index, field) in fields.iter().enumerate() {
let referenced = ReferenceId::StructMember(struct_id, field_index);
let reference = ReferenceId::Reference(Location::new(field.0.span(), self.file), false);
self.interner.add_reference(referenced, reference);
}

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

Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@ impl<'context> Elaborator<'context> {
Type::Struct(s, args) => {
let s = s.borrow();
if let Some((field, index)) = s.get_field(field_name, args) {
let referenced = ReferenceId::StructMember(s.id, index);
let reference = ReferenceId::Reference(Location::new(span, self.file), false);
self.interner.add_reference(referenced, reference);

return Some((field, index));
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@
vecmap(&self.fields, |(name, typ)| (name.0.contents.clone(), typ.clone()))
}

/// Returns the field at the given index. Panics if no field exists at the given index.
pub fn field_at(&self, index: usize) -> &(Ident, Type) {
&self.fields[index]
}

pub fn field_names(&self) -> BTreeSet<Ident> {
self.fields.iter().map(|(name, _)| name.clone()).collect()
}
Expand Down Expand Up @@ -1790,7 +1795,7 @@
}

let recur_on_binding = |id, replacement: &Type| {
// Prevent recuring forever if there's a `T := T` binding

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (recuring)
if replacement.type_variable_id() == Some(id) {
replacement.clone()
} else {
Expand Down
5 changes: 5 additions & 0 deletions compiler/noirc_frontend/src/locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ impl NodeInterner {
let struct_type = struct_type.borrow();
Location::new(struct_type.name.span(), struct_type.location.file)
}
ReferenceId::StructMember(id, field_index) => {
let struct_type = self.get_struct(id);
let struct_type = struct_type.borrow();
Location::new(struct_type.field_at(field_index).0.span(), struct_type.location.file)
}
ReferenceId::Trait(id) => {
let trait_type = self.get_trait(id);
Location::new(trait_type.name.span(), trait_type.location.file)
Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ pub enum DependencyId {
pub enum ReferenceId {
Module(ModuleId),
Struct(StructId),
StructMember(StructId, usize),
Trait(TraitId),
Global(GlobalId),
Function(FuncId),
Expand Down
5 changes: 5 additions & 0 deletions tooling/lsp/src/requests/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,9 @@ mod rename_tests {
async fn test_rename_local_variable() {
check_rename_succeeds("local_variable", "some_var").await;
}

#[test]
async fn test_rename_struct_member() {
check_rename_succeeds("struct_member", "some_member").await;
}
}
6 changes: 6 additions & 0 deletions tooling/lsp/test_programs/struct_member/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "struct_member"
type = "bin"
authors = [""]

[dependencies]
12 changes: 12 additions & 0 deletions tooling/lsp/test_programs/struct_member/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
struct Foo {
some_member: Field
}

fn main() {
let mut foo = Foo { some_member: 1 };
foo.some_member = 2;
let _ = foo.some_member;

let Foo { some_member } = foo;
let Foo { some_member: some_var } = foo;
}
Loading