Skip to content

Commit

Permalink
[dev.unified] cmd/compile/internal/noder: start writing implicit conv…
Browse files Browse the repository at this point in the history
…ersions

This CL adds support for implicit conversions to the unified IR export
data format, and starts inserting them in a few low-hanging
places (send statements, index expressions).

Subsequentl CLs will handle the remaining trickier cases.

Change-Id: Iaea9d1c5df8432b61bd82578ab2ef02adaf26367
Reviewed-on: https://go-review.googlesource.com/c/go/+/413396
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
  • Loading branch information
mdempsky committed Jun 23, 2022
1 parent 9cb784a commit 5f5422a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 11 deletions.
7 changes: 6 additions & 1 deletion src/cmd/compile/internal/noder/reader.go
Expand Up @@ -1782,6 +1782,7 @@ func (r *reader) expr() (res ir.Node) {
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))

case exprConvert:
implicit := r.Bool()
typ := r.typ()
pos := r.pos()
x := r.expr()
Expand All @@ -1799,7 +1800,11 @@ func (r *reader) expr() (res ir.Node) {
base.ErrorExit() // harsh, but prevents constructing invalid IR
}

return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONV, typ, x))
n := typecheck.Expr(ir.NewConvExpr(pos, ir.OCONV, typ, x))
if implicit && n.Op() != ir.OLITERAL {
n.(ImplicitNode).SetImplicit(true)
}
return n
}
}

Expand Down
58 changes: 48 additions & 10 deletions src/cmd/compile/internal/noder/writer.go
Expand Up @@ -1079,13 +1079,18 @@ func (w *writer) stmt1(stmt syntax.Stmt) {
w.op(binOps[stmt.Op])
w.expr(stmt.Lhs)
w.pos(stmt)
w.expr(stmt.Rhs)

var typ types2.Type
if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr {
typ = w.p.typeOf(stmt.Lhs)
}
w.implicitExpr(stmt, typ, stmt.Rhs)

default:
w.Code(stmtAssign)
w.pos(stmt)
w.assignList(stmt.Lhs)
w.exprList(stmt.Rhs)
w.exprList(stmt.Rhs) // TODO(mdempsky): Implicit conversions to Lhs types.
}

case *syntax.BlockStmt:
Expand Down Expand Up @@ -1130,17 +1135,19 @@ func (w *writer) stmt1(stmt syntax.Stmt) {
case *syntax.ReturnStmt:
w.Code(stmtReturn)
w.pos(stmt)
w.exprList(stmt.Results)
w.exprList(stmt.Results) // TODO(mdempsky): Implicit conversions to result types.

case *syntax.SelectStmt:
w.Code(stmtSelect)
w.selectStmt(stmt)

case *syntax.SendStmt:
chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan)

w.Code(stmtSend)
w.pos(stmt)
w.expr(stmt.Chan)
w.expr(stmt.Value)
w.implicitExpr(stmt, chanType.Elem(), stmt.Value)

case *syntax.SwitchStmt:
w.Code(stmtSwitch)
Expand Down Expand Up @@ -1196,7 +1203,7 @@ func (w *writer) declStmt(decl syntax.Decl) {
w.Code(stmtAssign)
w.pos(decl)
w.assignList(namesAsExpr(decl.NameList))
w.exprList(decl.Values)
w.exprList(decl.Values) // TODO(mdempsky): Implicit conversions to Lhs types.
}
}

Expand All @@ -1213,6 +1220,11 @@ func (w *writer) forStmt(stmt *syntax.ForStmt) {

if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) {
w.pos(rang)
// TODO(mdempsky): For !rang.Def, we need to handle implicit
// conversions; e.g., see #53328.
//
// This is tricky, because the assignments aren't introduced until
// lowering in walk.
w.assignList(rang.Lhs)
w.expr(rang.X)
} else {
Expand Down Expand Up @@ -1294,6 +1306,7 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
w.exprType(iface, cas, true)
}
} else {
// TODO(mdempsky): Implicit conversions to tagType, if appropriate.
w.exprList(clause.Cases)
}

Expand Down Expand Up @@ -1418,10 +1431,15 @@ func (w *writer) expr(expr syntax.Expr) {
case *syntax.IndexExpr:
_ = w.p.typeOf(expr.Index) // ensure this is an index expression, not an instantiation

var keyType types2.Type
if mapType, ok := types2.CoreType(w.p.typeOf(expr.X)).(*types2.Map); ok {
keyType = mapType.Key()
}

w.Code(exprIndex)
w.expr(expr.X)
w.pos(expr)
w.expr(expr.Index)
w.implicitExpr(expr, keyType, expr.Index)

case *syntax.SliceExpr:
w.Code(exprSlice)
Expand All @@ -1448,6 +1466,7 @@ func (w *writer) expr(expr syntax.Expr) {
break
}

// TODO(mdempsky): Implicit conversions to common type.
w.Code(exprBinaryOp)
w.op(binOps[expr.Op])
w.expr(expr.X)
Expand All @@ -1462,6 +1481,7 @@ func (w *writer) expr(expr syntax.Expr) {
assert(!expr.HasDots)

w.Code(exprConvert)
w.Bool(false) // explicit
w.typ(tv.Type)
w.pos(expr)
w.expr(expr.ArgList[0])
Expand Down Expand Up @@ -1512,9 +1532,9 @@ func (w *writer) expr(expr syntax.Expr) {
if w.Bool(len(expr.ArgList) == 1 && isMultiValueExpr(w.p.info, expr.ArgList[0])) {
// f(g()) call
assert(!expr.HasDots)
w.expr(expr.ArgList[0])
w.expr(expr.ArgList[0]) // TODO(mdempsky): Implicit conversions to parameter types.
} else {
w.exprs(expr.ArgList)
w.exprs(expr.ArgList) // TODO(mdempsky): Implicit conversions to parameter types.
w.Bool(expr.HasDots)
}
}
Expand All @@ -1526,6 +1546,24 @@ func (w *writer) optExpr(expr syntax.Expr) {
}
}

// implicitExpr is like expr, but if dst is non-nil and different from
// expr's type, then an implicit conversion operation is inserted at
// pos.
func (w *writer) implicitExpr(pos poser, dst types2.Type, expr syntax.Expr) {
src := w.p.typeOf(expr)
if dst != nil && !types2.Identical(src, dst) {
if !types2.AssignableTo(src, dst) {
w.p.fatalf(pos, "%v is not assignable to %v", src, dst)
}
w.Code(exprConvert)
w.Bool(true) // implicit
w.typ(dst)
w.pos(pos)
// fallthrough
}
w.expr(expr)
}

func (w *writer) compLit(lit *syntax.CompositeLit) {
typ := w.p.typeOf(lit)

Expand Down Expand Up @@ -1554,12 +1592,12 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) {
// use position of expr.Key rather than of elem (which has position of ':')
w.pos(kv.Key)
w.expr(kv.Key)
w.expr(kv.Key) // TODO(mdempsky): Implicit conversion to (map) key type.
elem = kv.Value
}
}
w.pos(elem)
w.expr(elem)
w.expr(elem) // TODO(mdempsky): Implicit conversion to element type.
}
}

Expand Down

0 comments on commit 5f5422a

Please sign in to comment.