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