aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/types.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-03-10 19:28:28 -0800
committerDan Scales <danscales@google.com>2021-03-12 00:52:00 +0000
commit71a6c13164f2151c14ebaeccdfcb3633fc8b618e (patch)
tree2642f0e45b87b873ec8796a66aaee6258876646a /src/cmd/compile/internal/noder/types.go
parent7fc638d6f1679f2e35862555531bf479c3e5b99c (diff)
downloadgo-71a6c13164f2151c14ebaeccdfcb3633fc8b618e.tar.gz
go-71a6c13164f2151c14ebaeccdfcb3633fc8b618e.zip
cmd/compile: call types.CheckSize() in g.typ()
Restore code to call types.CheckSize() in g.typ(). There are certain cases (involving maps) where we need to do CheckSize here. In general, the old typechecker calls CheckSize() a lot, and we want to eliminate calling it eventually, so should get do types.CheckSize() when we create a new concrete type. However, the test typeparams/cons.go does not work with just calling types.CheckSize() in g.typ() (which is why I disabled the calls originally). The reason is that g.typ() is called recursively within types.go, so it can be called on a partially-created recursive type, which leads to an error in CheckSize(). So, we need to call CheckSize() only on fully-created top-level types. So, I divided typ() into typ() and typ1(), where typ() is now the external entry point, and typ1() is called within types.go. Now, typ() can call CheckSize() safely. I also added in an extra condition - we do not currently need to call CheckSize() on non-fully-instantiated types, since they will not make it to the backend. That could change a bit with dictionaries. Fixes #44895 Change-Id: I783aa7d2999dd882ddbd99a7c19a6ff6ee420102 Reviewed-on: https://go-review.googlesource.com/c/go/+/300989 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dan Scales <danscales@google.com> Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/noder/types.go')
-rw-r--r--src/cmd/compile/internal/noder/types.go54
1 files changed, 31 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go
index 96bf75d594e..58b7262455a 100644
--- a/src/cmd/compile/internal/noder/types.go
+++ b/src/cmd/compile/internal/noder/types.go
@@ -30,6 +30,23 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
// typ converts a types2.Type to a types.Type, including caching of previously
// translated types.
func (g *irgen) typ(typ types2.Type) *types.Type {
+ res := g.typ1(typ)
+
+ // Calculate the size for all concrete types seen by the frontend. The old
+ // typechecker calls CheckSize() a lot, and we want to eliminate calling
+ // it eventually, so we should do it here instead. We only call it for
+ // top-level types (i.e. we do it here rather in typ1), to make sure that
+ // recursive types have been fully constructed before we call CheckSize.
+ if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
+ types.CheckSize(res)
+ }
+ return res
+}
+
+// typ1 is like typ, but doesn't call CheckSize, since it may have only
+// constructed part of a recursive type. Should not be called from outside this
+// file (g.typ is the "external" entry point).
+func (g *irgen) typ1(typ types2.Type) *types.Type {
// Cache type2-to-type mappings. Important so that each defined generic
// type (instantiated or not) has a single types.Type representation.
// Also saves a lot of computation and memory by avoiding re-translating
@@ -38,13 +55,6 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
if !ok {
res = g.typ0(typ)
g.typs[typ] = res
-
- // Ensure we calculate the size for all concrete types seen by
- // the frontend. This is another heavy hammer for something that
- // should really be the backend's responsibility instead.
- //if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() {
- // types.CheckSize(res)
- //}
}
return res
}
@@ -121,12 +131,12 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
// instantiated type.
rparams := make([]*types.Type, len(typ.TArgs()))
for i, targ := range typ.TArgs() {
- rparams[i] = g.typ(targ)
+ rparams[i] = g.typ1(targ)
}
ntyp.SetRParams(rparams)
//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
- ntyp.SetUnderlying(g.typ(typ.Underlying()))
+ ntyp.SetUnderlying(g.typ1(typ.Underlying()))
g.fillinMethods(typ, ntyp)
return ntyp
}
@@ -137,23 +147,23 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
return obj.Type()
case *types2.Array:
- return types.NewArray(g.typ(typ.Elem()), typ.Len())
+ return types.NewArray(g.typ1(typ.Elem()), typ.Len())
case *types2.Chan:
- return types.NewChan(g.typ(typ.Elem()), dirs[typ.Dir()])
+ return types.NewChan(g.typ1(typ.Elem()), dirs[typ.Dir()])
case *types2.Map:
- return types.NewMap(g.typ(typ.Key()), g.typ(typ.Elem()))
+ return types.NewMap(g.typ1(typ.Key()), g.typ1(typ.Elem()))
case *types2.Pointer:
- return types.NewPtr(g.typ(typ.Elem()))
+ return types.NewPtr(g.typ1(typ.Elem()))
case *types2.Signature:
return g.signature(nil, typ)
case *types2.Slice:
- return types.NewSlice(g.typ(typ.Elem()))
+ return types.NewSlice(g.typ1(typ.Elem()))
case *types2.Struct:
fields := make([]*types.Field, typ.NumFields())
for i := range fields {
v := typ.Field(i)
- f := types.NewField(g.pos(v), g.selector(v), g.typ(v.Type()))
+ f := types.NewField(g.pos(v), g.selector(v), g.typ1(v.Type()))
f.Note = typ.Tag(i)
if v.Embedded() {
f.Embedded = 1
@@ -167,7 +177,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
for i := range embeddeds {
// TODO(mdempsky): Get embedding position.
e := typ.EmbeddedType(i)
- embeddeds[i] = types.NewField(src.NoXPos, nil, g.typ(e))
+ embeddeds[i] = types.NewField(src.NoXPos, nil, g.typ1(e))
}
methods := make([]*types.Field, typ.NumExplicitMethods())
@@ -190,7 +200,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
// TODO(danscales): we don't currently need to use the bounds
// anywhere, so eventually we can probably remove.
- bound := g.typ(typ.Bound())
+ bound := g.typ1(typ.Bound())
*tp.Methods() = *bound.Methods()
return tp
@@ -205,8 +215,6 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
fields[i] = g.param(typ.At(i))
}
t := types.NewStruct(types.LocalPkg, fields)
- //types.CheckSize(t)
- // Can only set after doing the types.CheckSize()
t.StructType().Funarg = types.FunargResults
return t
@@ -223,7 +231,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
if typ.NumMethods() != 0 {
targs := make([]ir.Node, len(typ.TArgs()))
for i, targ := range typ.TArgs() {
- targs[i] = ir.TypeNode(g.typ(targ))
+ targs[i] = ir.TypeNode(g.typ1(targ))
}
methods := make([]*types.Field, typ.NumMethods())
@@ -256,7 +264,7 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
rparams := types2.AsSignature(m.Type()).RParams()
tparams := make([]*types.Field, len(rparams))
for i, rparam := range rparams {
- tparams[i] = types.NewField(src.NoXPos, nil, g.typ(rparam.Type()))
+ tparams[i] = types.NewField(src.NoXPos, nil, g.typ1(rparam.Type()))
}
assert(len(tparams) == len(targs))
subst := &subster{
@@ -286,7 +294,7 @@ func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type
tparams := make([]*types.Field, len(tparams2))
for i := range tparams {
tp := tparams2[i]
- tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ(tp.Type()))
+ tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type()))
}
do := func(typ *types2.Tuple) []*types.Field {
@@ -306,7 +314,7 @@ func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type
}
func (g *irgen) param(v *types2.Var) *types.Field {
- return types.NewField(g.pos(v), g.sym(v), g.typ(v.Type()))
+ return types.NewField(g.pos(v), g.sym(v), g.typ1(v.Type()))
}
func (g *irgen) sym(obj types2.Object) *types.Sym {