Skip to content

Commit 125a4df

Browse files
authored
feat: support contract Contract.toCell/toSlice from Tact 1.6.11 and Contract.fromCell/fromSlice from Tact 1.6.12 (#746)
Fixes #736
1 parent 0874308 commit 125a4df

File tree

9 files changed

+136
-7
lines changed

9 files changed

+136
-7
lines changed

server/src/e2e/suite/testcases/completion/fromCell.test

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,26 @@ fun test() {
4343
14 let Create variable
4444
14 not Negate expression
4545
14 repeat Create repeat loop
46+
47+
========================================================================
48+
fromCell/fromSlice for contract
49+
========================================================================
50+
primitive Int;
51+
52+
fun AnyContract_fromCell(cell: Cell): M {}
53+
fun AnyContract_fromSlice(slice: Slice): M {}
54+
55+
contract Foo {}
56+
57+
fun test() {
58+
Foo.<caret>;
59+
}
60+
------------------------------------------------------------------------
61+
2 fromCell(cell: Cell): M
62+
2 fromSlice(slice: Slice): M
63+
14 call Use as function argument
64+
14 do Create do-until loop
65+
14 if Create if statement
66+
14 let Create variable
67+
14 not Negate expression
68+
14 repeat Create repeat loop

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,21 @@ fun test() {
3333
```tact
3434
fun fromSlice(slice: Slice): M {}
3535
```
36+
37+
========================================================================
38+
fromCell/fromSlice for contract
39+
========================================================================
40+
primitive Int;
41+
42+
fun AnyContract_fromCell(cell: Cell): M {}
43+
fun AnyContract_fromSlice(slice: Slice): M {}
44+
45+
contract Foo {}
46+
47+
fun test() {
48+
Foo.<caret>fromSlice();
49+
}
50+
------------------------------------------------------------------------
51+
```tact
52+
fun fromSlice(slice: Slice): M {}
53+
```

server/src/e2e/suite/testcases/resolve/fromCell.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,21 @@ fun test() {
2929
}
3030
------------------------------------------------------------------------
3131
8:8 -> 3:4 resolved
32+
33+
========================================================================
34+
fromCell/fromSlice for contract
35+
========================================================================
36+
primitive Int;
37+
38+
fun AnyContract_fromCell(cell: Cell): M {}
39+
fun AnyContract_fromSlice(slice: Slice): M {}
40+
41+
contract Foo {}
42+
43+
fun test() {
44+
Foo.<caret>fromSlice();
45+
Foo.<caret>fromCell();
46+
}
47+
------------------------------------------------------------------------
48+
8:8 -> 3:4 resolved
49+
9:8 -> 2:4 resolved

server/src/e2e/suite/testcases/types/fromCell.test

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fun AnyStruct_fromSlice(slice: Slice): S {}
99
struct Foo {}
1010

1111
fun test() {
12-
let f = Foo.<caret>;
12+
let f = Foo.fromSlice();
1313
// ^! Foo
1414
}
1515
------------------------------------------------------------------------
@@ -26,7 +26,24 @@ fun AnyMessage_fromSlice(slice: Slice): M {}
2626
message Foo {}
2727

2828
fun test() {
29-
let f = Foo.<caret>;
29+
let f = Foo.fromCell();
30+
// ^! Foo
31+
}
32+
------------------------------------------------------------------------
33+
ok
34+
35+
========================================================================
36+
fromCell/fromSlice for contracts
37+
========================================================================
38+
primitive Int;
39+
40+
fun AnyContract_fromCell(cell: Cell): M {}
41+
fun AnyContract_fromSlice(slice: Slice): M {}
42+
43+
contract Foo {}
44+
45+
fun test() {
46+
let f = Foo.fromCell();
3047
// ^! Foo
3148
}
3249
------------------------------------------------------------------------

server/src/languages/tact/TypeInferer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ export class TypeInferer {
261261
// Handle `Struct.fromCell()` calls
262262
if (
263263
qualifier &&
264-
(calledName.startsWith("AnyStruct_") || calledName.startsWith("AnyMessage_"))
264+
(calledName.startsWith("AnyStruct_") ||
265+
calledName.startsWith("AnyMessage_") ||
266+
calledName.startsWith("AnyContract_"))
265267
) {
266268
return new Expression(qualifier, node.file).type()
267269
}

server/src/languages/tact/completion/ReferenceCompletionProcessor.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,16 @@ export class ReferenceCompletionProcessor implements ScopeProcessor {
8383
if (!(node instanceof NamedNode)) return true
8484

8585
const prefix = state.get("prefix") ?? ""
86-
const name = trimPrefix(trimPrefix(node.name(), "AnyMessage_"), "AnyStruct_")
87-
if (name.endsWith("DummyIdentifier") || name === "AnyStruct" || name === "AnyMessage") {
86+
const name = trimPrefix(
87+
trimPrefix(trimPrefix(node.name(), "AnyMessage_"), "AnyContract_"),
88+
"AnyStruct_",
89+
)
90+
if (
91+
name.endsWith("DummyIdentifier") ||
92+
name === "AnyStruct" ||
93+
name === "AnyMessage" ||
94+
name === "AnyContract"
95+
) {
8896
return true
8997
}
9098

server/src/languages/tact/documentation/documentation.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ export async function generateDocFor(node: NamedNode, place: SyntaxNode): Promis
8282
const extraDoc =
8383
func.name() === "require" ? requireFunctionDoc(place, node.file, settings) : ""
8484

85-
const name = trimPrefix(trimPrefix(node.name(), "AnyMessage_"), "AnyStruct_")
85+
const name = trimPrefix(
86+
trimPrefix(trimPrefix(node.name(), "AnyContract_"), "AnyMessage_"),
87+
"AnyStruct_",
88+
)
8689

8790
return defaultResult(
8891
`${func.modifiers()}fun ${name}${func.signaturePresentation()}${func.bodyPresentation(maxLinesBody)}`,

server/src/languages/tact/inlays/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import {
1818
BaseTy,
1919
BouncedTy,
20+
ContractTy,
2021
MapTy,
2122
MessageTy,
2223
OptionTy,
@@ -129,6 +130,8 @@ function processToCellCall(call: CallLike, result: InlayHint[], showToCellSize:
129130
return
130131
}
131132

133+
if (ty instanceof ContractTy) return
134+
132135
const sizeof = ty.sizeOf(new Map())
133136
if (!sizeof.valid) {
134137
return

server/src/languages/tact/psi/Reference.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,42 @@ export class Reference {
227227
}
228228
}
229229

230+
if (qualifierType instanceof ContractTy) {
231+
const methodRef = qualifier.node.parent?.type === "method_call_expression"
232+
233+
if (qualifier.node.type === "identifier") {
234+
const resolved = Reference.resolve(new NamedNode(qualifier.node, qualifier.file))
235+
if (resolved instanceof Contract) {
236+
// found `Contract.fromCell` case
237+
const fromCellName = "AnyContract_fromCell"
238+
const fromCell = index.elementByName(IndexKey.Funs, fromCellName)
239+
if (fromCell) {
240+
const newState = state.withValue(
241+
"search-name",
242+
"AnyContract_" + this.element.name(),
243+
)
244+
if (!proc.execute(fromCell, newState)) return false
245+
}
246+
247+
const fromSliceName = "AnyContract_fromSlice"
248+
const fromSlice = index.elementByName(IndexKey.Funs, fromSliceName)
249+
if (fromSlice) {
250+
const newState = state.withValue(
251+
"search-name",
252+
"AnyContract_" + this.element.name(),
253+
)
254+
if (!proc.execute(fromSlice, newState)) return false
255+
}
256+
}
257+
}
258+
259+
const nodeContract = index.elementByName(IndexKey.Primitives, "AnyContract")
260+
if (nodeContract && (methodRef || state.get("completion"))) {
261+
const contractPrimitiveTy = new PrimitiveTy("AnyContract", nodeContract, null)
262+
if (!this.processType(qualifier, contractPrimitiveTy, proc, state)) return false
263+
}
264+
}
265+
230266
if (qualifierType instanceof BouncedTy) {
231267
return this.processType(qualifier, qualifierType.innerTy, proc, state)
232268
}
@@ -575,7 +611,8 @@ export class Reference {
575611
if (node.withSelf()) return true // don't add methods to unqualified completion
576612
if (
577613
node.name().startsWith("AnyStruct_") ||
578-
node.name().startsWith("AnyMessage_")
614+
node.name().startsWith("AnyMessage_") ||
615+
node.name().startsWith("AnyContract_")
579616
) {
580617
// this functions in fact static methods
581618
return true

0 commit comments

Comments
 (0)