Skip to content

Commit 51931bf

Browse files
authored
feat(hover): show TL-B types in field documentation (#125)
Fixes #65
1 parent 7bfe3c9 commit 51931bf

File tree

7 files changed

+187
-5
lines changed

7 files changed

+187
-5
lines changed

server/src/TypeInferer.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ export class TypeInferer {
103103
return this.primitiveType("Int")
104104
}
105105

106+
if (resolved.node.type === "field" || resolved.node.type === "storage_variable") {
107+
const typeNode = resolved.node.childForFieldName("type")
108+
if (!typeNode) return null
109+
return this.inferTypeMaybeTlB(typeNode, resolved)
110+
}
111+
106112
if (isTypeOwnerNode(resolved.node)) {
107113
const typeNode = resolved.node.childForFieldName("type")
108114
if (!typeNode) return null
@@ -125,6 +131,22 @@ export class TypeInferer {
125131
const valueTy = this.inferChildFieldType(node, "value")
126132
if (valueTy === null) return null
127133

134+
if (keyTy instanceof PrimitiveTy) {
135+
const tlb = node.node.childForFieldName("tlb_key")
136+
const tlbType = tlb?.childForFieldName("type")
137+
if (tlbType) {
138+
keyTy.tlb = tlbType.text
139+
}
140+
}
141+
142+
if (valueTy instanceof PrimitiveTy) {
143+
const tlb = node.node.childForFieldName("tlb_value")
144+
const tlbType = tlb?.childForFieldName("type")
145+
if (tlbType) {
146+
valueTy.tlb = tlbType.text
147+
}
148+
}
149+
128150
return new MapTy(keyTy, valueTy)
129151
}
130152

@@ -314,7 +336,7 @@ export class TypeInferer {
314336
private primitiveType(name: string) {
315337
const node = index.elementByName(IndexKey.Primitives, name)
316338
if (!node) return null
317-
return new PrimitiveTy(name, node)
339+
return new PrimitiveTy(name, node, null)
318340
}
319341

320342
private inferTypeMaybeOption(typeNode: SyntaxNode, resolved: Node) {
@@ -325,9 +347,21 @@ export class TypeInferer {
325347
return inferred
326348
}
327349

350+
private inferTypeMaybeTlB(typeNode: SyntaxNode, resolved: Node) {
351+
const inferredType = this.inferTypeMaybeOption(typeNode, resolved)
352+
if (inferredType instanceof PrimitiveTy) {
353+
const tlb = resolved.node.childForFieldName("tlb")
354+
const tlbType = tlb?.childForFieldName("type")
355+
if (tlbType) {
356+
inferredType.tlb = tlbType.text
357+
}
358+
}
359+
return inferredType
360+
}
361+
328362
private inferTypeFromResolved(resolved: NamedNode): Ty | null {
329363
if (resolved instanceof Primitive) {
330-
return new PrimitiveTy(resolved.name(), resolved)
364+
return new PrimitiveTy(resolved.name(), resolved, null)
331365
}
332366
if (resolved instanceof Struct) {
333367
return new StructTy(resolved.name(), resolved)

server/src/completion/CompletionContext.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ export class CompletionContext {
170170
this.isInitOfName = true
171171
}
172172

173+
if (parent.type === "ERROR" && parent.parent?.type === "map_type") {
174+
this.isType = true
175+
this.isExpression = false
176+
this.isStatement = false
177+
}
178+
173179
if (parent.type === "ERROR" && parent.parent?.type === "parameter_list") {
174180
this.inParameter = true
175181
}

server/src/completion/providers/KeywordsCompletionProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import {NullTy, PrimitiveTy} from "@server/types/BaseTy"
1010

1111
export class KeywordsCompletionProvider implements CompletionProvider {
12-
boolTy: PrimitiveTy = new PrimitiveTy("Bool", null)
12+
boolTy: PrimitiveTy = new PrimitiveTy("Bool", null, null)
1313
nullTy: NullTy = new NullTy()
1414

1515
isAvailable(ctx: CompletionContext): boolean {

server/src/e2e/suite/testcases/documentation/structs.test

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,57 @@ fun foo() {
123123
struct Foo
124124
field: Int = 0
125125
```
126+
127+
========================================================================
128+
Field declaration with type with TL-B
129+
========================================================================
130+
primitive Int;
131+
132+
struct Foo {
133+
field: Int as uint8;
134+
}
135+
136+
fun foo() {
137+
let f = Foo { <caret>field: 10 };
138+
}
139+
------------------------------------------------------------------------
140+
```
141+
struct Foo
142+
field: Int as uint8
143+
```
144+
145+
========================================================================
146+
Field declaration with type with TL-B 2
147+
========================================================================
148+
primitive Slice;
149+
150+
struct Foo {
151+
field: Slice as remaining;
152+
}
153+
154+
fun foo() {
155+
let f = Foo { <caret>field: 10 };
156+
}
157+
------------------------------------------------------------------------
158+
```
159+
struct Foo
160+
field: Slice as remaining
161+
```
162+
163+
========================================================================
164+
Field declaration with type with TL-B 3
165+
========================================================================
166+
primitive Int;
167+
168+
struct Foo {
169+
field: map<Int as uint8, Int>;
170+
}
171+
172+
fun foo() {
173+
let f = Foo { <caret>field: 10 };
174+
}
175+
------------------------------------------------------------------------
176+
```
177+
struct Foo
178+
field: map<Int as uint8, Int>
179+
```
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
========================================================================
2+
Message field type with Tl-B
3+
========================================================================
4+
primitive Int;
5+
6+
message Point {
7+
x: Int as coins;
8+
//! ^ Int as coins
9+
y: Int;
10+
}
11+
------------------------------------------------------------------------
12+
ok
13+
14+
========================================================================
15+
Message field type with Tl-B 2
16+
========================================================================
17+
primitive Int;
18+
19+
message Point {
20+
x: Int as coins;
21+
y: Slice as remaining;
22+
//! ^ Slice as remaining
23+
}
24+
------------------------------------------------------------------------
25+
type inference error at line 5:4: expected Slice as remaining, got unknown
26+
27+
========================================================================
28+
Message field map type with Tl-B
29+
========================================================================
30+
primitive Int;
31+
32+
message Point {
33+
x: Int as coins;
34+
y: map<Int as uint8, Int>;
35+
//! ^ map<Int as uint8, Int>
36+
}
37+
------------------------------------------------------------------------
38+
ok
39+
40+
========================================================================
41+
Message field map type with Tl-B 2
42+
========================================================================
43+
primitive Int;
44+
45+
message Point {
46+
x: Int as coins;
47+
y: map<Int as uint8, Int as uint16>;
48+
//! ^ map<Int as uint8, Int as uint16>
49+
}
50+
------------------------------------------------------------------------
51+
ok
52+
53+
========================================================================
54+
Message field map type with Tl-B 3
55+
========================================================================
56+
primitive Int;
57+
58+
message Point {
59+
x: Int as coins;
60+
y: map<Int, Int as uint16>;
61+
//! ^ map<Int, Int as uint16>
62+
}
63+
------------------------------------------------------------------------
64+
ok

server/src/psi/Reference.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export class Reference {
181181
if (qualifierType instanceof StructTy || qualifierType instanceof MessageTy) {
182182
const node = index.elementByName(IndexKey.Primitives, "AnyStruct")
183183
if (node) {
184-
const structPrimitiveTy = new PrimitiveTy("AnyStruct", node)
184+
const structPrimitiveTy = new PrimitiveTy("AnyStruct", node, null)
185185
if (!this.processType(qualifier, structPrimitiveTy, proc, state)) return false
186186
}
187187
}

server/src/types/BaseTy.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,31 @@ export class StructTy extends FieldsOwnerTy<Struct> {}
4747

4848
export class MessageTy extends FieldsOwnerTy<Message> {}
4949

50-
export class PrimitiveTy extends BaseTy<Primitive> {}
50+
export class PrimitiveTy extends BaseTy<Primitive> {
51+
public constructor(
52+
name: string,
53+
anchor: Primitive | null,
54+
public tlb: string | null,
55+
) {
56+
super(name, anchor)
57+
}
58+
59+
public override name(): string {
60+
if (this.tlb) {
61+
return `${this._name} as ${this.tlb}`
62+
}
63+
64+
return this._name
65+
}
66+
67+
public override qualifiedName(): string {
68+
if (this.tlb) {
69+
return `${this._name} as ${this.tlb}`
70+
}
71+
72+
return this._name
73+
}
74+
}
5175

5276
export class PlaceholderTy extends BaseTy<NamedNode> {}
5377

0 commit comments

Comments
 (0)