1
0
mirror of https://github.com/golang/go synced 2024-11-23 06:20:07 -07:00

cmd/compile: move types init code into package types

This moves the package types setup code from package typecheck into
package types itself. This is a prereq for making types.Type more
opaque, because some unit tests depend on being able to init the basic
universal types.

A few notable details of this CL:

1. Creating the builtin types requires being able to create the
ir.Name/ir.OTYPE that represents it, but package types can't depend on
package ir. So we add a callback function to handle creating the
ir.Name.

2. This CL moves ir.Pkgs.Unsafe to types.UnsafePkg. Package unsafe is
part of the language, not like the other ir.Pkgs packages that are
purely implementation details.

3. This CL also moves typecheck.FakeRecv to types.FakeRecv, addressing
an outstanding TODO.

Change-Id: I64de04ce82fbcd1bb59f547e2eea3cda52d89429
Reviewed-on: https://go-review.googlesource.com/c/go/+/345474
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2021-08-26 13:17:56 -07:00
parent af80af22b5
commit 967a8017f7
14 changed files with 171 additions and 160 deletions

View File

@ -84,7 +84,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
types.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin types.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
// pseudo-package, accessed by import "unsafe" // pseudo-package, accessed by import "unsafe"
ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe") types.UnsafePkg = types.NewPkg("unsafe", "unsafe")
// Pseudo-package that contains the compiler's builtin // Pseudo-package that contains the compiler's builtin
// declarations for package runtime. These are declared in a // declarations for package runtime. These are declared in a

View File

@ -68,5 +68,4 @@ var Pkgs struct {
Go *types.Pkg Go *types.Pkg
Itab *types.Pkg Itab *types.Pkg
Runtime *types.Pkg Runtime *types.Pkg
Unsafe *types.Pkg
} }

View File

