mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: simplify OPTRLIT handling
Previously, we would recognize &(T{...}) expressions during type
checking, rewrite them into (*T){...}, and then do a lot of extra work
to make sure the user doesn't write (*T){...} themselves and
resynthesizing the OPTRLIT later on.
This CL simply handles &T{...} directly in the straight forward
manner, by changing OADDR directly to OPTRLIT when appropriate.
While here, match go/types's invalid composite literal type error
message.
Passes toolstash-check.
Change-Id: I902b14c7e2cd9fa93e6915dd58272d2352ba38f8
Reviewed-on: https://go-review.googlesource.com/c/go/+/197120
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
87e2b34f7b
commit
00b773a4a9
7 changed files with 67 additions and 113 deletions
|
|
@ -395,18 +395,16 @@ func walkclosure(clo *Node, init *Nodes) *Node {
|
||||||
|
|
||||||
typ := closureType(clo)
|
typ := closureType(clo)
|
||||||
|
|
||||||
clos := nod(OCOMPLIT, nil, nod(ODEREF, typenod(typ), nil))
|
clos := nod(OCOMPLIT, nil, typenod(typ))
|
||||||
clos.Esc = clo.Esc
|
clos.Esc = clo.Esc
|
||||||
clos.Right.SetImplicit(true)
|
|
||||||
clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...))
|
clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...))
|
||||||
|
|
||||||
|
clos = nod(OADDR, clos, nil)
|
||||||
|
clos.Esc = clo.Esc
|
||||||
|
|
||||||
// Force type conversion from *struct to the func type.
|
// Force type conversion from *struct to the func type.
|
||||||
clos = convnop(clos, clo.Type)
|
clos = convnop(clos, clo.Type)
|
||||||
|
|
||||||
// typecheck will insert a PTRLIT node under CONVNOP,
|
|
||||||
// tag it with escape analysis result.
|
|
||||||
clos.Left.Esc = clo.Esc
|
|
||||||
|
|
||||||
// non-escaping temp to use, if any.
|
// non-escaping temp to use, if any.
|
||||||
if x := prealloc[clo]; x != nil {
|
if x := prealloc[clo]; x != nil {
|
||||||
if !types.Identical(typ, x.Type) {
|
if !types.Identical(typ, x.Type) {
|
||||||
|
|
@ -547,18 +545,16 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
|
||||||
|
|
||||||
typ := partialCallType(n)
|
typ := partialCallType(n)
|
||||||
|
|
||||||
clos := nod(OCOMPLIT, nil, nod(ODEREF, typenod(typ), nil))
|
clos := nod(OCOMPLIT, nil, typenod(typ))
|
||||||
clos.Esc = n.Esc
|
clos.Esc = n.Esc
|
||||||
clos.Right.SetImplicit(true)
|
|
||||||
clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left)
|
clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left)
|
||||||
|
|
||||||
|
clos = nod(OADDR, clos, nil)
|
||||||
|
clos.Esc = n.Esc
|
||||||
|
|
||||||
// Force type conversion from *struct to the func type.
|
// Force type conversion from *struct to the func type.
|
||||||
clos = convnop(clos, n.Type)
|
clos = convnop(clos, n.Type)
|
||||||
|
|
||||||
// The typecheck inside convnop will insert a PTRLIT node under CONVNOP.
|
|
||||||
// Tag it with escape analysis result.
|
|
||||||
clos.Left.Esc = n.Esc
|
|
||||||
|
|
||||||
// non-escaping temp to use, if any.
|
// non-escaping temp to use, if any.
|
||||||
if x := prealloc[n]; x != nil {
|
if x := prealloc[n]; x != nil {
|
||||||
if !types.Identical(typ, x.Type) {
|
if !types.Identical(typ, x.Type) {
|
||||||
|
|
|
||||||
|
|
@ -1304,12 +1304,8 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
||||||
|
|
||||||
case OCOMPLIT:
|
case OCOMPLIT:
|
||||||
if mode == FErr {
|
if mode == FErr {
|
||||||
if n.Right != nil && n.Right.Type != nil && !n.Implicit() {
|
if n.Right != nil {
|
||||||
if n.Right.Implicit() && n.Right.Type.IsPtr() {
|
mode.Fprintf(s, "%v literal", n.Right)
|
||||||
mode.Fprintf(s, "&%v literal", n.Right.Type.Elem())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mode.Fprintf(s, "%v literal", n.Right.Type)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1181,10 +1181,10 @@ func (w *exportWriter) expr(n *Node) {
|
||||||
// should have been resolved by typechecking - handled by default case
|
// should have been resolved by typechecking - handled by default case
|
||||||
|
|
||||||
case OPTRLIT:
|
case OPTRLIT:
|
||||||
w.op(OPTRLIT)
|
w.op(OPTRLIT) // TODO(mdempsky): Replace with OADDR.
|
||||||
w.pos(n.Pos)
|
w.pos(n.Pos)
|
||||||
w.expr(n.Left)
|
w.expr(n.Left)
|
||||||
w.bool(n.Implicit())
|
w.bool(false)
|
||||||
|
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
w.op(OSTRUCTLIT)
|
w.op(OSTRUCTLIT)
|
||||||
|
|
|
||||||
|
|
@ -802,17 +802,8 @@ func (r *importReader) node() *Node {
|
||||||
// unimplemented
|
// unimplemented
|
||||||
|
|
||||||
case OPTRLIT:
|
case OPTRLIT:
|
||||||
pos := r.pos()
|
n := nodl(r.pos(), OADDR, r.expr(), nil)
|
||||||
n := npos(pos, r.expr())
|
_ = r.bool()
|
||||||
if !r.bool() /* !implicit, i.e. '&' operator */ {
|
|
||||||
if n.Op == OCOMPLIT {
|
|
||||||
// Special case for &T{...}: turn into (*T){...}.
|
|
||||||
n.Right = nodl(pos, ODEREF, n.Right, nil)
|
|
||||||
n.Right.SetImplicit(true)
|
|
||||||
} else {
|
|
||||||
n = nodl(pos, OADDR, n, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
|
|
|
||||||
|
|
@ -662,15 +662,6 @@ func (p *noder) expr(expr syntax.Expr) *Node {
|
||||||
}
|
}
|
||||||
x := p.expr(expr.X)
|
x := p.expr(expr.X)
|
||||||
if expr.Y == nil {
|
if expr.Y == nil {
|
||||||
if expr.Op == syntax.And {
|
|
||||||
x = unparen(x) // TODO(mdempsky): Needed?
|
|
||||||
if x.Op == OCOMPLIT {
|
|
||||||
// Special case for &T{...}: turn into (*T){...}.
|
|
||||||
x.Right = p.nod(expr, ODEREF, x.Right, nil)
|
|
||||||
x.Right.SetImplicit(true)
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.nod(expr, p.unOp(expr.Op), x, nil)
|
return p.nod(expr, p.unOp(expr.Op), x, nil)
|
||||||
}
|
}
|
||||||
return p.nod(expr, p.binOp(expr.Op), x, p.expr(expr.Y))
|
return p.nod(expr, p.binOp(expr.Op), x, p.expr(expr.Y))
|
||||||
|
|
|
||||||
|
|
@ -830,10 +830,18 @@ func typecheck1(n *Node, top int) (res *Node) {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch n.Left.Op {
|
||||||
|
case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT:
|
||||||
|
n.Op = OPTRLIT
|
||||||
|
|
||||||
|
default:
|
||||||
checklvalue(n.Left, "take the address of")
|
checklvalue(n.Left, "take the address of")
|
||||||
r := outervalue(n.Left)
|
r := outervalue(n.Left)
|
||||||
var l *Node
|
if r.Orig != r && r.Op == ONAME {
|
||||||
for l = n.Left; l != r; l = l.Left {
|
Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
|
||||||
|
}
|
||||||
|
for l := n.Left; ; l = l.Left {
|
||||||
l.SetAddrtaken(true)
|
l.SetAddrtaken(true)
|
||||||
if l.IsClosureVar() && !capturevarscomplete {
|
if l.IsClosureVar() && !capturevarscomplete {
|
||||||
// Mark the original variable as Addrtaken so that capturevars
|
// Mark the original variable as Addrtaken so that capturevars
|
||||||
|
|
@ -842,24 +850,18 @@ func typecheck1(n *Node, top int) (res *Node) {
|
||||||
// in case l.Name's containing function has not yet been compiled.
|
// in case l.Name's containing function has not yet been compiled.
|
||||||
l.Name.Defn.SetAddrtaken(true)
|
l.Name.Defn.SetAddrtaken(true)
|
||||||
}
|
}
|
||||||
|
if l == r {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Orig != l && l.Op == ONAME {
|
|
||||||
Fatalf("found non-orig name node %v", l)
|
|
||||||
}
|
|
||||||
l.SetAddrtaken(true)
|
|
||||||
if l.IsClosureVar() && !capturevarscomplete {
|
|
||||||
// See comments above about closure variables.
|
|
||||||
l.Name.Defn.SetAddrtaken(true)
|
|
||||||
}
|
}
|
||||||
n.Left = defaultlit(n.Left, nil)
|
n.Left = defaultlit(n.Left, nil)
|
||||||
l = n.Left
|
if n.Left.Type == nil {
|
||||||
t := l.Type
|
|
||||||
if t == nil {
|
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
n.Type = types.NewPtr(t)
|
}
|
||||||
|
|
||||||
|
n.Type = types.NewPtr(n.Left.Type)
|
||||||
|
|
||||||
case OCOMPLIT:
|
case OCOMPLIT:
|
||||||
ok |= ctxExpr
|
ok |= ctxExpr
|
||||||
|
|
@ -2723,13 +2725,8 @@ func fielddup(name string, hash map[string]bool) {
|
||||||
hash[name] = true
|
hash[name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// iscomptype reports whether type t is a composite literal type
|
// iscomptype reports whether type t is a composite literal type.
|
||||||
// or a pointer to one.
|
|
||||||
func iscomptype(t *types.Type) bool {
|
func iscomptype(t *types.Type) bool {
|
||||||
if t.IsPtr() {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
case TARRAY, TSLICE, TSTRUCT, TMAP:
|
case TARRAY, TSLICE, TSTRUCT, TMAP:
|
||||||
return true
|
return true
|
||||||
|
|
@ -2738,16 +2735,27 @@ func iscomptype(t *types.Type) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pushtype(n *Node, t *types.Type) {
|
// pushtype adds elided type information for composite literals if
|
||||||
if n == nil || n.Op != OCOMPLIT || !iscomptype(t) {
|
// appropriate, and returns the resulting expression.
|
||||||
return
|
func pushtype(n *Node, t *types.Type) *Node {
|
||||||
|
if n == nil || n.Op != OCOMPLIT || n.Right != nil {
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Right == nil {
|
switch {
|
||||||
|
case iscomptype(t):
|
||||||
|
// For T, return T{...}.
|
||||||
n.Right = typenod(t)
|
n.Right = typenod(t)
|
||||||
n.SetImplicit(true) // don't print
|
|
||||||
n.Right.SetImplicit(true) // * is okay
|
case t.IsPtr() && iscomptype(t.Elem()):
|
||||||
|
// For *T, return &T{...}.
|
||||||
|
n.Right = typenod(t.Elem())
|
||||||
|
|
||||||
|
n = nodl(n.Pos, OADDR, n, nil)
|
||||||
|
n.SetImplicit(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
||||||
|
|
@ -2782,28 +2790,9 @@ func typecheckcomplit(n *Node) (res *Node) {
|
||||||
nerr := nerrors
|
nerr := nerrors
|
||||||
n.Type = t
|
n.Type = t
|
||||||
|
|
||||||
if t.IsPtr() {
|
|
||||||
// For better or worse, we don't allow pointers as the composite literal type,
|
|
||||||
// except when using the &T syntax, which sets implicit on the ODEREF.
|
|
||||||
if !n.Right.Implicit() {
|
|
||||||
yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
|
|
||||||
n.Type = nil
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also, the underlying type must be a struct, map, slice, or array.
|
|
||||||
if !iscomptype(t) {
|
|
||||||
yyerror("invalid pointer type %v for composite literal", t)
|
|
||||||
n.Type = nil
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
default:
|
default:
|
||||||
yyerror("invalid type for composite literal: %v", t)
|
yyerror("invalid composite literal type %v", t)
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
|
|
||||||
case TARRAY, TSLICE:
|
case TARRAY, TSLICE:
|
||||||
|
|
@ -2850,7 +2839,7 @@ func typecheckcomplit(n *Node) (res *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r := *vp
|
r := *vp
|
||||||
pushtype(r, t.Elem())
|
r = pushtype(r, t.Elem())
|
||||||
r = typecheck(r, ctxExpr)
|
r = typecheck(r, ctxExpr)
|
||||||
*vp = assignconv(r, t.Elem(), "array or slice literal")
|
*vp = assignconv(r, t.Elem(), "array or slice literal")
|
||||||
|
|
||||||
|
|
@ -2887,13 +2876,13 @@ func typecheckcomplit(n *Node) (res *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r := l.Left
|
r := l.Left
|
||||||
pushtype(r, t.Key())
|
r = pushtype(r, t.Key())
|
||||||
r = typecheck(r, ctxExpr)
|
r = typecheck(r, ctxExpr)
|
||||||
l.Left = assignconv(r, t.Key(), "map key")
|
l.Left = assignconv(r, t.Key(), "map key")
|
||||||
cs.add(lineno, l.Left, "key", "map literal")
|
cs.add(lineno, l.Left, "key", "map literal")
|
||||||
|
|
||||||
r = l.Right
|
r = l.Right
|
||||||
pushtype(r, t.Elem())
|
r = pushtype(r, t.Elem())
|
||||||
r = typecheck(r, ctxExpr)
|
r = typecheck(r, ctxExpr)
|
||||||
l.Right = assignconv(r, t.Elem(), "map value")
|
l.Right = assignconv(r, t.Elem(), "map value")
|
||||||
}
|
}
|
||||||
|
|
@ -3024,15 +3013,6 @@ func typecheckcomplit(n *Node) (res *Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Orig = norig
|
|
||||||
if n.Type.IsPtr() {
|
|
||||||
n = nodl(n.Pos, OPTRLIT, n, nil)
|
|
||||||
n.SetTypecheck(1)
|
|
||||||
n.Type = n.Left.Type
|
|
||||||
n.Left.Type = t
|
|
||||||
n.Left.SetTypecheck(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.Orig = norig
|
n.Orig = norig
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ var (
|
||||||
_ = &T{0, 0, "", nil} // ok
|
_ = &T{0, 0, "", nil} // ok
|
||||||
_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
||||||
_ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
_ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal"
|
||||||
_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid pointer type"
|
_ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP"
|
||||||
_ = &Ti{} // ERROR "invalid pointer type"
|
_ = &Ti{} // ERROR "invalid composite literal type Ti"
|
||||||
)
|
)
|
||||||
|
|
||||||
type M map[T]T
|
type M map[T]T
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue