]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: break out transformations of tcCompLit into transformCompLit
authorDan Scales <danscales@google.com>
Wed, 7 Apr 2021 14:58:10 +0000 (07:58 -0700)
committerDan Scales <danscales@google.com>
Thu, 8 Apr 2021 19:32:37 +0000 (19:32 +0000)
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 <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/transform.go

index eee39ecadb545081b023eebcffb6e182343ecf87..fc97df7197ffe957c9da9dda4e64f3ba9ff14a91 100644 (file)
@@ -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 {
index ffe35d58742523562ece2f6a19a3900155d1333d..31f8d1d61b90a3283781810f45b944b69c843599 100644 (file)
@@ -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
+}