const forceObjFileStability = true
// Current export format version. Increase with each format change.
-// 3: added aliasTag and export of aliases
-// 2: removed unused bool in ODCL export
+// 4: type name objects support type aliases, uses aliasTag
+// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
+// 2: removed unused bool in ODCL export (compiler only)
// 1: header format change (more regular), export package for _ struct fields
// 0: Go1.7 encoding
-const exportVersion = 3
+const exportVersion = 4
// exportInlined enables the export of inlined function bodies and related
// dependencies. The compiler should work w/o any loss of functionality with
Fatalf("exporter: export of incomplete type %v", sym)
}
- p.tag(typeTag)
+ const alias = false // TODO(gri) fix this
+ if alias {
+ p.tag(aliasTag)
+ p.pos(n)
+ p.qualifiedName(sym)
+ } else {
+ p.tag(typeTag)
+ }
p.typ(t)
case ONAME:
func (p *exporter) method(m *Field) {
p.pos(m.Nname)
- p.fieldName(m)
+ p.methodName(m.Sym)
p.paramList(m.Type.Params(), false)
p.paramList(m.Type.Results(), false)
}
-// fieldName is like qualifiedName but it doesn't record the package for exported names.
func (p *exporter) fieldName(t *Field) {
name := t.Sym.Name
if t.Embedded != 0 {
- name = "" // anonymous field
- if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
- // anonymous field with unexported base type name
- name = "?" // unexported name to force export of package
+ // anonymous field - we distinguish between 3 cases:
+ // 1) field name matches base type name and name is exported
+ // 2) field name matches base type name and name is not exported
+ // 3) field name doesn't match base type name (type name is alias)
+ bname := basetypeName(t.Type)
+ if name == bname {
+ if exportname(name) {
+ name = "" // 1) we don't need to know the name
+ } else {
+ name = "?" // 2) use unexported name to force package export
+ }
+ } else {
+ // 3) indicate alias and export name as is
+ // (this requires an extra "@" but this is a rare case)
+ p.string("@")
}
}
p.string(name)
}
}
+// methodName is like qualifiedName but it doesn't record the package for exported names.
+func (p *exporter) methodName(sym *Sym) {
+ p.string(sym.Name)
+ if !exportname(sym.Name) {
+ p.pkg(sym.Pkg)
+ }
+}
+
func basetypeName(t *Type) string {
s := t.Sym
if s == nil && t.IsPtr() {
nilTag
unknownTag // not used by gc (only appears in packages with errors)
- // Aliases
+ // Type aliases
aliasTag
)
-nilTag: "nil",
-unknownTag: "unknown",
- // Aliases
+ // Type aliases
-aliasTag: "alias",
}
Types[TCOMPLEX128],
Types[TSTRING],
- // aliases
+ // basic type aliases
bytetype,
runetype,
// read version specific flags - extend as necessary
switch p.version {
- // case 4:
+ // case 5:
// ...
// fallthrough
- case 3, 2, 1:
+ case 4, 3, 2, 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.bool()
p.posInfoFormat = p.bool()
val := p.value(typ)
importconst(sym, idealType(typ), nodlit(val))
+ case aliasTag:
+ // TODO(gri) hook up type alias
+ p.pos()
+ p.qualifiedName()
+ p.typ()
+
case typeTag:
p.typ()
}
}
- case aliasTag:
- p.pos()
- alias := importpkg.Lookup(p.string())
- orig := p.qualifiedName()
-
- // Although the protocol allows the alias to precede the original,
- // this never happens in files produced by gc.
- alias.Flags |= SymAlias
- alias.Def = orig.Def
- importsym(alias, orig.Def.Op)
-
default:
formatErrorf("unexpected object (tag = %d)", tag)
}
}
sym = sym.Pkg.Lookup(s.Name)
f.Embedded = 1
+ } else if sym.Flags&SymAlias != 0 {
+ f.Embedded = 1
}
f.Sym = sym
func (p *importer) method() *Field {
p.pos()
- sym := p.fieldName()
+ sym := p.methodName()
params := p.paramList()
result := p.paramList()
func (p *importer) fieldName() *Sym {
name := p.string()
if p.version == 0 && name == "_" {
- // version 0 didn't export a package for _ fields
+ // version 0 didn't export a package for _ field names
// but used the builtin package instead
return builtinpkg.Lookup(name)
}
pkg := localpkg
- if name != "" && !exportname(name) {
- if name == "?" {
- name = ""
+ var flag SymFlags
+ switch name {
+ case "":
+ // field name is exported - nothing to do
+ case "?":
+ // field name is not exported - need package
+ name = ""
+ pkg = p.pkg()
+ case "@":
+ // field name doesn't match type name (alias)
+ name = p.string()
+ flag = SymAlias
+ fallthrough
+ default:
+ if !exportname(name) {
+ pkg = p.pkg()
}
+ }
+ sym := pkg.Lookup(name)
+ sym.Flags |= flag
+ return sym
+}
+
+func (p *importer) methodName() *Sym {
+ name := p.string()
+ if p.version == 0 && name == "_" {
+ // version 0 didn't export a package for _ method names
+ // but used the builtin package instead
+ return builtinpkg.Lookup(name)
+ }
+ pkg := localpkg
+ if !exportname(name) {
pkg = p.pkg()
}
return pkg.Lookup(name)
// read version specific flags - extend as necessary
switch p.version {
- // case 4:
+ // case 5:
// ...
// fallthrough
- case 3, 2, 1:
+ case 4, 3, 2, 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.int() != 0
p.posInfoFormat = p.int() != 0
}
// objTag returns the tag value for each object kind.
-// obj must not be a *types.Alias.
func objTag(obj types.Object) int {
switch obj.(type) {
case *types.Const:
return varTag
case *types.Func:
return funcTag
- // Aliases are not exported multiple times, thus we should not see them here.
default:
errorf("unexpected object: %v (%T)", obj, obj) // panics
panic("unreachable")
pkg := obj.Pkg()
if alt := pkg.Scope().Insert(obj); alt != nil {
// This can only trigger if we import a (non-type) object a second time.
- // Excluding aliases, this cannot happen because 1) we only import a package
+ // Excluding type aliases, this cannot happen because 1) we only import a package
// once; and b) we ignore compiler-specific export data which may contain
// functions whose inlined function bodies refer to other functions that
// were already imported.
- // However, aliases require reexporting the original object, so we need
+ // However, type aliases require reexporting the original type, so we need
// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
// method importer.obj, switch case importing functions).
- // Note that the original itself cannot be an alias.
+ // TODO(gri) review/update this comment once the gc compiler handles type aliases.
if !sameObj(obj, alt) {
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
}
val := p.value()
p.declare(types.NewConst(pos, pkg, name, typ, val))
+ case aliasTag:
+ // TODO(gri) verify type alias hookup is correct
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ typ := p.typ(nil)
+ p.declare(types.NewTypeName(pos, pkg, name, typ))
+
case typeTag:
p.typ(nil)
sig := types.NewSignature(nil, params, result, isddd)
p.declare(types.NewFunc(pos, pkg, name, sig))
- case aliasTag:
- pos := p.pos()
- name := p.string()
- var orig types.Object
- if pkg, name := p.qualifiedName(); pkg != nil {
- orig = pkg.Scope().Lookup(name)
- }
- // Alias-related code. Keep for now.
- _ = pos
- _ = name
- _ = orig
- // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
-
default:
errorf("unexpected object tag %d", tag)
}
fields = make([]*types.Var, n)
tags = make([]string, n)
for i := range fields {
- fields[i] = p.field(parent)
- tags[i] = p.string()
+ fields[i], tags[i] = p.field(parent)
}
}
return
}
-func (p *importer) field(parent *types.Package) *types.Var {
+func (p *importer) field(parent *types.Package) (*types.Var, string) {
pos := p.pos()
pkg, name := p.fieldName(parent)
typ := p.typ(parent)
+ tag := p.string()
anonymous := false
if name == "" {
anonymous = true
}
- return types.NewField(pos, pkg, name, typ, anonymous)
+ return types.NewField(pos, pkg, name, typ, anonymous), tag
}
func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
// version 0 didn't export a package for _ fields
return pkg, name
}
- if name != "" && !exported(name) {
- if name == "?" {
- name = ""
- }
+ switch name {
+ case "":
+ // field name is exported - nothing to do
+ case "?":
+ // field name is not exported - need package
+ name = ""
pkg = p.pkg()
+ case "@":
+ // field name doesn't match type name (alias)
+ name = p.string()
+ fallthrough
+ default:
+ if !exported(name) {
+ pkg = p.pkg()
+ }
}
return pkg, name
}
nilTag // only used by gc (appears in exported inlined function bodies)
unknownTag // not used by gc (only appears in packages with errors)
- // Aliases
+ // Type aliases
aliasTag
)
types.Typ[types.Complex128],
types.Typ[types.String],
- // aliases
+ // basic type aliases
types.Universe.Lookup("byte").Type(),
types.Universe.Lookup("rune").Type(),