Skip to content

Commit

Permalink
Fix labelled fields resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
maurobalbi committed Feb 18, 2024
1 parent 22c5f28 commit 29999ac
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 22 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## v0.1.7


### Fixed
- Fix labelled field resolution

## v0.1.6

### Fixed
Expand Down
1 change: 1 addition & 0 deletions crates/ide/src/def/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
64 changes: 49 additions & 15 deletions crates/ide/src/def/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -280,14 +280,19 @@ fn classify_label(sema: &Semantics, label: &ast::Label) -> Option<Definition> {

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();
Expand All @@ -298,14 +303,38 @@ fn classify_label(sema: &Semantics, label: &ast::Label) -> Option<Definition> {
}

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<Definition> {
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<Definition> {
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<HashMap<SyntaxNode, FileId>>,
Expand Down Expand Up @@ -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);
}
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/ide/src/ide/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, <next: Reader>)"])
}
}
124 changes: 118 additions & 6 deletions crates/ide/src/ide/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ fn name(a: Bobele) {
r#"
#- test.gleam
type Bobele {
Bobobo(name: String)
Bobobo(alpha: Int, name: String)
Dudu(name: String)
}
Expand All @@ -394,7 +394,7 @@ fn name(a: Bobele) {
r#"--- FileId(0)
type Bobele {
Bobobo(name: String)
Bobobo(alpha: Int, name: String)
Dudu(name: String)
}
Expand All @@ -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
Expand All @@ -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
}
}
"#,
Expand All @@ -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)
Expand All @@ -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)
}
"#
],
Expand Down
22 changes: 22 additions & 0 deletions crates/ide/src/ty/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"])
}
2 changes: 1 addition & 1 deletion editor/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down

0 comments on commit 29999ac

Please sign in to comment.