github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/internal/gcimporter/bexport.go (about) 1 // Copyright 2016 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 // Binary package export. 6 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; 7 // see that file for specification of the format. 8 9 package gcimporter 10 11 import ( 12 "bytes" 13 "encoding/binary" 14 "fmt" 15 "go/ast" 16 "go/constant" 17 "go/token" 18 "go/types" 19 "math" 20 "math/big" 21 "sort" 22 "strings" 23 ) 24 25 // If debugFormat is set, each integer and string value is preceded by a marker 26 // and position information in the encoding. This mechanism permits an importer 27 // to recognize immediately when it is out of sync. The importer recognizes this 28 // mode automatically (i.e., it can import export data produced with debugging 29 // support even if debugFormat is not set at the time of import). This mode will 30 // lead to massively larger export data (by a factor of 2 to 3) and should only 31 // be enabled during development and debugging. 32 // 33 // NOTE: This flag is the first flag to enable if importing dies because of 34 // (suspected) format errors, and whenever a change is made to the format. 35 const debugFormat = false // default: false 36 37 // Current export format version. Increase with each format change. 38 // Note: The latest binary (non-indexed) export format is at version 6. 39 // This exporter is still at level 4, but it doesn't matter since 40 // the binary importer can handle older versions just fine. 41 // 6: package height (CL 105038) -- NOT IMPLEMENTED HERE 42 // 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMEMTED HERE 43 // 4: type name objects support type aliases, uses aliasTag 44 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) 45 // 2: removed unused bool in ODCL export (compiler only) 46 // 1: header format change (more regular), export package for _ struct fields 47 // 0: Go1.7 encoding 48 const exportVersion = 4 49 50 // trackAllTypes enables cycle tracking for all types, not just named 51 // types. The existing compiler invariants assume that unnamed types 52 // that are not completely set up are not used, or else there are spurious 53 // errors. 54 // If disabled, only named types are tracked, possibly leading to slightly 55 // less efficient encoding in rare cases. It also prevents the export of 56 // some corner-case type declarations (but those are not handled correctly 57 // with with the textual export format either). 58 // TODO(gri) enable and remove once issues caused by it are fixed 59 const trackAllTypes = false 60 61 type exporter struct { 62 fset *token.FileSet 63 out bytes.Buffer 64 65 // object -> index maps, indexed in order of serialization 66 strIndex map[string]int 67 pkgIndex map[*types.Package]int 68 typIndex map[types.Type]int 69 70 // position encoding 71 posInfoFormat bool 72 prevFile string 73 prevLine int 74 75 // debugging support 76 written int // bytes written 77 indent int // for trace 78 } 79 80 // internalError represents an error generated inside this package. 81 type internalError string 82 83 func (e internalError) Error() string { return "gcimporter: " + string(e) } 84 85 func internalErrorf(format string, args ...interface{}) error { 86 return internalError(fmt.Sprintf(format, args...)) 87 } 88 89 // BExportData returns binary export data for pkg. 90 // If no file set is provided, position info will be missing. 91 func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { 92 if !debug { 93 defer func() { 94 if e := recover(); e != nil { 95 if ierr, ok := e.(internalError); ok { 96 err = ierr 97 return 98 } 99 // Not an internal error; panic again. 100 panic(e) 101 } 102 }() 103 } 104 105 p := exporter{ 106 fset: fset, 107 strIndex: map[string]int{"": 0}, // empty string is mapped to 0 108 pkgIndex: make(map[*types.Package]int), 109 typIndex: make(map[types.Type]int), 110 posInfoFormat: true, // TODO(gri) might become a flag, eventually 111 } 112 113 // write version info 114 // The version string must start with "version %d" where %d is the version 115 // number. Additional debugging information may follow after a blank; that 116 // text is ignored by the importer. 117 p.rawStringln(fmt.Sprintf("version %d", exportVersion)) 118 var debug string 119 if debugFormat { 120 debug = "debug" 121 } 122 p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly 123 p.bool(trackAllTypes) 124 p.bool(p.posInfoFormat) 125 126 // --- generic export data --- 127 128 // populate type map with predeclared "known" types 129 for index, typ := range predeclared() { 130 p.typIndex[typ] = index 131 } 132 if len(p.typIndex) != len(predeclared()) { 133 return nil, internalError("duplicate entries in type map?") 134 } 135 136 // write package data 137 p.pkg(pkg, true) 138 if trace { 139 p.tracef("\n") 140 } 141 142 // write objects 143 objcount := 0 144 scope := pkg.Scope() 145 for _, name := range scope.Names() { 146 if !ast.IsExported(name) { 147 continue 148 } 149 if trace { 150 p.tracef("\n") 151 } 152 p.obj(scope.Lookup(name)) 153 objcount++ 154 } 155 156 // indicate end of list 157 if trace { 158 p.tracef("\n") 159 } 160 p.tag(endTag) 161 162 // for self-verification only (redundant) 163 p.int(objcount) 164 165 if trace { 166 p.tracef("\n") 167 } 168 169 // --- end of export data --- 170 171 return p.out.Bytes(), nil 172 } 173 174 func (p *exporter) pkg(pkg *types.Package, emptypath bool) { 175 if pkg == nil { 176 panic(internalError("unexpected nil pkg")) 177 } 178 179 // if we saw the package before, write its index (>= 0) 180 if i, ok := p.pkgIndex[pkg]; ok { 181 p.index('P', i) 182 return 183 } 184 185 // otherwise, remember the package, write the package tag (< 0) and package data 186 if trace { 187 p.tracef("P%d = { ", len(p.pkgIndex)) 188 defer p.tracef("} ") 189 } 190 p.pkgIndex[pkg] = len(p.pkgIndex) 191 192 p.tag(packageTag) 193 p.string(pkg.Name()) 194 if emptypath { 195 p.string("") 196 } else { 197 p.string(pkg.Path()) 198 } 199 } 200 201 func (p *exporter) obj(obj types.Object) { 202 switch obj := obj.(type) { 203 case *types.Const: 204 p.tag(constTag) 205 p.pos(obj) 206 p.qualifiedName(obj) 207 p.typ(obj.Type()) 208 p.value(obj.Val()) 209 210 case *types.TypeName: 211 if obj.IsAlias() { 212 p.tag(aliasTag) 213 p.pos(obj) 214 p.qualifiedName(obj) 215 } else { 216 p.tag(typeTag) 217 } 218 p.typ(obj.Type()) 219 220 case *types.Var: 221 p.tag(varTag) 222 p.pos(obj) 223 p.qualifiedName(obj) 224 p.typ(obj.Type()) 225 226 case *types.Func: 227 p.tag(funcTag) 228 p.pos(obj) 229 p.qualifiedName(obj) 230 sig := obj.Type().(*types.Signature) 231 p.paramList(sig.Params(), sig.Variadic()) 232 p.paramList(sig.Results(), false) 233 234 default: 235 panic(internalErrorf("unexpected object %v (%T)", obj, obj)) 236 } 237 } 238 239 func (p *exporter) pos(obj types.Object) { 240 if !p.posInfoFormat { 241 return 242 } 243 244 file, line := p.fileLine(obj) 245 if file == p.prevFile { 246 // common case: write line delta 247 // delta == 0 means different file or no line change 248 delta := line - p.prevLine 249 p.int(delta) 250 if delta == 0 { 251 p.int(-1) // -1 means no file change 252 } 253 } else { 254 // different file 255 p.int(0) 256 // Encode filename as length of common prefix with previous 257 // filename, followed by (possibly empty) suffix. Filenames 258 // frequently share path prefixes, so this can save a lot 259 // of space and make export data size less dependent on file 260 // path length. The suffix is unlikely to be empty because 261 // file names tend to end in ".go". 262 n := commonPrefixLen(p.prevFile, file) 263 p.int(n) // n >= 0 264 p.string(file[n:]) // write suffix only 265 p.prevFile = file 266 p.int(line) 267 } 268 p.prevLine = line 269 } 270 271 func (p *exporter) fileLine(obj types.Object) (file string, line int) { 272 if p.fset != nil { 273 pos := p.fset.Position(obj.Pos()) 274 file = pos.Filename 275 line = pos.Line 276 } 277 return 278 } 279 280 func commonPrefixLen(a, b string) int { 281 if len(a) > len(b) { 282 a, b = b, a 283 } 284 // len(a) <= len(b) 285 i := 0 286 for i < len(a) && a[i] == b[i] { 287 i++ 288 } 289 return i 290 } 291 292 func (p *exporter) qualifiedName(obj types.Object) { 293 p.string(obj.Name()) 294 p.pkg(obj.Pkg(), false) 295 } 296 297 func (p *exporter) typ(t types.Type) { 298 if t == nil { 299 panic(internalError("nil type")) 300 } 301 302 // Possible optimization: Anonymous pointer types *T where 303 // T is a named type are common. We could canonicalize all 304 // such types *T to a single type PT = *T. This would lead 305 // to at most one *T entry in typIndex, and all future *T's 306 // would be encoded as the respective index directly. Would 307 // save 1 byte (pointerTag) per *T and reduce the typIndex 308 // size (at the cost of a canonicalization map). We can do 309 // this later, without encoding format change. 310 311 // if we saw the type before, write its index (>= 0) 312 if i, ok := p.typIndex[t]; ok { 313 p.index('T', i) 314 return 315 } 316 317 // otherwise, remember the type, write the type tag (< 0) and type data 318 if trackAllTypes { 319 if trace { 320 p.tracef("T%d = {>\n", len(p.typIndex)) 321 defer p.tracef("<\n} ") 322 } 323 p.typIndex[t] = len(p.typIndex) 324 } 325 326 switch t := t.(type) { 327 case *types.Named: 328 if !trackAllTypes { 329 // if we don't track all types, track named types now 330 p.typIndex[t] = len(p.typIndex) 331 } 332 333 p.tag(namedTag) 334 p.pos(t.Obj()) 335 p.qualifiedName(t.Obj()) 336 p.typ(t.Underlying()) 337 if !types.IsInterface(t) { 338 p.assocMethods(t) 339 } 340 341 case *types.Array: 342 p.tag(arrayTag) 343 p.int64(t.Len()) 344 p.typ(t.Elem()) 345 346 case *types.Slice: 347 p.tag(sliceTag) 348 p.typ(t.Elem()) 349 350 case *dddSlice: 351 p.tag(dddTag) 352 p.typ(t.elem) 353 354 case *types.Struct: 355 p.tag(structTag) 356 p.fieldList(t) 357 358 case *types.Pointer: 359 p.tag(pointerTag) 360 p.typ(t.Elem()) 361 362 case *types.Signature: 363 p.tag(signatureTag) 364 p.paramList(t.Params(), t.Variadic()) 365 p.paramList(t.Results(), false) 366 367 case *types.Interface: 368 p.tag(interfaceTag) 369 p.iface(t) 370 371 case *types.Map: 372 p.tag(mapTag) 373 p.typ(t.Key()) 374 p.typ(t.Elem()) 375 376 case *types.Chan: 377 p.tag(chanTag) 378 p.int(int(3 - t.Dir())) // hack 379 p.typ(t.Elem()) 380 381 default: 382 panic(internalErrorf("unexpected type %T: %s", t, t)) 383 } 384 } 385 386 func (p *exporter) assocMethods(named *types.Named) { 387 // Sort methods (for determinism). 388 var methods []*types.Func 389 for i := 0; i < named.NumMethods(); i++ { 390 methods = append(methods, named.Method(i)) 391 } 392 sort.Sort(methodsByName(methods)) 393 394 p.int(len(methods)) 395 396 if trace && methods != nil { 397 p.tracef("associated methods {>\n") 398 } 399 400 for i, m := range methods { 401 if trace && i > 0 { 402 p.tracef("\n") 403 } 404 405 p.pos(m) 406 name := m.Name() 407 p.string(name) 408 if !exported(name) { 409 p.pkg(m.Pkg(), false) 410 } 411 412 sig := m.Type().(*types.Signature) 413 p.paramList(types.NewTuple(sig.Recv()), false) 414 p.paramList(sig.Params(), sig.Variadic()) 415 p.paramList(sig.Results(), false) 416 p.int(0) // dummy value for go:nointerface pragma - ignored by importer 417 } 418 419 if trace && methods != nil { 420 p.tracef("<\n} ") 421 } 422 } 423 424 type methodsByName []*types.Func 425 426 func (x methodsByName) Len() int { return len(x) } 427 func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 428 func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } 429 430 func (p *exporter) fieldList(t *types.Struct) { 431 if trace && t.NumFields() > 0 { 432 p.tracef("fields {>\n") 433 defer p.tracef("<\n} ") 434 } 435 436 p.int(t.NumFields()) 437 for i := 0; i < t.NumFields(); i++ { 438 if trace && i > 0 { 439 p.tracef("\n") 440 } 441 p.field(t.Field(i)) 442 p.string(t.Tag(i)) 443 } 444 } 445 446 func (p *exporter) field(f *types.Var) { 447 if !f.IsField() { 448 panic(internalError("field expected")) 449 } 450 451 p.pos(f) 452 p.fieldName(f) 453 p.typ(f.Type()) 454 } 455 456 func (p *exporter) iface(t *types.Interface) { 457 // TODO(gri): enable importer to load embedded interfaces, 458 // then emit Embeddeds and ExplicitMethods separately here. 459 p.int(0) 460 461 n := t.NumMethods() 462 if trace && n > 0 { 463 p.tracef("methods {>\n") 464 defer p.tracef("<\n} ") 465 } 466 p.int(n) 467 for i := 0; i < n; i++ { 468 if trace && i > 0 { 469 p.tracef("\n") 470 } 471 p.method(t.Method(i)) 472 } 473 } 474 475 func (p *exporter) method(m *types.Func) { 476 sig := m.Type().(*types.Signature) 477 if sig.Recv() == nil { 478 panic(internalError("method expected")) 479 } 480 481 p.pos(m) 482 p.string(m.Name()) 483 if m.Name() != "_" && !ast.IsExported(m.Name()) { 484 p.pkg(m.Pkg(), false) 485 } 486 487 // interface method; no need to encode receiver. 488 p.paramList(sig.Params(), sig.Variadic()) 489 p.paramList(sig.Results(), false) 490 } 491 492 func (p *exporter) fieldName(f *types.Var) { 493 name := f.Name() 494 495 if f.Anonymous() { 496 // anonymous field - we distinguish between 3 cases: 497 // 1) field name matches base type name and is exported 498 // 2) field name matches base type name and is not exported 499 // 3) field name doesn't match base type name (alias name) 500 bname := basetypeName(f.Type()) 501 if name == bname { 502 if ast.IsExported(name) { 503 name = "" // 1) we don't need to know the field name or package 504 } else { 505 name = "?" // 2) use unexported name "?" to force package export 506 } 507 } else { 508 // 3) indicate alias and export name as is 509 // (this requires an extra "@" but this is a rare case) 510 p.string("@") 511 } 512 } 513 514 p.string(name) 515 if name != "" && !ast.IsExported(name) { 516 p.pkg(f.Pkg(), false) 517 } 518 } 519 520 func basetypeName(typ types.Type) string { 521 switch typ := deref(typ).(type) { 522 case *types.Basic: 523 return typ.Name() 524 case *types.Named: 525 return typ.Obj().Name() 526 default: 527 return "" // unnamed type 528 } 529 } 530 531 func (p *exporter) paramList(params *types.Tuple, variadic bool) { 532 // use negative length to indicate unnamed parameters 533 // (look at the first parameter only since either all 534 // names are present or all are absent) 535 n := params.Len() 536 if n > 0 && params.At(0).Name() == "" { 537 n = -n 538 } 539 p.int(n) 540 for i := 0; i < params.Len(); i++ { 541 q := params.At(i) 542 t := q.Type() 543 if variadic && i == params.Len()-1 { 544 t = &dddSlice{t.(*types.Slice).Elem()} 545 } 546 p.typ(t) 547 if n > 0 { 548 name := q.Name() 549 p.string(name) 550 if name != "_" { 551 p.pkg(q.Pkg(), false) 552 } 553 } 554 p.string("") // no compiler-specific info 555 } 556 } 557 558 func (p *exporter) value(x constant.Value) { 559 if trace { 560 p.tracef("= ") 561 } 562 563 switch x.Kind() { 564 case constant.Bool: 565 tag := falseTag 566 if constant.BoolVal(x) { 567 tag = trueTag 568 } 569 p.tag(tag) 570 571 case constant.Int: 572 if v, exact := constant.Int64Val(x); exact { 573 // common case: x fits into an int64 - use compact encoding 574 p.tag(int64Tag) 575 p.int64(v) 576 return 577 } 578 // uncommon case: large x - use float encoding 579 // (powers of 2 will be encoded efficiently with exponent) 580 p.tag(floatTag) 581 p.float(constant.ToFloat(x)) 582 583 case constant.Float: 584 p.tag(floatTag) 585 p.float(x) 586 587 case constant.Complex: 588 p.tag(complexTag) 589 p.float(constant.Real(x)) 590 p.float(constant.Imag(x)) 591 592 case constant.String: 593 p.tag(stringTag) 594 p.string(constant.StringVal(x)) 595 596 case constant.Unknown: 597 // package contains type errors 598 p.tag(unknownTag) 599 600 default: 601 panic(internalErrorf("unexpected value %v (%T)", x, x)) 602 } 603 } 604 605 func (p *exporter) float(x constant.Value) { 606 if x.Kind() != constant.Float { 607 panic(internalErrorf("unexpected constant %v, want float", x)) 608 } 609 // extract sign (there is no -0) 610 sign := constant.Sign(x) 611 if sign == 0 { 612 // x == 0 613 p.int(0) 614 return 615 } 616 // x != 0 617 618 var f big.Float 619 if v, exact := constant.Float64Val(x); exact { 620 // float64 621 f.SetFloat64(v) 622 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 623 // TODO(gri): add big.Rat accessor to constant.Value. 624 r := valueToRat(num) 625 f.SetRat(r.Quo(r, valueToRat(denom))) 626 } else { 627 // Value too large to represent as a fraction => inaccessible. 628 // TODO(gri): add big.Float accessor to constant.Value. 629 f.SetFloat64(math.MaxFloat64) // FIXME 630 } 631 632 // extract exponent such that 0.5 <= m < 1.0 633 var m big.Float 634 exp := f.MantExp(&m) 635 636 // extract mantissa as *big.Int 637 // - set exponent large enough so mant satisfies mant.IsInt() 638 // - get *big.Int from mant 639 m.SetMantExp(&m, int(m.MinPrec())) 640 mant, acc := m.Int(nil) 641 if acc != big.Exact { 642 panic(internalError("internal error")) 643 } 644 645 p.int(sign) 646 p.int(exp) 647 p.string(string(mant.Bytes())) 648 } 649 650 func valueToRat(x constant.Value) *big.Rat { 651 // Convert little-endian to big-endian. 652 // I can't believe this is necessary. 653 bytes := constant.Bytes(x) 654 for i := 0; i < len(bytes)/2; i++ { 655 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] 656 } 657 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) 658 } 659 660 func (p *exporter) bool(b bool) bool { 661 if trace { 662 p.tracef("[") 663 defer p.tracef("= %v] ", b) 664 } 665 666 x := 0 667 if b { 668 x = 1 669 } 670 p.int(x) 671 return b 672 } 673 674 // ---------------------------------------------------------------------------- 675 // Low-level encoders 676 677 func (p *exporter) index(marker byte, index int) { 678 if index < 0 { 679 panic(internalError("invalid index < 0")) 680 } 681 if debugFormat { 682 p.marker('t') 683 } 684 if trace { 685 p.tracef("%c%d ", marker, index) 686 } 687 p.rawInt64(int64(index)) 688 } 689 690 func (p *exporter) tag(tag int) { 691 if tag >= 0 { 692 panic(internalError("invalid tag >= 0")) 693 } 694 if debugFormat { 695 p.marker('t') 696 } 697 if trace { 698 p.tracef("%s ", tagString[-tag]) 699 } 700 p.rawInt64(int64(tag)) 701 } 702 703 func (p *exporter) int(x int) { 704 p.int64(int64(x)) 705 } 706 707 func (p *exporter) int64(x int64) { 708 if debugFormat { 709 p.marker('i') 710 } 711 if trace { 712 p.tracef("%d ", x) 713 } 714 p.rawInt64(x) 715 } 716 717 func (p *exporter) string(s string) { 718 if debugFormat { 719 p.marker('s') 720 } 721 if trace { 722 p.tracef("%q ", s) 723 } 724 // if we saw the string before, write its index (>= 0) 725 // (the empty string is mapped to 0) 726 if i, ok := p.strIndex[s]; ok { 727 p.rawInt64(int64(i)) 728 return 729 } 730 // otherwise, remember string and write its negative length and bytes 731 p.strIndex[s] = len(p.strIndex) 732 p.rawInt64(-int64(len(s))) 733 for i := 0; i < len(s); i++ { 734 p.rawByte(s[i]) 735 } 736 } 737 738 // marker emits a marker byte and position information which makes 739 // it easy for a reader to detect if it is "out of sync". Used for 740 // debugFormat format only. 741 func (p *exporter) marker(m byte) { 742 p.rawByte(m) 743 // Enable this for help tracking down the location 744 // of an incorrect marker when running in debugFormat. 745 if false && trace { 746 p.tracef("#%d ", p.written) 747 } 748 p.rawInt64(int64(p.written)) 749 } 750 751 // rawInt64 should only be used by low-level encoders. 752 func (p *exporter) rawInt64(x int64) { 753 var tmp [binary.MaxVarintLen64]byte 754 n := binary.PutVarint(tmp[:], x) 755 for i := 0; i < n; i++ { 756 p.rawByte(tmp[i]) 757 } 758 } 759 760 // rawStringln should only be used to emit the initial version string. 761 func (p *exporter) rawStringln(s string) { 762 for i := 0; i < len(s); i++ { 763 p.rawByte(s[i]) 764 } 765 p.rawByte('\n') 766 } 767 768 // rawByte is the bottleneck interface to write to p.out. 769 // rawByte escapes b as follows (any encoding does that 770 // hides '$'): 771 // 772 // '$' => '|' 'S' 773 // '|' => '|' '|' 774 // 775 // Necessary so other tools can find the end of the 776 // export data by searching for "$$". 777 // rawByte should only be used by low-level encoders. 778 func (p *exporter) rawByte(b byte) { 779 switch b { 780 case '$': 781 // write '$' as '|' 'S' 782 b = 'S' 783 fallthrough 784 case '|': 785 // write '|' as '|' '|' 786 p.out.WriteByte('|') 787 p.written++ 788 } 789 p.out.WriteByte(b) 790 p.written++ 791 } 792 793 // tracef is like fmt.Printf but it rewrites the format string 794 // to take care of indentation. 795 func (p *exporter) tracef(format string, args ...interface{}) { 796 if strings.ContainsAny(format, "<>\n") { 797 var buf bytes.Buffer 798 for i := 0; i < len(format); i++ { 799 // no need to deal with runes 800 ch := format[i] 801 switch ch { 802 case '>': 803 p.indent++ 804 continue 805 case '<': 806 p.indent-- 807 continue 808 } 809 buf.WriteByte(ch) 810 if ch == '\n' { 811 for j := p.indent; j > 0; j-- { 812 buf.WriteString(". ") 813 } 814 } 815 } 816 format = buf.String() 817 } 818 fmt.Printf(format, args...) 819 } 820 821 // Debugging support. 822 // (tagString is only used when tracing is enabled) 823 var tagString = [...]string{ 824 // Packages 825 -packageTag: "package", 826 827 // Types 828 -namedTag: "named type", 829 -arrayTag: "array", 830 -sliceTag: "slice", 831 -dddTag: "ddd", 832 -structTag: "struct", 833 -pointerTag: "pointer", 834 -signatureTag: "signature", 835 -interfaceTag: "interface", 836 -mapTag: "map", 837 -chanTag: "chan", 838 839 // Values 840 -falseTag: "false", 841 -trueTag: "true", 842 -int64Tag: "int64", 843 -floatTag: "float", 844 -fractionTag: "fraction", 845 -complexTag: "complex", 846 -stringTag: "string", 847 -unknownTag: "unknown", 848 849 // Type aliases 850 -aliasTag: "alias", 851 }