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.callArgs(&n.List)
+ o.exprList(n.List)
if n.Op != OCALLFUNC {
return
o.cleanTemp(t)
case ORETURN:
- o.callArgs(&n.List)
+ o.exprList(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.callArgs(&n.List)
+ o.exprList(n.List)
}
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
return n
}
- if n.List.Len() == 1 && !n.IsDDD() {
- n.List.SetFirst(typecheck(n.List.First(), ctxExpr|ctxMultiOK))
- } else {
- typecheckslice(n.List.Slice(), ctxExpr)
- }
+ typecheckargs(n)
t := l.Type
if t == nil {
n.Type = nil
case OCOMPLEX:
ok |= ctxExpr
- 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
+ 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
+ }
+ 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
}
- 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 := 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
}
case OCOPY:
ok |= ctxStmt | ctxExpr
- args := n.List
- if args.Len() < 2 {
- yyerror("missing arguments to copy")
+ typecheckargs(n)
+ if !twoarg(n) {
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
- if n.List.Len() == 1 {
- typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK)
- } else {
- typecheckslice(n.List.Slice(), ctxExpr)
- }
+ typecheckargs(n)
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() == 0 {
- yyerror("missing argument to %v - %v", n.Op, n)
+ 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)
+ }
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
- 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))
- }
+ for _, n := range nl.Slice() {
+ typeStrings = append(typeStrings, sigrepr(n.Type))
}
ddd := ""