@ -198,7 +198,7 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg {
return nil return nil
} }
if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight { if pkg != types.UnsafePkg && pkg.Height >= myheight {
myheight = pkg.Height + 1 myheight = pkg.Height + 1
} }
return pkg return pkg
@ -231,7 +231,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack
} }
if path == "unsafe" { if path == "unsafe" {
pkg1, pkg2 = ir.Pkgs.Unsafe, types2.Unsafe pkg1, pkg2 = types.UnsafePkg, types2.Unsafe
// TODO(mdempsky): Investigate if this actually matters. Why would // TODO(mdempsky): Investigate if this actually matters. Why would
// the linker or runtime care whether a package imported unsafe? // the linker or runtime care whether a package imported unsafe?

View File

@ -384,7 +384,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
return return
} }
if ipkg == ir.Pkgs.Unsafe { if ipkg == types.UnsafePkg {
p.importedUnsafe = true p.importedUnsafe = true
} }
if ipkg.Path == "embed" { if ipkg.Path == "embed" {

View File

@ -428,7 +428,7 @@ func (r *reader) interfaceType() *types.Type {
pos := r.pos() pos := r.pos()
pkg, sym := r.selector() pkg, sym := r.selector()
tpkg = pkg tpkg = pkg
mtyp := r.signature(pkg, typecheck.FakeRecv()) mtyp := r.signature(pkg, types.FakeRecv())
methods[i] = types.NewField(pos, sym, mtyp) methods[i] = types.NewField(pos, sym, mtyp)
} }
for i := range embeddeds { for i := range embeddeds {
@ -540,7 +540,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
if tag == objStub { if tag == objStub {
assert(!sym.IsBlank()) assert(!sym.IsBlank())
switch sym.Pkg { switch sym.Pkg {
case types.BuiltinPkg, ir.Pkgs.Unsafe: case types.BuiltinPkg, types.UnsafePkg:
return sym.Def.(ir.Node) return sym.Def.(ir.Node)
} }
if pri, ok := objReader[sym]; ok { if pri, ok := objReader[sym]; ok {

View File

@ -22,7 +22,7 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
case g.self: case g.self:
return types.LocalPkg return types.LocalPkg
case types2.Unsafe: case types2.Unsafe:
return ir.Pkgs.Unsafe return types.UnsafePkg
} }
return types.NewPkg(pkg.Path(), pkg.Name()) return types.NewPkg(pkg.Path(), pkg.Name())
} }
@ -206,7 +206,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
methods := make([]*types.Field, typ.NumExplicitMethods()) methods := make([]*types.Field, typ.NumExplicitMethods())
for i := range methods { for i := range methods {
m := typ.ExplicitMethod(i) m := typ.ExplicitMethod(i)
mtyp := g.signature(typecheck.FakeRecv(), m.Type().(*types2.Signature)) mtyp := g.signature(types.FakeRecv(), m.Type().(*types2.Signature))
methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp) methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
} }

View File

@ -1726,7 +1726,7 @@ func NeedEmit(typ *types.Type) bool {
// Local defined type; our responsibility. // Local defined type; our responsibility.
return true return true
case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe): case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg):
// Package runtime is responsible for including code for builtin // Package runtime is responsible for including code for builtin
// types (predeclared and package unsafe). // types (predeclared and package unsafe).
return true return true

View File

@ -314,13 +314,6 @@ func checkembeddedtype(t *types.Type) {
} }
} }
// TODO(mdempsky): Move to package types.
func FakeRecv() *types.Field {
return types.NewField(src.NoXPos, nil, types.FakeRecvType())
}
var fakeRecvField = FakeRecv
var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
type funcStackEnt struct { type funcStackEnt struct {

View File

@ -430,7 +430,7 @@ func (p *iexporter) pushDecl(n *ir.Name) {
} }
// Don't export predeclared declarations. // Don't export predeclared declarations.
if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == ir.Pkgs.Unsafe { if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == types.UnsafePkg {
return return
} }
@ -905,7 +905,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
// type orderedAbs[T any] T // type orderedAbs[T any] T
if t.IsTypeParam() && t.Underlying() == t { if t.IsTypeParam() && t.Underlying() == t {
assert(base.Flag.G > 0) assert(base.Flag.G > 0)
if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
base.Fatalf("builtin type missing from typIndex: %v", t) base.Fatalf("builtin type missing from typIndex: %v", t)
} }
// Write out the first use of a type param as a qualified ident. // Write out the first use of a type param as a qualified ident.
@ -916,7 +916,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
} }
if s != nil { if s != nil {
if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe { if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
base.Fatalf("builtin type missing from typIndex: %v", t) base.Fatalf("builtin type missing from typIndex: %v", t)
} }

View File

@ -607,7 +607,7 @@ func (r *importReader) exoticType() *types.Type {
case exoticTypeRecv: case exoticTypeRecv:
var rcvr *types.Field var rcvr *types.Field
if r.bool() { // isFakeRecv if r.bool() { // isFakeRecv
rcvr = fakeRecvField() rcvr = types.FakeRecv()
} else { } else {
rcvr = r.exoticParam() rcvr = r.exoticParam()
} }
@ -793,7 +793,7 @@ func (r *importReader) typ1() *types.Type {
for i := range methods { for i := range methods {
pos := r.pos() pos := r.pos()
sym := r.selector() sym := r.selector()
typ := r.signature(fakeRecvField(), nil) typ := r.signature(types.FakeRecv(), nil)
methods[i] = types.NewField(pos, sym, typ) methods[i] = types.NewField(pos, sym, typ)
} }

View File

@ -29,37 +29,6 @@ var (
okforarith [types.NTYPE]bool okforarith [types.NTYPE]bool
) )
var basicTypes = [...]struct {
name string
etype types.Kind
}{
{"int8", types.TINT8},
{"int16", types.TINT16},
{"int32", types.TINT32},
{"int64", types.TINT64},
{"uint8", types.TUINT8},
{"uint16", types.TUINT16},
{"uint32", types.TUINT32},
{"uint64", types.TUINT64},
{"float32", types.TFLOAT32},
{"float64", types.TFLOAT64},
{"complex64", types.TCOMPLEX64},
{"complex128", types.TCOMPLEX128},
{"bool", types.TBOOL},
{"string", types.TSTRING},
}
var typedefs = [...]struct {
name string
etype types.Kind
sameas32 types.Kind
sameas64 types.Kind
}{
{"int", types.TINT, types.TINT32, types.TINT64},
{"uint", types.TUINT, types.TUINT32, types.TUINT64},
{"uintptr", types.TUINTPTR, types.TUINT32, types.TUINT64},
}
var builtinFuncs = [...]struct { var builtinFuncs = [...]struct {
name string name string
op ir.Op op ir.Op
@ -94,86 +63,12 @@ var unsafeFuncs = [...]struct {
// InitUniverse initializes the universe block. // InitUniverse initializes the universe block.
func InitUniverse() { func InitUniverse() {
if types.PtrSize == 0 { types.InitTypes(func(sym *types.Sym, typ *types.Type) types.Object {
base.Fatalf("typeinit before betypeinit")
}
types.SlicePtrOffset = 0
types.SliceLenOffset = types.Rnd(types.SlicePtrOffset+int64(types.PtrSize), int64(types.PtrSize))
types.SliceCapOffset = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
types.SliceSize = types.Rnd(types.SliceCapOffset+int64(types.PtrSize), int64(types.PtrSize))
// string is same as slice wo the cap
types.StringSize = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
for et := types.Kind(0); et < types.NTYPE; et++ {
types.SimType[et] = et
}
types.Types[types.TANY] = types.New(types.TANY)
types.Types[types.TINTER] = types.NewInterface(types.LocalPkg, nil)
defBasic := func(kind types.Kind, pkg *types.Pkg, name string) *types.Type {
sym := pkg.Lookup(name)
n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym) n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
t := types.NewBasic(kind, n) n.SetType(typ)
n.SetType(t)
sym.Def = n sym.Def = n
if kind != types.TANY { return n
types.CalcSize(t) })
}
return t
}
for _, s := range &basicTypes {
types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
}
for _, s := range &typedefs {
sameas := s.sameas32
if types.PtrSize == 8 {
sameas = s.sameas64
}
types.SimType[s.etype] = sameas
types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
}
// We create separate byte and rune types for better error messages
// rather than just creating type alias *types.Sym's for the uint8 and
// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
// TODO(gri) Should we get rid of this special case (at the cost
// of less informative error messages involving bytes and runes)?
// (Alternatively, we could introduce an OTALIAS node representing
// type aliases, albeit at the cost of having to deal with it everywhere).
types.ByteType = defBasic(types.TUINT8, types.BuiltinPkg, "byte")
types.RuneType = defBasic(types.TINT32, types.BuiltinPkg, "rune")
// error type
s := types.BuiltinPkg.Lookup("error")
n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
types.ErrorType = types.NewNamed(n)
types.ErrorType.SetUnderlying(makeErrorInterface())
n.SetType(types.ErrorType)
s.Def = n
types.CalcSize(types.ErrorType)
// comparable type (interface)
s = types.BuiltinPkg.Lookup("comparable")
n = ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
types.ComparableType = types.NewNamed(n)
types.ComparableType.SetUnderlying(makeComparableInterface())
n.SetType(types.ComparableType)
s.Def = n
types.CalcSize(types.ComparableType)
types.Types[types.TUNSAFEPTR] = defBasic(types.TUNSAFEPTR, ir.Pkgs.Unsafe, "Pointer")
// simple aliases
types.SimType[types.TMAP] = types.TPTR
types.SimType[types.TCHAN] = types.TPTR
types.SimType[types.TFUNC] = types.TPTR
types.SimType[types.TUNSAFEPTR] = types.TPTR
for _, s := range &builtinFuncs { for _, s := range &builtinFuncs {
s2 := types.BuiltinPkg.Lookup(s.name) s2 := types.BuiltinPkg.Lookup(s.name)
@ -183,13 +78,13 @@ func InitUniverse() {
} }
for _, s := range &unsafeFuncs { for _, s := range &unsafeFuncs {
s2 := ir.Pkgs.Unsafe.Lookup(s.name) s2 := types.UnsafePkg.Lookup(s.name)
def := NewName(s2) def := NewName(s2)
def.BuiltinOp = s.op def.BuiltinOp = s.op
s2.Def = def s2.Def = def
} }
s = types.BuiltinPkg.Lookup("true") s := types.BuiltinPkg.Lookup("true")
s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(true)) s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(true))
s = types.BuiltinPkg.Lookup("false") s = types.BuiltinPkg.Lookup("false")
@ -219,19 +114,6 @@ func InitUniverse() {
s = types.BuiltinPkg.Lookup("iota") s = types.BuiltinPkg.Lookup("iota")
s.Def = ir.NewIota(base.Pos, s) s.Def = ir.NewIota(base.Pos, s)
for et := types.TINT8; et <= types.TUINT64; et++ {
types.IsInt[et] = true
}
types.IsInt[types.TINT] = true
types.IsInt[types.TUINT] = true
types.IsInt[types.TUINTPTR] = true
types.IsFloat[types.TFLOAT32] = true
types.IsFloat[types.TFLOAT64] = true
types.IsComplex[types.TCOMPLEX64] = true
types.IsComplex[types.TCOMPLEX128] = true
// initialize okfor // initialize okfor
for et := types.Kind(0); et < types.NTYPE; et++ { for et := types.Kind(0); et < types.NTYPE; et++ {
if types.IsInt[et] || et == types.TIDEAL { if types.IsInt[et] || et == types.TIDEAL {
@ -331,20 +213,6 @@ func InitUniverse() {
okfor[ir.OLEN] = okforlen[:] okfor[ir.OLEN] = okforlen[:]
} }
func makeErrorInterface() *types.Type {
sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, []*types.Field{
types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
})
method := types.NewField(src.NoXPos, Lookup("Error"), sig)
return types.NewInterface(types.NoPkg, []*types.Field{method})
}
func makeComparableInterface() *types.Type {
sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, nil)
method := types.NewField(src.NoXPos, Lookup("=="), sig)
return types.NewInterface(types.NoPkg, []*types.Field{method})
}
// DeclareUniverse makes the universe block visible within the current package. // DeclareUniverse makes the universe block visible within the current package.
func DeclareUniverse() { func DeclareUniverse() {
// Operationally, this is similar to a dot import of builtinpkg, except // Operationally, this is similar to a dot import of builtinpkg, except

View File

@ -23,6 +23,9 @@ var BuiltinPkg *Pkg
// LocalPkg is the package being compiled. // LocalPkg is the package being compiled.
var LocalPkg *Pkg var LocalPkg *Pkg
// UnsafePkg is package unsafe.
var UnsafePkg *Pkg
// BlankSym is the blank (_) symbol. // BlankSym is the blank (_) symbol.
var BlankSym *Sym var BlankSym *Sym

View File

@ -1738,6 +1738,10 @@ func FakeRecvType() *Type {
return recvType return recvType
} }
func FakeRecv() *Field {
return NewField(src.NoXPos, nil, FakeRecvType())
}
var ( var (
// TSSA types. HasPointers assumes these are pointer-free. // TSSA types. HasPointers assumes these are pointer-free.
TypeInvalid = newSSA("invalid") TypeInvalid = newSSA("invalid")

View File

@ -0,0 +1,144 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import (
"cmd/compile/internal/base"
"cmd/internal/src"
)
var basicTypes = [...]struct {
name string
etype Kind
}{
{"int8", TINT8},
{"int16", TINT16},
{"int32", TINT32},
{"int64", TINT64},
{"uint8", TUINT8},
{"uint16", TUINT16},
{"uint32", TUINT32},
{"uint64", TUINT64},
{"float32", TFLOAT32},
{"float64", TFLOAT64},
{"complex64", TCOMPLEX64},
{"complex128", TCOMPLEX128},
{"bool", TBOOL},
{"string", TSTRING},
}
var typedefs = [...]struct {
name string
etype Kind
sameas32 Kind
sameas64 Kind
}{
{"int", TINT, TINT32, TINT64},
{"uint", TUINT, TUINT32, TUINT64},
{"uintptr", TUINTPTR, TUINT32, TUINT64},
}
func InitTypes(defTypeName func(sym *Sym, typ *Type) Object) {
if PtrSize == 0 {
base.Fatalf("typeinit before betypeinit")
}
SlicePtrOffset = 0
SliceLenOffset = Rnd(SlicePtrOffset+int64(PtrSize), int64(PtrSize))
SliceCapOffset = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
SliceSize = Rnd(SliceCapOffset+int64(PtrSize), int64(PtrSize))
// string is same as slice wo the cap
StringSize = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
for et := Kind(0); et < NTYPE; et++ {
SimType[et] = et
}
Types[TANY] = New(TANY)
Types[TINTER] = NewInterface(LocalPkg, nil)
defBasic := func(kind Kind, pkg *Pkg, name string) *Type {
typ := New(kind)
obj := defTypeName(pkg.Lookup(name), typ)
typ.sym = obj.Sym()
typ.nod = obj
if kind != TANY {
CheckSize(typ)
}
return typ
}
for _, s := range &basicTypes {
Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
}
for _, s := range &typedefs {
sameas := s.sameas32
if PtrSize == 8 {
sameas = s.sameas64
}
SimType[s.etype] = sameas
Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
}
// We create separate byte and rune types for better error messages
// rather than just creating type alias *Sym's for the uint8 and
// int32 Hence, (bytetype|runtype).Sym.isAlias() is false.
// TODO(gri) Should we get rid of this special case (at the cost
// of less informative error messages involving bytes and runes)?
// (Alternatively, we could introduce an OTALIAS node representing
// type aliases, albeit at the cost of having to deal with it everywhere).
ByteType = defBasic(TUINT8, BuiltinPkg, "byte")
RuneType = defBasic(TINT32, BuiltinPkg, "rune")
// error type
DeferCheckSize()
ErrorType = defBasic(TFORW, BuiltinPkg, "error")
ErrorType.SetUnderlying(makeErrorInterface())
ResumeCheckSize()
// comparable type (interface)
DeferCheckSize()
ComparableType = defBasic(TFORW, BuiltinPkg, "comparable")
ComparableType.SetUnderlying(makeComparableInterface())
ResumeCheckSize()
Types[TUNSAFEPTR] = defBasic(TUNSAFEPTR, UnsafePkg, "Pointer")
// simple aliases
SimType[TMAP] = TPTR
SimType[TCHAN] = TPTR
SimType[TFUNC] = TPTR
SimType[TUNSAFEPTR] = TPTR
for et := TINT8; et <= TUINT64; et++ {
IsInt[et] = true
}
IsInt[TINT] = true
IsInt[TUINT] = true
IsInt[TUINTPTR] = true
IsFloat[TFLOAT32] = true
IsFloat[TFLOAT64] = true
IsComplex[TCOMPLEX64] = true
IsComplex[TCOMPLEX128] = true
}
func makeErrorInterface() *Type {
sig := NewSignature(NoPkg, FakeRecv(), nil, nil, []*Field{
NewField(src.NoXPos, nil, Types[TSTRING]),
})
method := NewField(src.NoXPos, LocalPkg.Lookup("Error"), sig)
return NewInterface(NoPkg, []*Field{method})
}
func makeComparableInterface() *Type {
sig := NewSignature(NoPkg, FakeRecv(), nil, nil, nil)
method := NewField(src.NoXPos, LocalPkg.Lookup("=="), sig)
return NewInterface(NoPkg, []*Field{method})
}