bridge.go raw

   1  // Package bridge translates go/types objects into typecheck objects.
   2  // It is a temporary shim used during B1 validation: the loader uses go/types
   3  // to parse and type-check packages, and this bridge exposes the results to
   4  // the native typecheck.Checker so it can look up imported names and types.
   5  //
   6  // Removed in B3 when the native checker replaces go/types entirely.
   7  package bridge
   8  
   9  import (
  10  	"go/types"
  11  	"sync"
  12  	"unsafe"
  13  
  14  	"moxie/typecheck"
  15  )
  16  
  17  // Importer wraps a go/types package map and satisfies typecheck.Importer.
  18  // Each package is translated lazily and cached.
  19  type Importer struct {
  20  	mu    sync.Mutex
  21  	pkgs  map[string]*types.Package // import path → go/types Package
  22  	cache map[string]*typecheck.Package
  23  }
  24  
  25  // New returns an Importer pre-loaded with the given package map.
  26  func New(pkgs map[string]*types.Package) *Importer {
  27  	return &Importer{
  28  		pkgs:  pkgs,
  29  		cache: map[string]*typecheck.Package{},
  30  	}
  31  }
  32  
  33  // Import satisfies typecheck.Importer.
  34  func (imp *Importer) Import(path string) (*typecheck.Package, error) {
  35  	imp.mu.Lock()
  36  	defer imp.mu.Unlock()
  37  	if p, ok := imp.cache[path]; ok {
  38  		return p, nil
  39  	}
  40  	gp, ok := imp.pkgs[path]
  41  	if !ok {
  42  		// Return an empty package — the checker will report "undefined"
  43  		// for any names not found, which is the correct B1 behaviour.
  44  		p := typecheck.NewPackage(path, "")
  45  		imp.cache[path] = p
  46  		return p, nil
  47  	}
  48  	p := translatePackage(gp, imp)
  49  	imp.cache[path] = p
  50  	return p, nil
  51  }
  52  
  53  // typeCache maps go/types.Type values to their typecheck equivalents.
  54  // Keyed by pointer identity (uintptr extracted from the interface data word)
  55  // to avoid the runtime's typehash recursing into complex recursive types.
  56  type typeCache struct {
  57  	m     map[uintptr]typecheck.Type
  58  	depth int // recursion depth limiter
  59  }
  60  
  61  func newTypeCache() *typeCache { return &typeCache{m: map[uintptr]typecheck.Type{}} }
  62  
  63  // typePtr extracts the data pointer from a types.Type interface value.
  64  // This gives stable pointer identity without triggering recursive hashing.
  65  func typePtr(t types.Type) uintptr {
  66  	type iface struct{ typ, ptr uintptr }
  67  	return (*iface)(unsafe.Pointer(&t)).ptr
  68  }
  69  
  70  func translatePackage(gp *types.Package, imp *Importer) *typecheck.Package {
  71  	p := typecheck.NewPackage(gp.Path(), gp.Name())
  72  	cache := newTypeCache()
  73  	scope := gp.Scope()
  74  	for _, name := range scope.Names() {
  75  		obj := scope.Lookup(name)
  76  		if obj == nil {
  77  			continue
  78  		}
  79  		tc := translateObject(obj, p, cache, imp)
  80  		if tc != nil {
  81  			p.Scope().Insert(tc)
  82  		}
  83  	}
  84  	p.MarkComplete()
  85  	return p
  86  }
  87  
  88  func translateObject(obj types.Object, pkg *typecheck.Package, cache *typeCache, imp *Importer) typecheck.Object {
  89  	typ := translateType(obj.Type(), cache, imp)
  90  	switch obj := obj.(type) {
  91  	case *types.TypeName:
  92  		return typecheck.NewTypeName(pkg, obj.Name(), typ)
  93  	case *types.Func:
  94  		if sig, ok := typ.(*typecheck.Signature); ok {
  95  			return typecheck.NewFunc(pkg, obj.Name(), sig)
  96  		}
  97  		return typecheck.NewFunc(pkg, obj.Name(), nil)
  98  	case *types.Var:
  99  		return typecheck.NewVar(pkg, obj.Name(), typ)
 100  	case *types.Const:
 101  		return typecheck.NewConst(pkg, obj.Name(), typ, obj.Val())
 102  	case *types.PkgName:
 103  		var imported *typecheck.Package
 104  		if obj.Imported() != nil {
 105  			imported, _ = imp.Import(obj.Imported().Path())
 106  		}
 107  		return typecheck.NewPkgName(pkg, obj.Name(), imported)
 108  	}
 109  	return nil
 110  }
 111  
 112  // translateType converts a go/types.Type to a typecheck.Type.
 113  // The cache prevents infinite recursion on recursive types.
 114  func translateType(t types.Type, cache *typeCache, imp *Importer) typecheck.Type {
 115  	if t == nil {
 116  		return nil
 117  	}
 118  	key := typePtr(t)
 119  	if tc, ok := cache.m[key]; ok {
 120  		return tc
 121  	}
 122  	// Depth limiter: skip translation for very deep type hierarchies.
 123  	// The native checker will report "undefined" for anything that can't
 124  	// be resolved, which is acceptable during B1 validation.
 125  	cache.depth++
 126  	defer func() { cache.depth-- }()
 127  	if cache.depth > 150 {
 128  		return nil
 129  	}
 130  
 131  	switch t := t.(type) {
 132  	case *types.Basic:
 133  		return translateBasic(t)
 134  
 135  	case *types.Pointer:
 136  		elem := translateType(t.Elem(), cache, imp)
 137  		return typecheck.NewPointer(elem)
 138  
 139  	case *types.Array:
 140  		elem := translateType(t.Elem(), cache, imp)
 141  		return typecheck.NewArray(elem, t.Len())
 142  
 143  	case *types.Slice:
 144  		elem := translateType(t.Elem(), cache, imp)
 145  		return typecheck.NewSlice(elem)
 146  
 147  	case *types.Map:
 148  		key := translateType(t.Key(), cache, imp)
 149  		elem := translateType(t.Elem(), cache, imp)
 150  		return typecheck.NewMap(key, elem)
 151  
 152  	case *types.Chan:
 153  		elem := translateType(t.Elem(), cache, imp)
 154  		var dir typecheck.ChanDir
 155  		switch t.Dir() {
 156  		case types.SendOnly:
 157  			dir = typecheck.SendOnly
 158  		case types.RecvOnly:
 159  			dir = typecheck.RecvOnly
 160  		default:
 161  			dir = typecheck.SendRecv
 162  		}
 163  		return typecheck.NewChan(dir, elem)
 164  
 165  	case *types.Struct:
 166  		var fields []*typecheck.Var
 167  		var tags []string
 168  		for i := 0; i < t.NumFields(); i++ {
 169  			f := t.Field(i)
 170  			ft := translateType(f.Type(), cache, imp)
 171  			fields = append(fields, typecheck.NewField(nil, f.Name(), ft, f.Anonymous()))
 172  			tags = append(tags, t.Tag(i))
 173  		}
 174  		return typecheck.NewStruct(fields, tags)
 175  
 176  	case *types.Interface:
 177  		var methods []*typecheck.IfaceMethod
 178  		for i := 0; i < t.NumExplicitMethods(); i++ {
 179  			m := t.ExplicitMethod(i)
 180  			sig, _ := translateType(m.Type(), cache, imp).(*typecheck.Signature)
 181  			methods = append(methods, typecheck.NewIfaceMethod(m.Name(), sig))
 182  		}
 183  		var embeds []typecheck.Type
 184  		for i := 0; i < t.NumEmbeddeds(); i++ {
 185  			embeds = append(embeds, translateType(t.EmbeddedType(i), cache, imp))
 186  		}
 187  		iface := typecheck.NewInterface(methods, embeds)
 188  		iface.Complete()
 189  		return iface
 190  
 191  	case *types.Signature:
 192  		var recv *typecheck.Var
 193  		if r := t.Recv(); r != nil {
 194  			recv = typecheck.NewVar(nil, r.Name(), translateType(r.Type(), cache, imp))
 195  		}
 196  		params := translateTuple(t.Params(), cache, imp)
 197  		results := translateTuple(t.Results(), cache, imp)
 198  		return typecheck.NewSignature(recv, params, results, t.Variadic())
 199  
 200  	case *types.Named:
 201  		// Reserve a slot in the cache before recursing to handle cycles.
 202  		obj := typecheck.NewTypeName(nil, t.Obj().Name(), nil)
 203  		named := typecheck.NewNamed(obj, nil)
 204  		cache.m[typePtr(t)] = named
 205  		underlying := translateType(t.Underlying(), cache, imp)
 206  		named.SetUnderlying(underlying)
 207  		// Translate methods.
 208  		for i := 0; i < t.NumMethods(); i++ {
 209  			m := t.Method(i)
 210  			sig, _ := translateType(m.Type(), cache, imp).(*typecheck.Signature)
 211  			named.AddMethod(typecheck.NewFunc(nil, m.Name(), sig))
 212  		}
 213  		return named
 214  
 215  	case *types.TypeParam:
 216  		obj := typecheck.NewTypeName(nil, t.Obj().Name(), nil)
 217  		return typecheck.NewTypeParam(obj, nil)
 218  
 219  	case *types.Alias:
 220  		return translateType(types.Unalias(t), cache, imp)
 221  	}
 222  	return nil
 223  }
 224  
 225  func translateTuple(t *types.Tuple, cache *typeCache, imp *Importer) *typecheck.Tuple {
 226  	if t == nil || t.Len() == 0 {
 227  		return nil
 228  	}
 229  	vars := make([]*typecheck.Var, t.Len())
 230  	for i := range vars {
 231  		v := t.At(i)
 232  		vars[i] = typecheck.NewVar(nil, v.Name(), translateType(v.Type(), cache, imp))
 233  	}
 234  	return typecheck.NewTuple(vars...)
 235  }
 236  
 237  func translateBasic(t *types.Basic) *typecheck.Basic {
 238  	switch t.Kind() {
 239  	case types.Bool:
 240  		return typecheck.Typ[typecheck.Bool]
 241  	case types.Int8:
 242  		return typecheck.Typ[typecheck.Int8]
 243  	case types.Int16:
 244  		return typecheck.Typ[typecheck.Int16]
 245  	case types.Int32, types.Int: // Moxie: int≡int32
 246  		return typecheck.Typ[typecheck.Int32]
 247  	case types.Int64:
 248  		return typecheck.Typ[typecheck.Int64]
 249  	case types.Uint8:
 250  		return typecheck.Typ[typecheck.Uint8]
 251  	case types.Uint16:
 252  		return typecheck.Typ[typecheck.Uint16]
 253  	case types.Uint32, types.Uint: // Moxie: uint≡uint32
 254  		return typecheck.Typ[typecheck.Uint32]
 255  	case types.Uint64, types.Uintptr:
 256  		return typecheck.Typ[typecheck.Uint64]
 257  	case types.Float32:
 258  		return typecheck.Typ[typecheck.Float32]
 259  	case types.Float64:
 260  		return typecheck.Typ[typecheck.Float64]
 261  	case types.String:
 262  		return typecheck.Typ[typecheck.String]
 263  	case types.UnsafePointer:
 264  		return typecheck.Typ[typecheck.UnsafePointer]
 265  	case types.UntypedBool:
 266  		return typecheck.Typ[typecheck.UntypedBool]
 267  	case types.UntypedInt:
 268  		return typecheck.Typ[typecheck.UntypedInt]
 269  	case types.UntypedRune:
 270  		return typecheck.Typ[typecheck.UntypedRune]
 271  	case types.UntypedFloat:
 272  		return typecheck.Typ[typecheck.UntypedFloat]
 273  	case types.UntypedString:
 274  		return typecheck.Typ[typecheck.UntypedString]
 275  	case types.UntypedNil:
 276  		return typecheck.Typ[typecheck.UntypedNil]
 277  	}
 278  	return typecheck.Typ[typecheck.Invalid]
 279  }
 280