From 46ffbec1d6715f62c724a7180aec12ffd8acf57f Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Wed, 7 Apr 2021 07:58:10 -0700 Subject: [PATCH] cmd/compile: break out transformations of tcCompLit into transformCompLit Create transformCompLit, which does the transformations done by tcCompLit without the typechecking. This removes the final use of the old typechecker in the noder2 pass. Other changes: - Used the transformCompLit in stringstorunelit(), which creates an OCOMPLIT that needs transformation as well. - Fixed one place in transformIndex where we were still using typecheck.AssignConv, when we should be using its equivalent noder.assignconvfn. The go/test tests always run with -G=3, and I also tested that the "go test" tests continue to run correctly with -G=3. Change-Id: I4a976534ab7311cf2a5f43841026dbf7401e62b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/308529 Trust: Dan Scales Run-TryBot: Dan Scales Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/expr.go | 5 +- src/cmd/compile/internal/noder/transform.go | 166 +++++++++++++++++++- 2 files changed, 163 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index eee39ecadb5..fc97df7197f 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -346,8 +346,9 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { } } - // TODO(mdempsky): Remove dependency on typecheck.Expr. - return typecheck.Expr(ir.NewCompLitExpr(g.pos(lit), ir.OCOMPLIT, ir.TypeNode(g.typ(typ)), exprs)) + n := ir.NewCompLitExpr(g.pos(lit), ir.OCOMPLIT, nil, exprs) + typed(g.typ(typ), n) + return transformCompLit(n) } func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index ffe35d58742..31f8d1d61b9 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -61,18 +61,24 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node { base.Fatalf("stringtoarraylit %v", n) } - var l []ir.Node + var list []ir.Node i := 0 + eltType := n.Type().Elem() for _, r := range ir.StringVal(n.X) { - l = append(l, ir.NewKeyExpr(base.Pos, ir.NewInt(int64(i)), ir.NewInt(int64(r)))) + elt := ir.NewKeyExpr(base.Pos, ir.NewInt(int64(i)), ir.NewInt(int64(r))) + // Change from untyped int to the actual element type determined + // by types2. No need to change elt.Key, since the array indexes + // are just used for setting up the element ordering. + elt.Value.SetType(eltType) + list = append(list, elt) i++ } nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()), nil) - nn.List = l + nn.List = list + typed(n.Type(), nn) // Need to transform the OCOMPLIT. - // TODO(danscales): update this when we have written transformCompLit() - return typecheck.Expr(nn) + return transformCompLit(nn) } // transformConv transforms an OCONV node as needed, based on the types involved, @@ -225,7 +231,7 @@ func transformIndex(n *ir.IndexExpr) { l := n.X t := l.Type() if t.Kind() == types.TMAP { - n.Index = typecheck.AssignConv(n.Index, t.Key(), "map index") + n.Index = assignconvfn(n.Index, t.Key()) n.SetOp(ir.OINDEXMAP) // Set type to just the map value, not (value, bool). This is // different from types2, but fits the later stages of the @@ -805,3 +811,151 @@ func transformBuiltin(n *ir.CallExpr) ir.Node { return n } + +func hasKeys(l ir.Nodes) bool { + for _, n := range l { + if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY { + return true + } + } + return false +} + +// transformArrayLit runs assignconvfn on each array element and returns the +// length of the slice/array that is needed to hold all the array keys/indexes +// (one more than the highest index). Corresponds to typecheck.typecheckarraylit. +func transformArrayLit(elemType *types.Type, bound int64, elts []ir.Node) int64 { + var key, length int64 + for i, elt := range elts { + ir.SetPos(elt) + r := elts[i] + var kv *ir.KeyExpr + if elt.Op() == ir.OKEY { + elt := elt.(*ir.KeyExpr) + key = typecheck.IndexConst(elt.Key) + assert(key >= 0) + kv = elt + r = elt.Value + } + + r = assignconvfn(r, elemType) + if kv != nil { + kv.Value = r + } else { + elts[i] = r + } + + key++ + if key > length { + length = key + } + } + + return length +} + +// transformCompLit transforms n to an OARRAYLIT, OSLICELIT, OMAPLIT, or +// OSTRUCTLIT node, with any needed conversions. Corresponds to +// typecheck.tcCompLit. +func transformCompLit(n *ir.CompLitExpr) (res ir.Node) { + assert(n.Type() != nil && n.Typecheck() == 1) + lno := base.Pos + defer func() { + base.Pos = lno + }() + + // Save original node (including n.Right) + n.SetOrig(ir.Copy(n)) + + ir.SetPos(n) + + t := n.Type() + + switch t.Kind() { + default: + base.Fatalf("transformCompLit %v", t.Kind()) + + case types.TARRAY: + transformArrayLit(t.Elem(), t.NumElem(), n.List) + n.SetOp(ir.OARRAYLIT) + + case types.TSLICE: + length := transformArrayLit(t.Elem(), -1, n.List) + n.SetOp(ir.OSLICELIT) + n.Len = length + + case types.TMAP: + for _, l := range n.List { + ir.SetPos(l) + assert(l.Op() == ir.OKEY) + l := l.(*ir.KeyExpr) + + r := l.Key + l.Key = assignconvfn(r, t.Key()) + + r = l.Value + l.Value = assignconvfn(r, t.Elem()) + } + + n.SetOp(ir.OMAPLIT) + + case types.TSTRUCT: + // Need valid field offsets for Xoffset below. + types.CalcSize(t) + + if len(n.List) != 0 && !hasKeys(n.List) { + // simple list of values + ls := n.List + for i, n1 := range ls { + ir.SetPos(n1) + + f := t.Field(i) + n1 = assignconvfn(n1, f.Type) + sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1) + sk.Offset = f.Offset + ls[i] = sk + } + assert(len(ls) >= t.NumFields()) + } else { + // keyed list + ls := n.List + for i, l := range ls { + ir.SetPos(l) + + if l.Op() == ir.OKEY { + kv := l.(*ir.KeyExpr) + key := kv.Key + + // Sym might have resolved to name in other top-level + // package, because of import dot. Redirect to correct sym + // before we do the lookup. + s := key.Sym() + if id, ok := key.(*ir.Ident); ok && typecheck.DotImportRefs[id] != nil { + s = typecheck.Lookup(s.Name) + } + + // An OXDOT uses the Sym field to hold + // the field to the right of the dot, + // so s will be non-nil, but an OXDOT + // is never a valid struct literal key. + assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank())) + + l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value) + ls[i] = l + } + + assert(l.Op() == ir.OSTRUCTKEY) + l := l.(*ir.StructKeyExpr) + + f := typecheck.Lookdot1(nil, l.Field, t, t.Fields(), 0) + l.Offset = f.Offset + + l.Value = assignconvfn(l.Value, f.Type) + } + } + + n.SetOp(ir.OSTRUCTLIT) + } + + return n +}