]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/type.go
[dev.typeparams] all: merge master (296ddf2) into dev.typeparams
[gostls13.git] / src / runtime / type.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Runtime type representation.
6
7 package runtime
8
9 import (
10         "internal/abi"
11         "unsafe"
12 )
13
14 // tflag is documented in reflect/type.go.
15 //
16 // tflag values must be kept in sync with copies in:
17 //      cmd/compile/internal/reflectdata/reflect.go
18 //      cmd/link/internal/ld/decodesym.go
19 //      reflect/type.go
20 //      internal/reflectlite/type.go
21 type tflag uint8
22
23 const (
24         tflagUncommon      tflag = 1 << 0
25         tflagExtraStar     tflag = 1 << 1
26         tflagNamed         tflag = 1 << 2
27         tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
28 )
29
30 // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
31 // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
32 // ../reflect/type.go:/^type.rtype.
33 // ../internal/reflectlite/type.go:/^type.rtype.
34 type _type struct {
35         size       uintptr
36         ptrdata    uintptr // size of memory prefix holding all pointers
37         hash       uint32
38         tflag      tflag
39         align      uint8
40         fieldAlign uint8
41         kind       uint8
42         // function for comparing objects of this type
43         // (ptr to object A, ptr to object B) -> ==?
44         equal func(unsafe.Pointer, unsafe.Pointer) bool
45         // gcdata stores the GC type data for the garbage collector.
46         // If the KindGCProg bit is set in kind, gcdata is a GC program.
47         // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
48         gcdata    *byte
49         str       nameOff
50         ptrToThis typeOff
51 }
52
53 func (t *_type) string() string {
54         s := t.nameOff(t.str).name()
55         if t.tflag&tflagExtraStar != 0 {
56                 return s[1:]
57         }
58         return s
59 }
60
61 func (t *_type) uncommon() *uncommontype {
62         if t.tflag&tflagUncommon == 0 {
63                 return nil
64         }
65         switch t.kind & kindMask {
66         case kindStruct:
67                 type u struct {
68                         structtype
69                         u uncommontype
70                 }
71                 return &(*u)(unsafe.Pointer(t)).u
72         case kindPtr:
73                 type u struct {
74                         ptrtype
75                         u uncommontype
76                 }
77                 return &(*u)(unsafe.Pointer(t)).u
78         case kindFunc:
79                 type u struct {
80                         functype
81                         u uncommontype
82                 }
83                 return &(*u)(unsafe.Pointer(t)).u
84         case kindSlice:
85                 type u struct {
86                         slicetype
87                         u uncommontype
88                 }
89                 return &(*u)(unsafe.Pointer(t)).u
90         case kindArray:
91                 type u struct {
92                         arraytype
93                         u uncommontype
94                 }
95                 return &(*u)(unsafe.Pointer(t)).u
96         case kindChan:
97                 type u struct {
98                         chantype
99                         u uncommontype
100                 }
101                 return &(*u)(unsafe.Pointer(t)).u
102         case kindMap:
103                 type u struct {
104                         maptype
105                         u uncommontype
106                 }
107                 return &(*u)(unsafe.Pointer(t)).u
108         case kindInterface:
109                 type u struct {
110                         interfacetype
111                         u uncommontype
112                 }
113                 return &(*u)(unsafe.Pointer(t)).u
114         default:
115                 type u struct {
116                         _type
117                         u uncommontype
118                 }
119                 return &(*u)(unsafe.Pointer(t)).u
120         }
121 }
122
123 func (t *_type) name() string {
124         if t.tflag&tflagNamed == 0 {
125                 return ""
126         }
127         s := t.string()
128         i := len(s) - 1
129         for i >= 0 && s[i] != '.' {
130                 i--
131         }
132         return s[i+1:]
133 }
134
135 // pkgpath returns the path of the package where t was defined, if
136 // available. This is not the same as the reflect package's PkgPath
137 // method, in that it returns the package path for struct and interface
138 // types, not just named types.
139 func (t *_type) pkgpath() string {
140         if u := t.uncommon(); u != nil {
141                 return t.nameOff(u.pkgpath).name()
142         }
143         switch t.kind & kindMask {
144         case kindStruct:
145                 st := (*structtype)(unsafe.Pointer(t))
146                 return st.pkgPath.name()
147         case kindInterface:
148                 it := (*interfacetype)(unsafe.Pointer(t))
149                 return it.pkgpath.name()
150         }
151         return ""
152 }
153
154 // reflectOffs holds type offsets defined at run time by the reflect package.
155 //
156 // When a type is defined at run time, its *rtype data lives on the heap.
157 // There are a wide range of possible addresses the heap may use, that
158 // may not be representable as a 32-bit offset. Moreover the GC may
159 // one day start moving heap memory, in which case there is no stable
160 // offset that can be defined.
161 //
162 // To provide stable offsets, we add pin *rtype objects in a global map
163 // and treat the offset as an identifier. We use negative offsets that
164 // do not overlap with any compile-time module offsets.
165 //
166 // Entries are created by reflect.addReflectOff.
167 var reflectOffs struct {
168         lock mutex
169         next int32
170         m    map[int32]unsafe.Pointer
171         minv map[unsafe.Pointer]int32
172 }
173
174 func reflectOffsLock() {
175         lock(&reflectOffs.lock)
176         if raceenabled {
177                 raceacquire(unsafe.Pointer(&reflectOffs.lock))
178         }
179 }
180
181 func reflectOffsUnlock() {
182         if raceenabled {
183                 racerelease(unsafe.Pointer(&reflectOffs.lock))
184         }
185         unlock(&reflectOffs.lock)
186 }
187
188 func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
189         if off == 0 {
190                 return name{}
191         }
192         base := uintptr(ptrInModule)
193         for md := &firstmoduledata; md != nil; md = md.next {
194                 if base >= md.types && base < md.etypes {
195                         res := md.types + uintptr(off)
196                         if res > md.etypes {
197                                 println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
198                                 throw("runtime: name offset out of range")
199                         }
200                         return name{(*byte)(unsafe.Pointer(res))}
201                 }
202         }
203
204         // No module found. see if it is a run time name.
205         reflectOffsLock()
206         res, found := reflectOffs.m[int32(off)]
207         reflectOffsUnlock()
208         if !found {
209                 println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
210                 for next := &firstmoduledata; next != nil; next = next.next {
211                         println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
212                 }
213                 throw("runtime: name offset base pointer out of range")
214         }
215         return name{(*byte)(res)}
216 }
217
218 func (t *_type) nameOff(off nameOff) name {
219         return resolveNameOff(unsafe.Pointer(t), off)
220 }
221
222 func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
223         if off == 0 || off == -1 {
224                 // -1 is the sentinel value for unreachable code.
225                 // See cmd/link/internal/ld/data.go:relocsym.
226                 return nil
227         }
228         base := uintptr(ptrInModule)
229         var md *moduledata
230         for next := &firstmoduledata; next != nil; next = next.next {
231                 if base >= next.types && base < next.etypes {
232                         md = next
233                         break
234                 }
235         }
236         if md == nil {
237                 reflectOffsLock()
238                 res := reflectOffs.m[int32(off)]
239                 reflectOffsUnlock()
240                 if res == nil {
241                         println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
242                         for next := &firstmoduledata; next != nil; next = next.next {
243                                 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
244                         }
245                         throw("runtime: type offset base pointer out of range")
246                 }
247                 return (*_type)(res)
248         }
249         if t := md.typemap[off]; t != nil {
250                 return t
251         }
252         res := md.types + uintptr(off)
253         if res > md.etypes {
254                 println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
255                 throw("runtime: type offset out of range")
256         }
257         return (*_type)(unsafe.Pointer(res))
258 }
259
260 func (t *_type) typeOff(off typeOff) *_type {
261         return resolveTypeOff(unsafe.Pointer(t), off)
262 }
263
264 func (t *_type) textOff(off textOff) unsafe.Pointer {
265         if off == -1 {
266                 // -1 is the sentinel value for unreachable code.
267                 // See cmd/link/internal/ld/data.go:relocsym.
268                 return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
269         }
270         base := uintptr(unsafe.Pointer(t))
271         var md *moduledata
272         for next := &firstmoduledata; next != nil; next = next.next {
273                 if base >= next.types && base < next.etypes {
274                         md = next
275                         break
276                 }
277         }
278         if md == nil {
279                 reflectOffsLock()
280                 res := reflectOffs.m[int32(off)]
281                 reflectOffsUnlock()
282                 if res == nil {
283                         println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
284                         for next := &firstmoduledata; next != nil; next = next.next {
285                                 println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
286                         }
287                         throw("runtime: text offset base pointer out of range")
288                 }
289                 return res
290         }
291         res := uintptr(0)
292
293         // The text, or instruction stream is generated as one large buffer.  The off (offset) for a method is
294         // its offset within this buffer.  If the total text size gets too large, there can be issues on platforms like ppc64 if
295         // the target of calls are too far for the call instruction.  To resolve the large text issue, the text is split
296         // into multiple text sections to allow the linker to generate long calls when necessary.  When this happens, the vaddr
297         // for each text section is set to its offset within the text.  Each method's offset is compared against the section
298         // vaddrs and sizes to determine the containing section.  Then the section relative offset is added to the section's
299         // relocated baseaddr to compute the method addess.
300
301         if len(md.textsectmap) > 1 {
302                 for i := range md.textsectmap {
303                         sectaddr := md.textsectmap[i].vaddr
304                         sectlen := md.textsectmap[i].length
305                         if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
306                                 res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
307                                 break
308                         }
309                 }
310         } else {
311                 // single text section
312                 res = md.text + uintptr(off)
313         }
314
315         if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
316                 println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
317                 throw("runtime: text offset out of range")
318         }
319         return unsafe.Pointer(res)
320 }
321
322 func (t *functype) in() []*_type {
323         // See funcType in reflect/type.go for details on data layout.
324         uadd := uintptr(unsafe.Sizeof(functype{}))
325         if t.typ.tflag&tflagUncommon != 0 {
326                 uadd += unsafe.Sizeof(uncommontype{})
327         }
328         return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
329 }
330
331 func (t *functype) out() []*_type {
332         // See funcType in reflect/type.go for details on data layout.
333         uadd := uintptr(unsafe.Sizeof(functype{}))
334         if t.typ.tflag&tflagUncommon != 0 {
335                 uadd += unsafe.Sizeof(uncommontype{})
336         }
337         outCount := t.outCount & (1<<15 - 1)
338         return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
339 }
340
341 func (t *functype) dotdotdot() bool {
342         return t.outCount&(1<<15) != 0
343 }
344
345 type nameOff int32
346 type typeOff int32
347 type textOff int32
348
349 type method struct {
350         name nameOff
351         mtyp typeOff
352         ifn  textOff
353         tfn  textOff
354 }
355
356 type uncommontype struct {
357         pkgpath nameOff
358         mcount  uint16 // number of methods
359         xcount  uint16 // number of exported methods
360         moff    uint32 // offset from this uncommontype to [mcount]method
361         _       uint32 // unused
362 }
363
364 type imethod struct {
365         name nameOff
366         ityp typeOff
367 }
368
369 type interfacetype struct {
370         typ     _type
371         pkgpath name
372         mhdr    []imethod
373 }
374
375 type maptype struct {
376         typ    _type
377         key    *_type
378         elem   *_type
379         bucket *_type // internal type representing a hash bucket
380         // function for hashing keys (ptr to key, seed) -> hash
381         hasher     func(unsafe.Pointer, uintptr) uintptr
382         keysize    uint8  // size of key slot
383         elemsize   uint8  // size of elem slot
384         bucketsize uint16 // size of bucket
385         flags      uint32
386 }
387
388 // Note: flag values must match those used in the TMAP case
389 // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
390 func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
391         return mt.flags&1 != 0
392 }
393 func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself
394         return mt.flags&2 != 0
395 }
396 func (mt *maptype) reflexivekey() bool { // true if k==k for all keys
397         return mt.flags&4 != 0
398 }
399 func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite
400         return mt.flags&8 != 0
401 }
402 func (mt *maptype) hashMightPanic() bool { // true if hash function might panic
403         return mt.flags&16 != 0
404 }
405
406 type arraytype struct {
407         typ   _type
408         elem  *_type
409         slice *_type
410         len   uintptr
411 }
412
413 type chantype struct {
414         typ  _type
415         elem *_type
416         dir  uintptr
417 }
418
419 type slicetype struct {
420         typ  _type
421         elem *_type
422 }
423
424 type functype struct {
425         typ      _type
426         inCount  uint16
427         outCount uint16
428 }
429
430 type ptrtype struct {
431         typ  _type
432         elem *_type
433 }
434
435 type structfield struct {
436         name       name
437         typ        *_type
438         offsetAnon uintptr
439 }
440
441 func (f *structfield) offset() uintptr {
442         return f.offsetAnon >> 1
443 }
444
445 type structtype struct {
446         typ     _type
447         pkgPath name
448         fields  []structfield
449 }
450
451 // name is an encoded type name with optional extra data.
452 // See reflect/type.go for details.
453 type name struct {
454         bytes *byte
455 }
456
457 func (n name) data(off int) *byte {
458         return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
459 }
460
461 func (n name) isExported() bool {
462         return (*n.bytes)&(1<<0) != 0
463 }
464
465 func (n name) readvarint(off int) (int, int) {
466         v := 0
467         for i := 0; ; i++ {
468                 x := *n.data(off + i)
469                 v += int(x&0x7f) << (7 * i)
470                 if x&0x80 == 0 {
471                         return i + 1, v
472                 }
473         }
474 }
475
476 func (n name) name() (s string) {
477         if n.bytes == nil {
478                 return ""
479         }
480         i, l := n.readvarint(1)
481         if l == 0 {
482                 return ""
483         }
484         hdr := (*stringStruct)(unsafe.Pointer(&s))
485         hdr.str = unsafe.Pointer(n.data(1 + i))
486         hdr.len = l
487         return
488 }
489
490 func (n name) tag() (s string) {
491         if *n.data(0)&(1<<1) == 0 {
492                 return ""
493         }
494         i, l := n.readvarint(1)
495         i2, l2 := n.readvarint(1 + i + l)
496         hdr := (*stringStruct)(unsafe.Pointer(&s))
497         hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
498         hdr.len = l2
499         return
500 }
501
502 func (n name) pkgPath() string {
503         if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
504                 return ""
505         }
506         i, l := n.readvarint(1)
507         off := 1 + i + l
508         if *n.data(0)&(1<<1) != 0 {
509                 i2, l2 := n.readvarint(off)
510                 off += i2 + l2
511         }
512         var nameOff nameOff
513         copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
514         pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
515         return pkgPathName.name()
516 }
517
518 func (n name) isBlank() bool {
519         if n.bytes == nil {
520                 return false
521         }
522         _, l := n.readvarint(1)
523         return l == 1 && *n.data(2) == '_'
524 }
525
526 // typelinksinit scans the types from extra modules and builds the
527 // moduledata typemap used to de-duplicate type pointers.
528 func typelinksinit() {
529         if firstmoduledata.next == nil {
530                 return
531         }
532         typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
533
534         modules := activeModules()
535         prev := modules[0]
536         for _, md := range modules[1:] {
537                 // Collect types from the previous module into typehash.
538         collect:
539                 for _, tl := range prev.typelinks {
540                         var t *_type
541                         if prev.typemap == nil {
542                                 t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
543                         } else {
544                                 t = prev.typemap[typeOff(tl)]
545                         }
546                         // Add to typehash if not seen before.
547                         tlist := typehash[t.hash]
548                         for _, tcur := range tlist {
549                                 if tcur == t {
550                                         continue collect
551                                 }
552                         }
553                         typehash[t.hash] = append(tlist, t)
554                 }
555
556                 if md.typemap == nil {
557                         // If any of this module's typelinks match a type from a
558                         // prior module, prefer that prior type by adding the offset
559                         // to this module's typemap.
560                         tm := make(map[typeOff]*_type, len(md.typelinks))
561                         pinnedTypemaps = append(pinnedTypemaps, tm)
562                         md.typemap = tm
563                         for _, tl := range md.typelinks {
564                                 t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
565                                 for _, candidate := range typehash[t.hash] {
566                                         seen := map[_typePair]struct{}{}
567                                         if typesEqual(t, candidate, seen) {
568                                                 t = candidate
569                                                 break
570                                         }
571                                 }
572                                 md.typemap[typeOff(tl)] = t
573                         }
574                 }
575
576                 prev = md
577         }
578 }
579
580 type _typePair struct {
581         t1 *_type
582         t2 *_type
583 }
584
585 // typesEqual reports whether two types are equal.
586 //
587 // Everywhere in the runtime and reflect packages, it is assumed that
588 // there is exactly one *_type per Go type, so that pointer equality
589 // can be used to test if types are equal. There is one place that
590 // breaks this assumption: buildmode=shared. In this case a type can
591 // appear as two different pieces of memory. This is hidden from the
592 // runtime and reflect package by the per-module typemap built in
593 // typelinksinit. It uses typesEqual to map types from later modules
594 // back into earlier ones.
595 //
596 // Only typelinksinit needs this function.
597 func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
598         tp := _typePair{t, v}
599         if _, ok := seen[tp]; ok {
600                 return true
601         }
602
603         // mark these types as seen, and thus equivalent which prevents an infinite loop if
604         // the two types are identical, but recursively defined and loaded from
605         // different modules
606         seen[tp] = struct{}{}
607
608         if t == v {
609                 return true
610         }
611         kind := t.kind & kindMask
612         if kind != v.kind&kindMask {
613                 return false
614         }
615         if t.string() != v.string() {
616                 return false
617         }
618         ut := t.uncommon()
619         uv := v.uncommon()
620         if ut != nil || uv != nil {
621                 if ut == nil || uv == nil {
622                         return false
623                 }
624                 pkgpatht := t.nameOff(ut.pkgpath).name()
625                 pkgpathv := v.nameOff(uv.pkgpath).name()
626                 if pkgpatht != pkgpathv {
627                         return false
628                 }
629         }
630         if kindBool <= kind && kind <= kindComplex128 {
631                 return true
632         }
633         switch kind {
634         case kindString, kindUnsafePointer:
635                 return true
636         case kindArray:
637                 at := (*arraytype)(unsafe.Pointer(t))
638                 av := (*arraytype)(unsafe.Pointer(v))
639                 return typesEqual(at.elem, av.elem, seen) && at.len == av.len
640         case kindChan:
641                 ct := (*chantype)(unsafe.Pointer(t))
642                 cv := (*chantype)(unsafe.Pointer(v))
643                 return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
644         case kindFunc:
645                 ft := (*functype)(unsafe.Pointer(t))
646                 fv := (*functype)(unsafe.Pointer(v))
647                 if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
648                         return false
649                 }
650                 tin, vin := ft.in(), fv.in()
651                 for i := 0; i < len(tin); i++ {
652                         if !typesEqual(tin[i], vin[i], seen) {
653                                 return false
654                         }
655                 }
656                 tout, vout := ft.out(), fv.out()
657                 for i := 0; i < len(tout); i++ {
658                         if !typesEqual(tout[i], vout[i], seen) {
659                                 return false
660                         }
661                 }
662                 return true
663         case kindInterface:
664                 it := (*interfacetype)(unsafe.Pointer(t))
665                 iv := (*interfacetype)(unsafe.Pointer(v))
666                 if it.pkgpath.name() != iv.pkgpath.name() {
667                         return false
668                 }
669                 if len(it.mhdr) != len(iv.mhdr) {
670                         return false
671                 }
672                 for i := range it.mhdr {
673                         tm := &it.mhdr[i]
674                         vm := &iv.mhdr[i]
675                         // Note the mhdr array can be relocated from
676                         // another module. See #17724.
677                         tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
678                         vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
679                         if tname.name() != vname.name() {
680                                 return false
681                         }
682                         if tname.pkgPath() != vname.pkgPath() {
683                                 return false
684                         }
685                         tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
686                         vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
687                         if !typesEqual(tityp, vityp, seen) {
688                                 return false
689                         }
690                 }
691                 return true
692         case kindMap:
693                 mt := (*maptype)(unsafe.Pointer(t))
694                 mv := (*maptype)(unsafe.Pointer(v))
695                 return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
696         case kindPtr:
697                 pt := (*ptrtype)(unsafe.Pointer(t))
698                 pv := (*ptrtype)(unsafe.Pointer(v))
699                 return typesEqual(pt.elem, pv.elem, seen)
700         case kindSlice:
701                 st := (*slicetype)(unsafe.Pointer(t))
702                 sv := (*slicetype)(unsafe.Pointer(v))
703                 return typesEqual(st.elem, sv.elem, seen)
704         case kindStruct:
705                 st := (*structtype)(unsafe.Pointer(t))
706                 sv := (*structtype)(unsafe.Pointer(v))
707                 if len(st.fields) != len(sv.fields) {
708                         return false
709                 }
710                 if st.pkgPath.name() != sv.pkgPath.name() {
711                         return false
712                 }
713                 for i := range st.fields {
714                         tf := &st.fields[i]
715                         vf := &sv.fields[i]
716                         if tf.name.name() != vf.name.name() {
717                                 return false
718                         }
719                         if !typesEqual(tf.typ, vf.typ, seen) {
720                                 return false
721                         }
722                         if tf.name.tag() != vf.name.tag() {
723                                 return false
724                         }
725                         if tf.offsetAnon != vf.offsetAnon {
726                                 return false
727                         }
728                 }
729                 return true
730         default:
731                 println("runtime: impossible type kind", kind)
732                 throw("runtime: impossible type kind")
733                 return false
734         }
735 }