]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: add and use ir.RawOrigExpr
authorMatthew Dempsky <mdempsky@google.com>
Thu, 27 May 2021 09:50:17 +0000 (02:50 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 27 May 2021 22:13:46 +0000 (22:13 +0000)
This CL adds ir.RawOrigExpr, which can be used to represent arbitrary
constant expressions without needing to build and carry around an
entire IR representation of the original expression. It also allows
distinguishing how the constant was originally written by the
user (e.g., "0xff" vs "255").

This CL then also updates irgen to make use of this functionality for
expressions that were constant folded by types2.

Change-Id: I41e04e228e715ae2735c357b75633a2d08ee7021
Reviewed-on: https://go-review.googlesource.com/c/go/+/323210
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/node_gen.go
src/cmd/compile/internal/ir/val.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/helpers.go

index 9ea8b619653a4907c29f6516c28e26bd8d7bae48..519120ed6b89c337338db0dfbbbcf6e78d231f09 100644 (file)
@@ -448,6 +448,20 @@ func (n *ParenExpr) SetOTYPE(t *types.Type) {
        t.SetNod(n)
 }
 
+// A RawOrigExpr represents an arbitrary Go expression as a string value.
+// When printed in diagnostics, the string value is written out exactly as-is.
+type RawOrigExpr struct {
+       miniExpr
+       Raw string
+}
+
+func NewRawOrigExpr(pos src.XPos, op Op, raw string) *RawOrigExpr {
+       n := &RawOrigExpr{Raw: raw}
+       n.pos = pos
+       n.op = op
+       return n
+}
+
 // A ResultExpr represents a direct access to a result.
 type ResultExpr struct {
        miniExpr
index 4ac5f3fea294b95e1cb2790e30dbc78e06114316..d9cc5f109f5810dd7646da585734257ad481b0f1 100644 (file)
@@ -567,6 +567,11 @@ func exprFmt(n Node, s fmt.State, prec int) {
                return
        }
 
+       if n, ok := n.(*RawOrigExpr); ok {
+               fmt.Fprint(s, n.Raw)
+               return
+       }
+
        switch n.Op() {
        case OPAREN:
                n := n.(*ParenExpr)
index 22855d7163f44a6e9d51586c60cabc3c397dccff..9a4858d0371f5275dec8bfdc6377698b7ad110c4 100644 (file)
@@ -947,6 +947,22 @@ func (n *RangeStmt) editChildren(edit func(Node) Node) {
        }
 }
 
+func (n *RawOrigExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *RawOrigExpr) copy() Node {
+       c := *n
+       c.init = copyNodes(c.init)
+       return &c
+}
+func (n *RawOrigExpr) doChildren(do func(Node) bool) bool {
+       if doNodes(n.init, do) {
+               return true
+       }
+       return false
+}
+func (n *RawOrigExpr) editChildren(edit func(Node) Node) {
+       editNodes(n.init, edit)
+}
+
 func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
 func (n *ResultExpr) copy() Node {
        c := *n
index af9f95b29d7a7367cc0fa67b1f4a3c82f68906f7..bfe7d2bb436c8999631fdbf364c7c766006118a5 100644 (file)
@@ -66,7 +66,7 @@ func Float64Val(v constant.Value) float64 {
 
 func AssertValidTypeForConst(t *types.Type, v constant.Value) {
        if !ValidTypeForConst(t, v) {
-               base.Fatalf("%v does not represent %v (%v)", t, v, v.Kind())
+               base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind())
        }
 }
 
index f96144f8d70f3659b4ddbad003db7535c4d61e54..c901dc55345bbab9207b6cd53c702a6c77bc801e 100644 (file)
@@ -5,6 +5,8 @@
 package noder
 
 import (
+       "fmt"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
@@ -15,6 +17,8 @@ import (
 )
 
 func (g *irgen) expr(expr syntax.Expr) ir.Node {
+       expr = unparen(expr) // skip parens; unneeded after parse+typecheck
+
        if expr == nil {
                return nil
        }
@@ -67,7 +71,9 @@ func (g *irgen) expr(expr syntax.Expr) ir.Node {
 
        // Constant expression.
        if tv.Value != nil {
-               return Const(g.pos(expr), g.typ(typ), tv.Value)
+               typ := g.typ(typ)
+               value := FixValue(typ, tv.Value)
+               return OrigConst(g.pos(expr), typ, value, constExprOp(expr), syntax.String(expr))
        }
 
        n := g.expr0(typ, expr)
@@ -161,9 +167,6 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
                typed(g.typ(typ), n)
                return n
 
-       case *syntax.ParenExpr:
-               return g.expr(expr.X) // skip parens; unneeded after parse+typecheck
-
        case *syntax.SelectorExpr:
                // Qualified identifier.
                if name, ok := expr.X.(*syntax.Name); ok {
@@ -317,13 +320,17 @@ func getTargs(selinfo *types2.Selection) []types2.Type {
 }
 
 func (g *irgen) exprList(expr syntax.Expr) []ir.Node {
+       return g.exprs(unpackListExpr(expr))
+}
+
+func unpackListExpr(expr syntax.Expr) []syntax.Expr {
        switch expr := expr.(type) {
        case nil:
                return nil
        case *syntax.ListExpr:
-               return g.exprs(expr.ElemList)
+               return expr.ElemList
        default:
-               return []ir.Node{g.expr(expr)}
+               return []syntax.Expr{expr}
        }
 }
 
@@ -402,3 +409,35 @@ func (g *irgen) typeExpr(typ syntax.Expr) *types.Type {
        }
        return n.Type()
 }
+
+// constExprOp returns an ir.Op that represents the outermost
+// operation of the given constant expression. It's intended for use
+// with ir.RawOrigExpr.
+func constExprOp(expr syntax.Expr) ir.Op {
+       switch expr := expr.(type) {
+       default:
+               panic(fmt.Sprintf("%s: unexpected expression: %T", expr.Pos(), expr))
+
+       case *syntax.BasicLit:
+               return ir.OLITERAL
+       case *syntax.Name, *syntax.SelectorExpr:
+               return ir.ONAME
+       case *syntax.CallExpr:
+               return ir.OCALL
+       case *syntax.Operation:
+               if expr.Y == nil {
+                       return unOps[expr.Op]
+               }
+               return binOps[expr.Op]
+       }
+}
+
+func unparen(expr syntax.Expr) syntax.Expr {
+       for {
+               paren, ok := expr.(*syntax.ParenExpr)
+               if !ok {
+                       return expr
+               }
+               expr = paren.X
+       }
+}
index 9da0e493007a0687899eb59fe64f2eaa03d95e0c..ea30a3bfa9994637346452ef45d97c09d40878c9 100644 (file)
@@ -43,6 +43,32 @@ func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node {
        return typed(typ, ir.NewBasicLit(pos, val))
 }
 
+func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
+       orig := ir.NewRawOrigExpr(pos, op, raw)
+       return ir.NewConstExpr(val, typed(typ, orig))
+}
+
+// FixValue returns val after converting and truncating it as
+// appropriate for typ.
+func FixValue(typ *types.Type, val constant.Value) constant.Value {
+       assert(typ.Kind() != types.TFORW)
+       switch {
+       case typ.IsInteger():
+               val = constant.ToInt(val)
+       case typ.IsFloat():
+               val = constant.ToFloat(val)
+       case typ.IsComplex():
+               val = constant.ToComplex(val)
+       }
+       if !typ.IsUntyped() {
+               val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val()
+       }
+       if typ.Kind() != types.TTYPEPARAM {
+               ir.AssertValidTypeForConst(typ, val)
+       }
+       return val
+}
+
 func Nil(pos src.XPos, typ *types.Type) ir.Node {
        return typed(typ, ir.NewNilExpr(pos))
 }