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.
// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
func (o *Order) call(n *Node) {
n.Left = o.expr(n.Left, nil)
n.Right = o.expr(n.Right, nil) // ODDDARG temp
- o.exprList(n.List)
+ o.callArgs(&n.List)
if n.Op != OCALLFUNC {
return
o.cleanTemp(t)
case ORETURN:
- o.exprList(n.List)
+ o.callArgs(&n.List)
o.out = append(o.out, n)
// Special: clean case temporaries in each block entry.
n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
} else {
- o.exprList(n.List)
+ o.callArgs(&n.List)
}
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
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
if t == nil {
n.Type = nil
case OCOMPLEX:
ok |= ctxExpr
- typecheckargs(n)
- if !twoarg(n) {
- n.Type = nil
- return n
- }
- 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
+ var r *Node
+ var l *Node
+ if n.List.Len() == 1 {
+ 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
}
- n.Left = l
- n.Right = r
if !types.Identical(l.Type, r.Type) {
yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
ok |= ctxStmt
case ODELETE:
- ok |= ctxStmt
- typecheckargs(n)
args := n.List
if args.Len() == 0 {
yyerror("missing arguments to delete")
return n
}
+ ok |= ctxStmt
+ typecheckslice(args.Slice(), ctxExpr)
l := args.First()
r := args.Second()
if l.Type != nil && !l.Type.IsMap() {
case OAPPEND:
ok |= ctxExpr
- typecheckargs(n)
args := n.List
if args.Len() == 0 {
yyerror("missing arguments to append")
return n
}
+ if args.Len() == 1 && !n.IsDDD() {
+ args.SetFirst(typecheck(args.First(), ctxExpr|ctxMultiOK))
+ } else {
+ typecheckslice(args.Slice(), ctxExpr)
+ }
+
t := args.First().Type
if t == nil {
n.Type = nil
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
if !t.IsSlice() {
if Isconst(args.First(), CTNIL) {
break
}
- as := args.Slice()[1:]
- for i, n := range as {
- if n.Type == nil {
- continue
+ if funarg != nil {
+ for _, t := range funarg.FieldSlice()[1:] {
+ if assignop(t.Type, n.Type.Elem(), nil) == 0 {
+ 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:
ok |= ctxStmt | ctxExpr
- typecheckargs(n)
- if !twoarg(n) {
+ args := n.List
+ if args.Len() < 2 {
+ yyerror("missing arguments to copy")
n.Type = nil
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.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
if n.Left.Type == nil || n.Right.Type == nil {
n.Type = nil
return n
case ORETURN:
ok |= ctxStmt
- typecheckargs(n)
+ if n.List.Len() == 1 {
+ typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK)
+ } else {
+ typecheckslice(n.List.Slice(), ctxExpr)
+ }
if Curfn == nil {
yyerror("return outside function")
n.Type = nil
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 {
t := r.Type
if t == nil {
if n.Left != nil {
return true
}
- if n.List.Len() != 2 {
- if n.List.Len() < 2 {
- yyerror("not enough arguments in call to %v", n)
- } else {
- yyerror("too many arguments in call to %v", n)
- }
+ if n.List.Len() == 0 {
+ yyerror("missing argument to %v - %v", n.Op, n)
return false
}
+
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.List.Set(nil)
return true
// typecheck assignment: type list = expression list
func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
var t *types.Type
+ var n1 int
+ var n2 int
var i int
lno := lineno
var n *Node
if nl.Len() == 1 {
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()
- n2 := nl.Len()
+ n1 = tstruct.NumFields()
+ n2 = nl.Len()
if !hasddd(tstruct) {
if n2 > n1 {
goto toomany
return
}
- // TODO(mdempsky): Make into ... call with implicit slice.
for ; i < nl.Len(); i++ {
n = nl.Index(i)
setlineno(n)
}
var typeStrings []string
- for _, n := range nl.Slice() {
- typeStrings = append(typeStrings, sigrepr(n.Type))
+ if nl.Len() == 1 && nl.First().Type != nil && nl.First().Type.IsFuncArgStruct() {
+ 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 := ""