1 package loader
2 3 // Moxie type unification.
4 //
5 // Moxie defines int as always 32 bits on all targets. This file patches
6 // Go's type checker to agree: int becomes type-identical to int32, and
7 // uint becomes type-identical to uint32. This eliminates the need for
8 // int32(len(...)) casts throughout all Moxie code.
9 //
10 // The patch works by overwriting the kind field of types.Typ[Int] and
11 // types.Typ[Uint] via unsafe. The Basic struct layout is:
12 // {kind BasicKind, info BasicInfo, name string}
13 // with kind at offset 0. Type identity in go/types uses kind comparison
14 // (x.kind == y.kind), so after patching, Identical(int, int32) returns true.
15 //
16 // On 64-bit targets, slice headers still use uintptr-sized (i64) len/cap
17 // internally. The compiler inserts trunc/ext at the int boundary (len/cap
18 // builtins, make, indexing). Max addressable length is 2^31-1.
19 20 import (
21 "go/token"
22 "go/types"
23 "unsafe"
24 )
25 26 // patchIntTypes makes int≡int32 and uint≡uint32 in the type checker.
27 // Applied unconditionally on all targets. Must be called before any type
28 // checking begins. Idempotent - safe to call multiple times.
29 //
30 // Also registers push/pop/resize as universe-scope functions so go/types
31 // accepts them in all packages including the runtime.
32 func patchIntTypes() {
33 // Already patched - idempotent guard.
34 if types.Typ[types.Int].Kind() == types.Int32 {
35 return
36 }
37 38 // Patch int.kind from Int(2) to Int32(5).
39 kindPtr := (*types.BasicKind)(unsafe.Pointer(types.Typ[types.Int]))
40 *kindPtr = types.Int32
41 42 // Patch uint.kind from Uint(7) to Uint32(10).
43 kindPtr = (*types.BasicKind)(unsafe.Pointer(types.Typ[types.Uint]))
44 *kindPtr = types.Uint32
45 46 // Register push/pop/resize in go/types universe scope.
47 // push(s, v...) - variadic, mutates slice length, no return.
48 // pop(s) - returns element, mutates slice length.
49 // resize(s, n) - mutates slice length, no return.
50 // Typed as func(...any) any so go/types accepts any argument types.
51 // The real type checking happens in the Moxie type checker.
52 anySlice := types.NewSlice(types.Universe.Lookup("any").Type())
53 pushSig := types.NewSignatureType(nil, nil, nil,
54 types.NewTuple(types.NewVar(token.NoPos, nil, "args", anySlice)),
55 nil, true)
56 types.Universe.Insert(types.NewFunc(token.NoPos, nil, "push", pushSig))
57 58 popSig := types.NewSignatureType(nil, nil, nil,
59 types.NewTuple(types.NewVar(token.NoPos, nil, "s", anySlice)),
60 types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("any").Type())),
61 false)
62 types.Universe.Insert(types.NewFunc(token.NoPos, nil, "pop", popSig))
63 64 resizeSig := types.NewSignatureType(nil, nil, nil,
65 types.NewTuple(
66 types.NewVar(token.NoPos, nil, "s", anySlice),
67 types.NewVar(token.NoPos, nil, "n", types.Typ[types.Int32]),
68 ),
69 nil, false)
70 types.Universe.Insert(types.NewFunc(token.NoPos, nil, "resize", resizeSig))
71 }
72