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