From 29999ac964f22e62962c0694874f7262ea06b702 Mon Sep 17 00:00:00 2001 From: Mauro Balbi Date: Sun, 18 Feb 2024 07:56:03 +0100 Subject: [PATCH] Fix labelled fields resolution --- CHANGELOG.md | 6 ++ crates/ide/src/def/lower.rs | 1 + crates/ide/src/def/semantics.rs | 64 +++++++++---- crates/ide/src/ide/goto_definition.rs | 16 ++++ crates/ide/src/ide/rename.rs | 124 ++++++++++++++++++++++++-- crates/ide/src/ty/tests.rs | 22 +++++ editor/code/package.json | 2 +- 7 files changed, 213 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 013f546..885e67f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v0.1.7 + + +### Fixed +- Fix labelled field resolution + ## v0.1.6 ### Fixed diff --git a/crates/ide/src/def/lower.rs b/crates/ide/src/def/lower.rs index 8e75e2e..0b1d59e 100644 --- a/crates/ide/src/def/lower.rs +++ b/crates/ide/src/def/lower.rs @@ -348,6 +348,7 @@ impl LowerCtx { let start = self.next_field_idx(); if let Some(fields) = constructor.field_list() { for field in fields.fields() { + tracing::info!("FIELD {:#?}", field); if let Some(type_ref) = module::typeref_from_ast_opt(field.type_()) { let label = field.label().and_then(|t| t.text()); self.alloc_field(FieldData { diff --git a/crates/ide/src/def/semantics.rs b/crates/ide/src/def/semantics.rs index 950535b..249d5d8 100644 --- a/crates/ide/src/def/semantics.rs +++ b/crates/ide/src/def/semantics.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap}; use smol_str::SmolStr; use syntax::{ - ast::{self, AstNode}, + ast::{self, AstNode, VariantRefField}, match_ast, GleamLanguage, SyntaxNode, TextRange, }; @@ -280,14 +280,19 @@ fn classify_label(sema: &Semantics, label: &ast::Label) -> Option { let parent = label.syntax().parent()?; - let ref_field = ast::VariantRefField::cast(parent.clone())?; - let field_list = ast::VariantRefFieldList::cast(ref_field.syntax().parent()?)?; - let variant_ref = ast::VariantRef::cast(field_list.syntax().parent()?)?; - let variant_name = variant_ref.variant()?; - - let variant = match classify_name_ref(sema, &variant_name)? { - Definition::Variant(variant) => variant, - _ => return None, + let Definition::Variant(variant) = match_ast! { + match parent { + ast::VariantRefField(ref_field) => { + classify_ref_field(sema, &ref_field) + }, + ast::Arg(arg) => { + classify_arg(sema, &arg) + }, + _ => return None + } + }? + else { + return None; }; let adt = variant.parent(); @@ -298,14 +303,38 @@ fn classify_label(sema: &Semantics, label: &ast::Label) -> Option { } for field in variant.fields(sema.db.upcast()).iter() { - if field.label(sema.db.upcast())? == label_text { - return Some(Definition::Field(*field)); + if let Some(field_label) = field.label(sema.db.upcast()) { + if field_label == *label_text { + return Some(Definition::Field(*field)); + } } } None } +fn classify_ref_field(sema: &Semantics, ref_field: &ast::VariantRefField) -> Option { + let field_list = ast::VariantRefFieldList::cast(ref_field.syntax().parent()?)?; + let variant_ref = ast::VariantRef::cast(field_list.syntax().parent()?)?; + let variant_name = variant_ref.variant()?; + + classify_name_ref(sema, &variant_name) +} + +fn classify_arg(sema: &Semantics, arg: &ast::Arg) -> Option { + let arg_list = ast::ArgList::cast(arg.syntax().parent()?)?; + let constructor = arg_list.syntax().prev_sibling()?; + if let Some(constr) = ast::VariantConstructor::cast(constructor.clone()) { + return classify_name_ref(sema, &constr.name()?); + }; + + if let Some(constr) = ast::FieldAccessExpr::cast(constructor) { + return classify_name_ref(sema, &constr.label()?); + }; + + None +} + pub struct Semantics<'db> { pub db: &'db dyn TyDatabase, cache: RefCell>, @@ -471,16 +500,21 @@ impl ToDef for ast::VariantField { if let ModuleDefId::VariantId(it) = container { let text = src.value.label()?.text()?; - let variant = Variant { id: it.local_id, parent: it.parent }; + let variant = Variant { + id: it.local_id, + parent: it.parent, + }; let adt = variant.parent(); if let Some(field) = adt.common_fields(sema.db.upcast()).get(&text) { - return Some(*field) + return Some(*field); } for field in variant.fields(sema.db.upcast()) { - if field.label(sema.db.upcast())? == text { - return Some(field) + if let Some(label) = field.label(sema.db.upcast()) { + if label == text { + return Some(field); + } } } } diff --git a/crates/ide/src/ide/goto_definition.rs b/crates/ide/src/ide/goto_definition.rs index 3594750..7561fc5 100644 --- a/crates/ide/src/ide/goto_definition.rs +++ b/crates/ide/src/ide/goto_definition.rs @@ -398,4 +398,20 @@ fn get_age(d: Dolly) { ], ) } + +#[test] +fn resovle_constr_field() { + check(r#" + type Reader = + fn(Int) -> Result(Read, Nil) + +type Read { + Chunk(a: Int, next: Reader) + ReadingFinished +} + +fn bla(a: read, b: next) { + Chunk($0next: b, a: a) +}"#, expect!["Chunk(a: Int, )"]) +} } diff --git a/crates/ide/src/ide/rename.rs b/crates/ide/src/ide/rename.rs index 717e4c9..c4b07bb 100644 --- a/crates/ide/src/ide/rename.rs +++ b/crates/ide/src/ide/rename.rs @@ -377,7 +377,7 @@ fn name(a: Bobele) { r#" #- test.gleam type Bobele { - Bobobo(name: String) + Bobobo(alpha: Int, name: String) Dudu(name: String) } @@ -394,7 +394,7 @@ fn name(a: Bobele) { r#"--- FileId(0) type Bobele { - Bobobo(name: String) + Bobobo(alpha: Int, name: String) Dudu(name: String) } @@ -416,7 +416,7 @@ fn name(a: Bobele) { #- test.gleam type Bobele { Bobobo(name: String) - Second($0dodo: String) + Second(alpha: Int, $0dodo: String) } #- test2.gleam @@ -425,7 +425,7 @@ import test as t fn name(a: Bobele) { case a { Bobobo(name: name) -> name - t.Second(dodo: name) -> name + t.Second(alpha: Int, dodo: name) -> name } } "#, @@ -435,7 +435,7 @@ fn name(a: Bobele) { type Bobele { Bobobo(name: String) - Second(new_name: String) + Second(alpha: Int, new_name: String) } --- FileId(1) @@ -444,8 +444,120 @@ import test as t fn name(a: Bobele) { case a { Bobobo(name: name) -> name - t.Second(new_name: name) -> name + t.Second(alpha: Int, new_name: name) -> name + } +} +"# + ], + ); + } + + #[test] + fn rename_variant_label() { + check( + r#" +type Read { + Chunk(a: BitArray, $0next: Reader) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> BitArray { + case reader { + ReadingFinished -> <<1>> + Chunk(chunk, next: asb) -> { + chunk + } + } +} +"#, + "new_name", + expect![ + r#"--- FileId(0) + +type Read { + Chunk(a: BitArray, new_name: Reader) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> BitArray { + case reader { + ReadingFinished -> <<1>> + Chunk(chunk, new_name: asb) -> { + chunk + } + } +} +"# + ], + ); + } + + #[test] + fn rename_variant_constructor_field() { + check( + r#" +type Read { + Chunk(a: BitArray, $0next: Reader) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> Read { + Chunk(chunk, next: asb) +} +"#, + "new_name", + expect![ + r#"--- FileId(0) + +type Read { + Chunk(a: BitArray, new_name: Reader) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> Read { + Chunk(chunk, new_name: asb) +} +"# + ], + ); } + + #[test] + fn rename_variant_constructor_field_no_label() { + check( + r#" +type Read { + Chunk(BitArray, $0next: Read) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> Read { + Chunk(chunk, next: Read) +} +"#, + "new_name", + expect![ + r#"--- FileId(0) + +type Read { + Chunk(BitArray, new_name: Read) + ReadingFinished +} + +fn read_body_loop( +reader: Read, +) -> Read { + Chunk(chunk, new_name: Read) } "# ], diff --git a/crates/ide/src/ty/tests.rs b/crates/ide/src/ty/tests.rs index fce4499..994a65b 100644 --- a/crates/ide/src/ty/tests.rs +++ b/crates/ide/src/ty/tests.rs @@ -766,4 +766,26 @@ fn labels_infer_pattern() { inst2: fn(Bobo(String)) -> String"# ], ) + + } + +#[test] +fn labels_variant() { + check_fn( + r#" +type Read(a) { + Chunk(BitArray, next: a) + ReadingFinished + } + + fn read_body_loop(reader: Read(a)) { + case reader { + ReadingFinished -> <<1>> + Chunk(chunk, next: p) -> { + p + 1 + } + } + } + "#, expect!["read_body_loop: fn(Read(Int)) -> Int"]) +} \ No newline at end of file diff --git a/editor/code/package.json b/editor/code/package.json index b7f7ce5..d04d4f4 100644 --- a/editor/code/package.json +++ b/editor/code/package.json @@ -3,7 +3,7 @@ "displayName": "glas: Gleam Language Server", "description": "Gleam language server for VSCode", "repository": "https://github.com/maurobalbi/glas", - "version": "0.1.6", + "version": "0.1.7", "icon": "images/icon.png", "publisher": "maurobalbi", "engines": {