[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
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go
index d657ddc..24f34b8 100644
--- a/src/cmd/compile/internal/abi/abiutils.go
+++ b/src/cmd/compile/internal/abi/abiutils.go
@@ -722,14 +722,17 @@
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)
})
}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 9660ef9d..8a365f8 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -84,7 +84,7 @@
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
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index f071cb7..8784f9e 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -334,6 +334,16 @@
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.
diff --git a/src/cmd/compile/internal/ir/scc.go b/src/cmd/compile/internal/ir/scc.go
index 2cfceaa..a42951c 100644
--- a/src/cmd/compile/internal/ir/scc.go
+++ b/src/cmd/compile/internal/ir/scc.go
@@ -116,12 +116,11 @@
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]
diff --git a/src/cmd/compile/internal/ir/symtab.go b/src/cmd/compile/internal/ir/symtab.go
index 61727fb..1e82618 100644
--- a/src/cmd/compile/internal/ir/symtab.go
+++ b/src/cmd/compile/internal/ir/symtab.go
@@ -68,5 +68,4 @@
Go *types.Pkg
Itab *types.Pkg
Runtime *types.Pkg
- Unsafe *types.Pkg
}
diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go
index b23dd47..54a13b4 100644
--- a/src/cmd/compile/internal/noder/decl.go
+++ b/src/cmd/compile/internal/noder/decl.go
@@ -154,8 +154,7 @@
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)
diff --git a/src/cmd/compile/internal/noder/func.go b/src/cmd/compile/internal/noder/func.go
index 7021381..6077b34 100644
--- a/src/cmd/compile/internal/noder/func.go
+++ b/src/cmd/compile/internal/noder/func.go
@@ -37,8 +37,7 @@
// 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
diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go
index 48f0e48..c26340c 100644
--- a/src/cmd/compile/internal/noder/import.go
+++ b/src/cmd/compile/internal/noder/import.go
@@ -198,7 +198,7 @@
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 @@
}
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?
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 29882eb..d53c254 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -149,6 +149,9 @@
// 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 @@
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()
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index e1b485b..61a7f8a 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -384,7 +384,7 @@
return
}
- if ipkg == ir.Pkgs.Unsafe {
+ if ipkg == types.UnsafePkg {
p.importedUnsafe = true
}
if ipkg.Path == "embed" {
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 985453a..e7a9d96 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -428,7 +428,7 @@
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 @@
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 {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index b3ff4b8..0c6bb51 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -903,7 +903,7 @@
ir.EditChildren(m, edit)
m.SetTypecheck(1)
- if typecheck.IsCmp(x.Op()) {
+ if x.Op().IsCmp() {
transformCompare(m.(*ir.BinaryExpr))
} else {
switch x.Op() {
diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go
index c9f7c2b..e00a3a5 100644
--- a/src/cmd/compile/internal/noder/types.go
+++ b/src/cmd/compile/internal/noder/types.go
@@ -22,7 +22,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-// 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
+ meth = meth2
}
- 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)
- }
+ 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)
}
}
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 9b9efe0..ca48db0 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -927,7 +927,7 @@
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 @@
// 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
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 6d3c0f3..c4e87ec 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -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 @@
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()
}
diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go
index 93157bf..0ddf11b 100644
--- a/src/cmd/compile/internal/ssagen/pgen.go
+++ b/src/cmd/compile/internal/ssagen/pgen.go
@@ -75,7 +75,22 @@
// 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) {
diff --git a/src/cmd/compile/internal/ssagen/pgen_test.go b/src/cmd/compile/internal/ssagen/pgen_test.go
deleted file mode 100644
index 69ed8ad..0000000
--- a/src/cmd/compile/internal/ssagen/pgen_test.go
+++ /dev/null
@@ -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)
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go
index 22680dc..033283a 100644
--- a/src/cmd/compile/internal/syntax/dumper_test.go
+++ b/src/cmd/compile/internal/syntax/dumper_test.go
@@ -13,11 +13,7 @@
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)
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index fd97279..3d1ca9d 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -1924,7 +1924,7 @@
}
// 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 @@
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)
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
index ec4b1de..638e6d4 100644
--- a/src/cmd/compile/internal/syntax/printer_test.go
+++ b/src/cmd/compile/internal/syntax/printer_test.go
@@ -18,11 +18,7 @@
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)
diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go
index 472d8d2..76fc6de 100644
--- a/src/cmd/compile/internal/typecheck/dcl.go
+++ b/src/cmd/compile/internal/typecheck/dcl.go
@@ -314,13 +314,6 @@
}
}
-// 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 {
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index 7e974df..d83bc65 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -77,10 +77,6 @@
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 @@
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.
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index 75d6115..82006c3 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -430,7 +430,7 @@
}
// 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 @@
// 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 @@
}
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)
}
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index a1a3ac3..87ad5d1 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -607,7 +607,7 @@
case exoticTypeRecv:
var rcvr *types.Field
if r.bool() { // isFakeRecv
- rcvr = fakeRecvField()
+ rcvr = types.FakeRecv()
} else {
rcvr = r.exoticParam()
}
@@ -793,7 +793,7 @@
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)
}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index db1b11c..404af5b 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -1736,11 +1736,6 @@
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 @@
t := types.NewNamed(n)
if n.Curfn != nil {
- TypeGen++
- t.Vargen = TypeGen
+ t.SetVargen()
}
if n.Pragma()&ir.NotInHeap != 0 {
diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go
index 54f3c89..ebe338e 100644
--- a/src/cmd/compile/internal/typecheck/universe.go
+++ b/src/cmd/compile/internal/typecheck/universe.go
@@ -29,37 +29,6 @@
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 @@
// 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 @@
}
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 @@
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 @@
// 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.
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go
index 0824f6d..2f81c7b 100644
--- a/src/cmd/compile/internal/types/fmt.go
+++ b/src/cmd/compile/internal/types/fmt.go
@@ -23,6 +23,9 @@
// 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 @@
return
}
if t.Kind() == TSSA {
- b.WriteString(t.Extra.(string))
+ b.WriteString(t.extra.(string))
return
}
if t.Kind() == TTUPLE {
@@ -309,7 +312,7 @@
}
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 @@
// 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
}
diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go
index 89391ad..2546f0e 100644
--- a/src/cmd/compile/internal/types/size.go
+++ b/src/cmd/compile/internal/types/size.go
@@ -526,7 +526,7 @@
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 @@
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
//
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 875b0ba..e84e89f 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -139,7 +139,7 @@
// 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 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
}
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 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 newResults(types []*Type) *Type {
t := New(TRESULTS)
- t.Extra.(*Results).Types = types
+ t.extra.(*Results).Types = types
return t
}
@@ -700,7 +700,7 @@
func newSSA(name string) *Type {
t := New(TSSA)
- t.Extra = name
+ t.extra = name
return t
}
@@ -747,7 +747,7 @@
}
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
// 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) 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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) 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 @@
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) NumElem() int64 {
t.wantEtype(TARRAY)
- return t.Extra.(*Array).Bound
+ return t.extra.(*Array).Bound
}
type componentsIncludeBlankFields bool
@@ -1639,15 +1639,15 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
if anyBroke(methods) {
t.SetBroke(true)
}
- t.Extra.(*Interface).pkg = pkg
+ t.extra.(*Interface).pkg = pkg
return t
}
@@ -1874,7 +1897,7 @@
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 @@
// 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 @@
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 @@
// 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 @@
if anyBroke(fields) {
t.SetBroke(true)
}
- t.Extra.(*Struct).pkg = pkg
+ t.extra.(*Struct).pkg = pkg
if fieldsHasTParam(fields) {
t.SetHasTParam(true)
}
diff --git a/src/cmd/compile/internal/types/type_test.go b/src/cmd/compile/internal/types/type_test.go
index fe3f380..1fd05b3 100644
--- a/src/cmd/compile/internal/types/type_test.go
+++ b/src/cmd/compile/internal/types/type_test.go
@@ -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)
}
}
}
diff --git a/src/cmd/compile/internal/types/universe.go b/src/cmd/compile/internal/types/universe.go
new file mode 100644
index 0000000..abceecd
--- /dev/null
+++ b/src/cmd/compile/internal/types/universe.go
@@ -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})
+}
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index f9cde24..4113d24 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -75,7 +75,7 @@
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--
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index d28e7b8..ddad1f0 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -132,7 +132,7 @@
// 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 @@
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."
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index ff8dd13..7c33e7a 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -281,12 +281,6 @@
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.
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
new file mode 100644
index 0000000..bbbe680
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
@@ -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
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
new file mode 100644
index 0000000..56e9094
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
@@ -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 } */
diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go
index 3258a5e..c3befb0 100644
--- a/src/cmd/compile/internal/types2/typelists.go
+++ b/src/cmd/compile/internal/types2/typelists.go
@@ -4,6 +4,8 @@
package types2
+import "bytes"
+
// TParamList holds a list of type parameters.
type TParamList struct{ tparams []*TypeParam }
@@ -52,6 +54,17 @@
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
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index d2f6c74..4ef9ef7 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -376,7 +376,7 @@
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)
diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go
index 3478bd2..ceb21c4 100644
--- a/src/encoding/gob/timing_test.go
+++ b/src/encoding/gob/timing_test.go
@@ -280,6 +280,14 @@
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 {
diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go
new file mode 100644
index 0000000..782b1d2
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/a.go
@@ -0,0 +1,5 @@
+package a
+
+type Doer[T any] interface {
+ Do() T
+}
diff --git a/test/typeparam/issue47514c.dir/main.go b/test/typeparam/issue47514c.dir/main.go
new file mode 100644
index 0000000..bc1166f
--- /dev/null
+++ b/test/typeparam/issue47514c.dir/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "a"
+
+func Do[T any](doer a.Doer[T]) {
+ doer.Do()
+}
+
+func main() {
+}
diff --git a/test/typeparam/issue47514c.go b/test/typeparam/issue47514c.go
new file mode 100644
index 0000000..76930e5
--- /dev/null
+++ b/test/typeparam/issue47514c.go
@@ -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
diff --git a/test/typeparam/issue47710.go b/test/typeparam/issue47710.go
new file mode 100644
index 0000000..0882cb4
--- /dev/null
+++ b/test/typeparam/issue47710.go
@@ -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() {}