mxtypes.go raw

   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/types"
  22  	"unsafe"
  23  )
  24  
  25  // patchIntTypes makes int≡int32 and uint≡uint32 in the type checker.
  26  // Applied unconditionally on all targets. Must be called before any type
  27  // checking begins. Idempotent — safe to call multiple times.
  28  func patchIntTypes() {
  29  	// Already patched — idempotent guard.
  30  	if types.Typ[types.Int].Kind() == types.Int32 {
  31  		return
  32  	}
  33  
  34  	// Patch int.kind from Int(2) to Int32(5).
  35  	kindPtr := (*types.BasicKind)(unsafe.Pointer(types.Typ[types.Int]))
  36  	*kindPtr = types.Int32
  37  
  38  	// Patch uint.kind from Uint(7) to Uint32(10).
  39  	kindPtr = (*types.BasicKind)(unsafe.Pointer(types.Typ[types.Uint]))
  40  	*kindPtr = types.Uint32
  41  }
  42