mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.cmdgo] all: merge master (67f7e16) into dev.cmdgo
Merge List: + 2021-08-27 67f7e16bcc encoding/gob: optimize decoding of []byte + 2021-08-27 2c60a99f72 cmd/compile/internal/syntax: make valid type parameter list in presence of errors + 2021-08-27 d350a66532 cmd/compile: eagerly CalcStructSize for synthetic ABI types + 2021-08-27 d7e2e2ec2b cmd/compile: delay fillinMethods to deal with mutually-recursive types + 2021-08-27 c927599783 cmd/compile: eliminate repetitive code + 2021-08-27 62f88b6dc8 cmd/compile: add types.RecalcSize + 2021-08-27 e7eee5e265 cmd/compile: remove ssagen/pgen_test.go + 2021-08-27 f153b6739b cmd/compile: use typecheck.InitUniverse in unit tests + 2021-08-26 967a8017f7 cmd/compile: move types init code into package types + 2021-08-26 af80af22b5 cmd/compile/internal/types2: do not declare new methods on instantiated types + 2021-08-26 03db2c2413 cmd/compile/internal/types2: implement TypeList.String (debugging support) + 2021-08-26 c9e05fdcf7 cmd/compile: fix reference to generic type needed by crawler + 2021-08-26 eb6a07fcf9 cmd/compile: unexport Type.Vargen + 2021-08-26 3836983779 cmd/compile/internal/types: unexport Type.Extra + 2021-08-26 1f8d4562de cmd/compile: change typecheck.iscmp into ir.Op.IsCmp Change-Id: I95c040a0e984a13a3b12c50458148007221ee300
This commit is contained in:
commit
220bc44a4c
@ -722,14 +722,17 @@ func setup() {
|
|||||||
types.NewField(nxp, fname("len"), ui),
|
types.NewField(nxp, fname("len"), ui),
|
||||||
types.NewField(nxp, fname("cap"), ui),
|
types.NewField(nxp, fname("cap"), ui),
|
||||||
})
|
})
|
||||||
|
types.CalcStructSize(synthSlice)
|
||||||
synthString = types.NewStruct(types.NoPkg, []*types.Field{
|
synthString = types.NewStruct(types.NoPkg, []*types.Field{
|
||||||
types.NewField(nxp, fname("data"), unsp),
|
types.NewField(nxp, fname("data"), unsp),
|
||||||
types.NewField(nxp, fname("len"), ui),
|
types.NewField(nxp, fname("len"), ui),
|
||||||
})
|
})
|
||||||
|
types.CalcStructSize(synthString)
|
||||||
synthIface = types.NewStruct(types.NoPkg, []*types.Field{
|
synthIface = types.NewStruct(types.NoPkg, []*types.Field{
|
||||||
types.NewField(nxp, fname("f1"), unsp),
|
types.NewField(nxp, fname("f1"), unsp),
|
||||||
types.NewField(nxp, fname("f2"), unsp),
|
types.NewField(nxp, fname("f2"), unsp),
|
||||||
})
|
})
|
||||||
|
types.CalcStructSize(synthIface)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -334,6 +334,16 @@ const (
|
|||||||
OEND
|
OEND
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IsCmp reports whether op is a comparison operation (==, !=, <, <=,
|
||||||
|
// >, or >=).
|
||||||
|
func (op Op) IsCmp() bool {
|
||||||
|
switch op {
|
||||||
|
case OEQ, ONE, OLT, OLE, OGT, OGE:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Nodes is a pointer to a slice of *Node.
|
// Nodes is a pointer to a slice of *Node.
|
||||||
// For fields that are not used in most nodes, this is used instead of
|
// For fields that are not used in most nodes, this is used instead of
|
||||||
// a slice to save space.
|
// a slice to save space.
|
||||||
|
@ -116,12 +116,11 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
|
|||||||
var i int
|
var i int
|
||||||
for i = len(v.stack) - 1; i >= 0; i-- {
|
for i = len(v.stack) - 1; i >= 0; i-- {
|
||||||
x := v.stack[i]
|
x := v.stack[i]
|
||||||
|
v.nodeID[x] = ^uint32(0)
|
||||||
if x == n {
|
if x == n {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.nodeID[x] = ^uint32(0)
|
|
||||||
}
|
}
|
||||||
v.nodeID[n] = ^uint32(0)
|
|
||||||
block := v.stack[i:]
|
block := v.stack[i:]
|
||||||
// Run escape analysis on this set of functions.
|
// Run escape analysis on this set of functions.
|
||||||
v.stack = v.stack[:i]
|
v.stack = v.stack[:i]
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -154,8 +154,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
|
|||||||
name, obj := g.def(decl.Name)
|
name, obj := g.def(decl.Name)
|
||||||
ntyp, otyp := name.Type(), obj.Type()
|
ntyp, otyp := name.Type(), obj.Type()
|
||||||
if ir.CurFunc != nil {
|
if ir.CurFunc != nil {
|
||||||
typecheck.TypeGen++
|
ntyp.SetVargen()
|
||||||
ntyp.Vargen = typecheck.TypeGen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
|
pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
|
||||||
|
@ -37,8 +37,7 @@ func (g *irgen) funcBody(fn *ir.Func, recv *syntax.Field, sig *syntax.FuncType,
|
|||||||
// calculated its size, including parameter offsets. Now that we've
|
// calculated its size, including parameter offsets. Now that we've
|
||||||
// created the parameter Names, force a recalculation to ensure
|
// created the parameter Names, force a recalculation to ensure
|
||||||
// their offsets are correct.
|
// their offsets are correct.
|
||||||
typ.Align = 0
|
types.RecalcSize(typ)
|
||||||
types.CalcSize(typ)
|
|
||||||
|
|
||||||
if block != nil {
|
if block != nil {
|
||||||
typecheck.DeclContext = ir.PAUTO
|
typecheck.DeclContext = ir.PAUTO
|
||||||
|
@ -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?
|
||||||
|
@ -149,6 +149,9 @@ type irgen struct {
|
|||||||
// statements yet.
|
// statements yet.
|
||||||
exprStmtOK bool
|
exprStmtOK bool
|
||||||
|
|
||||||
|
// types which we need to finish, by doing g.fillinMethods.
|
||||||
|
typesToFinalize []*typeDelayInfo
|
||||||
|
|
||||||
// Fully-instantiated generic types whose methods should be instantiated
|
// Fully-instantiated generic types whose methods should be instantiated
|
||||||
instTypeList []*types.Type
|
instTypeList []*types.Type
|
||||||
|
|
||||||
@ -184,6 +187,11 @@ type delayInfo struct {
|
|||||||
off int
|
off int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type typeDelayInfo struct {
|
||||||
|
typ *types2.Named
|
||||||
|
ntyp *types.Type
|
||||||
|
}
|
||||||
|
|
||||||
func (g *irgen) generate(noders []*noder) {
|
func (g *irgen) generate(noders []*noder) {
|
||||||
types.LocalPkg.Name = g.self.Name()
|
types.LocalPkg.Name = g.self.Name()
|
||||||
types.LocalPkg.Height = g.self.Height()
|
types.LocalPkg.Height = g.self.Height()
|
||||||
|
@ -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" {
|
||||||
|
@ -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 {
|
||||||
|
@ -903,7 +903,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||||||
ir.EditChildren(m, edit)
|
ir.EditChildren(m, edit)
|
||||||
|
|
||||||
m.SetTypecheck(1)
|
m.SetTypecheck(1)
|
||||||
if typecheck.IsCmp(x.Op()) {
|
if x.Op().IsCmp() {
|
||||||
transformCompare(m.(*ir.BinaryExpr))
|
transformCompare(m.(*ir.BinaryExpr))
|
||||||
} else {
|
} else {
|
||||||
switch x.Op() {
|
switch x.Op() {
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
@ -35,6 +35,16 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
|
|||||||
types.DeferCheckSize()
|
types.DeferCheckSize()
|
||||||
res := g.typ1(typ)
|
res := g.typ1(typ)
|
||||||
types.ResumeCheckSize()
|
types.ResumeCheckSize()
|
||||||
|
|
||||||
|
// Finish up any types on typesToFinalize, now that we are at the top of a
|
||||||
|
// fully-defined (possibly recursive) type. fillinMethods could create more
|
||||||
|
// types to finalize.
|
||||||
|
for len(g.typesToFinalize) > 0 {
|
||||||
|
l := len(g.typesToFinalize)
|
||||||
|
info := g.typesToFinalize[l-1]
|
||||||
|
g.typesToFinalize = g.typesToFinalize[:l-1]
|
||||||
|
g.fillinMethods(info.typ, info.ntyp)
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +128,14 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
|||||||
return s.Def.Type()
|
return s.Def.Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the base generic type exists in type1 (it may
|
||||||
|
// not yet if we are referecing an imported generic type, as
|
||||||
|
// opposed to a generic type declared in this package).
|
||||||
|
_ = g.obj(typ.Orig().Obj())
|
||||||
|
|
||||||
// Create a forwarding type first and put it in the g.typs
|
// Create a forwarding type first and put it in the g.typs
|
||||||
// map, in order to deal with recursive generic types
|
// map, in order to deal with recursive generic types
|
||||||
// (including via method signatures).. Set up the extra
|
// (including via method signatures). Set up the extra
|
||||||
// ntyp information (Def, RParams, which may set
|
// ntyp information (Def, RParams, which may set
|
||||||
// HasTParam) before translating the underlying type
|
// HasTParam) before translating the underlying type
|
||||||
// itself, so we handle recursion correctly.
|
// itself, so we handle recursion correctly.
|
||||||
@ -146,10 +161,19 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
|||||||
ntyp.SetRParams(rparams)
|
ntyp.SetRParams(rparams)
|
||||||
//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
|
//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
|
||||||
|
|
||||||
ntyp.SetUnderlying(g.typ1(typ.Underlying()))
|
|
||||||
g.fillinMethods(typ, ntyp)
|
|
||||||
// Save the symbol for the base generic type.
|
// Save the symbol for the base generic type.
|
||||||
ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())
|
ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())
|
||||||
|
ntyp.SetUnderlying(g.typ1(typ.Underlying()))
|
||||||
|
if typ.NumMethods() != 0 {
|
||||||
|
// Save a delayed call to g.fillinMethods() (once
|
||||||
|
// potentially recursive types have been fully
|
||||||
|
// resolved).
|
||||||
|
g.typesToFinalize = append(g.typesToFinalize,
|
||||||
|
&typeDelayInfo{
|
||||||
|
typ: typ,
|
||||||
|
ntyp: ntyp,
|
||||||
|
})
|
||||||
|
}
|
||||||
return ntyp
|
return ntyp
|
||||||
}
|
}
|
||||||
obj := g.obj(typ.Obj())
|
obj := g.obj(typ.Obj())
|
||||||
@ -201,7 +225,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,11 +285,11 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillinMethods fills in the method name nodes and types for a defined type. This
|
// fillinMethods fills in the method name nodes and types for a defined type with at
|
||||||
// is needed for later typechecking when looking up methods of instantiated types,
|
// least one method. This is needed for later typechecking when looking up methods of
|
||||||
// and for actually generating the methods for instantiated types.
|
// instantiated types, and for actually generating the methods for instantiated
|
||||||
|
// types.
|
||||||
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
||||||
if typ.NumMethods() != 0 {
|
|
||||||
targs2 := typ.TArgs()
|
targs2 := typ.TArgs()
|
||||||
targs := make([]*types.Type, targs2.Len())
|
targs := make([]*types.Type, targs2.Len())
|
||||||
for i := range targs {
|
for i := range targs {
|
||||||
@ -331,7 +355,6 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
|||||||
// Generate all the methods for a new fully-instantiated type.
|
// Generate all the methods for a new fully-instantiated type.
|
||||||
g.instTypeList = append(g.instTypeList, ntyp)
|
g.instTypeList = append(g.instTypeList, ntyp)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
|
func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
|
||||||
|
@ -927,7 +927,7 @@ func formalType(t *types.Type) *types.Type {
|
|||||||
|
|
||||||
func writeType(t *types.Type) *obj.LSym {
|
func writeType(t *types.Type) *obj.LSym {
|
||||||
t = formalType(t)
|
t = formalType(t)
|
||||||
if t.IsUntyped() {
|
if t.IsUntyped() || t.HasTParam() {
|
||||||
base.Fatalf("writeType %v", t)
|
base.Fatalf("writeType %v", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -5,14 +5,16 @@
|
|||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
|
"cmd/compile/internal/typecheck"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/internal/obj/arm64"
|
"cmd/internal/obj/arm64"
|
||||||
"cmd/internal/obj/s390x"
|
"cmd/internal/obj/s390x"
|
||||||
"cmd/internal/obj/x86"
|
"cmd/internal/obj/x86"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var CheckFunc = checkFunc
|
var CheckFunc = checkFunc
|
||||||
@ -104,33 +106,12 @@ func (d TestFrontend) MyImportPath() string {
|
|||||||
var testTypes Types
|
var testTypes Types
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Initialize just enough of the universe and the types package to make our tests function.
|
// TODO(mdempsky): Push into types.InitUniverse or typecheck.InitUniverse.
|
||||||
// TODO(josharian): move universe initialization to the types package,
|
types.PtrSize = 8
|
||||||
// so this test setup can share it.
|
types.RegSize = 8
|
||||||
|
types.MaxWidth = 1 << 50
|
||||||
|
|
||||||
for _, typ := range [...]struct {
|
typecheck.InitUniverse()
|
||||||
width int64
|
|
||||||
et types.Kind
|
|
||||||
}{
|
|
||||||
{1, types.TINT8},
|
|
||||||
{1, types.TUINT8},
|
|
||||||
{1, types.TBOOL},
|
|
||||||
{2, types.TINT16},
|
|
||||||
{2, types.TUINT16},
|
|
||||||
{4, types.TINT32},
|
|
||||||
{4, types.TUINT32},
|
|
||||||
{4, types.TFLOAT32},
|
|
||||||
{4, types.TFLOAT64},
|
|
||||||
{8, types.TUINT64},
|
|
||||||
{8, types.TINT64},
|
|
||||||
{8, types.TINT},
|
|
||||||
{8, types.TUINTPTR},
|
|
||||||
} {
|
|
||||||
t := types.New(typ.et)
|
|
||||||
t.Width = typ.width
|
|
||||||
t.Align = uint8(typ.width)
|
|
||||||
types.Types[typ.et] = t
|
|
||||||
}
|
|
||||||
testTypes.SetTypPtrs()
|
testTypes.SetTypPtrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,22 @@ func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|||||||
// allocate space. In particular, it excludes arguments and results, which are in
|
// allocate space. In particular, it excludes arguments and results, which are in
|
||||||
// the callers frame.
|
// the callers frame.
|
||||||
func needAlloc(n *ir.Name) bool {
|
func needAlloc(n *ir.Name) bool {
|
||||||
return n.Class == ir.PAUTO || n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()
|
if n.Op() != ir.ONAME {
|
||||||
|
base.FatalfAt(n.Pos(), "%v has unexpected Op %v", n, n.Op())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch n.Class {
|
||||||
|
case ir.PAUTO:
|
||||||
|
return true
|
||||||
|
case ir.PPARAM:
|
||||||
|
return false
|
||||||
|
case ir.PPARAMOUT:
|
||||||
|
return n.IsOutputParamInRegisters()
|
||||||
|
|
||||||
|
default:
|
||||||
|
base.FatalfAt(n.Pos(), "%v has unexpected Class %v", n, n.Class)
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ssafn) AllocFrame(f *ssa.Func) {
|
func (s *ssafn) AllocFrame(f *ssa.Func) {
|
||||||
|
@ -1,209 +0,0 @@
|
|||||||
// Copyright 2015 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 ssagen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"cmd/compile/internal/ir"
|
|
||||||
"cmd/compile/internal/typecheck"
|
|
||||||
"cmd/compile/internal/types"
|
|
||||||
"cmd/internal/src"
|
|
||||||
)
|
|
||||||
|
|
||||||
func typeWithoutPointers() *types.Type {
|
|
||||||
return types.NewStruct(types.NoPkg, []*types.Field{
|
|
||||||
types.NewField(src.NoXPos, nil, types.New(types.TINT)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeWithPointers() *types.Type {
|
|
||||||
return types.NewStruct(types.NoPkg, []*types.Field{
|
|
||||||
types.NewField(src.NoXPos, nil, types.NewPtr(types.New(types.TINT))),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func markUsed(n *ir.Name) *ir.Name {
|
|
||||||
n.SetUsed(true)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func markNeedZero(n *ir.Name) *ir.Name {
|
|
||||||
n.SetNeedzero(true)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test all code paths for cmpstackvarlt.
|
|
||||||
func TestCmpstackvar(t *testing.T) {
|
|
||||||
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
|
|
||||||
if s == nil {
|
|
||||||
s = &types.Sym{Name: "."}
|
|
||||||
}
|
|
||||||
n := typecheck.NewName(s)
|
|
||||||
n.SetType(t)
|
|
||||||
n.SetFrameOffset(xoffset)
|
|
||||||
n.Class = cl
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
testdata := []struct {
|
|
||||||
a, b *ir.Name
|
|
||||||
lt bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
nod(0, nil, nil, ir.PAUTO),
|
|
||||||
nod(0, nil, nil, ir.PFUNC),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, nil, nil, ir.PFUNC),
|
|
||||||
nod(0, nil, nil, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, nil, nil, ir.PFUNC),
|
|
||||||
nod(10, nil, nil, ir.PFUNC),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(20, nil, nil, ir.PFUNC),
|
|
||||||
nod(10, nil, nil, ir.PFUNC),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(10, nil, nil, ir.PFUNC),
|
|
||||||
nod(10, nil, nil, ir.PFUNC),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(10, nil, nil, ir.PPARAM),
|
|
||||||
nod(20, nil, nil, ir.PPARAMOUT),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(10, nil, nil, ir.PPARAMOUT),
|
|
||||||
nod(20, nil, nil, ir.PPARAM),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
markUsed(nod(0, nil, nil, ir.PAUTO)),
|
|
||||||
nod(0, nil, nil, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, nil, nil, ir.PAUTO),
|
|
||||||
markUsed(nod(0, nil, nil, ir.PAUTO)),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, typeWithoutPointers(), nil, ir.PAUTO),
|
|
||||||
nod(0, typeWithPointers(), nil, ir.PAUTO),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, typeWithPointers(), nil, ir.PAUTO),
|
|
||||||
nod(0, typeWithoutPointers(), nil, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
|
|
||||||
nod(0, &types.Type{}, nil, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{}, nil, ir.PAUTO),
|
|
||||||
markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, d := range testdata {
|
|
||||||
got := cmpstackvarlt(d.a, d.b)
|
|
||||||
if got != d.lt {
|
|
||||||
t.Errorf("want %v < %v", d.a, d.b)
|
|
||||||
}
|
|
||||||
// If we expect a < b to be true, check that b < a is false.
|
|
||||||
if d.lt && cmpstackvarlt(d.b, d.a) {
|
|
||||||
t.Errorf("unexpected %v < %v", d.b, d.a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStackvarSort(t *testing.T) {
|
|
||||||
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
|
|
||||||
n := typecheck.NewName(s)
|
|
||||||
n.SetType(t)
|
|
||||||
n.SetFrameOffset(xoffset)
|
|
||||||
n.Class = cl
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
inp := []*ir.Name{
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
|
|
||||||
nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
|
|
||||||
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
|
|
||||||
nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
|
|
||||||
}
|
|
||||||
want := []*ir.Name{
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
|
|
||||||
markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
|
|
||||||
markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
|
|
||||||
nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
|
|
||||||
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
|
|
||||||
nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
|
|
||||||
}
|
|
||||||
sort.Sort(byStackVar(inp))
|
|
||||||
if !reflect.DeepEqual(want, inp) {
|
|
||||||
t.Error("sort failed")
|
|
||||||
for i := range inp {
|
|
||||||
g := inp[i]
|
|
||||||
w := want[i]
|
|
||||||
eq := reflect.DeepEqual(w, g)
|
|
||||||
if !eq {
|
|
||||||
t.Log(i, w, g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,11 +13,7 @@ func TestDump(t *testing.T) {
|
|||||||
t.Skip("skipping test in short mode")
|
t.Skip("skipping test in short mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// provide a no-op error handler so parsing doesn't stop after first error
|
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
|
||||||
ast, err := ParseFile(*src_, func(error) {}, nil, CheckBranches)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ast != nil {
|
if ast != nil {
|
||||||
Fdump(testOut(), ast)
|
Fdump(testOut(), ast)
|
||||||
|
@ -1924,7 +1924,7 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// distribute parameter types (len(list) > 0)
|
// distribute parameter types (len(list) > 0)
|
||||||
if named == 0 {
|
if named == 0 && !requireNames {
|
||||||
// all unnamed => found names are named types
|
// all unnamed => found names are named types
|
||||||
for _, par := range list {
|
for _, par := range list {
|
||||||
if typ := par.Name; typ != nil {
|
if typ := par.Name; typ != nil {
|
||||||
@ -1932,9 +1932,6 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
|
|||||||
par.Name = nil
|
par.Name = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if requireNames {
|
|
||||||
p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named")
|
|
||||||
}
|
|
||||||
} else if named != len(list) {
|
} else if named != len(list) {
|
||||||
// some named => all must have names and types
|
// some named => all must have names and types
|
||||||
var pos Pos // left-most error position (or unknown)
|
var pos Pos // left-most error position (or unknown)
|
||||||
|
@ -18,11 +18,7 @@ func TestPrint(t *testing.T) {
|
|||||||
t.Skip("skipping test in short mode")
|
t.Skip("skipping test in short mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// provide a no-op error handler so parsing doesn't stop after first error
|
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
|
||||||
ast, err := ParseFile(*src_, func(error) {}, nil, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ast != nil {
|
if ast != nil {
|
||||||
Fprint(testOut(), ast, LineForm)
|
Fprint(testOut(), ast, LineForm)
|
||||||
|
@ -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 {
|
||||||
|
@ -77,10 +77,6 @@ func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
|
|||||||
return l, r, t
|
return l, r, t
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsCmp(op ir.Op) bool {
|
|
||||||
return iscmp[op]
|
|
||||||
}
|
|
||||||
|
|
||||||
// tcArith typechecks operands of a binary arithmetic expression.
|
// tcArith typechecks operands of a binary arithmetic expression.
|
||||||
// The result of tcArith MUST be assigned back to original operands,
|
// The result of tcArith MUST be assigned back to original operands,
|
||||||
// t is the type of the expression, and should be set by the caller. e.g:
|
// t is the type of the expression, and should be set by the caller. e.g:
|
||||||
@ -96,7 +92,7 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type)
|
|||||||
t = r.Type()
|
t = r.Type()
|
||||||
}
|
}
|
||||||
aop := ir.OXXX
|
aop := ir.OXXX
|
||||||
if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
if n.Op().IsCmp() && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
||||||
// comparison is okay as long as one side is
|
// comparison is okay as long as one side is
|
||||||
// assignable to the other. convert so they have
|
// assignable to the other. convert so they have
|
||||||
// the same type.
|
// the same type.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -1736,11 +1736,6 @@ func CheckMapKeys() {
|
|||||||
mapqueue = nil
|
mapqueue = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeGen tracks the number of function-scoped defined types that
|
|
||||||
// have been declared. It's used to generate unique linker symbols for
|
|
||||||
// their runtime type descriptors.
|
|
||||||
var TypeGen int32
|
|
||||||
|
|
||||||
func typecheckdeftype(n *ir.Name) {
|
func typecheckdeftype(n *ir.Name) {
|
||||||
if base.EnableTrace && base.Flag.LowerT {
|
if base.EnableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckdeftype", n)(nil)
|
defer tracePrint("typecheckdeftype", n)(nil)
|
||||||
@ -1748,8 +1743,7 @@ func typecheckdeftype(n *ir.Name) {
|
|||||||
|
|
||||||
t := types.NewNamed(n)
|
t := types.NewNamed(n)
|
||||||
if n.Curfn != nil {
|
if n.Curfn != nil {
|
||||||
TypeGen++
|
t.SetVargen()
|
||||||
t.Vargen = TypeGen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Pragma()&ir.NotInHeap != 0 {
|
if n.Pragma()&ir.NotInHeap != 0 {
|
||||||
|
@ -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 {
|
||||||
@ -329,28 +211,6 @@ func InitUniverse() {
|
|||||||
// special
|
// special
|
||||||
okfor[ir.OCAP] = okforcap[:]
|
okfor[ir.OCAP] = okforcap[:]
|
||||||
okfor[ir.OLEN] = okforlen[:]
|
okfor[ir.OLEN] = okforlen[:]
|
||||||
|
|
||||||
// comparison
|
|
||||||
iscmp[ir.OLT] = true
|
|
||||||
iscmp[ir.OGT] = true
|
|
||||||
iscmp[ir.OGE] = true
|
|
||||||
iscmp[ir.OLE] = true
|
|
||||||
iscmp[ir.OEQ] = true
|
|
||||||
iscmp[ir.ONE] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -298,7 +301,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Kind() == TSSA {
|
if t.Kind() == TSSA {
|
||||||
b.WriteString(t.Extra.(string))
|
b.WriteString(t.extra.(string))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Kind() == TTUPLE {
|
if t.Kind() == TTUPLE {
|
||||||
@ -309,7 +312,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t.Kind() == TRESULTS {
|
if t.Kind() == TRESULTS {
|
||||||
tys := t.Extra.(*Results).Types
|
tys := t.extra.(*Results).Types
|
||||||
for i, et := range tys {
|
for i, et := range tys {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
b.WriteByte(',')
|
b.WriteByte(',')
|
||||||
@ -361,8 +364,8 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
|||||||
// output too. It seems like it should, but that mode is currently
|
// output too. It seems like it should, but that mode is currently
|
||||||
// used in string representation used by reflection, which is
|
// used in string representation used by reflection, which is
|
||||||
// user-visible and doesn't expect this.
|
// user-visible and doesn't expect this.
|
||||||
if mode == fmtTypeID && t.Vargen != 0 {
|
if mode == fmtTypeID && t.vargen != 0 {
|
||||||
fmt.Fprintf(b, "·%d", t.Vargen)
|
fmt.Fprintf(b, "·%d", t.vargen)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,7 @@ func CalcSize(t *Type) {
|
|||||||
w = calcStructOffset(t1, t1.Recvs(), 0, 0)
|
w = calcStructOffset(t1, t1.Recvs(), 0, 0)
|
||||||
w = calcStructOffset(t1, t1.Params(), w, RegSize)
|
w = calcStructOffset(t1, t1.Params(), w, RegSize)
|
||||||
w = calcStructOffset(t1, t1.Results(), w, RegSize)
|
w = calcStructOffset(t1, t1.Results(), w, RegSize)
|
||||||
t1.Extra.(*Func).Argwid = w
|
t1.extra.(*Func).Argwid = w
|
||||||
if w%int64(RegSize) != 0 {
|
if w%int64(RegSize) != 0 {
|
||||||
base.Warn("bad type %v %d\n", t1, w)
|
base.Warn("bad type %v %d\n", t1, w)
|
||||||
}
|
}
|
||||||
@ -562,6 +562,14 @@ func CalcStructSize(s *Type) {
|
|||||||
s.Width = calcStructOffset(s, s, 0, 1) // sets align
|
s.Width = calcStructOffset(s, s, 0, 1) // sets align
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RecalcSize is like CalcSize, but recalculates t's size even if it
|
||||||
|
// has already been calculated before. It does not recalculate other
|
||||||
|
// types.
|
||||||
|
func RecalcSize(t *Type) {
|
||||||
|
t.Align = 0
|
||||||
|
CalcSize(t)
|
||||||
|
}
|
||||||
|
|
||||||
// when a type's width should be known, we call CheckSize
|
// when a type's width should be known, we call CheckSize
|
||||||
// to compute it. during a declaration like
|
// to compute it. during a declaration like
|
||||||
//
|
//
|
||||||
|
@ -139,7 +139,7 @@ var (
|
|||||||
|
|
||||||
// A Type represents a Go type.
|
// A Type represents a Go type.
|
||||||
type Type struct {
|
type Type struct {
|
||||||
// Extra contains extra etype-specific fields.
|
// extra contains extra etype-specific fields.
|
||||||
// As an optimization, those etype-specific structs which contain exactly
|
// As an optimization, those etype-specific structs which contain exactly
|
||||||
// one pointer-shaped field are stored as values rather than pointers when possible.
|
// one pointer-shaped field are stored as values rather than pointers when possible.
|
||||||
//
|
//
|
||||||
@ -156,7 +156,7 @@ type Type struct {
|
|||||||
// TSLICE: Slice
|
// TSLICE: Slice
|
||||||
// TSSA: string
|
// TSSA: string
|
||||||
// TTYPEPARAM: *Typeparam
|
// TTYPEPARAM: *Typeparam
|
||||||
Extra interface{}
|
extra interface{}
|
||||||
|
|
||||||
// Width is the width of this Type in bytes.
|
// Width is the width of this Type in bytes.
|
||||||
Width int64 // valid if Align > 0
|
Width int64 // valid if Align > 0
|
||||||
@ -178,7 +178,7 @@ type Type struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sym *Sym // symbol containing name, for named types
|
sym *Sym // symbol containing name, for named types
|
||||||
Vargen int32 // unique name for OTYPE/ONAME
|
vargen int32 // unique name for OTYPE/ONAME
|
||||||
|
|
||||||
kind Kind // kind of type
|
kind Kind // kind of type
|
||||||
Align uint8 // the required alignment of this type, in bytes (0 means Width and Align have not yet been computed)
|
Align uint8 // the required alignment of this type, in bytes (0 means Width and Align have not yet been computed)
|
||||||
@ -325,11 +325,11 @@ var NoPkg *Pkg = nil
|
|||||||
func (t *Type) Pkg() *Pkg {
|
func (t *Type) Pkg() *Pkg {
|
||||||
switch t.kind {
|
switch t.kind {
|
||||||
case TFUNC:
|
case TFUNC:
|
||||||
return t.Extra.(*Func).pkg
|
return t.extra.(*Func).pkg
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
return t.Extra.(*Struct).pkg
|
return t.extra.(*Struct).pkg
|
||||||
case TINTER:
|
case TINTER:
|
||||||
return t.Extra.(*Interface).pkg
|
return t.extra.(*Interface).pkg
|
||||||
default:
|
default:
|
||||||
base.Fatalf("Pkg: unexpected kind: %v", t)
|
base.Fatalf("Pkg: unexpected kind: %v", t)
|
||||||
return nil
|
return nil
|
||||||
@ -349,7 +349,7 @@ type Map struct {
|
|||||||
// MapType returns t's extra map-specific fields.
|
// MapType returns t's extra map-specific fields.
|
||||||
func (t *Type) MapType() *Map {
|
func (t *Type) MapType() *Map {
|
||||||
t.wantEtype(TMAP)
|
t.wantEtype(TMAP)
|
||||||
return t.Extra.(*Map)
|
return t.extra.(*Map)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward contains Type fields specific to forward types.
|
// Forward contains Type fields specific to forward types.
|
||||||
@ -361,7 +361,7 @@ type Forward struct {
|
|||||||
// ForwardType returns t's extra forward-type-specific fields.
|
// ForwardType returns t's extra forward-type-specific fields.
|
||||||
func (t *Type) ForwardType() *Forward {
|
func (t *Type) ForwardType() *Forward {
|
||||||
t.wantEtype(TFORW)
|
t.wantEtype(TFORW)
|
||||||
return t.Extra.(*Forward)
|
return t.extra.(*Forward)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Func contains Type fields specific to func types.
|
// Func contains Type fields specific to func types.
|
||||||
@ -382,7 +382,7 @@ type Func struct {
|
|||||||
// FuncType returns t's extra func-specific fields.
|
// FuncType returns t's extra func-specific fields.
|
||||||
func (t *Type) FuncType() *Func {
|
func (t *Type) FuncType() *Func {
|
||||||
t.wantEtype(TFUNC)
|
t.wantEtype(TFUNC)
|
||||||
return t.Extra.(*Func)
|
return t.extra.(*Func)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructType contains Type fields specific to struct types.
|
// StructType contains Type fields specific to struct types.
|
||||||
@ -411,7 +411,7 @@ const (
|
|||||||
// StructType returns t's extra struct-specific fields.
|
// StructType returns t's extra struct-specific fields.
|
||||||
func (t *Type) StructType() *Struct {
|
func (t *Type) StructType() *Struct {
|
||||||
t.wantEtype(TSTRUCT)
|
t.wantEtype(TSTRUCT)
|
||||||
return t.Extra.(*Struct)
|
return t.extra.(*Struct)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface contains Type fields specific to interface types.
|
// Interface contains Type fields specific to interface types.
|
||||||
@ -455,7 +455,7 @@ type Chan struct {
|
|||||||
// ChanType returns t's extra channel-specific fields.
|
// ChanType returns t's extra channel-specific fields.
|
||||||
func (t *Type) ChanType() *Chan {
|
func (t *Type) ChanType() *Chan {
|
||||||
t.wantEtype(TCHAN)
|
t.wantEtype(TCHAN)
|
||||||
return t.Extra.(*Chan)
|
return t.extra.(*Chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tuple struct {
|
type Tuple struct {
|
||||||
@ -590,31 +590,31 @@ func New(et Kind) *Type {
|
|||||||
// TODO(josharian): lazily initialize some of these?
|
// TODO(josharian): lazily initialize some of these?
|
||||||
switch t.kind {
|
switch t.kind {
|
||||||
case TMAP:
|
case TMAP:
|
||||||
t.Extra = new(Map)
|
t.extra = new(Map)
|
||||||
case TFORW:
|
case TFORW:
|
||||||
t.Extra = new(Forward)
|
t.extra = new(Forward)
|
||||||
case TFUNC:
|
case TFUNC:
|
||||||
t.Extra = new(Func)
|
t.extra = new(Func)
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
t.Extra = new(Struct)
|
t.extra = new(Struct)
|
||||||
case TINTER:
|
case TINTER:
|
||||||
t.Extra = new(Interface)
|
t.extra = new(Interface)
|
||||||
case TPTR:
|
case TPTR:
|
||||||
t.Extra = Ptr{}
|
t.extra = Ptr{}
|
||||||
case TCHANARGS:
|
case TCHANARGS:
|
||||||
t.Extra = ChanArgs{}
|
t.extra = ChanArgs{}
|
||||||
case TFUNCARGS:
|
case TFUNCARGS:
|
||||||
t.Extra = FuncArgs{}
|
t.extra = FuncArgs{}
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
t.Extra = new(Chan)
|
t.extra = new(Chan)
|
||||||
case TTUPLE:
|
case TTUPLE:
|
||||||
t.Extra = new(Tuple)
|
t.extra = new(Tuple)
|
||||||
case TRESULTS:
|
case TRESULTS:
|
||||||
t.Extra = new(Results)
|
t.extra = new(Results)
|
||||||
case TTYPEPARAM:
|
case TTYPEPARAM:
|
||||||
t.Extra = new(Typeparam)
|
t.extra = new(Typeparam)
|
||||||
case TUNION:
|
case TUNION:
|
||||||
t.Extra = new(Union)
|
t.extra = new(Union)
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
@ -625,7 +625,7 @@ func NewArray(elem *Type, bound int64) *Type {
|
|||||||
base.Fatalf("NewArray: invalid bound %v", bound)
|
base.Fatalf("NewArray: invalid bound %v", bound)
|
||||||
}
|
}
|
||||||
t := New(TARRAY)
|
t := New(TARRAY)
|
||||||
t.Extra = &Array{Elem: elem, Bound: bound}
|
t.extra = &Array{Elem: elem, Bound: bound}
|
||||||
t.SetNotInHeap(elem.NotInHeap())
|
t.SetNotInHeap(elem.NotInHeap())
|
||||||
if elem.HasTParam() {
|
if elem.HasTParam() {
|
||||||
t.SetHasTParam(true)
|
t.SetHasTParam(true)
|
||||||
@ -646,7 +646,7 @@ func NewSlice(elem *Type) *Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t := New(TSLICE)
|
t := New(TSLICE)
|
||||||
t.Extra = Slice{Elem: elem}
|
t.extra = Slice{Elem: elem}
|
||||||
elem.cache.slice = t
|
elem.cache.slice = t
|
||||||
if elem.HasTParam() {
|
if elem.HasTParam() {
|
||||||
t.SetHasTParam(true)
|
t.SetHasTParam(true)
|
||||||
@ -674,8 +674,8 @@ func NewChan(elem *Type, dir ChanDir) *Type {
|
|||||||
|
|
||||||
func NewTuple(t1, t2 *Type) *Type {
|
func NewTuple(t1, t2 *Type) *Type {
|
||||||
t := New(TTUPLE)
|
t := New(TTUPLE)
|
||||||
t.Extra.(*Tuple).first = t1
|
t.extra.(*Tuple).first = t1
|
||||||
t.Extra.(*Tuple).second = t2
|
t.extra.(*Tuple).second = t2
|
||||||
if t1.HasTParam() || t2.HasTParam() {
|
if t1.HasTParam() || t2.HasTParam() {
|
||||||
t.SetHasTParam(true)
|
t.SetHasTParam(true)
|
||||||
}
|
}
|
||||||
@ -687,7 +687,7 @@ func NewTuple(t1, t2 *Type) *Type {
|
|||||||
|
|
||||||
func newResults(types []*Type) *Type {
|
func newResults(types []*Type) *Type {
|
||||||
t := New(TRESULTS)
|
t := New(TRESULTS)
|
||||||
t.Extra.(*Results).Types = types
|
t.extra.(*Results).Types = types
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +700,7 @@ func NewResults(types []*Type) *Type {
|
|||||||
|
|
||||||
func newSSA(name string) *Type {
|
func newSSA(name string) *Type {
|
||||||
t := New(TSSA)
|
t := New(TSSA)
|
||||||
t.Extra = name
|
t.extra = name
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +747,7 @@ func NewPtr(elem *Type) *Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t := New(TPTR)
|
t := New(TPTR)
|
||||||
t.Extra = Ptr{Elem: elem}
|
t.extra = Ptr{Elem: elem}
|
||||||
t.Width = int64(PtrSize)
|
t.Width = int64(PtrSize)
|
||||||
t.Align = uint8(PtrSize)
|
t.Align = uint8(PtrSize)
|
||||||
if NewPtrCacheEnabled {
|
if NewPtrCacheEnabled {
|
||||||
@ -765,14 +765,14 @@ func NewPtr(elem *Type) *Type {
|
|||||||
// NewChanArgs returns a new TCHANARGS type for channel type c.
|
// NewChanArgs returns a new TCHANARGS type for channel type c.
|
||||||
func NewChanArgs(c *Type) *Type {
|
func NewChanArgs(c *Type) *Type {
|
||||||
t := New(TCHANARGS)
|
t := New(TCHANARGS)
|
||||||
t.Extra = ChanArgs{T: c}
|
t.extra = ChanArgs{T: c}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFuncArgs returns a new TFUNCARGS type for func type f.
|
// NewFuncArgs returns a new TFUNCARGS type for func type f.
|
||||||
func NewFuncArgs(f *Type) *Type {
|
func NewFuncArgs(f *Type) *Type {
|
||||||
t := New(TFUNCARGS)
|
t := New(TFUNCARGS)
|
||||||
t.Extra = FuncArgs{T: f}
|
t.extra = FuncArgs{T: f}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,28 +811,28 @@ func SubstAny(t *Type, types *[]*Type) *Type {
|
|||||||
elem := SubstAny(t.Elem(), types)
|
elem := SubstAny(t.Elem(), types)
|
||||||
if elem != t.Elem() {
|
if elem != t.Elem() {
|
||||||
t = t.copy()
|
t = t.copy()
|
||||||
t.Extra = Ptr{Elem: elem}
|
t.extra = Ptr{Elem: elem}
|
||||||
}
|
}
|
||||||
|
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
elem := SubstAny(t.Elem(), types)
|
elem := SubstAny(t.Elem(), types)
|
||||||
if elem != t.Elem() {
|
if elem != t.Elem() {
|
||||||
t = t.copy()
|
t = t.copy()
|
||||||
t.Extra.(*Array).Elem = elem
|
t.extra.(*Array).Elem = elem
|
||||||
}
|
}
|
||||||
|
|
||||||
case TSLICE:
|
case TSLICE:
|
||||||
elem := SubstAny(t.Elem(), types)
|
elem := SubstAny(t.Elem(), types)
|
||||||
if elem != t.Elem() {
|
if elem != t.Elem() {
|
||||||
t = t.copy()
|
t = t.copy()
|
||||||
t.Extra = Slice{Elem: elem}
|
t.extra = Slice{Elem: elem}
|
||||||
}
|
}
|
||||||
|
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
elem := SubstAny(t.Elem(), types)
|
elem := SubstAny(t.Elem(), types)
|
||||||
if elem != t.Elem() {
|
if elem != t.Elem() {
|
||||||
t = t.copy()
|
t = t.copy()
|
||||||
t.Extra.(*Chan).Elem = elem
|
t.extra.(*Chan).Elem = elem
|
||||||
}
|
}
|
||||||
|
|
||||||
case TMAP:
|
case TMAP:
|
||||||
@ -840,8 +840,8 @@ func SubstAny(t *Type, types *[]*Type) *Type {
|
|||||||
elem := SubstAny(t.Elem(), types)
|
elem := SubstAny(t.Elem(), types)
|
||||||
if key != t.Key() || elem != t.Elem() {
|
if key != t.Key() || elem != t.Elem() {
|
||||||
t = t.copy()
|
t = t.copy()
|
||||||
t.Extra.(*Map).Key = key
|
t.extra.(*Map).Key = key
|
||||||
t.Extra.(*Map).Elem = elem
|
t.extra.(*Map).Elem = elem
|
||||||
}
|
}
|
||||||
|
|
||||||
case TFUNC:
|
case TFUNC:
|
||||||
@ -882,26 +882,26 @@ func (t *Type) copy() *Type {
|
|||||||
// copy any *T Extra fields, to avoid aliasing
|
// copy any *T Extra fields, to avoid aliasing
|
||||||
switch t.kind {
|
switch t.kind {
|
||||||
case TMAP:
|
case TMAP:
|
||||||
x := *t.Extra.(*Map)
|
x := *t.extra.(*Map)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TFORW:
|
case TFORW:
|
||||||
x := *t.Extra.(*Forward)
|
x := *t.extra.(*Forward)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TFUNC:
|
case TFUNC:
|
||||||
x := *t.Extra.(*Func)
|
x := *t.extra.(*Func)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
x := *t.Extra.(*Struct)
|
x := *t.extra.(*Struct)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TINTER:
|
case TINTER:
|
||||||
x := *t.Extra.(*Interface)
|
x := *t.extra.(*Interface)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
x := *t.Extra.(*Chan)
|
x := *t.extra.(*Chan)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
x := *t.Extra.(*Array)
|
x := *t.extra.(*Array)
|
||||||
nt.Extra = &x
|
nt.extra = &x
|
||||||
case TTYPEPARAM:
|
case TTYPEPARAM:
|
||||||
base.Fatalf("typeparam types cannot be copied")
|
base.Fatalf("typeparam types cannot be copied")
|
||||||
case TTUPLE, TSSA, TRESULTS:
|
case TTUPLE, TSSA, TRESULTS:
|
||||||
@ -970,7 +970,7 @@ var ParamsResults = [2]func(*Type) *Type{
|
|||||||
// Key returns the key type of map type t.
|
// Key returns the key type of map type t.
|
||||||
func (t *Type) Key() *Type {
|
func (t *Type) Key() *Type {
|
||||||
t.wantEtype(TMAP)
|
t.wantEtype(TMAP)
|
||||||
return t.Extra.(*Map).Key
|
return t.extra.(*Map).Key
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elem returns the type of elements of t.
|
// Elem returns the type of elements of t.
|
||||||
@ -978,15 +978,15 @@ func (t *Type) Key() *Type {
|
|||||||
func (t *Type) Elem() *Type {
|
func (t *Type) Elem() *Type {
|
||||||
switch t.kind {
|
switch t.kind {
|
||||||
case TPTR:
|
case TPTR:
|
||||||
return t.Extra.(Ptr).Elem
|
return t.extra.(Ptr).Elem
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
return t.Extra.(*Array).Elem
|
return t.extra.(*Array).Elem
|
||||||
case TSLICE:
|
case TSLICE:
|
||||||
return t.Extra.(Slice).Elem
|
return t.extra.(Slice).Elem
|
||||||
case TCHAN:
|
case TCHAN:
|
||||||
return t.Extra.(*Chan).Elem
|
return t.extra.(*Chan).Elem
|
||||||
case TMAP:
|
case TMAP:
|
||||||
return t.Extra.(*Map).Elem
|
return t.extra.(*Map).Elem
|
||||||
}
|
}
|
||||||
base.Fatalf("Type.Elem %s", t.kind)
|
base.Fatalf("Type.Elem %s", t.kind)
|
||||||
return nil
|
return nil
|
||||||
@ -995,18 +995,18 @@ func (t *Type) Elem() *Type {
|
|||||||
// ChanArgs returns the channel type for TCHANARGS type t.
|
// ChanArgs returns the channel type for TCHANARGS type t.
|
||||||
func (t *Type) ChanArgs() *Type {
|
func (t *Type) ChanArgs() *Type {
|
||||||
t.wantEtype(TCHANARGS)
|
t.wantEtype(TCHANARGS)
|
||||||
return t.Extra.(ChanArgs).T
|
return t.extra.(ChanArgs).T
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncArgs returns the func type for TFUNCARGS type t.
|
// FuncArgs returns the func type for TFUNCARGS type t.
|
||||||
func (t *Type) FuncArgs() *Type {
|
func (t *Type) FuncArgs() *Type {
|
||||||
t.wantEtype(TFUNCARGS)
|
t.wantEtype(TFUNCARGS)
|
||||||
return t.Extra.(FuncArgs).T
|
return t.extra.(FuncArgs).T
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFuncArgStruct reports whether t is a struct representing function parameters or results.
|
// IsFuncArgStruct reports whether t is a struct representing function parameters or results.
|
||||||
func (t *Type) IsFuncArgStruct() bool {
|
func (t *Type) IsFuncArgStruct() bool {
|
||||||
return t.kind == TSTRUCT && t.Extra.(*Struct).Funarg != FunargNone
|
return t.kind == TSTRUCT && t.extra.(*Struct).Funarg != FunargNone
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods returns a pointer to the base methods (excluding embedding) for type t.
|
// Methods returns a pointer to the base methods (excluding embedding) for type t.
|
||||||
@ -1037,7 +1037,7 @@ func (t *Type) SetAllMethods(fs []*Field) {
|
|||||||
// Fields returns the fields of struct type t.
|
// Fields returns the fields of struct type t.
|
||||||
func (t *Type) Fields() *Fields {
|
func (t *Type) Fields() *Fields {
|
||||||
t.wantEtype(TSTRUCT)
|
t.wantEtype(TSTRUCT)
|
||||||
return &t.Extra.(*Struct).fields
|
return &t.extra.(*Struct).fields
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field returns the i'th field of struct type t.
|
// Field returns the i'th field of struct type t.
|
||||||
@ -1091,7 +1091,7 @@ func (t *Type) WidthCalculated() bool {
|
|||||||
// It includes the receiver, parameters, and results.
|
// It includes the receiver, parameters, and results.
|
||||||
func (t *Type) ArgWidth() int64 {
|
func (t *Type) ArgWidth() int64 {
|
||||||
t.wantEtype(TFUNC)
|
t.wantEtype(TFUNC)
|
||||||
return t.Extra.(*Func).Argwid
|
return t.extra.(*Func).Argwid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) Size() int64 {
|
func (t *Type) Size() int64 {
|
||||||
@ -1221,8 +1221,8 @@ func (t *Type) cmp(x *Type) Cmp {
|
|||||||
|
|
||||||
if x.sym != nil {
|
if x.sym != nil {
|
||||||
// Syms non-nil, if vargens match then equal.
|
// Syms non-nil, if vargens match then equal.
|
||||||
if t.Vargen != x.Vargen {
|
if t.vargen != x.vargen {
|
||||||
return cmpForNe(t.Vargen < x.Vargen)
|
return cmpForNe(t.vargen < x.vargen)
|
||||||
}
|
}
|
||||||
return CMPeq
|
return CMPeq
|
||||||
}
|
}
|
||||||
@ -1234,8 +1234,8 @@ func (t *Type) cmp(x *Type) Cmp {
|
|||||||
return CMPeq
|
return CMPeq
|
||||||
|
|
||||||
case TSSA:
|
case TSSA:
|
||||||
tname := t.Extra.(string)
|
tname := t.extra.(string)
|
||||||
xname := x.Extra.(string)
|
xname := x.extra.(string)
|
||||||
// desire fast sorting, not pretty sorting.
|
// desire fast sorting, not pretty sorting.
|
||||||
if len(tname) == len(xname) {
|
if len(tname) == len(xname) {
|
||||||
if tname == xname {
|
if tname == xname {
|
||||||
@ -1252,16 +1252,16 @@ func (t *Type) cmp(x *Type) Cmp {
|
|||||||
return CMPlt
|
return CMPlt
|
||||||
|
|
||||||
case TTUPLE:
|
case TTUPLE:
|
||||||
xtup := x.Extra.(*Tuple)
|
xtup := x.extra.(*Tuple)
|
||||||
ttup := t.Extra.(*Tuple)
|
ttup := t.extra.(*Tuple)
|
||||||
if c := ttup.first.Compare(xtup.first); c != CMPeq {
|
if c := ttup.first.Compare(xtup.first); c != CMPeq {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
return ttup.second.Compare(xtup.second)
|
return ttup.second.Compare(xtup.second)
|
||||||
|
|
||||||
case TRESULTS:
|
case TRESULTS:
|
||||||
xResults := x.Extra.(*Results)
|
xResults := x.extra.(*Results)
|
||||||
tResults := t.Extra.(*Results)
|
tResults := t.extra.(*Results)
|
||||||
xl, tl := len(xResults.Types), len(tResults.Types)
|
xl, tl := len(xResults.Types), len(tResults.Types)
|
||||||
if tl != xl {
|
if tl != xl {
|
||||||
if tl < xl {
|
if tl < xl {
|
||||||
@ -1548,7 +1548,7 @@ func (t *Type) PtrTo() *Type {
|
|||||||
|
|
||||||
func (t *Type) NumFields() int {
|
func (t *Type) NumFields() int {
|
||||||
if t.kind == TRESULTS {
|
if t.kind == TRESULTS {
|
||||||
return len(t.Extra.(*Results).Types)
|
return len(t.extra.(*Results).Types)
|
||||||
}
|
}
|
||||||
return t.Fields().Len()
|
return t.Fields().Len()
|
||||||
}
|
}
|
||||||
@ -1556,15 +1556,15 @@ func (t *Type) FieldType(i int) *Type {
|
|||||||
if t.kind == TTUPLE {
|
if t.kind == TTUPLE {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
return t.Extra.(*Tuple).first
|
return t.extra.(*Tuple).first
|
||||||
case 1:
|
case 1:
|
||||||
return t.Extra.(*Tuple).second
|
return t.extra.(*Tuple).second
|
||||||
default:
|
default:
|
||||||
panic("bad tuple index")
|
panic("bad tuple index")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t.kind == TRESULTS {
|
if t.kind == TRESULTS {
|
||||||
return t.Extra.(*Results).Types[i]
|
return t.extra.(*Results).Types[i]
|
||||||
}
|
}
|
||||||
return t.Field(i).Type
|
return t.Field(i).Type
|
||||||
}
|
}
|
||||||
@ -1577,7 +1577,7 @@ func (t *Type) FieldName(i int) string {
|
|||||||
|
|
||||||
func (t *Type) NumElem() int64 {
|
func (t *Type) NumElem() int64 {
|
||||||
t.wantEtype(TARRAY)
|
t.wantEtype(TARRAY)
|
||||||
return t.Extra.(*Array).Bound
|
return t.extra.(*Array).Bound
|
||||||
}
|
}
|
||||||
|
|
||||||
type componentsIncludeBlankFields bool
|
type componentsIncludeBlankFields bool
|
||||||
@ -1639,15 +1639,15 @@ func (t *Type) SoleComponent() *Type {
|
|||||||
// The direction will be one of Crecv, Csend, or Cboth.
|
// The direction will be one of Crecv, Csend, or Cboth.
|
||||||
func (t *Type) ChanDir() ChanDir {
|
func (t *Type) ChanDir() ChanDir {
|
||||||
t.wantEtype(TCHAN)
|
t.wantEtype(TCHAN)
|
||||||
return t.Extra.(*Chan).Dir
|
return t.extra.(*Chan).Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) IsMemory() bool {
|
func (t *Type) IsMemory() bool {
|
||||||
if t == TypeMem || t.kind == TTUPLE && t.Extra.(*Tuple).second == TypeMem {
|
if t == TypeMem || t.kind == TTUPLE && t.extra.(*Tuple).second == TypeMem {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if t.kind == TRESULTS {
|
if t.kind == TRESULTS {
|
||||||
if types := t.Extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
|
if types := t.extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1699,11 +1699,11 @@ func (t *Type) HasPointers() bool {
|
|||||||
return !t.Elem().NotInHeap()
|
return !t.Elem().NotInHeap()
|
||||||
|
|
||||||
case TTUPLE:
|
case TTUPLE:
|
||||||
ttup := t.Extra.(*Tuple)
|
ttup := t.extra.(*Tuple)
|
||||||
return ttup.first.HasPointers() || ttup.second.HasPointers()
|
return ttup.first.HasPointers() || ttup.second.HasPointers()
|
||||||
|
|
||||||
case TRESULTS:
|
case TRESULTS:
|
||||||
types := t.Extra.(*Results).Types
|
types := t.extra.(*Results).Types
|
||||||
for _, et := range types {
|
for _, et := range types {
|
||||||
if et.HasPointers() {
|
if et.HasPointers() {
|
||||||
return true
|
return true
|
||||||
@ -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")
|
||||||
@ -1768,6 +1772,25 @@ func (t *Type) Obj() Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// typeGen tracks the number of function-scoped defined types that
|
||||||
|
// have been declared. It's used to generate unique linker symbols for
|
||||||
|
// their runtime type descriptors.
|
||||||
|
var typeGen int32
|
||||||
|
|
||||||
|
// SetVargen assigns a unique generation number to type t, which must
|
||||||
|
// be a defined type declared within function scope. The generation
|
||||||
|
// number is used to distinguish it from other similarly spelled
|
||||||
|
// defined types from the same package.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Come up with a better solution.
|
||||||
|
func (t *Type) SetVargen() {
|
||||||
|
base.Assertf(t.Sym() != nil, "SetVargen on anonymous type %v", t)
|
||||||
|
base.Assertf(t.vargen == 0, "type %v already has Vargen %v", t, t.vargen)
|
||||||
|
|
||||||
|
typeGen++
|
||||||
|
t.vargen = typeGen
|
||||||
|
}
|
||||||
|
|
||||||
// SetUnderlying sets the underlying type. SetUnderlying automatically updates any
|
// SetUnderlying sets the underlying type. SetUnderlying automatically updates any
|
||||||
// types that were waiting for this type to be completed.
|
// types that were waiting for this type to be completed.
|
||||||
func (t *Type) SetUnderlying(underlying *Type) {
|
func (t *Type) SetUnderlying(underlying *Type) {
|
||||||
@ -1781,7 +1804,7 @@ func (t *Type) SetUnderlying(underlying *Type) {
|
|||||||
|
|
||||||
// TODO(mdempsky): Fix Type rekinding.
|
// TODO(mdempsky): Fix Type rekinding.
|
||||||
t.kind = underlying.kind
|
t.kind = underlying.kind
|
||||||
t.Extra = underlying.Extra
|
t.extra = underlying.extra
|
||||||
t.Width = underlying.Width
|
t.Width = underlying.Width
|
||||||
t.Align = underlying.Align
|
t.Align = underlying.Align
|
||||||
t.underlying = underlying.underlying
|
t.underlying = underlying.underlying
|
||||||
@ -1865,7 +1888,7 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
|
|||||||
if anyBroke(methods) {
|
if anyBroke(methods) {
|
||||||
t.SetBroke(true)
|
t.SetBroke(true)
|
||||||
}
|
}
|
||||||
t.Extra.(*Interface).pkg = pkg
|
t.extra.(*Interface).pkg = pkg
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1874,7 +1897,7 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
|
|||||||
func NewTypeParam(sym *Sym, index int) *Type {
|
func NewTypeParam(sym *Sym, index int) *Type {
|
||||||
t := New(TTYPEPARAM)
|
t := New(TTYPEPARAM)
|
||||||
t.sym = sym
|
t.sym = sym
|
||||||
t.Extra.(*Typeparam).index = index
|
t.extra.(*Typeparam).index = index
|
||||||
t.SetHasTParam(true)
|
t.SetHasTParam(true)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
@ -1882,25 +1905,25 @@ func NewTypeParam(sym *Sym, index int) *Type {
|
|||||||
// Index returns the index of the type param within its param list.
|
// Index returns the index of the type param within its param list.
|
||||||
func (t *Type) Index() int {
|
func (t *Type) Index() int {
|
||||||
t.wantEtype(TTYPEPARAM)
|
t.wantEtype(TTYPEPARAM)
|
||||||
return t.Extra.(*Typeparam).index
|
return t.extra.(*Typeparam).index
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetIndex sets the index of the type param within its param list.
|
// SetIndex sets the index of the type param within its param list.
|
||||||
func (t *Type) SetIndex(i int) {
|
func (t *Type) SetIndex(i int) {
|
||||||
t.wantEtype(TTYPEPARAM)
|
t.wantEtype(TTYPEPARAM)
|
||||||
t.Extra.(*Typeparam).index = i
|
t.extra.(*Typeparam).index = i
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBound sets the bound of a typeparam.
|
// SetBound sets the bound of a typeparam.
|
||||||
func (t *Type) SetBound(bound *Type) {
|
func (t *Type) SetBound(bound *Type) {
|
||||||
t.wantEtype(TTYPEPARAM)
|
t.wantEtype(TTYPEPARAM)
|
||||||
t.Extra.(*Typeparam).bound = bound
|
t.extra.(*Typeparam).bound = bound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bound returns the bound of a typeparam.
|
// Bound returns the bound of a typeparam.
|
||||||
func (t *Type) Bound() *Type {
|
func (t *Type) Bound() *Type {
|
||||||
t.wantEtype(TTYPEPARAM)
|
t.wantEtype(TTYPEPARAM)
|
||||||
return t.Extra.(*Typeparam).bound
|
return t.extra.(*Typeparam).bound
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnion returns a new union with the specified set of terms (types). If
|
// NewUnion returns a new union with the specified set of terms (types). If
|
||||||
@ -1910,8 +1933,8 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
|
|||||||
if len(terms) != len(tildes) {
|
if len(terms) != len(tildes) {
|
||||||
base.Fatalf("Mismatched terms and tildes for NewUnion")
|
base.Fatalf("Mismatched terms and tildes for NewUnion")
|
||||||
}
|
}
|
||||||
t.Extra.(*Union).terms = terms
|
t.extra.(*Union).terms = terms
|
||||||
t.Extra.(*Union).tildes = tildes
|
t.extra.(*Union).tildes = tildes
|
||||||
nt := len(terms)
|
nt := len(terms)
|
||||||
for i := 0; i < nt; i++ {
|
for i := 0; i < nt; i++ {
|
||||||
if terms[i].HasTParam() {
|
if terms[i].HasTParam() {
|
||||||
@ -1927,14 +1950,14 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
|
|||||||
// NumTerms returns the number of terms in a union type.
|
// NumTerms returns the number of terms in a union type.
|
||||||
func (t *Type) NumTerms() int {
|
func (t *Type) NumTerms() int {
|
||||||
t.wantEtype(TUNION)
|
t.wantEtype(TUNION)
|
||||||
return len(t.Extra.(*Union).terms)
|
return len(t.extra.(*Union).terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Term returns ith term of a union type as (term, tilde). If tilde is true, term
|
// Term returns ith term of a union type as (term, tilde). If tilde is true, term
|
||||||
// represents ~T, rather than just T.
|
// represents ~T, rather than just T.
|
||||||
func (t *Type) Term(i int) (*Type, bool) {
|
func (t *Type) Term(i int) (*Type, bool) {
|
||||||
t.wantEtype(TUNION)
|
t.wantEtype(TUNION)
|
||||||
u := t.Extra.(*Union)
|
u := t.extra.(*Union)
|
||||||
return u.terms[i], u.tildes[i]
|
return u.terms[i], u.tildes[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1995,7 +2018,7 @@ func NewStruct(pkg *Pkg, fields []*Field) *Type {
|
|||||||
if anyBroke(fields) {
|
if anyBroke(fields) {
|
||||||
t.SetBroke(true)
|
t.SetBroke(true)
|
||||||
}
|
}
|
||||||
t.Extra.(*Struct).pkg = pkg
|
t.extra.(*Struct).pkg = pkg
|
||||||
if fieldsHasTParam(fields) {
|
if fieldsHasTParam(fields) {
|
||||||
t.SetHasTParam(true)
|
t.SetHasTParam(true)
|
||||||
}
|
}
|
||||||
|
@ -2,26 +2,25 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package types_test
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/types"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSSACompare(t *testing.T) {
|
func TestSSACompare(t *testing.T) {
|
||||||
a := []*types.Type{
|
a := []*Type{
|
||||||
types.TypeInvalid,
|
TypeInvalid,
|
||||||
types.TypeMem,
|
TypeMem,
|
||||||
types.TypeFlags,
|
TypeFlags,
|
||||||
types.TypeVoid,
|
TypeVoid,
|
||||||
types.TypeInt128,
|
TypeInt128,
|
||||||
}
|
}
|
||||||
for _, x := range a {
|
for _, x := range a {
|
||||||
for _, y := range a {
|
for _, y := range a {
|
||||||
c := x.Compare(y)
|
c := x.Compare(y)
|
||||||
if x == y && c != types.CMPeq || x != y && c == types.CMPeq {
|
if x == y && c != CMPeq || x != y && c == CMPeq {
|
||||||
t.Errorf("%s compare %s == %d\n", x.Extra, y.Extra, c)
|
t.Errorf("%s compare %s == %d\n", x.extra, y.extra, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
144
src/cmd/compile/internal/types/universe.go
Normal file
144
src/cmd/compile/internal/types/universe.go
Normal 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})
|
||||||
|
}
|
@ -75,7 +75,7 @@ func Instantiate(env *Environment, typ Type, targs []Type, validate bool) (Type,
|
|||||||
func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos) (res Type) {
|
func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos) (res Type) {
|
||||||
assert(check != nil)
|
assert(check != nil)
|
||||||
if check.conf.Trace {
|
if check.conf.Trace {
|
||||||
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
|
check.trace(pos, "-- instantiating %s with %s", typ, NewTypeList(targs))
|
||||||
check.indent++
|
check.indent++
|
||||||
defer func() {
|
defer func() {
|
||||||
check.indent--
|
check.indent--
|
||||||
|
@ -132,7 +132,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||||||
// Also: Don't report an error via genericType since it will be reported
|
// Also: Don't report an error via genericType since it will be reported
|
||||||
// again when we type-check the signature.
|
// again when we type-check the signature.
|
||||||
// TODO(gri) maybe the receiver should be marked as invalid instead?
|
// TODO(gri) maybe the receiver should be marked as invalid instead?
|
||||||
if recv := asNamed(check.genericType(rname, false)); recv != nil {
|
if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
|
||||||
recvTParams = recv.TParams().list()
|
recvTParams = recv.TParams().list()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,6 +211,12 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||||||
switch T := rtyp.(type) {
|
switch T := rtyp.(type) {
|
||||||
case *Named:
|
case *Named:
|
||||||
T.expand(nil)
|
T.expand(nil)
|
||||||
|
// The receiver type may be an instantiated type referred to
|
||||||
|
// by an alias (which cannot have receiver parameters for now).
|
||||||
|
if T.TArgs() != nil && sig.RParams() == nil {
|
||||||
|
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
|
||||||
|
break
|
||||||
|
}
|
||||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||||
// be a pointer or interface type and it must be declared in the same package
|
// be a pointer or interface type and it must be declared in the same package
|
||||||
// as the method."
|
// as the method."
|
||||||
|
@ -281,12 +281,6 @@ func instantiatedHash(typ *Named, targs []Type) string {
|
|||||||
return string(res[:i])
|
return string(res[:i])
|
||||||
}
|
}
|
||||||
|
|
||||||
func typeListString(list []Type) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
writeTypeList(&buf, list, nil, nil)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
|
// typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
|
||||||
// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
|
// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
|
||||||
// where an array/slice element is accessed before it is set up.
|
// where an array/slice element is accessed before it is set up.
|
||||||
|
21
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
vendored
Normal file
21
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2021 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 p
|
||||||
|
|
||||||
|
type T[P any] struct{}
|
||||||
|
|
||||||
|
func (T[P]) m1()
|
||||||
|
|
||||||
|
type A1 = T
|
||||||
|
|
||||||
|
func (A1[P]) m2() {}
|
||||||
|
|
||||||
|
type A2 = T[int]
|
||||||
|
|
||||||
|
func (A2 /* ERROR cannot define methods on instantiated type T\[int\] */) m3() {}
|
||||||
|
func (_ /* ERROR cannot define methods on instantiated type T\[int\] */ A2) m4() {}
|
||||||
|
|
||||||
|
func (T[int]) m5() {} // int is the type parameter name, not an instantiation
|
||||||
|
func (T[* /* ERROR must be an identifier */ int]) m6() {} // syntax error
|
8
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
vendored
Normal file
8
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2021 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 p
|
||||||
|
|
||||||
|
// don't crash
|
||||||
|
func T /* ERROR missing */ [P /* ERROR named */ ] m /* ERROR m */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
package types2
|
package types2
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
// TParamList holds a list of type parameters.
|
// TParamList holds a list of type parameters.
|
||||||
type TParamList struct{ tparams []*TypeParam }
|
type TParamList struct{ tparams []*TypeParam }
|
||||||
|
|
||||||
@ -52,6 +54,17 @@ func (l *TypeList) list() []Type {
|
|||||||
return l.types
|
return l.types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *TypeList) String() string {
|
||||||
|
if l == nil || len(l.types) == 0 {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteByte('[')
|
||||||
|
writeTypeList(&buf, l.types, nil, nil)
|
||||||
|
buf.WriteByte(']')
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Implementation
|
// Implementation
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
|
|||||||
if value.Cap() < n {
|
if value.Cap() < n {
|
||||||
value.Set(reflect.MakeSlice(value.Type(), n, n))
|
value.Set(reflect.MakeSlice(value.Type(), n, n))
|
||||||
} else {
|
} else {
|
||||||
value.Set(value.Slice(0, n))
|
value.SetLen(n)
|
||||||
}
|
}
|
||||||
if _, err := state.b.Read(value.Bytes()); err != nil {
|
if _, err := state.b.Read(value.Bytes()); err != nil {
|
||||||
errorf("error decoding []byte: %s", err)
|
errorf("error decoding []byte: %s", err)
|
||||||
|
@ -280,6 +280,14 @@ func BenchmarkDecodeStringSlice(b *testing.B) {
|
|||||||
benchmarkDecodeSlice(b, a)
|
benchmarkDecodeSlice(b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeBytesSlice(b *testing.B) {
|
||||||
|
a := make([][]byte, 1000)
|
||||||
|
for i := range a {
|
||||||
|
a[i] = []byte("now is the time")
|
||||||
|
}
|
||||||
|
benchmarkDecodeSlice(b, a)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkDecodeInterfaceSlice(b *testing.B) {
|
func BenchmarkDecodeInterfaceSlice(b *testing.B) {
|
||||||
a := make([]interface{}, 1000)
|
a := make([]interface{}, 1000)
|
||||||
for i := range a {
|
for i := range a {
|
||||||
|
5
test/typeparam/issue47514c.dir/a.go
Normal file
5
test/typeparam/issue47514c.dir/a.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
type Doer[T any] interface {
|
||||||
|
Do() T
|
||||||
|
}
|
10
test/typeparam/issue47514c.dir/main.go
Normal file
10
test/typeparam/issue47514c.dir/main.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "a"
|
||||||
|
|
||||||
|
func Do[T any](doer a.Doer[T]) {
|
||||||
|
doer.Do()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
7
test/typeparam/issue47514c.go
Normal file
7
test/typeparam/issue47514c.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// rundir -G=3
|
||||||
|
|
||||||
|
// Copyright 2021 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 ignored
|
19
test/typeparam/issue47710.go
Normal file
19
test/typeparam/issue47710.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// compile -G=3
|
||||||
|
|
||||||
|
// Copyright 2021 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 p
|
||||||
|
|
||||||
|
type FooType[t any] interface {
|
||||||
|
Foo(BarType[t])
|
||||||
|
}
|
||||||
|
type BarType[t any] interface {
|
||||||
|
Int(IntType[t]) FooType[int]
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntType[t any] int
|
||||||
|
|
||||||
|
func (n IntType[t]) Foo(BarType[t]) {}
|
||||||
|
func (n IntType[_]) String() {}
|
Loading…
x
Reference in New Issue
Block a user