mirror of
https://github.com/golang/go
synced 2024-11-12 03:00:22 -07:00
Revert "cmd/compile: rewrite f(g()) for multi-value g() during typecheck"
This reverts commit d96b7fbf98
.
Reason for revert: broke noopt and longtest builders.
Change-Id: Ifaec64d817c4336cb255a2e9db00526b7bc5606a
Reviewed-on: https://go-review.googlesource.com/c/164757
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
13d24b685a
commit
38642b9fce
@ -1604,6 +1604,13 @@ func (e *EscState) esccall(call *Node, parent *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
argList := call.List
|
argList := call.List
|
||||||
|
if argList.Len() == 1 {
|
||||||
|
arg := argList.First()
|
||||||
|
if arg.Type.IsFuncArgStruct() { // f(g())
|
||||||
|
argList = e.nodeEscState(arg).Retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
args := argList.Slice()
|
args := argList.Slice()
|
||||||
|
|
||||||
if indirect {
|
if indirect {
|
||||||
|
@ -1404,11 +1404,14 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
|||||||
}
|
}
|
||||||
mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
|
mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
|
||||||
|
|
||||||
case OCOMPLEX, OCOPY:
|
case OCOPY:
|
||||||
if n.Left != nil {
|
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
|
||||||
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
|
|
||||||
|
case OCOMPLEX:
|
||||||
|
if n.List.Len() == 1 {
|
||||||
|
mode.Fprintf(s, "%#v(%v)", n.Op, n.List.First())
|
||||||
} else {
|
} else {
|
||||||
mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
|
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCONV,
|
case OCONV,
|
||||||
@ -1537,8 +1540,6 @@ func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
|
|||||||
if flag&FmtLong != 0 && t != nil {
|
if flag&FmtLong != 0 && t != nil {
|
||||||
if t.Etype == TNIL {
|
if t.Etype == TNIL {
|
||||||
fmt.Fprint(s, "nil")
|
fmt.Fprint(s, "nil")
|
||||||
} else if n.Op == ONAME && n.Name.AutoTemp() {
|
|
||||||
mode.Fprintf(s, "%v value", t)
|
|
||||||
} else {
|
} else {
|
||||||
mode.Fprintf(s, "%v (type %v)", n, t)
|
mode.Fprintf(s, "%v (type %v)", n, t)
|
||||||
}
|
}
|
||||||
|
@ -1387,8 +1387,7 @@ func (w *exportWriter) localIdent(s *types.Sym, v int32) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mdempsky): Fix autotmp hack.
|
if i := strings.LastIndex(name, "."); i >= 0 {
|
||||||
if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") {
|
|
||||||
Fatalf("unexpected dot in identifier: %v", name)
|
Fatalf("unexpected dot in identifier: %v", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,6 @@ import (
|
|||||||
// the name, normally "pkg.init", is altered to "pkg.init.0".
|
// the name, normally "pkg.init", is altered to "pkg.init.0".
|
||||||
var renameinitgen int
|
var renameinitgen int
|
||||||
|
|
||||||
// Dummy function for autotmps generated during typechecking.
|
|
||||||
var dummyInitFn = nod(ODCLFUNC, nil, nil)
|
|
||||||
|
|
||||||
func renameinit() *types.Sym {
|
func renameinit() *types.Sym {
|
||||||
s := lookupN("init.", renameinitgen)
|
s := lookupN("init.", renameinitgen)
|
||||||
renameinitgen++
|
renameinitgen++
|
||||||
@ -117,12 +114,6 @@ func fninit(n []*Node) {
|
|||||||
initsym := lookup("init")
|
initsym := lookup("init")
|
||||||
fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
|
fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
|
||||||
|
|
||||||
for _, dcl := range dummyInitFn.Func.Dcl {
|
|
||||||
dcl.Name.Curfn = fn
|
|
||||||
}
|
|
||||||
fn.Func.Dcl = append(fn.Func.Dcl, dummyInitFn.Func.Dcl...)
|
|
||||||
dummyInitFn = nil
|
|
||||||
|
|
||||||
// (3)
|
// (3)
|
||||||
a := nod(OIF, nil, nil)
|
a := nod(OIF, nil, nil)
|
||||||
a.Left = nod(OGT, gatevar, nodintconst(1))
|
a.Left = nod(OGT, gatevar, nodintconst(1))
|
||||||
|
@ -589,13 +589,24 @@ func inlnode(n *Node, maxCost int32) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inlnodelist(n.List, maxCost)
|
inlnodelist(n.List, maxCost)
|
||||||
if n.Op == OBLOCK {
|
switch n.Op {
|
||||||
|
case OBLOCK:
|
||||||
for _, n2 := range n.List.Slice() {
|
for _, n2 := range n.List.Slice() {
|
||||||
if n2.Op == OINLCALL {
|
if n2.Op == OINLCALL {
|
||||||
inlconv2stmt(n2)
|
inlconv2stmt(n2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
|
||||||
|
// if we just replaced arg in f(arg()) or return arg with an inlined call
|
||||||
|
// and arg returns multiple values, glue as list
|
||||||
|
if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
|
||||||
|
n.List.Set(inlconv2list(n.List.First()))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
default:
|
||||||
s := n.List.Slice()
|
s := n.List.Slice()
|
||||||
for i1, n1 := range s {
|
for i1, n1 := range s {
|
||||||
if n1 != nil && n1.Op == OINLCALL {
|
if n1 != nil && n1.Op == OINLCALL {
|
||||||
@ -1005,6 +1016,9 @@ func mkinlcall(n, fn *Node, maxCost int32) *Node {
|
|||||||
// to pass as a slice.
|
// to pass as a slice.
|
||||||
|
|
||||||
numvals := n.List.Len()
|
numvals := n.List.Len()
|
||||||
|
if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
|
||||||
|
numvals = n.List.First().Type.NumFields()
|
||||||
|
}
|
||||||
|
|
||||||
x := as.List.Len()
|
x := as.List.Len()
|
||||||
for as.List.Len() < numvals {
|
for as.List.Len() < numvals {
|
||||||
|
@ -380,12 +380,66 @@ func (o *Order) init(n *Node) {
|
|||||||
n.Ninit.Set(nil)
|
n.Ninit.Set(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ismulticall reports whether the list l is f() for a multi-value function.
|
||||||
|
// Such an f() could appear as the lone argument to a multi-arg function.
|
||||||
|
func ismulticall(l Nodes) bool {
|
||||||
|
// one arg only
|
||||||
|
if l.Len() != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n := l.First()
|
||||||
|
|
||||||
|
// must be call
|
||||||
|
switch n.Op {
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
case OCALLFUNC, OCALLMETH, OCALLINTER:
|
||||||
|
// call must return multiple values
|
||||||
|
return n.Left.Type.NumResults() > 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyRet emits t1, t2, ... = n, where n is a function call,
|
||||||
|
// and then returns the list t1, t2, ....
|
||||||
|
func (o *Order) copyRet(n *Node) []*Node {
|
||||||
|
if !n.Type.IsFuncArgStruct() {
|
||||||
|
Fatalf("copyret %v %d", n.Type, n.Left.Type.NumResults())
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := n.Type.Fields().Slice()
|
||||||
|
l1 := make([]*Node, len(slice))
|
||||||
|
l2 := make([]*Node, len(slice))
|
||||||
|
for i, t := range slice {
|
||||||
|
tmp := temp(t.Type)
|
||||||
|
l1[i] = tmp
|
||||||
|
l2[i] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
as := nod(OAS2, nil, nil)
|
||||||
|
as.List.Set(l1)
|
||||||
|
as.Rlist.Set1(n)
|
||||||
|
as = typecheck(as, ctxStmt)
|
||||||
|
o.stmt(as)
|
||||||
|
|
||||||
|
return l2
|
||||||
|
}
|
||||||
|
|
||||||
|
// callArgs orders the list of call arguments *l.
|
||||||
|
func (o *Order) callArgs(l *Nodes) {
|
||||||
|
if ismulticall(*l) {
|
||||||
|
// return f() where f() is multiple values.
|
||||||
|
l.Set(o.copyRet(l.First()))
|
||||||
|
} else {
|
||||||
|
o.exprList(*l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// call orders the call expression n.
|
// call orders the call expression n.
|
||||||
// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
|
// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
|
||||||
func (o *Order) call(n *Node) {
|
func (o *Order) call(n *Node) {
|
||||||
n.Left = o.expr(n.Left, nil)
|
n.Left = o.expr(n.Left, nil)
|
||||||
n.Right = o.expr(n.Right, nil) // ODDDARG temp
|
n.Right = o.expr(n.Right, nil) // ODDDARG temp
|
||||||
o.exprList(n.List)
|
o.callArgs(&n.List)
|
||||||
|
|
||||||
if n.Op != OCALLFUNC {
|
if n.Op != OCALLFUNC {
|
||||||
return
|
return
|
||||||
@ -757,7 +811,7 @@ func (o *Order) stmt(n *Node) {
|
|||||||
o.cleanTemp(t)
|
o.cleanTemp(t)
|
||||||
|
|
||||||
case ORETURN:
|
case ORETURN:
|
||||||
o.exprList(n.List)
|
o.callArgs(&n.List)
|
||||||
o.out = append(o.out, n)
|
o.out = append(o.out, n)
|
||||||
|
|
||||||
// Special: clean case temporaries in each block entry.
|
// Special: clean case temporaries in each block entry.
|
||||||
@ -1120,7 +1174,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
|||||||
n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
|
n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
|
||||||
n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
|
n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
|
||||||
} else {
|
} else {
|
||||||
o.exprList(n.List)
|
o.callArgs(&n.List)
|
||||||
}
|
}
|
||||||
|
|
||||||
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
|
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
|
||||||
|
@ -1318,7 +1318,11 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheckargs(n)
|
if n.List.Len() == 1 && !n.IsDDD() {
|
||||||
|
n.List.SetFirst(typecheck(n.List.First(), ctxExpr|ctxMultiOK))
|
||||||
|
} else {
|
||||||
|
typecheckslice(n.List.Slice(), ctxExpr)
|
||||||
|
}
|
||||||
t := l.Type
|
t := l.Type
|
||||||
if t == nil {
|
if t == nil {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
@ -1512,24 +1516,51 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
|
|
||||||
case OCOMPLEX:
|
case OCOMPLEX:
|
||||||
ok |= ctxExpr
|
ok |= ctxExpr
|
||||||
typecheckargs(n)
|
var r *Node
|
||||||
if !twoarg(n) {
|
var l *Node
|
||||||
n.Type = nil
|
if n.List.Len() == 1 {
|
||||||
return n
|
typecheckslice(n.List.Slice(), ctxMultiOK)
|
||||||
|
if n.List.First().Op != OCALLFUNC && n.List.First().Op != OCALLMETH {
|
||||||
|
yyerror("invalid operation: complex expects two arguments")
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
t := n.List.First().Left.Type
|
||||||
|
if !t.IsKind(TFUNC) {
|
||||||
|
// Bail. This error will be reported elsewhere.
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
if t.NumResults() != 2 {
|
||||||
|
yyerror("invalid operation: complex expects two arguments, %v returns %d results", n.List.First(), t.NumResults())
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
t = n.List.First().Type
|
||||||
|
l = asNode(t.Field(0).Nname)
|
||||||
|
r = asNode(t.Field(1).Nname)
|
||||||
|
} else {
|
||||||
|
if !twoarg(n) {
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
n.Left = typecheck(n.Left, ctxExpr)
|
||||||
|
n.Right = typecheck(n.Right, ctxExpr)
|
||||||
|
l = n.Left
|
||||||
|
r = n.Right
|
||||||
|
if l.Type == nil || r.Type == nil {
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
l, r = defaultlit2(l, r, false)
|
||||||
|
if l.Type == nil || r.Type == nil {
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
n.Left = l
|
||||||
|
n.Right = r
|
||||||
}
|
}
|
||||||
l := n.Left
|
|
||||||
r := n.Right
|
|
||||||
if l.Type == nil || r.Type == nil {
|
|
||||||
n.Type = nil
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
l, r = defaultlit2(l, r, false)
|
|
||||||
if l.Type == nil || r.Type == nil {
|
|
||||||
n.Type = nil
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
n.Left = l
|
|
||||||
n.Right = r
|
|
||||||
|
|
||||||
if !types.Identical(l.Type, r.Type) {
|
if !types.Identical(l.Type, r.Type) {
|
||||||
yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
|
yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
|
||||||
@ -1591,8 +1622,6 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
ok |= ctxStmt
|
ok |= ctxStmt
|
||||||
|
|
||||||
case ODELETE:
|
case ODELETE:
|
||||||
ok |= ctxStmt
|
|
||||||
typecheckargs(n)
|
|
||||||
args := n.List
|
args := n.List
|
||||||
if args.Len() == 0 {
|
if args.Len() == 0 {
|
||||||
yyerror("missing arguments to delete")
|
yyerror("missing arguments to delete")
|
||||||
@ -1612,6 +1641,8 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ok |= ctxStmt
|
||||||
|
typecheckslice(args.Slice(), ctxExpr)
|
||||||
l := args.First()
|
l := args.First()
|
||||||
r := args.Second()
|
r := args.Second()
|
||||||
if l.Type != nil && !l.Type.IsMap() {
|
if l.Type != nil && !l.Type.IsMap() {
|
||||||
@ -1624,7 +1655,6 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
|
|
||||||
case OAPPEND:
|
case OAPPEND:
|
||||||
ok |= ctxExpr
|
ok |= ctxExpr
|
||||||
typecheckargs(n)
|
|
||||||
args := n.List
|
args := n.List
|
||||||
if args.Len() == 0 {
|
if args.Len() == 0 {
|
||||||
yyerror("missing arguments to append")
|
yyerror("missing arguments to append")
|
||||||
@ -1632,12 +1662,25 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.Len() == 1 && !n.IsDDD() {
|
||||||
|
args.SetFirst(typecheck(args.First(), ctxExpr|ctxMultiOK))
|
||||||
|
} else {
|
||||||
|
typecheckslice(args.Slice(), ctxExpr)
|
||||||
|
}
|
||||||
|
|
||||||
t := args.First().Type
|
t := args.First().Type
|
||||||
if t == nil {
|
if t == nil {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unpack multiple-return result before type-checking.
|
||||||
|
var funarg *types.Type
|
||||||
|
if t.IsFuncArgStruct() {
|
||||||
|
funarg = t
|
||||||
|
t = t.Field(0).Type
|
||||||
|
}
|
||||||
|
|
||||||
n.Type = t
|
n.Type = t
|
||||||
if !t.IsSlice() {
|
if !t.IsSlice() {
|
||||||
if Isconst(args.First(), CTNIL) {
|
if Isconst(args.First(), CTNIL) {
|
||||||
@ -1673,23 +1716,44 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
as := args.Slice()[1:]
|
if funarg != nil {
|
||||||
for i, n := range as {
|
for _, t := range funarg.FieldSlice()[1:] {
|
||||||
if n.Type == nil {
|
if assignop(t.Type, n.Type.Elem(), nil) == 0 {
|
||||||
continue
|
yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
as := args.Slice()[1:]
|
||||||
|
for i, n := range as {
|
||||||
|
if n.Type == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
as[i] = assignconv(n, t.Elem(), "append")
|
||||||
|
checkwidth(as[i].Type) // ensure width is calculated for backend
|
||||||
}
|
}
|
||||||
as[i] = assignconv(n, t.Elem(), "append")
|
|
||||||
checkwidth(as[i].Type) // ensure width is calculated for backend
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCOPY:
|
case OCOPY:
|
||||||
ok |= ctxStmt | ctxExpr
|
ok |= ctxStmt | ctxExpr
|
||||||
typecheckargs(n)
|
args := n.List
|
||||||
if !twoarg(n) {
|
if args.Len() < 2 {
|
||||||
|
yyerror("missing arguments to copy")
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.Len() > 2 {
|
||||||
|
yyerror("too many arguments to copy")
|
||||||
|
n.Type = nil
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
n.Left = args.First()
|
||||||
|
n.Right = args.Second()
|
||||||
|
n.List.Set(nil)
|
||||||
n.Type = types.Types[TINT]
|
n.Type = types.Types[TINT]
|
||||||
|
n.Left = typecheck(n.Left, ctxExpr)
|
||||||
|
n.Right = typecheck(n.Right, ctxExpr)
|
||||||
if n.Left.Type == nil || n.Right.Type == nil {
|
if n.Left.Type == nil || n.Right.Type == nil {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
@ -2085,7 +2149,11 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
|
|
||||||
case ORETURN:
|
case ORETURN:
|
||||||
ok |= ctxStmt
|
ok |= ctxStmt
|
||||||
typecheckargs(n)
|
if n.List.Len() == 1 {
|
||||||
|
typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK)
|
||||||
|
} else {
|
||||||
|
typecheckslice(n.List.Slice(), ctxExpr)
|
||||||
|
}
|
||||||
if Curfn == nil {
|
if Curfn == nil {
|
||||||
yyerror("return outside function")
|
yyerror("return outside function")
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
@ -2189,51 +2257,6 @@ func typecheck1(n *Node, top int) (res *Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckargs(n *Node) {
|
|
||||||
if n.List.Len() != 1 || n.IsDDD() {
|
|
||||||
typecheckslice(n.List.Slice(), ctxExpr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK)
|
|
||||||
t := n.List.First().Type
|
|
||||||
if t == nil || !t.IsFuncArgStruct() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
|
|
||||||
|
|
||||||
// Save n as n.Orig for fmt.go.
|
|
||||||
if n.Orig == n {
|
|
||||||
n.Orig = n.sepcopy()
|
|
||||||
}
|
|
||||||
|
|
||||||
as := nod(OAS2, nil, nil)
|
|
||||||
as.Rlist.AppendNodes(&n.List)
|
|
||||||
|
|
||||||
// If we're outside of function context, then this call will
|
|
||||||
// be executed during the generated init function. However,
|
|
||||||
// init.go hasn't yet created it. Instead, associate the
|
|
||||||
// temporary variables with dummyInitFn for now, and init.go
|
|
||||||
// will reassociate them later when it's appropriate.
|
|
||||||
static := Curfn == nil
|
|
||||||
if static {
|
|
||||||
Curfn = dummyInitFn
|
|
||||||
}
|
|
||||||
for _, f := range t.FieldSlice() {
|
|
||||||
t := temp(f.Type)
|
|
||||||
as.Ninit.Append(nod(ODCL, t, nil))
|
|
||||||
as.List.Append(t)
|
|
||||||
n.List.Append(t)
|
|
||||||
}
|
|
||||||
if static {
|
|
||||||
Curfn = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
as = typecheck(as, ctxStmt)
|
|
||||||
n.Ninit.Append(as)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
|
func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
|
||||||
t := r.Type
|
t := r.Type
|
||||||
if t == nil {
|
if t == nil {
|
||||||
@ -2373,15 +2396,24 @@ func twoarg(n *Node) bool {
|
|||||||
if n.Left != nil {
|
if n.Left != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if n.List.Len() != 2 {
|
if n.List.Len() == 0 {
|
||||||
if n.List.Len() < 2 {
|
yyerror("missing argument to %v - %v", n.Op, n)
|
||||||
yyerror("not enough arguments in call to %v", n)
|
|
||||||
} else {
|
|
||||||
yyerror("too many arguments in call to %v", n)
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Left = n.List.First()
|
n.Left = n.List.First()
|
||||||
|
if n.List.Len() == 1 {
|
||||||
|
yyerror("missing argument to %v - %v", n.Op, n)
|
||||||
|
n.List.Set(nil)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.List.Len() > 2 {
|
||||||
|
yyerror("too many arguments to %v - %v", n.Op, n)
|
||||||
|
n.List.Set(nil)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
n.Right = n.List.Second()
|
n.Right = n.List.Second()
|
||||||
n.List.Set(nil)
|
n.List.Set(nil)
|
||||||
return true
|
return true
|
||||||
@ -2641,6 +2673,8 @@ func hasddd(t *types.Type) bool {
|
|||||||
// typecheck assignment: type list = expression list
|
// typecheck assignment: type list = expression list
|
||||||
func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
|
func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
|
||||||
var t *types.Type
|
var t *types.Type
|
||||||
|
var n1 int
|
||||||
|
var n2 int
|
||||||
var i int
|
var i int
|
||||||
|
|
||||||
lno := lineno
|
lno := lineno
|
||||||
@ -2653,10 +2687,57 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
|||||||
var n *Node
|
var n *Node
|
||||||
if nl.Len() == 1 {
|
if nl.Len() == 1 {
|
||||||
n = nl.First()
|
n = nl.First()
|
||||||
|
if n.Type != nil && n.Type.IsFuncArgStruct() {
|
||||||
|
if !hasddd(tstruct) {
|
||||||
|
n1 := tstruct.NumFields()
|
||||||
|
n2 := n.Type.NumFields()
|
||||||
|
if n2 > n1 {
|
||||||
|
goto toomany
|
||||||
|
}
|
||||||
|
if n2 < n1 {
|
||||||
|
goto notenough
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs := tstruct.FieldSlice()
|
||||||
|
rfs := n.Type.FieldSlice()
|
||||||
|
var why string
|
||||||
|
for i, tl := range lfs {
|
||||||
|
if tl.IsDDD() {
|
||||||
|
for _, tn := range rfs[i:] {
|
||||||
|
if assignop(tn.Type, tl.Type.Elem(), &why) == 0 {
|
||||||
|
if call != nil {
|
||||||
|
yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
|
||||||
|
} else {
|
||||||
|
yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Elem(), desc(), why)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= len(rfs) {
|
||||||
|
goto notenough
|
||||||
|
}
|
||||||
|
tn := rfs[i]
|
||||||
|
if assignop(tn.Type, tl.Type, &why) == 0 {
|
||||||
|
if call != nil {
|
||||||
|
yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
|
||||||
|
} else {
|
||||||
|
yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rfs) > len(lfs) {
|
||||||
|
goto toomany
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n1 := tstruct.NumFields()
|
n1 = tstruct.NumFields()
|
||||||
n2 := nl.Len()
|
n2 = nl.Len()
|
||||||
if !hasddd(tstruct) {
|
if !hasddd(tstruct) {
|
||||||
if n2 > n1 {
|
if n2 > n1 {
|
||||||
goto toomany
|
goto toomany
|
||||||
@ -2698,7 +2779,6 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mdempsky): Make into ... call with implicit slice.
|
|
||||||
for ; i < nl.Len(); i++ {
|
for ; i < nl.Len(); i++ {
|
||||||
n = nl.Index(i)
|
n = nl.Index(i)
|
||||||
setlineno(n)
|
setlineno(n)
|
||||||
@ -2806,8 +2886,14 @@ func (nl Nodes) retsigerr(isddd bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var typeStrings []string
|
var typeStrings []string
|
||||||
for _, n := range nl.Slice() {
|
if nl.Len() == 1 && nl.First().Type != nil && nl.First().Type.IsFuncArgStruct() {
|
||||||
typeStrings = append(typeStrings, sigrepr(n.Type))
|
for _, f := range nl.First().Type.Fields().Slice() {
|
||||||
|
typeStrings = append(typeStrings, sigrepr(f.Type))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, n := range nl.Slice() {
|
||||||
|
typeStrings = append(typeStrings, sigrepr(n.Type))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ddd := ""
|
ddd := ""
|
||||||
|
@ -49,10 +49,10 @@ func main() {
|
|||||||
_ = complex(f64, F64) // ERROR "complex"
|
_ = complex(f64, F64) // ERROR "complex"
|
||||||
_ = complex(F64, f64) // ERROR "complex"
|
_ = complex(F64, f64) // ERROR "complex"
|
||||||
|
|
||||||
_ = complex(F1()) // ERROR "not enough arguments"
|
_ = complex(F1()) // ERROR "expects two arguments.*returns 1"
|
||||||
_ = complex(F3()) // ERROR "too many arguments"
|
_ = complex(F3()) // ERROR "expects two arguments.*returns 3"
|
||||||
|
|
||||||
_ = complex() // ERROR "not enough arguments"
|
_ = complex() // ERROR "missing argument"
|
||||||
|
|
||||||
c128 = complex(f32, f32) // ERROR "cannot use"
|
c128 = complex(f32, f32) // ERROR "cannot use"
|
||||||
c64 = complex(f64, f64) // ERROR "cannot use"
|
c64 = complex(f64, f64) // ERROR "cannot use"
|
||||||
|
@ -14,7 +14,7 @@ func main() {
|
|||||||
si := make([]int, 8)
|
si := make([]int, 8)
|
||||||
sf := make([]float64, 8)
|
sf := make([]float64, 8)
|
||||||
|
|
||||||
_ = copy() // ERROR "not enough arguments"
|
_ = copy() // ERROR "missing arguments"
|
||||||
_ = copy(1, 2, 3) // ERROR "too many arguments"
|
_ = copy(1, 2, 3) // ERROR "too many arguments"
|
||||||
|
|
||||||
_ = copy(si, "hi") // ERROR "have different element types.*int.*string"
|
_ = copy(si, "hi") // ERROR "have different element types.*int.*string"
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
// run
|
|
||||||
|
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func f(a []byte) ([]byte, []byte) {
|
|
||||||
return a, []byte("abc")
|
|
||||||
}
|
|
||||||
|
|
||||||
func g(a []byte) ([]byte, string) {
|
|
||||||
return a, "abc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func h(m map[int]int) (map[int]int, int) {
|
|
||||||
return m, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
a := []byte{1, 2, 3}
|
|
||||||
n := copy(f(a))
|
|
||||||
fmt.Println(n, a)
|
|
||||||
|
|
||||||
b := []byte{1, 2, 3}
|
|
||||||
n = copy(f(b))
|
|
||||||
fmt.Println(n, b)
|
|
||||||
|
|
||||||
m := map[int]int{0: 0}
|
|
||||||
fmt.Println(len(m))
|
|
||||||
delete(h(m))
|
|
||||||
fmt.Println(len(m))
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
3 [97 98 99]
|
|
||||||
3 [97 98 99]
|
|
||||||
1
|
|
||||||
0
|
|
@ -6,4 +6,4 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant" "not enough arguments"
|
const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant"
|
||||||
|
@ -13,6 +13,6 @@ func f() (_, _ []int) { return }
|
|||||||
func g() (x []int, y float64) { return }
|
func g() (x []int, y float64) { return }
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
_ = append(f()) // ERROR "cannot use \[\]int value as type int in append"
|
_ = append(f()) // ERROR "cannot append \[\]int value to \[\]int"
|
||||||
_ = append(g()) // ERROR "cannot use float64 value as type int in append"
|
_ = append(g()) // ERROR "cannot append float64 value to \[\]int"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user