diff options
author | Michael Matloob <matloob@golang.org> | 2021-08-27 08:06:55 -0400 |
---|---|---|
committer | Michael Matloob <matloob@golang.org> | 2021-08-27 08:06:57 -0400 |
commit | 220bc44a4c7b8ccc15c38f593531d5f0e721485c (patch) | |
tree | ac1b44473eef42e587c36bda6e097160634598a4 | |
parent | de83ef67acaaf5c2ce12dd831e8d3d04f02a6fc9 (diff) | |
parent | 67f7e16bcce0a3e68bf92e233ea16c8a9d2ac07a (diff) | |
download | go-git-dev.cmdgo.tar.gz |
[dev.cmdgo] all: merge master (67f7e16) into dev.cmdgodev.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
43 files changed, 552 insertions, 625 deletions
diff --git a/src/cmd/compile/internal/abi/abiutils.go b/src/cmd/compile/internal/abi/abiutils.go index d657ddc867..24f34b8263 100644 --- a/src/cmd/compile/internal/abi/abiutils.go +++ b/src/cmd/compile/internal/abi/abiutils.go @@ -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) }) } diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 9660ef9dd5..8a365f8f6a 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -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 diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index f071cb78ce..8784f9ef99 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -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. diff --git a/src/cmd/compile/internal/ir/scc.go b/src/cmd/compile/internal/ir/scc.go index 2cfceaa1f6..a42951c1dd 100644 --- a/src/cmd/compile/internal/ir/scc.go +++ b/src/cmd/compile/internal/ir/scc.go @@ -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] diff --git a/src/cmd/compile/internal/ir/symtab.go b/src/cmd/compile/internal/ir/symtab.go index 61727fb1c4..1e8261810f 100644 --- a/src/cmd/compile/internal/ir/symtab.go +++ b/src/cmd/compile/internal/ir/symtab.go @@ -68,5 +68,4 @@ var Pkgs struct { 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 b23dd47600..54a13b498b 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -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) diff --git a/src/cmd/compile/internal/noder/func.go b/src/cmd/compile/internal/noder/func.go index 702138157c..6077b348a5 100644 --- a/src/cmd/compile/internal/noder/func.go +++ b/src/cmd/compile/internal/noder/func.go @@ -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 diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 48f0e48028..c26340c960 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -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? diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 29882eb773..d53c254001 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -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() diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index e1b485b2b3..61a7f8aad4 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -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" { diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 985453a1bb..e7a9d9655b 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -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 { diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index b3ff4b8855..0c6bb5100c 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -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() { diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index c9f7c2bbe4..e00a3a5da9 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -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) } } diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 9b9efe04a2..ca48db03f5 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 6d3c0f3ccb..c4e87ec7d0 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 @@ 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. - - 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 - } + // TODO(mdempsky): Push into types.InitUniverse or typecheck.InitUniverse. + types.PtrSize = 8 + types.RegSize = 8 + types.MaxWidth = 1 << 50 + + typecheck.InitUniverse() testTypes.SetTypPtrs() } diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 93157bfa11..0ddf11b426 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -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) { 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 69ed8ad74e..0000000000 --- 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 22680dce78..033283a352 100644 --- a/src/cmd/compile/internal/syntax/dumper_test.go +++ b/src/cmd/compile/internal/syntax/dumper_test.go @@ -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) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index fd97279f9d..3d1ca9d6d4 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -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) diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go index ec4b1de573..638e6d4a9d 100644 --- a/src/cmd/compile/internal/syntax/printer_test.go +++ b/src/cmd/compile/internal/syntax/printer_test.go @@ -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) diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index 472d8d2b8a..76fc6de621 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -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 { diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 7e974dfda8..d83bc65bed 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -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. diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 75d6115783..82006c3245 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -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) } diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index a1a3ac3e8a..87ad5d1c54 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -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) } diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index db1b11c4cf..404af5b1b2 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -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 { diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go index 54f3c89c24..ebe338e2aa 100644 --- a/src/cmd/compile/internal/typecheck/universe.go +++ b/src/cmd/compile/internal/typecheck/universe.go @@ -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. diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 0824f6d093..2f81c7b2e1 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -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 } diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index 89391ade68..2546f0e2d1 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -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 // diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index 875b0ba82f..e84e89fd15 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -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) } diff --git a/src/cmd/compile/internal/types/type_test.go b/src/cmd/compile/internal/types/type_test.go index fe3f380b21..1fd05b3f5e 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 0000000000..abceecd15d --- /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 f9cde24dfc..4113d248b8 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -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-- diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index d28e7b8944..ddad1f0311 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -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." diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index ff8dd13b6d..7c33e7ade4 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -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. 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 0000000000..bbbe6805f2 --- /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 0000000000..56e90942ab --- /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 3258a5e9f8..c3befb077f 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 @@ 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 diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index d2f6c749b1..4ef9ef7243 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -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) diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go index 3478bd247e..ceb21c4107 100644 --- a/src/encoding/gob/timing_test.go +++ b/src/encoding/gob/timing_test.go @@ -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 { diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go new file mode 100644 index 0000000000..782b1d2a4f --- /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 0000000000..bc1166f761 --- /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 0000000000..76930e5e4f --- /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 0000000000..0882cb4137 --- /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() {} |