mirror of
https://github.com/golang/go
synced 2024-11-26 05:07:59 -07:00
[dev.cmdgo] all: merge master (67f7e16
) into dev.cmdgo
Merge List: + 2021-08-2767f7e16bcc
encoding/gob: optimize decoding of []byte + 2021-08-272c60a99f72
cmd/compile/internal/syntax: make valid type parameter list in presence of errors + 2021-08-27d350a66532
cmd/compile: eagerly CalcStructSize for synthetic ABI types + 2021-08-27d7e2e2ec2b
cmd/compile: delay fillinMethods to deal with mutually-recursive types + 2021-08-27c927599783
cmd/compile: eliminate repetitive code + 2021-08-2762f88b6dc8
cmd/compile: add types.RecalcSize + 2021-08-27e7eee5e265
cmd/compile: remove ssagen/pgen_test.go + 2021-08-27f153b6739b
cmd/compile: use typecheck.InitUniverse in unit tests + 2021-08-26967a8017f7
cmd/compile: move types init code into package types + 2021-08-26af80af22b5
cmd/compile/internal/types2: do not declare new methods on instantiated types + 2021-08-2603db2c2413
cmd/compile/internal/types2: implement TypeList.String (debugging support) + 2021-08-26c9e05fdcf7
cmd/compile: fix reference to generic type needed by crawler + 2021-08-26eb6a07fcf9
cmd/compile: unexport Type.Vargen + 2021-08-263836983779
cmd/compile/internal/types: unexport Type.Extra + 2021-08-261f8d4562de
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("cap"), ui),
|
||||
})
|
||||
types.CalcStructSize(synthSlice)
|
||||
synthString = types.NewStruct(types.NoPkg, []*types.Field{
|
||||
types.NewField(nxp, fname("data"), unsp),
|
||||
types.NewField(nxp, fname("len"), ui),
|
||||
})
|
||||
types.CalcStructSize(synthString)
|
||||
synthIface = types.NewStruct(types.NoPkg, []*types.Field{
|
||||
types.NewField(nxp, fname("f1"), 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
|
||||
|
||||
// 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
|
||||
// declarations for package runtime. These are declared in a
|
||||
|
@ -334,6 +334,16 @@ const (
|
||||
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.
|
||||
// For fields that are not used in most nodes, this is used instead of
|
||||
// a slice to save space.
|
||||
|
@ -116,12 +116,11 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
|
||||
var i int
|
||||
for i = len(v.stack) - 1; i >= 0; i-- {
|
||||
x := v.stack[i]
|
||||
v.nodeID[x] = ^uint32(0)
|
||||
if x == n {
|
||||
break
|
||||
}
|
||||
v.nodeID[x] = ^uint32(0)
|
||||
}
|
||||
v.nodeID[n] = ^uint32(0)
|
||||
block := v.stack[i:]
|
||||
// Run escape analysis on this set of functions.
|
||||
v.stack = v.stack[:i]
|
||||
|
@ -68,5 +68,4 @@ var Pkgs struct {
|
||||
Go *types.Pkg
|
||||
Itab *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)
|
||||
ntyp, otyp := name.Type(), obj.Type()
|
||||
if ir.CurFunc != nil {
|
||||
typecheck.TypeGen++
|
||||
ntyp.Vargen = typecheck.TypeGen
|
||||
ntyp.SetVargen()
|
||||
}
|
||||
|
||||
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
|
||||
// created the parameter Names, force a recalculation to ensure
|
||||
// their offsets are correct.
|
||||
typ.Align = 0
|
||||
types.CalcSize(typ)
|
||||
types.RecalcSize(typ)
|
||||
|
||||
if block != nil {
|
||||
typecheck.DeclContext = ir.PAUTO
|
||||
|
@ -198,7 +198,7 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight {
|
||||
if pkg != types.UnsafePkg && pkg.Height >= myheight {
|
||||
myheight = pkg.Height + 1
|
||||
}
|
||||
return pkg
|
||||
@ -231,7 +231,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack
|
||||
}
|
||||
|
||||
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
|
||||
// the linker or runtime care whether a package imported unsafe?
|
||||
|
@ -149,6 +149,9 @@ type irgen struct {
|
||||
// statements yet.
|
||||
exprStmtOK bool
|
||||
|
||||
// types which we need to finish, by doing g.fillinMethods.
|
||||
typesToFinalize []*typeDelayInfo
|
||||
|
||||
// Fully-instantiated generic types whose methods should be instantiated
|
||||
instTypeList []*types.Type
|
||||
|
||||
@ -184,6 +187,11 @@ type delayInfo struct {
|
||||
off int
|
||||
}
|
||||
|
||||
type typeDelayInfo struct {
|
||||
typ *types2.Named
|
||||
ntyp *types.Type
|
||||
}
|
||||
|
||||
func (g *irgen) generate(noders []*noder) {
|
||||
types.LocalPkg.Name = g.self.Name()
|
||||
types.LocalPkg.Height = g.self.Height()
|
||||
|
@ -384,7 +384,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||
return
|
||||
}
|
||||
|
||||
if ipkg == ir.Pkgs.Unsafe {
|
||||
if ipkg == types.UnsafePkg {
|
||||
p.importedUnsafe = true
|
||||
}
|
||||
if ipkg.Path == "embed" {
|
||||
|
@ -428,7 +428,7 @@ func (r *reader) interfaceType() *types.Type {
|
||||
pos := r.pos()
|
||||
pkg, sym := r.selector()
|
||||
tpkg = pkg
|
||||
mtyp := r.signature(pkg, typecheck.FakeRecv())
|
||||
mtyp := r.signature(pkg, types.FakeRecv())
|
||||
methods[i] = types.NewField(pos, sym, mtyp)
|
||||
}
|
||||
for i := range embeddeds {
|
||||
@ -540,7 +540,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
|
||||
if tag == objStub {
|
||||
assert(!sym.IsBlank())
|
||||
switch sym.Pkg {
|
||||
case types.BuiltinPkg, ir.Pkgs.Unsafe:
|
||||
case types.BuiltinPkg, types.UnsafePkg:
|
||||
return sym.Def.(ir.Node)
|
||||
}
|
||||
if pri, ok := objReader[sym]; ok {
|
||||
|
@ -903,7 +903,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
ir.EditChildren(m, edit)
|
||||
|
||||
m.SetTypecheck(1)
|
||||
if typecheck.IsCmp(x.Op()) {
|
||||
if x.Op().IsCmp() {
|
||||
transformCompare(m.(*ir.BinaryExpr))
|
||||
} else {
|
||||
switch x.Op() {
|
||||
|
@ -22,7 +22,7 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
|
||||
case g.self:
|
||||
return types.LocalPkg
|
||||
case types2.Unsafe:
|
||||
return ir.Pkgs.Unsafe
|
||||
return types.UnsafePkg
|
||||
}
|
||||
return types.NewPkg(pkg.Path(), pkg.Name())
|
||||
}
|
||||
@ -35,6 +35,16 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
|
||||
types.DeferCheckSize()
|
||||
res := g.typ1(typ)
|
||||
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
|
||||
}
|
||||
|
||||
@ -118,9 +128,14 @@ func (g *irgen) typ0(typ types2.Type) *types.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
|
||||
// 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
|
||||
// HasTParam) before translating the underlying type
|
||||
// itself, so we handle recursion correctly.
|
||||
@ -146,10 +161,19 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
||||
ntyp.SetRParams(rparams)
|
||||
//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.
|
||||
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
|
||||
}
|
||||
obj := g.obj(typ.Obj())
|
||||
@ -201,7 +225,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
||||
methods := make([]*types.Field, typ.NumExplicitMethods())
|
||||
for i := range methods {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -261,76 +285,75 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
|
||||
}
|
||||
}
|
||||
|
||||
// fillinMethods fills in the method name nodes and types for a defined type. This
|
||||
// is needed for later typechecking when looking up methods of instantiated types,
|
||||
// and for actually generating the methods for instantiated types.
|
||||
// fillinMethods fills in the method name nodes and types for a defined type with at
|
||||
// least one method. This is needed for later typechecking when looking up methods of
|
||||
// instantiated types, and for actually generating the methods for instantiated
|
||||
// types.
|
||||
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
|
||||
if typ.NumMethods() != 0 {
|
||||
targs2 := typ.TArgs()
|
||||
targs := make([]*types.Type, targs2.Len())
|
||||
for i := range targs {
|
||||
targs[i] = g.typ1(targs2.At(i))
|
||||
}
|
||||
targs2 := typ.TArgs()
|
||||
targs := make([]*types.Type, targs2.Len())
|
||||
for i := range targs {
|
||||
targs[i] = g.typ1(targs2.At(i))
|
||||
}
|
||||
|
||||
methods := make([]*types.Field, typ.NumMethods())
|
||||
for i := range methods {
|
||||
m := typ.Method(i)
|
||||
recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
|
||||
var meth *ir.Name
|
||||
if m.Pkg() != g.self {
|
||||
// Imported methods cannot be loaded by name (what
|
||||
// g.obj() does) - they must be loaded via their
|
||||
// type.
|
||||
meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
|
||||
methods := make([]*types.Field, typ.NumMethods())
|
||||
for i := range methods {
|
||||
m := typ.Method(i)
|
||||
recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
|
||||
var meth *ir.Name
|
||||
if m.Pkg() != g.self {
|
||||
// Imported methods cannot be loaded by name (what
|
||||
// g.obj() does) - they must be loaded via their
|
||||
// type.
|
||||
meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
|
||||
} else {
|
||||
meth = g.obj(m)
|
||||
}
|
||||
if recvType != types2.Type(typ) {
|
||||
// Unfortunately, meth is the type of the method of the
|
||||
// generic type, so we have to do a substitution to get
|
||||
// the name/type of the method of the instantiated type,
|
||||
// using m.Type().RParams() and typ.TArgs()
|
||||
inst2 := instTypeName2("", typ.TArgs())
|
||||
name := meth.Sym().Name
|
||||
i1 := strings.Index(name, "[")
|
||||
i2 := strings.Index(name[i1:], "]")
|
||||
assert(i1 >= 0 && i2 >= 0)
|
||||
// Generate the name of the instantiated method.
|
||||
name = name[0:i1] + inst2 + name[i1+i2+1:]
|
||||
newsym := meth.Sym().Pkg.Lookup(name)
|
||||
var meth2 *ir.Name
|
||||
if newsym.Def != nil {
|
||||
meth2 = newsym.Def.(*ir.Name)
|
||||
} else {
|
||||
meth = g.obj(m)
|
||||
}
|
||||
if recvType != types2.Type(typ) {
|
||||
// Unfortunately, meth is the type of the method of the
|
||||
// generic type, so we have to do a substitution to get
|
||||
// the name/type of the method of the instantiated type,
|
||||
// using m.Type().RParams() and typ.TArgs()
|
||||
inst2 := instTypeName2("", typ.TArgs())
|
||||
name := meth.Sym().Name
|
||||
i1 := strings.Index(name, "[")
|
||||
i2 := strings.Index(name[i1:], "]")
|
||||
assert(i1 >= 0 && i2 >= 0)
|
||||
// Generate the name of the instantiated method.
|
||||
name = name[0:i1] + inst2 + name[i1+i2+1:]
|
||||
newsym := meth.Sym().Pkg.Lookup(name)
|
||||
var meth2 *ir.Name
|
||||
if newsym.Def != nil {
|
||||
meth2 = newsym.Def.(*ir.Name)
|
||||
} else {
|
||||
meth2 = ir.NewNameAt(meth.Pos(), newsym)
|
||||
rparams := types2.AsSignature(m.Type()).RParams()
|
||||
tparams := make([]*types.Type, rparams.Len())
|
||||
for i := range tparams {
|
||||
tparams[i] = g.typ1(rparams.At(i))
|
||||
}
|
||||
assert(len(tparams) == len(targs))
|
||||
ts := typecheck.Tsubster{
|
||||
Tparams: tparams,
|
||||
Targs: targs,
|
||||
}
|
||||
// Do the substitution of the type
|
||||
meth2.SetType(ts.Typ(meth.Type()))
|
||||
// Add any new fully instantiated types
|
||||
// seen during the substitution to
|
||||
// g.instTypeList.
|
||||
g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
|
||||
newsym.Def = meth2
|
||||
meth2 = ir.NewNameAt(meth.Pos(), newsym)
|
||||
rparams := types2.AsSignature(m.Type()).RParams()
|
||||
tparams := make([]*types.Type, rparams.Len())
|
||||
for i := range tparams {
|
||||
tparams[i] = g.typ1(rparams.At(i))
|
||||
}
|
||||
meth = meth2
|
||||
assert(len(tparams) == len(targs))
|
||||
ts := typecheck.Tsubster{
|
||||
Tparams: tparams,
|
||||
Targs: targs,
|
||||
}
|
||||
// Do the substitution of the type
|
||||
meth2.SetType(ts.Typ(meth.Type()))
|
||||
// Add any new fully instantiated types
|
||||
// seen during the substitution to
|
||||
// g.instTypeList.
|
||||
g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
|
||||
newsym.Def = meth2
|
||||
}
|
||||
methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
|
||||
methods[i].Nname = meth
|
||||
}
|
||||
ntyp.Methods().Set(methods)
|
||||
if !ntyp.HasTParam() && !ntyp.HasShape() {
|
||||
// Generate all the methods for a new fully-instantiated type.
|
||||
g.instTypeList = append(g.instTypeList, ntyp)
|
||||
meth = meth2
|
||||
}
|
||||
methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
|
||||
methods[i].Nname = meth
|
||||
}
|
||||
ntyp.Methods().Set(methods)
|
||||
if !ntyp.HasTParam() && !ntyp.HasShape() {
|
||||
// Generate all the methods for a new fully-instantiated type.
|
||||
g.instTypeList = append(g.instTypeList, ntyp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -927,7 +927,7 @@ func formalType(t *types.Type) *types.Type {
|
||||
|
||||
func writeType(t *types.Type) *obj.LSym {
|
||||
t = formalType(t)
|
||||
if t.IsUntyped() {
|
||||
if t.IsUntyped() || t.HasTParam() {
|
||||
base.Fatalf("writeType %v", t)
|
||||
}
|
||||
|
||||
@ -1726,7 +1726,7 @@ func NeedEmit(typ *types.Type) bool {
|
||||
// Local defined type; our responsibility.
|
||||
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
|
||||
// types (predeclared and package unsafe).
|
||||
return true
|
||||
|
@ -5,14 +5,16 @@
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"cmd/internal/obj/s390x"
|
||||
"cmd/internal/obj/x86"
|
||||
"cmd/internal/src"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var CheckFunc = checkFunc
|
||||
@ -104,33 +106,12 @@ func (d TestFrontend) MyImportPath() string {
|
||||
var testTypes Types
|
||||
|
||||
func init() {
|
||||
// Initialize just enough of the universe and the types package to make our tests function.
|
||||
// TODO(josharian): move universe initialization to the types package,
|
||||
// so this test setup can share it.
|
||||
// TODO(mdempsky): Push into types.InitUniverse or typecheck.InitUniverse.
|
||||
types.PtrSize = 8
|
||||
types.RegSize = 8
|
||||
types.MaxWidth = 1 << 50
|
||||
|
||||
for _, typ := range [...]struct {
|
||||
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
|
||||
}
|
||||
typecheck.InitUniverse()
|
||||
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
|
||||
// the callers frame.
|
||||
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) {
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
// provide a no-op error handler so parsing doesn't stop after first error
|
||||
ast, err := ParseFile(*src_, func(error) {}, nil, CheckBranches)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
|
||||
|
||||
if ast != nil {
|
||||
Fdump(testOut(), ast)
|
||||
|
@ -1924,7 +1924,7 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
|
||||
}
|
||||
|
||||
// distribute parameter types (len(list) > 0)
|
||||
if named == 0 {
|
||||
if named == 0 && !requireNames {
|
||||
// all unnamed => found names are named types
|
||||
for _, par := range list {
|
||||
if typ := par.Name; typ != nil {
|
||||
@ -1932,9 +1932,6 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
|
||||
par.Name = nil
|
||||
}
|
||||
}
|
||||
if requireNames {
|
||||
p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named")
|
||||
}
|
||||
} else if named != len(list) {
|
||||
// some named => all must have names and types
|
||||
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")
|
||||
}
|
||||
|
||||
// provide a no-op error handler so parsing doesn't stop after first error
|
||||
ast, err := ParseFile(*src_, func(error) {}, nil, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
|
||||
|
||||
if ast != nil {
|
||||
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
|
||||
|
||||
type funcStackEnt struct {
|
||||
|
@ -77,10 +77,6 @@ func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
|
||||
return l, r, t
|
||||
}
|
||||
|
||||
func IsCmp(op ir.Op) bool {
|
||||
return iscmp[op]
|
||||
}
|
||||
|
||||
// tcArith typechecks operands of a binary arithmetic expression.
|
||||
// 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:
|
||||
@ -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()
|
||||
}
|
||||
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
|
||||
// assignable to the other. convert so they have
|
||||
// the same type.
|
||||
|
@ -430,7 +430,7 @@ func (p *iexporter) pushDecl(n *ir.Name) {
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -905,7 +905,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
|
||||
// type orderedAbs[T any] T
|
||||
if t.IsTypeParam() && t.Underlying() == t {
|
||||
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)
|
||||
}
|
||||
// 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.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)
|
||||
}
|
||||
|
||||
|
@ -607,7 +607,7 @@ func (r *importReader) exoticType() *types.Type {
|
||||
case exoticTypeRecv:
|
||||
var rcvr *types.Field
|
||||
if r.bool() { // isFakeRecv
|
||||
rcvr = fakeRecvField()
|
||||
rcvr = types.FakeRecv()
|
||||
} else {
|
||||
rcvr = r.exoticParam()
|
||||
}
|
||||
@ -793,7 +793,7 @@ func (r *importReader) typ1() *types.Type {
|
||||
for i := range methods {
|
||||
pos := r.pos()
|
||||
sym := r.selector()
|
||||
typ := r.signature(fakeRecvField(), nil)
|
||||
typ := r.signature(types.FakeRecv(), nil)
|
||||
|
||||
methods[i] = types.NewField(pos, sym, typ)
|
||||
}
|
||||
|
@ -1736,11 +1736,6 @@ func CheckMapKeys() {
|
||||
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) {
|
||||
if base.EnableTrace && base.Flag.LowerT {
|
||||
defer tracePrint("typecheckdeftype", n)(nil)
|
||||
@ -1748,8 +1743,7 @@ func typecheckdeftype(n *ir.Name) {
|
||||
|
||||
t := types.NewNamed(n)
|
||||
if n.Curfn != nil {
|
||||
TypeGen++
|
||||
t.Vargen = TypeGen
|
||||
t.SetVargen()
|
||||
}
|
||||
|
||||
if n.Pragma()&ir.NotInHeap != 0 {
|
||||
|
@ -29,37 +29,6 @@ var (
|
||||
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 {
|
||||
name string
|
||||
op ir.Op
|
||||
@ -94,86 +63,12 @@ var unsafeFuncs = [...]struct {
|
||||
|
||||
// InitUniverse initializes the universe block.
|
||||
func InitUniverse() {
|
||||
if types.PtrSize == 0 {
|
||||
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)
|
||||
types.InitTypes(func(sym *types.Sym, typ *types.Type) types.Object {
|
||||
n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
|
||||
t := types.NewBasic(kind, n)
|
||||
n.SetType(t)
|
||||
n.SetType(typ)
|
||||
sym.Def = n
|
||||
if kind != types.TANY {
|
||||
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
|
||||
return n
|
||||
})
|
||||
|
||||
for _, s := range &builtinFuncs {
|
||||
s2 := types.BuiltinPkg.Lookup(s.name)
|
||||
@ -183,13 +78,13 @@ func InitUniverse() {
|
||||
}
|
||||
|
||||
for _, s := range &unsafeFuncs {
|
||||
s2 := ir.Pkgs.Unsafe.Lookup(s.name)
|
||||
s2 := types.UnsafePkg.Lookup(s.name)
|
||||
def := NewName(s2)
|
||||
def.BuiltinOp = s.op
|
||||
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 = types.BuiltinPkg.Lookup("false")
|
||||
@ -219,19 +114,6 @@ func InitUniverse() {
|
||||
s = types.BuiltinPkg.Lookup("iota")
|
||||
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
|
||||
for et := types.Kind(0); et < types.NTYPE; et++ {
|
||||
if types.IsInt[et] || et == types.TIDEAL {
|
||||
@ -329,28 +211,6 @@ func InitUniverse() {
|
||||
// special
|
||||
okfor[ir.OCAP] = okforcap[:]
|
||||
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.
|
||||
|
@ -23,6 +23,9 @@ var BuiltinPkg *Pkg
|
||||
// LocalPkg is the package being compiled.
|
||||
var LocalPkg *Pkg
|
||||
|
||||
// UnsafePkg is package unsafe.
|
||||
var UnsafePkg *Pkg
|
||||
|
||||
// BlankSym is the blank (_) symbol.
|
||||
var BlankSym *Sym
|
||||
|
||||
@ -298,7 +301,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
return
|
||||
}
|
||||
if t.Kind() == TSSA {
|
||||
b.WriteString(t.Extra.(string))
|
||||
b.WriteString(t.extra.(string))
|
||||
return
|
||||
}
|
||||
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 {
|
||||
tys := t.Extra.(*Results).Types
|
||||
tys := t.extra.(*Results).Types
|
||||
for i, et := range tys {
|
||||
if i > 0 {
|
||||
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
|
||||
// used in string representation used by reflection, which is
|
||||
// user-visible and doesn't expect this.
|
||||
if mode == fmtTypeID && t.Vargen != 0 {
|
||||
fmt.Fprintf(b, "·%d", t.Vargen)
|
||||
if mode == fmtTypeID && t.vargen != 0 {
|
||||
fmt.Fprintf(b, "·%d", t.vargen)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ func CalcSize(t *Type) {
|
||||
w = calcStructOffset(t1, t1.Recvs(), 0, 0)
|
||||
w = calcStructOffset(t1, t1.Params(), w, RegSize)
|
||||
w = calcStructOffset(t1, t1.Results(), w, RegSize)
|
||||
t1.Extra.(*Func).Argwid = w
|
||||
t1.extra.(*Func).Argwid = w
|
||||
if w%int64(RegSize) != 0 {
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
// to compute it. during a declaration like
|
||||
//
|
||||
|
@ -139,7 +139,7 @@ var (
|
||||
|
||||
// A Type represents a Go type.
|
||||
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
|
||||
// one pointer-shaped field are stored as values rather than pointers when possible.
|
||||
//
|
||||
@ -156,7 +156,7 @@ type Type struct {
|
||||
// TSLICE: Slice
|
||||
// TSSA: string
|
||||
// TTYPEPARAM: *Typeparam
|
||||
Extra interface{}
|
||||
extra interface{}
|
||||
|
||||
// Width is the width of this Type in bytes.
|
||||
Width int64 // valid if Align > 0
|
||||
@ -178,7 +178,7 @@ type Type struct {
|
||||
}
|
||||
|
||||
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
|
||||
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 {
|
||||
switch t.kind {
|
||||
case TFUNC:
|
||||
return t.Extra.(*Func).pkg
|
||||
return t.extra.(*Func).pkg
|
||||
case TSTRUCT:
|
||||
return t.Extra.(*Struct).pkg
|
||||
return t.extra.(*Struct).pkg
|
||||
case TINTER:
|
||||
return t.Extra.(*Interface).pkg
|
||||
return t.extra.(*Interface).pkg
|
||||
default:
|
||||
base.Fatalf("Pkg: unexpected kind: %v", t)
|
||||
return nil
|
||||
@ -349,7 +349,7 @@ type Map struct {
|
||||
// MapType returns t's extra map-specific fields.
|
||||
func (t *Type) MapType() *Map {
|
||||
t.wantEtype(TMAP)
|
||||
return t.Extra.(*Map)
|
||||
return t.extra.(*Map)
|
||||
}
|
||||
|
||||
// Forward contains Type fields specific to forward types.
|
||||
@ -361,7 +361,7 @@ type Forward struct {
|
||||
// ForwardType returns t's extra forward-type-specific fields.
|
||||
func (t *Type) ForwardType() *Forward {
|
||||
t.wantEtype(TFORW)
|
||||
return t.Extra.(*Forward)
|
||||
return t.extra.(*Forward)
|
||||
}
|
||||
|
||||
// Func contains Type fields specific to func types.
|
||||
@ -382,7 +382,7 @@ type Func struct {
|
||||
// FuncType returns t's extra func-specific fields.
|
||||
func (t *Type) FuncType() *Func {
|
||||
t.wantEtype(TFUNC)
|
||||
return t.Extra.(*Func)
|
||||
return t.extra.(*Func)
|
||||
}
|
||||
|
||||
// StructType contains Type fields specific to struct types.
|
||||
@ -411,7 +411,7 @@ const (
|
||||
// StructType returns t's extra struct-specific fields.
|
||||
func (t *Type) StructType() *Struct {
|
||||
t.wantEtype(TSTRUCT)
|
||||
return t.Extra.(*Struct)
|
||||
return t.extra.(*Struct)
|
||||
}
|
||||
|
||||
// Interface contains Type fields specific to interface types.
|
||||
@ -455,7 +455,7 @@ type Chan struct {
|
||||
// ChanType returns t's extra channel-specific fields.
|
||||
func (t *Type) ChanType() *Chan {
|
||||
t.wantEtype(TCHAN)
|
||||
return t.Extra.(*Chan)
|
||||
return t.extra.(*Chan)
|
||||
}
|
||||
|
||||
type Tuple struct {
|
||||
@ -590,31 +590,31 @@ func New(et Kind) *Type {
|
||||
// TODO(josharian): lazily initialize some of these?
|
||||
switch t.kind {
|
||||
case TMAP:
|
||||
t.Extra = new(Map)
|
||||
t.extra = new(Map)
|
||||
case TFORW:
|
||||
t.Extra = new(Forward)
|
||||
t.extra = new(Forward)
|
||||
case TFUNC:
|
||||
t.Extra = new(Func)
|
||||
t.extra = new(Func)
|
||||
case TSTRUCT:
|
||||
t.Extra = new(Struct)
|
||||
t.extra = new(Struct)
|
||||
case TINTER:
|
||||
t.Extra = new(Interface)
|
||||
t.extra = new(Interface)
|
||||
case TPTR:
|
||||
t.Extra = Ptr{}
|
||||
t.extra = Ptr{}
|
||||
case TCHANARGS:
|
||||
t.Extra = ChanArgs{}
|
||||
t.extra = ChanArgs{}
|
||||
case TFUNCARGS:
|
||||
t.Extra = FuncArgs{}
|
||||
t.extra = FuncArgs{}
|
||||
case TCHAN:
|
||||
t.Extra = new(Chan)
|
||||
t.extra = new(Chan)
|
||||
case TTUPLE:
|
||||
t.Extra = new(Tuple)
|
||||
t.extra = new(Tuple)
|
||||
case TRESULTS:
|
||||
t.Extra = new(Results)
|
||||
t.extra = new(Results)
|
||||
case TTYPEPARAM:
|
||||
t.Extra = new(Typeparam)
|
||||
t.extra = new(Typeparam)
|
||||
case TUNION:
|
||||
t.Extra = new(Union)
|
||||
t.extra = new(Union)
|
||||
}
|
||||
return t
|
||||
}
|
||||
@ -625,7 +625,7 @@ func NewArray(elem *Type, bound int64) *Type {
|
||||
base.Fatalf("NewArray: invalid bound %v", bound)
|
||||
}
|
||||
t := New(TARRAY)
|
||||
t.Extra = &Array{Elem: elem, Bound: bound}
|
||||
t.extra = &Array{Elem: elem, Bound: bound}
|
||||
t.SetNotInHeap(elem.NotInHeap())
|
||||
if elem.HasTParam() {
|
||||
t.SetHasTParam(true)
|
||||
@ -646,7 +646,7 @@ func NewSlice(elem *Type) *Type {
|
||||
}
|
||||
|
||||
t := New(TSLICE)
|
||||
t.Extra = Slice{Elem: elem}
|
||||
t.extra = Slice{Elem: elem}
|
||||
elem.cache.slice = t
|
||||
if elem.HasTParam() {
|
||||
t.SetHasTParam(true)
|
||||
@ -674,8 +674,8 @@ func NewChan(elem *Type, dir ChanDir) *Type {
|
||||
|
||||
func NewTuple(t1, t2 *Type) *Type {
|
||||
t := New(TTUPLE)
|
||||
t.Extra.(*Tuple).first = t1
|
||||
t.Extra.(*Tuple).second = t2
|
||||
t.extra.(*Tuple).first = t1
|
||||
t.extra.(*Tuple).second = t2
|
||||
if t1.HasTParam() || t2.HasTParam() {
|
||||
t.SetHasTParam(true)
|
||||
}
|
||||
@ -687,7 +687,7 @@ func NewTuple(t1, t2 *Type) *Type {
|
||||
|
||||
func newResults(types []*Type) *Type {
|
||||
t := New(TRESULTS)
|
||||
t.Extra.(*Results).Types = types
|
||||
t.extra.(*Results).Types = types
|
||||
return t
|
||||
}
|
||||
|
||||
@ -700,7 +700,7 @@ func NewResults(types []*Type) *Type {
|
||||
|
||||
func newSSA(name string) *Type {
|
||||
t := New(TSSA)
|
||||
t.Extra = name
|
||||
t.extra = name
|
||||
return t
|
||||
}
|
||||
|
||||
@ -747,7 +747,7 @@ func NewPtr(elem *Type) *Type {
|
||||
}
|
||||
|
||||
t := New(TPTR)
|
||||
t.Extra = Ptr{Elem: elem}
|
||||
t.extra = Ptr{Elem: elem}
|
||||
t.Width = int64(PtrSize)
|
||||
t.Align = uint8(PtrSize)
|
||||
if NewPtrCacheEnabled {
|
||||
@ -765,14 +765,14 @@ func NewPtr(elem *Type) *Type {
|
||||
// NewChanArgs returns a new TCHANARGS type for channel type c.
|
||||
func NewChanArgs(c *Type) *Type {
|
||||
t := New(TCHANARGS)
|
||||
t.Extra = ChanArgs{T: c}
|
||||
t.extra = ChanArgs{T: c}
|
||||
return t
|
||||
}
|
||||
|
||||
// NewFuncArgs returns a new TFUNCARGS type for func type f.
|
||||
func NewFuncArgs(f *Type) *Type {
|
||||
t := New(TFUNCARGS)
|
||||
t.Extra = FuncArgs{T: f}
|
||||
t.extra = FuncArgs{T: f}
|
||||
return t
|
||||
}
|
||||
|
||||
@ -811,28 +811,28 @@ func SubstAny(t *Type, types *[]*Type) *Type {
|
||||
elem := SubstAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.copy()
|
||||
t.Extra = Ptr{Elem: elem}
|
||||
t.extra = Ptr{Elem: elem}
|
||||
}
|
||||
|
||||
case TARRAY:
|
||||
elem := SubstAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.copy()
|
||||
t.Extra.(*Array).Elem = elem
|
||||
t.extra.(*Array).Elem = elem
|
||||
}
|
||||
|
||||
case TSLICE:
|
||||
elem := SubstAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.copy()
|
||||
t.Extra = Slice{Elem: elem}
|
||||
t.extra = Slice{Elem: elem}
|
||||
}
|
||||
|
||||
case TCHAN:
|
||||
elem := SubstAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.copy()
|
||||
t.Extra.(*Chan).Elem = elem
|
||||
t.extra.(*Chan).Elem = elem
|
||||
}
|
||||
|
||||
case TMAP:
|
||||
@ -840,8 +840,8 @@ func SubstAny(t *Type, types *[]*Type) *Type {
|
||||
elem := SubstAny(t.Elem(), types)
|
||||
if key != t.Key() || elem != t.Elem() {
|
||||
t = t.copy()
|
||||
t.Extra.(*Map).Key = key
|
||||
t.Extra.(*Map).Elem = elem
|
||||
t.extra.(*Map).Key = key
|
||||
t.extra.(*Map).Elem = elem
|
||||
}
|
||||
|
||||
case TFUNC:
|
||||
@ -882,26 +882,26 @@ func (t *Type) copy() *Type {
|
||||
// copy any *T Extra fields, to avoid aliasing
|
||||
switch t.kind {
|
||||
case TMAP:
|
||||
x := *t.Extra.(*Map)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Map)
|
||||
nt.extra = &x
|
||||
case TFORW:
|
||||
x := *t.Extra.(*Forward)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Forward)
|
||||
nt.extra = &x
|
||||
case TFUNC:
|
||||
x := *t.Extra.(*Func)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Func)
|
||||
nt.extra = &x
|
||||
case TSTRUCT:
|
||||
x := *t.Extra.(*Struct)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Struct)
|
||||
nt.extra = &x
|
||||
case TINTER:
|
||||
x := *t.Extra.(*Interface)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Interface)
|
||||
nt.extra = &x
|
||||
case TCHAN:
|
||||
x := *t.Extra.(*Chan)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Chan)
|
||||
nt.extra = &x
|
||||
case TARRAY:
|
||||
x := *t.Extra.(*Array)
|
||||
nt.Extra = &x
|
||||
x := *t.extra.(*Array)
|
||||
nt.extra = &x
|
||||
case TTYPEPARAM:
|
||||
base.Fatalf("typeparam types cannot be copied")
|
||||
case TTUPLE, TSSA, TRESULTS:
|
||||
@ -970,7 +970,7 @@ var ParamsResults = [2]func(*Type) *Type{
|
||||
// Key returns the key type of map type t.
|
||||
func (t *Type) Key() *Type {
|
||||
t.wantEtype(TMAP)
|
||||
return t.Extra.(*Map).Key
|
||||
return t.extra.(*Map).Key
|
||||
}
|
||||
|
||||
// Elem returns the type of elements of t.
|
||||
@ -978,15 +978,15 @@ func (t *Type) Key() *Type {
|
||||
func (t *Type) Elem() *Type {
|
||||
switch t.kind {
|
||||
case TPTR:
|
||||
return t.Extra.(Ptr).Elem
|
||||
return t.extra.(Ptr).Elem
|
||||
case TARRAY:
|
||||
return t.Extra.(*Array).Elem
|
||||
return t.extra.(*Array).Elem
|
||||
case TSLICE:
|
||||
return t.Extra.(Slice).Elem
|
||||
return t.extra.(Slice).Elem
|
||||
case TCHAN:
|
||||
return t.Extra.(*Chan).Elem
|
||||
return t.extra.(*Chan).Elem
|
||||
case TMAP:
|
||||
return t.Extra.(*Map).Elem
|
||||
return t.extra.(*Map).Elem
|
||||
}
|
||||
base.Fatalf("Type.Elem %s", t.kind)
|
||||
return nil
|
||||
@ -995,18 +995,18 @@ func (t *Type) Elem() *Type {
|
||||
// ChanArgs returns the channel type for TCHANARGS type t.
|
||||
func (t *Type) ChanArgs() *Type {
|
||||
t.wantEtype(TCHANARGS)
|
||||
return t.Extra.(ChanArgs).T
|
||||
return t.extra.(ChanArgs).T
|
||||
}
|
||||
|
||||
// FuncArgs returns the func type for TFUNCARGS type t.
|
||||
func (t *Type) FuncArgs() *Type {
|
||||
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.
|
||||
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.
|
||||
@ -1037,7 +1037,7 @@ func (t *Type) SetAllMethods(fs []*Field) {
|
||||
// Fields returns the fields of struct type t.
|
||||
func (t *Type) Fields() *Fields {
|
||||
t.wantEtype(TSTRUCT)
|
||||
return &t.Extra.(*Struct).fields
|
||||
return &t.extra.(*Struct).fields
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (t *Type) ArgWidth() int64 {
|
||||
t.wantEtype(TFUNC)
|
||||
return t.Extra.(*Func).Argwid
|
||||
return t.extra.(*Func).Argwid
|
||||
}
|
||||
|
||||
func (t *Type) Size() int64 {
|
||||
@ -1221,8 +1221,8 @@ func (t *Type) cmp(x *Type) Cmp {
|
||||
|
||||
if x.sym != nil {
|
||||
// Syms non-nil, if vargens match then equal.
|
||||
if t.Vargen != x.Vargen {
|
||||
return cmpForNe(t.Vargen < x.Vargen)
|
||||
if t.vargen != x.vargen {
|
||||
return cmpForNe(t.vargen < x.vargen)
|
||||
}
|
||||
return CMPeq
|
||||
}
|
||||
@ -1234,8 +1234,8 @@ func (t *Type) cmp(x *Type) Cmp {
|
||||
return CMPeq
|
||||
|
||||
case TSSA:
|
||||
tname := t.Extra.(string)
|
||||
xname := x.Extra.(string)
|
||||
tname := t.extra.(string)
|
||||
xname := x.extra.(string)
|
||||
// desire fast sorting, not pretty sorting.
|
||||
if len(tname) == len(xname) {
|
||||
if tname == xname {
|
||||
@ -1252,16 +1252,16 @@ func (t *Type) cmp(x *Type) Cmp {
|
||||
return CMPlt
|
||||
|
||||
case TTUPLE:
|
||||
xtup := x.Extra.(*Tuple)
|
||||
ttup := t.Extra.(*Tuple)
|
||||
xtup := x.extra.(*Tuple)
|
||||
ttup := t.extra.(*Tuple)
|
||||
if c := ttup.first.Compare(xtup.first); c != CMPeq {
|
||||
return c
|
||||
}
|
||||
return ttup.second.Compare(xtup.second)
|
||||
|
||||
case TRESULTS:
|
||||
xResults := x.Extra.(*Results)
|
||||
tResults := t.Extra.(*Results)
|
||||
xResults := x.extra.(*Results)
|
||||
tResults := t.extra.(*Results)
|
||||
xl, tl := len(xResults.Types), len(tResults.Types)
|
||||
if tl != xl {
|
||||
if tl < xl {
|
||||
@ -1548,7 +1548,7 @@ func (t *Type) PtrTo() *Type {
|
||||
|
||||
func (t *Type) NumFields() int {
|
||||
if t.kind == TRESULTS {
|
||||
return len(t.Extra.(*Results).Types)
|
||||
return len(t.extra.(*Results).Types)
|
||||
}
|
||||
return t.Fields().Len()
|
||||
}
|
||||
@ -1556,15 +1556,15 @@ func (t *Type) FieldType(i int) *Type {
|
||||
if t.kind == TTUPLE {
|
||||
switch i {
|
||||
case 0:
|
||||
return t.Extra.(*Tuple).first
|
||||
return t.extra.(*Tuple).first
|
||||
case 1:
|
||||
return t.Extra.(*Tuple).second
|
||||
return t.extra.(*Tuple).second
|
||||
default:
|
||||
panic("bad tuple index")
|
||||
}
|
||||
}
|
||||
if t.kind == TRESULTS {
|
||||
return t.Extra.(*Results).Types[i]
|
||||
return t.extra.(*Results).Types[i]
|
||||
}
|
||||
return t.Field(i).Type
|
||||
}
|
||||
@ -1577,7 +1577,7 @@ func (t *Type) FieldName(i int) string {
|
||||
|
||||
func (t *Type) NumElem() int64 {
|
||||
t.wantEtype(TARRAY)
|
||||
return t.Extra.(*Array).Bound
|
||||
return t.extra.(*Array).Bound
|
||||
}
|
||||
|
||||
type componentsIncludeBlankFields bool
|
||||
@ -1639,15 +1639,15 @@ func (t *Type) SoleComponent() *Type {
|
||||
// The direction will be one of Crecv, Csend, or Cboth.
|
||||
func (t *Type) ChanDir() ChanDir {
|
||||
t.wantEtype(TCHAN)
|
||||
return t.Extra.(*Chan).Dir
|
||||
return t.extra.(*Chan).Dir
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1699,11 +1699,11 @@ func (t *Type) HasPointers() bool {
|
||||
return !t.Elem().NotInHeap()
|
||||
|
||||
case TTUPLE:
|
||||
ttup := t.Extra.(*Tuple)
|
||||
ttup := t.extra.(*Tuple)
|
||||
return ttup.first.HasPointers() || ttup.second.HasPointers()
|
||||
|
||||
case TRESULTS:
|
||||
types := t.Extra.(*Results).Types
|
||||
types := t.extra.(*Results).Types
|
||||
for _, et := range types {
|
||||
if et.HasPointers() {
|
||||
return true
|
||||
@ -1738,6 +1738,10 @@ func FakeRecvType() *Type {
|
||||
return recvType
|
||||
}
|
||||
|
||||
func FakeRecv() *Field {
|
||||
return NewField(src.NoXPos, nil, FakeRecvType())
|
||||
}
|
||||
|
||||
var (
|
||||
// TSSA types. HasPointers assumes these are pointer-free.
|
||||
TypeInvalid = newSSA("invalid")
|
||||
@ -1768,6 +1772,25 @@ func (t *Type) Obj() Object {
|
||||
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
|
||||
// types that were waiting for this type to be completed.
|
||||
func (t *Type) SetUnderlying(underlying *Type) {
|
||||
@ -1781,7 +1804,7 @@ func (t *Type) SetUnderlying(underlying *Type) {
|
||||
|
||||
// TODO(mdempsky): Fix Type rekinding.
|
||||
t.kind = underlying.kind
|
||||
t.Extra = underlying.Extra
|
||||
t.extra = underlying.extra
|
||||
t.Width = underlying.Width
|
||||
t.Align = underlying.Align
|
||||
t.underlying = underlying.underlying
|
||||
@ -1865,7 +1888,7 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
|
||||
if anyBroke(methods) {
|
||||
t.SetBroke(true)
|
||||
}
|
||||
t.Extra.(*Interface).pkg = pkg
|
||||
t.extra.(*Interface).pkg = pkg
|
||||
return t
|
||||
}
|
||||
|
||||
@ -1874,7 +1897,7 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
|
||||
func NewTypeParam(sym *Sym, index int) *Type {
|
||||
t := New(TTYPEPARAM)
|
||||
t.sym = sym
|
||||
t.Extra.(*Typeparam).index = index
|
||||
t.extra.(*Typeparam).index = index
|
||||
t.SetHasTParam(true)
|
||||
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.
|
||||
func (t *Type) Index() int {
|
||||
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.
|
||||
func (t *Type) SetIndex(i int) {
|
||||
t.wantEtype(TTYPEPARAM)
|
||||
t.Extra.(*Typeparam).index = i
|
||||
t.extra.(*Typeparam).index = i
|
||||
}
|
||||
|
||||
// SetBound sets the bound of a typeparam.
|
||||
func (t *Type) SetBound(bound *Type) {
|
||||
t.wantEtype(TTYPEPARAM)
|
||||
t.Extra.(*Typeparam).bound = bound
|
||||
t.extra.(*Typeparam).bound = bound
|
||||
}
|
||||
|
||||
// Bound returns the bound of a typeparam.
|
||||
func (t *Type) Bound() *Type {
|
||||
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
|
||||
@ -1910,8 +1933,8 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
|
||||
if len(terms) != len(tildes) {
|
||||
base.Fatalf("Mismatched terms and tildes for NewUnion")
|
||||
}
|
||||
t.Extra.(*Union).terms = terms
|
||||
t.Extra.(*Union).tildes = tildes
|
||||
t.extra.(*Union).terms = terms
|
||||
t.extra.(*Union).tildes = tildes
|
||||
nt := len(terms)
|
||||
for i := 0; i < nt; i++ {
|
||||
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.
|
||||
func (t *Type) NumTerms() int {
|
||||
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
|
||||
// represents ~T, rather than just T.
|
||||
func (t *Type) Term(i int) (*Type, bool) {
|
||||
t.wantEtype(TUNION)
|
||||
u := t.Extra.(*Union)
|
||||
u := t.extra.(*Union)
|
||||
return u.terms[i], u.tildes[i]
|
||||
}
|
||||
|
||||
@ -1995,7 +2018,7 @@ func NewStruct(pkg *Pkg, fields []*Field) *Type {
|
||||
if anyBroke(fields) {
|
||||
t.SetBroke(true)
|
||||
}
|
||||
t.Extra.(*Struct).pkg = pkg
|
||||
t.extra.(*Struct).pkg = pkg
|
||||
if fieldsHasTParam(fields) {
|
||||
t.SetHasTParam(true)
|
||||
}
|
||||
|
@ -2,26 +2,25 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package types_test
|
||||
package types
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSSACompare(t *testing.T) {
|
||||
a := []*types.Type{
|
||||
types.TypeInvalid,
|
||||
types.TypeMem,
|
||||
types.TypeFlags,
|
||||
types.TypeVoid,
|
||||
types.TypeInt128,
|
||||
a := []*Type{
|
||||
TypeInvalid,
|
||||
TypeMem,
|
||||
TypeFlags,
|
||||
TypeVoid,
|
||||
TypeInt128,
|
||||
}
|
||||
for _, x := range a {
|
||||
for _, y := range a {
|
||||
c := x.Compare(y)
|
||||
if x == y && c != types.CMPeq || x != y && c == types.CMPeq {
|
||||
t.Errorf("%s compare %s == %d\n", x.Extra, y.Extra, c)
|
||||
if x == y && c != CMPeq || x != y && c == CMPeq {
|
||||
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) {
|
||||
assert(check != nil)
|
||||
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++
|
||||
defer func() {
|
||||
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
|
||||
// again when we type-check the signature.
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
@ -211,6 +211,12 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
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
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
|
@ -281,12 +281,6 @@ func instantiatedHash(typ *Named, targs []Type) string {
|
||||
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].
|
||||
// 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.
|
||||
|
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
|
||||
|
||||
import "bytes"
|
||||
|
||||
// TParamList holds a list of type parameters.
|
||||
type TParamList struct{ tparams []*TypeParam }
|
||||
|
||||
@ -52,6 +54,17 @@ func (l *TypeList) list() []Type {
|
||||
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
|
||||
|
||||
|
@ -376,7 +376,7 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
|
||||
if value.Cap() < n {
|
||||
value.Set(reflect.MakeSlice(value.Type(), n, n))
|
||||
} else {
|
||||
value.Set(value.Slice(0, n))
|
||||
value.SetLen(n)
|
||||
}
|
||||
if _, err := state.b.Read(value.Bytes()); err != nil {
|
||||
errorf("error decoding []byte: %s", err)
|
||||
|
@ -280,6 +280,14 @@ func BenchmarkDecodeStringSlice(b *testing.B) {
|
||||
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) {
|
||||
a := make([]interface{}, 1000)
|
||||
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…
Reference in New Issue
Block a user