[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:
Michael Matloob 2021-08-27 08:06:55 -04:00
commit 220bc44a4c
43 changed files with 551 additions and 624 deletions

View file

@ -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)
})
}

View file

@ -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

View file

@ -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.

View file

@ -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]

View file

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

View file

@ -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)

View file

@ -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

View file

@ -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?

View file

@ -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()

View file

@ -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" {

View file

@ -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 {

View file

@ -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() {

View file

@ -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)
}
}

View file

@ -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

View file

@ -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()
}

View file

@ -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) {

View file

@ -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)
}
}
}
}

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

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

View file

@ -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.

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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.

View file

@ -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
}

View file

@ -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
//

View file

@ -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)
}

View file

@ -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)
}
}
}

View file

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

View file

@ -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--

View file

@ -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."

View file

@ -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.

View 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

View 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 } */

View file

@ -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

View file

@ -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)

View file

@ -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 {

View file

@ -0,0 +1,5 @@
package a
type Doer[T any] interface {
Do() T
}

View file

@ -0,0 +1,10 @@
package main
import "a"
func Do[T any](doer a.Doer[T]) {
doer.Do()
}
func main() {
}

View 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

View 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() {}