1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

[Tolk] Rewrite the type system from Hindley-Milner to static typing

FunC's (and Tolk's before this PR) type system is based on Hindley-Milner.
This is a common approach for functional languages, where
types are inferred from usage through unification.
As a result, type declarations are not necessary:
() f(a,b) { return a+b; } // a and b now int, since `+` (int, int)

While this approach works for now, problems arise with the introduction
of new types like bool, where `!x` must handle both int and bool.
It will also become incompatible with int32 and other strict integers.
This will clash with structure methods, struggle with proper generics,
and become entirely impractical for union types.

This PR completely rewrites the type system targeting the future.
1) type of any expression is inferred and never changed
2) this is available because dependent expressions already inferred
3) forall completely removed, generic functions introduced
   (they work like template functions actually, instantiated while inferring)
4) instantiation `<...>` syntax, example: `t.tupleAt<int>(0)`
5) `as` keyword, for example `t.tupleAt(0) as int`
6) methods binding is done along with type inferring, not before
   ("before", as worked previously, was always a wrong approach)
This commit is contained in:
tolk-vm 2024-12-30 22:31:27 +07:00
parent 3540424aa1
commit 799e2d1265
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
101 changed files with 5402 additions and 2713 deletions

View file

@ -35,7 +35,7 @@ fun test88(x: int) {
}
@method_id(89)
fun test89(last: int) {
fun test89(last: int): (int, int, int, int) {
var t: tuple = createEmptyTuple();
t.tuplePush(1);
t.tuplePush(2);

View file

@ -9,6 +9,7 @@ fun calc_phi(): int {
repeat (70) { n*=10; };
var p= 1;
var `q`=1;
_=`q`;
do {
(p,q)=(q,p+q);
} while (q <= n); //;;
@ -27,7 +28,7 @@ fun calc_sqrt2(): int {
return mulDivRound(p, n, q);
}
fun calc_root(m: auto): auto {
fun calc_root(m: int) {
var base: int=1;
repeat(70) { base *= 10; }
var (a, b, c) = (1,0,-m);

View file

@ -1,5 +1,5 @@
@deprecated
fun twice(f: auto, x: auto): auto {
fun twice(f: int -> int, x: int) {
return f (f (x));
}

View file

@ -138,5 +138,5 @@ fun main() {
inc CALLDICT // self newY
}>
"""
@code_hash 33262590582878205026101577472505372101182291690814957175155528952950621243206
@code_hash 7627024945492125068389905298530400936797031708759561372406088054030801992712
*/

View file

@ -0,0 +1,28 @@
fun extractFromTypedTuple(params: [int]) {
var [payload: int] = params;
return payload + 10;
}
@method_id(101)
fun test101(x: int) {
var params = [x];
return extractFromTypedTuple(params);
}
fun autoInferIntNull(x: int) {
if (x > 10) { return null; }
return x;
}
fun main(value: int) {
var (x: int, y) = (autoInferIntNull(value), autoInferIntNull(value * 2));
if (x == null && y == null) { return null; }
return x == null || y == null ? -1 : x + y;
}
/**
@testcase | 0 | 3 | 9
@testcase | 0 | 6 | -1
@testcase | 0 | 11 | (null)
@testcase | 101 | 78 | 88
*/

View file

@ -4,7 +4,7 @@ fun check_assoc(a: int, b: int, c: int): int {
return op(op(a, b), c) == op(a, op(b, c));
}
fun unnamed_args(_: int, _: slice, _: auto): auto {
fun unnamed_args(_: int, _: slice, _: int) {
return true;
}
@ -14,7 +14,7 @@ fun main(x: int, y: int, z: int): int {
}
@method_id(101)
fun test101(x: int, z: int): auto {
fun test101(x: int, z: int) {
return unnamed_args(x, "asdf", z);
}

View file

@ -1,4 +1,4 @@
fun check_assoc(op: auto, a: int, b: int, c: int) {
fun check_assoc(op: (int, int) -> int, a: int, b: int, c: int) {
return op(op(a, b), c) == op(a, op(b, c));
}

View file

@ -0,0 +1,150 @@
fun eq1<X>(value: X): X { return value; }
fun eq2<X>(value: X) { return value; }
fun eq3<X>(value: X): X { var cp: [X] = [eq1(value)]; var ((([v: X]))) = cp; return v; }
fun eq4<X>(value: X) { return eq1<X>(value); }
@method_id(101)
fun test101(x: int) {
var (a, b, c) = (x, (x,x), [x,x]);
return (eq1(a), eq1(b), eq1(c), eq2(a), eq2(b), eq2(c), eq3(a), eq4(b), eq3(createEmptyTuple()));
}
fun getTwo<X>(): X { return 2 as X; }
fun takeInt(a: int) { return a; }
@method_id(102)
fun test102(): (int, int, int, [(int, int)]) {
var a: int = getTwo();
var _: int = getTwo();
var b = getTwo() as int;
var c: int = 1 ? getTwo() : getTwo();
var c redef = getTwo();
return (eq1<int>(a), eq2<int>(b), takeInt(getTwo()), [(getTwo(), getTwo())]);
}
@method_id(103)
fun test103(first: int): (int, int, int) {
var t = createEmptyTuple();
var cs = beginCell().storeInt(100, 32).endCell().beginParse();
t.tuplePush(first);
t.tuplePush(2);
t.tuplePush(cs);
cs = t.tupleAt(2);
cs = t.tupleAt(2) as slice;
return (t.tupleAt(0), cs.loadInt(32), t.tupleAt<slice>(2).loadInt(32));
}
fun manyEq<T1, T2, T3>(a: T1, b: T2, c: T3): [T1, T2, T3] {
return [a, b, c];
}
@method_id(104)
fun test104(f: int) {
return (
manyEq(1 ? 1 : 1, f ? 0 : null, !f ? getTwo() as int : null),
manyEq((f ? null as int : eq2(2), beginCell().storeBool(true).endCell().beginParse().loadBool()), 0, eq4(f))
);
}
fun calcSum<X>(x: X, y: X) { return x + y; }
@method_id(105)
fun test105() {
if (0) { calcSum(((0)), null); }
return (calcSum(1, 2));
}
fun calcYPlus1<Y>(value: Y) { return value + 1; }
fun calcLoad32(cs: slice) { return cs.loadInt(32); }
fun calcTensorPlus1(tens: (int, int)) { var (f, s) = tens; return (f + 1, s + 1); }
fun calcTensorMul2(tens: (int, int)) { var (f, s) = tens; return (f * 2, s * 2); }
fun cellToSlice(c: cell) { return c.beginParse(); }
fun abstractTransform<X, Y, R>(xToY: (X) -> Y, yToR: (((Y))) -> R, initialX: X): R {
var y = xToY(initialX);
return yToR(y);
}
@method_id(106)
fun test106() {
var c = beginCell().storeInt(106, 32).endCell();
return [
abstractTransform(cellToSlice, calcLoad32, c),
abstractTransform(calcYPlus1<int>, calcYPlus1<int>, 0),
abstractTransform(calcTensorPlus1, calcTensorMul2, (2, 2))
];
}
fun callTupleFirst<X, Y>(t: X): Y { return t.tupleFirst(); }
fun callTuplePush<T, V>(mutate self: T, v1: V, v2: V): self { self.tuplePush(v1); tuplePush(mutate self, v2); return self; }
fun getTupleLastInt(t: tuple) { return t.tupleLast<int>(); }
fun getTupleSize(t: tuple) { return t.tupleSize(); }
fun callAnyFn<TObj, TResult>(f: (TObj) -> TResult, arg: TObj) { return f(arg); }
fun callAnyFn2<TCallback>(f: TCallback, arg: tuple) { return f(arg); }
global t107: tuple;
@method_id(107)
fun test107() {
t107 = createEmptyTuple();
callTuplePush(mutate t107, 1, 2);
t107.callTuplePush(3, 4).callTuplePush(5, 6);
var first: int = t107.callTupleFirst();
return (
callAnyFn<tuple, int>(getTupleSize, t107),
callAnyFn2(getTupleSize, t107),
first,
callTupleFirst(t107) as int,
callAnyFn(getTupleLastInt, t107),
callAnyFn2(getTupleLastInt, t107)
);
}
global g108: int;
fun inc108(by: int) { g108 += by; }
fun getInc108() { return inc108; }
fun returnResult<RetT>(f: () -> RetT): RetT { return f(); }
fun applyAndReturn<ArgT, RetT>(f: () -> (ArgT) -> RetT, arg: ArgT): () -> ArgT -> RetT {
f()(arg);
return f;
}
@method_id(108)
fun test108() {
g108 = 0;
getInc108()(1);
returnResult<(int) -> void>(getInc108)(2);
applyAndReturn<int, void>(getInc108, 10)()(10);
returnResult(getInc108)(2);
applyAndReturn(getInc108, 10)()(10);
return g108;
}
fun main(x: int): (int, [[int, int]]) {
try { if(x) { throw (1, x); } }
catch (excNo, arg) { return (arg as int, [[eq2(arg as int), getTwo()]]); }
return (0, [[x, 1]]);
}
/**
@testcase | 0 | 1 | 1 [ [ 1 2 ] ]
@testcase | 101 | 0 | 0 0 0 [ 0 0 ] 0 0 0 [ 0 0 ] 0 0 0 []
@testcase | 102 | | 2 2 2 [ 2 2 ]
@testcase | 103 | 0 | 0 100 100
@testcase | 104 | 0 | [ 1 (null) 2 ] [ 2 -1 0 0 ]
@testcase | 105 | | 3
@testcase | 106 | | [ 106 2 6 6 ]
@testcase | 107 | | 6 6 1 1 6 6
@testcase | 108 | | 45
@fif_codegen DECLPROC eq1<int>
@fif_codegen DECLPROC eq1<tuple>
@fif_codegen DECLPROC eq1<(int,int)>
@fif_codegen DECLPROC eq1<[int,int]>
@fif_codegen DECLPROC getTwo<int>
@fif_codegen_avoid DECLPROC eq1
@fif_codegen_avoid DECLPROC eq2
@fif_codegen_avoid DECLPROC eq3
*/

View file

@ -1,9 +1,10 @@
fun main() {
return true();
const asdf = 1;
fun main(x: int) {
return x.asdf();
}
/**
@compilation_should_fail
The message is weird now, but later I'll rework error messages anyway.
@stderr cannot apply expression of type int to an expression of type (): cannot unify type () -> ??2 with int
@stderr calling a non-function
*/

View file

@ -0,0 +1,10 @@
fun getOne() { return 1; }
fun main() {
return getOne<int>();
}
/**
@compilation_should_fail
@stderr calling a not generic function with generic T
*/

View file

@ -0,0 +1,13 @@
// this function is declared incorrectly,
// since it should return 2 values onto a stack (1 for returned slice, 1 for mutated int)
// but contains not 2 numbers in asm ret_order
fun loadAddress2(mutate self: int): slice
asm( -> 1 0 2) "LDMSGADDR";
fun main(){}
/**
@compilation_should_fail
@stderr ret_order (after ->) expected to contain 2 numbers
@stderr asm( -> 1 0 2)
*/

View file

@ -0,0 +1,16 @@
fun proxy(x: int) {
return factorial(x);
}
fun factorial(x: int) {
if (x <= 0) {
return 1;
}
return x * proxy(x-1);
}
/**
@compilation_should_fail
@stderr could not infer return type of `factorial`, because it appears in a recursive call chain
@stderr fun factorial
*/

View file

@ -0,0 +1,7 @@
const c: slice = 123 + 456;
/**
@compilation_should_fail
@stderr expression type does not match declared type
@stderr const c
*/

View file

@ -0,0 +1,10 @@
fun f<X>(v: int, x: X) {}
fun failCantDeduceWithoutArgument() {
return f(1);
}
/**
@compilation_should_fail
@stderr can not deduce X for generic function `f<X>`
*/

View file

@ -0,0 +1,9 @@
fun invalidReferencingGenericMethodWithoutGeneric() {
var t = createEmptyTuple();
var cb = t.tupleLast;
}
/**
@compilation_should_fail
@stderr can not use a generic function `tupleLast<T>` as non-call
*/

View file

@ -0,0 +1,11 @@
global gVar: int;
fun main() {
var x = gVar<int>;
return x;
}
/**
@compilation_should_fail
@stderr generic T not expected here
*/

View file

@ -0,0 +1,10 @@
fun f<T>(v: int, x: T) {}
fun failCantDeduceWithPlainNull() {
return f(0, null);
}
/**
@compilation_should_fail
@stderr can not deduce T for generic function `f<T>`
*/

View file

@ -0,0 +1,11 @@
fun f<T>(x: T, y: T) {}
fun failIncompatibleTypesForT() {
return f(32, "");
}
/**
@compilation_should_fail
@stderr T is both int and slice for generic function `f<T>`
@stderr f(32
*/

View file

@ -0,0 +1,10 @@
fun f<T>(x: T): void asm "NOP";
fun failInstantiatingAsmFunctionWithNon1Slot() {
f((1, 2));
}
/**
@compilation_should_fail
@stderr can not call `f<T>` with T=(int, int), because it occupies 2 stack slots in TVM, not 1
*/

View file

@ -0,0 +1,10 @@
fun f<T>(x: T): void asm "NOP";
fun failUsingGenericFunctionPartially() {
var cb = f;
}
/**
@compilation_should_fail
@stderr can not use a generic function `f<T>` as non-call
*/

View file

@ -0,0 +1,10 @@
fun eq<X>(t: X) { return t; }
fun failUsingGenericFunctionPartially() {
var cb = createEmptyTuple().eq().eq().tuplePush;
}
/**
@compilation_should_fail
@stderr can not use a generic function `tuplePush<T>` as non-call
*/

View file

@ -0,0 +1,18 @@
fun failOnInstantiation(a: slice) {
var b: slice = foo(a);
}
fun bar<X>(value: X) : X {
return 1;
}
fun foo<X>(value: X) : X {
return bar(value);
}
/**
@compilation_should_fail
@stderr while instantiating generic function `foo<slice>`
@stderr while instantiating generic function `bar<slice>`
@stderr can not convert type `int` to return type `slice`
@stderr return 1
*/

View file

@ -0,0 +1,11 @@
fun withT1T2<T1, T2>(a: (T1, T2)) {}
fun wrongTCountPassed() {
withT1T2<int>((5, ""));
}
/**
@compilation_should_fail
@stderr wrong count of generic T: expected 2, got 1
@stderr <int>
*/

View file

@ -0,0 +1,8 @@
fun invalidProvidingGenericTsToNotGeneric() {
beginCell<builder>();
}
/**
@compilation_should_fail
@stderr calling a not generic function with generic T
*/

View file

@ -0,0 +1,9 @@
fun cantCallMutatingFunctionWithAssignmentLValue() {
var t: tuple = createEmptyTuple();
(t = createEmptyTuple()).tuplePush(1);
}
/**
@compilation_should_fail
@stderr assignment can not be used as lvalue
*/

View file

@ -0,0 +1,13 @@
@pure
fun tupleMut(mutate self: tuple): int
asm "TLEN";
fun main() {
var t = createEmptyTuple();
return [[t.tupleMut]];
}
/**
@compilation_should_fail
@stderr saving `tupleMut` into a variable is impossible, since it has `mutate` parameters
*/

View file

@ -4,5 +4,5 @@ fun load_u32(cs: slice): (slice, int) {
/**
@compilation_should_fail
@stderr expected `(`, got `32`
@stderr expected `;`, got `32`
*/

View file

@ -1,16 +0,0 @@
global set: int;
@pure
fun someF(): int {
var set redef = 0;
return set;
}
/**
@compilation_should_fail
@stderr
"""
an impure operation in a pure function
var set
"""
*/

View file

@ -4,6 +4,6 @@ fun cantReturnNothingFromSelf(mutate self: int): self {
/**
@compilation_should_fail
@stderr missing return; forgot `return self`?
@stderr missing return
@stderr }
*/

View file

@ -4,5 +4,5 @@ fun main(x: int) {
/**
@compilation_should_fail
@stderr null is not a function: use `null`, not `null()`
@stderr calling a non-function
*/

View file

@ -0,0 +1,9 @@
fun main() {
var a = 1;
(a += 1) += 2;
}
/**
@compilation_should_fail
@stderr assignment can not be used as lvalue
*/

View file

@ -0,0 +1,9 @@
fun main() {
var x = 1;
x += (var y = 2);
}
/**
@compilation_should_fail
@stderr expected <expression>, got `var`
*/

View file

@ -6,5 +6,5 @@ fun main() {
/**
@compilation_should_fail
@stderr .tolk:2
@stderr expected <type>, got `scli`
@stderr unknown type name `scli`
*/

View file

@ -0,0 +1,10 @@
fun failAssignNullToTensor() {
var ab = (1, 2);
ab = null;
return ab;
}
/**
@compilation_should_fail
@stderr can not assign `null` to variable of type `(int, int)`
*/

View file

@ -15,5 +15,5 @@ fun cantMixDifferentThis() {
/**
@compilation_should_fail
@stderr cannot apply function appendBuilder : builder -> (builder, ()) to arguments of type int: cannot unify type int with builder
@stderr can not call method for `builder` with object of type `int`
*/

View file

@ -7,8 +7,6 @@ fun cantCallNotChainedMethodsInAChain(x: int) {
}
/**
The error is very weird, but nevertheless, the type system prevents of doing such errors.
@compilation_should_fail
@stderr cannot apply function incNotChained : int -> (int, ()) to arguments of type (): cannot unify type () with int
@stderr can not call method for `int` with object of type `void`
*/

View file

@ -7,8 +7,7 @@ fun failWhenReturnANotChainedValue(x: int): int {
}
/**
The error is very weird, but nevertheless, the type system prevents of doing such errors.
@compilation_should_fail
@stderr previous function return type int cannot be unified with return statement expression type (): cannot unify type () with int
@stderr x.incNotChained()
@stderr can not convert type `void` to return type `int`
*/

View file

@ -4,5 +4,5 @@ fun failWhenTernaryConditionNotInt(cs: slice) {
/**
@compilation_should_fail
@stderr condition of ternary ?: operator must be an integer
@stderr condition of ternary operator must be an integer
*/

View file

@ -0,0 +1,9 @@
fun failAssignPlainNullToVariable() {
var x = null;
}
/**
@compilation_should_fail
@stderr can not infer type of `x`, it's always null
@stderr specify its type with `x: <type>` or use `null as <type>`
*/

View file

@ -0,0 +1,8 @@
fun failExplicitCastIncompatible(c: cell) {
return c as slice;
}
/**
@compilation_should_fail
@stderr type `cell` can not be cast to `slice`
*/

View file

@ -0,0 +1,13 @@
fun getTupleLastGetter<X>(): tuple -> X {
return tupleLast<X>;
}
fun failTypeMismatch() {
var t = createEmptyTuple();
var c: cell = getTupleLastGetter<int>()(t);
}
/**
@compilation_should_fail
@stderr can not assign `int` to variable of type `cell`
*/

View file

@ -54,7 +54,8 @@ fun testDict(last: int) {
@method_id(105)
fun testNotNull(x: int) {
return [x == null, null == x, !(x == null), null == null, +(null != null)];
// return [x == null, null == x, !(x == null), null == null, +(null != null)];
return [x == null, null == x, !(x == null)];
}
@method_id(106)
@ -144,8 +145,8 @@ fun main() {
@testcase | 104 | 50 | 3 5 -1
@testcase | 104 | 100 | 3 5 5
@testcase | 104 | 0 | 3 -1 5
@testcase | 105 | 0 | [ 0 0 -1 -1 0 ]
@testcase | 105 | null | [ -1 -1 0 -1 0 ]
@testcase | 105 | 0 | [ 0 0 -1 ]
@testcase | 105 | null | [ -1 -1 0 ]
@testcase | 106 | | [ 0 0 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ 0 -1 ]
@testcase | 107 | | [ -1 -1 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ -1 0 ]
@testcase | 108 | 1 2 | -1

View file

@ -154,7 +154,7 @@ fun getSumOfNumbersInCell(c: cell): int {
@method_id(110)
fun testStoreChaining() {
var b = beginCell().storeUint(1, 32).storeUint(2, 32).storeUint(3, 32);
var b = ((beginCell()).storeUint(1, 32)).storeUint(2, 32).storeUint(3, 32);
b.storeUint(4, 32);
b.myStoreUint(5, 32).storeUint(6, 32);
storeUint(mutate b, 7, 32);
@ -198,7 +198,7 @@ fun testStoreAndMutateBoth() {
b.myStoreU32_and_mutate_x(mutate x);
var cs: slice = b.endCell().beginParse();
var (n1,n2,n3,n4,n5) = (cs.loadUint(32),cs.loadUint(32),cs.loadUint(32),cs.loadUint(32),cs.loadUint(32));
var (n1,n2,n3,n4,n5) = (cs.loadUint(32),((cs)).loadUint(32),cs.loadUint(32),cs.loadUint(32),cs.loadUint(32));
assert(n5 == x) throw 100;
return [n1,n2,n3,n4,n5];

View file

@ -7,12 +7,14 @@ fun test1() {
numbers = listPrepend(2, numbers);
numbers = listPrepend(3, numbers);
numbers = listPrepend(4, numbers);
var (h, numbers redef) = listSplit(numbers);
var (h: int, numbers redef) = listSplit(numbers);
h += listGetHead(numbers);
_ = null;
(_, _) = (null, null);
var t = createEmptyTuple();
do {
var num = numbers.listNext();
var num: int = numbers.listNext();
t.tuplePush(num);
} while (numbers != null);
@ -44,7 +46,7 @@ fun test3(x: int) {
}
fun getUntypedNull() {
var untyped = null;
var untyped: null = null;
if (true) {
return untyped;
}
@ -52,8 +54,8 @@ fun getUntypedNull() {
}
@method_id(104)
fun test4() {
var (_, (_, untyped)) = (3, (createEmptyTuple, null));
fun test4(): null {
var (_, (_, untyped: null)) = (3, (createEmptyTuple, null));
if (true) {
return untyped;
}
@ -62,15 +64,10 @@ fun test4() {
@method_id(105)
fun test5() {
var n = getUntypedNull();
var n: slice = getUntypedNull();
return !(null == n) ? n.loadInt(32) : 100;
}
@method_id(106)
fun test6(x: int) {
return x > null; // this compiles (for now), but fails at runtime
}
@method_id(107)
fun test7() {
var b = beginCell().storeMaybeRef(null);
@ -132,15 +129,6 @@ fun main() {
}>
"""
@fif_codegen
"""
test6 PROC:<{
// x
PUSHNULL // x _1
GREATER // _2
}>
"""
@fif_codegen
"""
test7 PROC:<{

View file

@ -56,7 +56,7 @@ fun test8(b: int): int {
return a;
}
fun `_<p`(a: auto, b: auto): int { return true; }
fun `_<p`(a: int, b: int): int { return true; }
fun main() {
// ok to parse

View file

@ -32,7 +32,7 @@ fun test1(): int {
@method_id(102)
fun test2(value: int): int {
save_contract_data(value);
var (_, restored: auto) = get_contract_data();
var (_, restored) = get_contract_data();
return restored;
}

View file

@ -10,9 +10,9 @@ fun used_from_noncall2(): int { return int20; }
fun used_as_noncall2(): int { return 0 * 0 + used_from_noncall2() + (0 << 0); }
global unused_gv: int;
global used_gv: auto;
global used_gv: int;
fun receiveGetter(): (() -> int) { return used_as_noncall2; }
fun receiveGetter(): () -> int { return used_as_noncall2; }
@pure
fun usedButOptimizedOut(x: int): int { return x + 2; }

View file

@ -187,7 +187,7 @@ fun myTupleAt<T>(self: tuple, idx: int): T {
global tup111: tuple;
@method_id(111)
fun testForallFunctionsWithSelf() {
fun testForallFunctionsWithSelf(): (int, int, tuple) {
var t = createEmptyTuple();
tup111 = createEmptyTuple();
t.myTuplePush(10);

View file

@ -218,7 +218,7 @@ fun fixed248_log2_const(): int {
@pure
@inline
fun Pi_const_f254(): int {
var (c: auto, _) = Pi_xconst_f254();
var (c, _) = Pi_xconst_f254();
return c;
}
@ -1019,7 +1019,8 @@ fun test_nrand(n: int): tuple {
repeat (n) {
var x: int = fixed248_nrand();
var bucket: int = (abs(x) >> 243); // 255 buckets starting from x=0, each 1/32 wide
t.tset(bucket, t.tupleAt(bucket) + 1);
var at_bucket: int = t.tupleAt(bucket);
t.tset(bucket, at_bucket + 1);
}
return t;
}

View file

@ -1,6 +1,3 @@
fun unsafeGetInt<X>(any: X): int
asm "NOP";
fun foo(x: int): int {
try {
if (x == 7) {
@ -28,7 +25,7 @@ fun foo_inlineref(x: int): int {
if (x == 7) { throw (44, 2); }
return x;
} catch (_, arg) {
return unsafeGetInt(arg);
return arg as int;
}
}
@ -83,7 +80,7 @@ fun foo_big(
}
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
} catch (code, arg) {
return unsafeGetInt(arg);
return arg as int;
}
}

View file

@ -92,7 +92,7 @@ fun always_throw2(x: int) {
throw 239 + x;
}
global global_f: int -> ();
global global_f: int -> void;
@method_id(104)
fun testGlobalVarApply() {
@ -105,6 +105,30 @@ fun testGlobalVarApply() {
}
}
@method_id(105)
fun testVarApply2() {
var creator = createEmptyTuple;
var t = creator();
t.tuplePush(1);
var sizer = t.tupleSize;
return sizer(t);
}
fun getTupleLastGetter<X>(): (tuple) -> X {
return tupleLast<X>;
}
@method_id(106)
fun testVarApply3() {
var t = createEmptyTuple();
t.tuplePush(1);
t.tuplePush([2]);
var getIntAt = t.tupleAt<int>;
var getTupleFirstInt = createEmptyTuple().tupleFirst<int>;
var getTupleLastTuple = getTupleLastGetter<tuple>();
return (getIntAt(t, 0), getTupleFirstInt(t), getTupleLastTuple(t), getTupleLastGetter<tuple>()(t));
}
fun main() {}
/**
@ -112,4 +136,6 @@ fun main() {}
@testcase | 102 | | 1000
@testcase | 103 | | [ 1000 1000 0 1001 ]
@testcase | 104 | | 240
@testcase | 105 | | 1
@testcase | 106 | | 1 1 [ 2 ] [ 2 ]
*/