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