]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: rewrite untyped constant conversion logic
authorMatthew Dempsky <mdempsky@google.com>
Thu, 5 Sep 2019 20:33:06 +0000 (13:33 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 6 Sep 2019 23:15:48 +0000 (23:15 +0000)
This CL detangles the hairy mess that was convlit+defaultlit. In
particular, it makes the following changes:

1. convlit1 now follows the standard typecheck behavior of setting
"n.Type = nil" if there's an error. Notably, this means for a lot of
test cases, we now avoid reporting useless follow-on error messages.
For example, after reporting that "1 << s + 1.0" has an invalid shift,
we no longer also report that it can't be assigned to string.

2. Previously, assignconvfn had some extra logic for trying to
suppress errors from convlit/defaultlit so that it could provide its
own errors with better context information. Instead, this extra
context information is now passed down into convlit1 directly.

3. Relatedly, this CL also removes redundant calls to defaultlit prior
to assignconv. As a consequence, when an expression doesn't make sense
for a particular assignment (e.g., assigning an untyped string to an
integer), the error messages now say "untyped string" instead of just
"string". This is more consistent with go/types behavior.

4. defaultlit2 is now smarter about only trying to convert pairs of
untyped constants when it's likely to succeed. This allows us to
report better error messages for things like 3+"x"; instead of "cannot
convert 3 to string" we now report "mismatched types untyped number
and untyped string".

Passes toolstash-check.

Change-Id: I26822a02dc35855bd0ac774907b1cf5737e91882
Reviewed-on: https://go-review.googlesource.com/c/go/+/187657
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
13 files changed:
src/cmd/compile/internal/gc/const.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/types/type.go
test/convlit.go
test/ddd1.go
test/fixedbugs/issue17645.go
test/fixedbugs/issue7153.go
test/fixedbugs/issue7310.go
test/fixedbugs/issue8438.go
test/rename1.go
test/shift1.go

index d8e68bf25d4d4a0c7edf350a184910c35f4ae65d..47601ecf5f57ce5e3fee455c465ae3825feb2d3b 100644 (file)
@@ -204,223 +204,207 @@ func trunccmplxlit(oldv *Mpcplx, t *types.Type) *Mpcplx {
        return cv
 }
 
-// canReuseNode indicates whether it is known to be safe
-// to reuse a Node.
-type canReuseNode bool
+// TODO(mdempsky): Replace these with better APIs.
+func convlit(n *Node, t *types.Type) *Node    { return convlit1(n, t, false, nil) }
+func defaultlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil) }
 
-const (
-       noReuse canReuseNode = false // not necessarily safe to reuse
-       reuseOK canReuseNode = true  // safe to reuse
-)
-
-// convert n, if literal, to type t.
-// implicit conversion.
-// The result of convlit MUST be assigned back to n, e.g.
-//     n.Left = convlit(n.Left, t)
-func convlit(n *Node, t *types.Type) *Node {
-       return convlit1(n, t, false, noReuse)
-}
+// convlit1 converts an untyped expression n to type t. If n already
+// has a type, convlit1 has no effect.
+//
+// For explicit conversions, t must be non-nil, and integer-to-string
+// conversions are allowed.
+//
+// For implicit conversions (e.g., assignments), t may be nil; if so,
+// n is converted to its default type.
+//
+// If there's an error converting n to t, context is used in the error
+// message.
+func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Node {
+       if explicit && t == nil {
+               Fatalf("explicit conversion missing type")
+       }
+       if t != nil && t.IsUntyped() {
+               Fatalf("bad conversion to untyped: %v", t)
+       }
 
-// convlit1 converts n, if literal, to type t.
-// It returns a new node if necessary.
-// The result of convlit1 MUST be assigned back to n, e.g.
-//     n.Left = convlit1(n.Left, t, explicit, reuse)
-func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
-       if n == nil || t == nil || n.Type == nil || t.IsUntyped() || n.Type == t {
+       if n == nil || n.Type == nil {
+               // Allow sloppy callers.
                return n
        }
-       if !explicit && !n.Type.IsUntyped() {
+       if !n.Type.IsUntyped() {
+               // Already typed; nothing to do.
                return n
        }
 
-       if n.Op == OLITERAL && !reuse {
+       if n.Op == OLITERAL {
                // Can't always set n.Type directly on OLITERAL nodes.
                // See discussion on CL 20813.
                n = n.rawcopy()
-               reuse = true
        }
 
-       switch n.Op {
-       default:
-               if n.Type == types.Idealbool {
-                       if !t.IsBoolean() {
-                               t = types.Types[TBOOL]
-                       }
-                       switch n.Op {
-                       case ONOT:
-                               n.Left = convlit(n.Left, t)
-                       case OANDAND, OOROR:
-                               n.Left = convlit(n.Left, t)
-                               n.Right = convlit(n.Right, t)
-                       }
-                       n.Type = t
+       // Nil is technically not a constant, so handle it specially.
+       if n.Type.Etype == TNIL {
+               if t == nil {
+                       yyerror("use of untyped nil")
+                       n.SetDiag(true)
+                       n.Type = nil
+                       return n
                }
 
-               if n.Type.IsUntyped() {
-                       if t.IsInterface() {
-                               n.Left, n.Right = defaultlit2(n.Left, n.Right, true)
-                               n.Type = n.Left.Type // same as n.Right.Type per defaultlit2
-                       } else {
-                               n.Left = convlit(n.Left, t)
-                               n.Right = convlit(n.Right, t)
-                               n.Type = t
-                       }
+               if !t.HasNil() {
+                       // Leave for caller to handle.
+                       return n
                }
 
+               n.Type = t
                return n
+       }
 
-       // target is invalid type for a constant? leave alone.
-       case OLITERAL:
-               if !okforconst[t.Etype] && n.Type.Etype != TNIL {
-                       return defaultlitreuse(n, nil, reuse)
-               }
+       if t == nil || !okforconst[t.Etype] {
+               t = defaultType(idealkind(n))
+       }
 
-       case OLSH, ORSH:
-               n.Left = convlit1(n.Left, t, explicit && n.Left.Type.IsUntyped(), noReuse)
-               t = n.Left.Type
-               if t != nil && t.Etype == TIDEAL && n.Val().Ctype() != CTINT {
-                       n.SetVal(toint(n.Val()))
-               }
-               if t != nil && !t.IsInteger() {
-                       yyerror("invalid operation: %v (shift of type %v)", n, t)
-                       t = nil
-               }
+       switch n.Op {
+       default:
+               Fatalf("unexpected untyped expression: %v", n)
 
+       case OLITERAL:
+               v := convertVal(n.Val(), t, explicit)
+               if v.U == nil {
+                       break
+               }
+               n.SetVal(v)
                n.Type = t
                return n
 
-       case OCOMPLEX:
-               if n.Type.Etype == TIDEAL {
-                       switch t.Etype {
-                       default:
-                               // If trying to convert to non-complex type,
-                               // leave as complex128 and let typechecker complain.
-                               t = types.Types[TCOMPLEX128]
-                               fallthrough
-                       case types.TCOMPLEX128:
-                               n.Type = t
-                               n.Left = convlit(n.Left, types.Types[TFLOAT64])
-                               n.Right = convlit(n.Right, types.Types[TFLOAT64])
-
-                       case TCOMPLEX64:
-                               n.Type = t
-                               n.Left = convlit(n.Left, types.Types[TFLOAT32])
-                               n.Right = convlit(n.Right, types.Types[TFLOAT32])
-                       }
+       case OPLUS, ONEG, OBITNOT, ONOT, OREAL, OIMAG:
+               ot := operandType(n.Op, t)
+               if ot == nil {
+                       n = defaultlit(n, nil)
+                       break
                }
 
+               n.Left = convlit(n.Left, ot)
+               if n.Left.Type == nil {
+                       n.Type = nil
+                       return n
+               }
+               n.Type = t
                return n
-       }
-
-       // avoid repeated calculations, errors
-       if types.Identical(n.Type, t) {
-               return n
-       }
 
-       ct := consttype(n)
-       var et types.EType
-       if ct == 0 {
-               goto bad
-       }
+       case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND, OCOMPLEX:
+               ot := operandType(n.Op, t)
+               if ot == nil {
+                       n = defaultlit(n, nil)
+                       break
+               }
 
-       et = t.Etype
-       if et == TINTER {
-               if ct == CTNIL && n.Type == types.Types[TNIL] {
-                       n.Type = t
+               n.Left = convlit(n.Left, ot)
+               n.Right = convlit(n.Right, ot)
+               if n.Left.Type == nil || n.Right.Type == nil {
+                       n.Type = nil
                        return n
                }
-               return defaultlitreuse(n, nil, reuse)
-       }
-
-       switch ct {
-       default:
-               goto bad
-
-       case CTNIL:
-               switch et {
-               default:
+               if !types.Identical(n.Left.Type, n.Right.Type) {
+                       yyerror("invalid operation: %v (mismatched types %v and %v)", n, n.Left.Type, n.Right.Type)
                        n.Type = nil
-                       goto bad
-
-                       // let normal conversion code handle it
-               case TSTRING:
                        return n
+               }
 
-               case TARRAY:
-                       goto bad
+               n.Type = t
+               return n
 
-               case TCHAN, TFUNC, TINTER, TMAP, TPTR, TSLICE, TUNSAFEPTR:
+       case OEQ, ONE, OLT, OLE, OGT, OGE:
+               if !t.IsBoolean() {
                        break
                }
+               n.Type = t
+               return n
 
-       case CTSTR, CTBOOL:
-               if et != n.Type.Etype {
-                       goto bad
-               }
-
-       case CTINT, CTRUNE, CTFLT, CTCPLX:
-               if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
-                       goto bad
+       case OLSH, ORSH:
+               n.Left = convlit1(n.Left, t, explicit, nil)
+               n.Type = n.Left.Type
+               if n.Type != nil && !n.Type.IsInteger() {
+                       yyerror("invalid operation: %v (shift of type %v)", n, n.Type)
+                       n.Type = nil
                }
-               ct := n.Val().Ctype()
-               if isInt[et] {
-                       switch ct {
-                       default:
-                               goto bad
-
-                       case CTCPLX, CTFLT, CTRUNE:
-                               n.SetVal(toint(n.Val()))
-                               fallthrough
-
-                       case CTINT:
-                               overflow(n.Val(), t)
-                       }
-               } else if isFloat[et] {
-                       switch ct {
-                       default:
-                               goto bad
-
-                       case CTCPLX, CTINT, CTRUNE:
-                               n.SetVal(toflt(n.Val()))
-                               fallthrough
-
-                       case CTFLT:
-                               n.SetVal(Val{truncfltlit(n.Val().U.(*Mpflt), t)})
-                       }
-               } else if isComplex[et] {
-                       switch ct {
-                       default:
-                               goto bad
-
-                       case CTFLT, CTINT, CTRUNE:
-                               n.SetVal(tocplx(n.Val()))
-                               fallthrough
+               return n
+       }
 
-                       case CTCPLX:
-                               n.SetVal(Val{trunccmplxlit(n.Val().U.(*Mpcplx), t)})
+       if !n.Diag() {
+               if !t.Broke() {
+                       if explicit {
+                               yyerror("cannot convert %L to type %v", n, t)
+                       } else if context != nil {
+                               yyerror("cannot use %L as type %v in %s", n, t, context())
+                       } else {
+                               yyerror("cannot use %L as type %v", n, t)
                        }
-               } else if et == types.TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
-                       n.SetVal(tostr(n.Val()))
-               } else {
-                       goto bad
                }
+               n.SetDiag(true)
        }
-
-       n.Type = t
+       n.Type = nil
        return n
+}
 
-bad:
-       if !n.Diag() {
-               if !t.Broke() {
-                       yyerror("cannot convert %L to type %v", n, t)
+func operandType(op Op, t *types.Type) *types.Type {
+       switch op {
+       case OCOMPLEX:
+               if t.IsComplex() {
+                       return floatForComplex(t)
+               }
+       case OREAL, OIMAG:
+               if t.IsFloat() {
+                       return complexForFloat(t)
+               }
+       default:
+               if okfor[op][t.Etype] {
+                       return t
                }
-               n.SetDiag(true)
        }
+       return nil
+}
 
-       if n.Type.IsUntyped() {
-               n = defaultlitreuse(n, nil, reuse)
+// convertVal converts v into a representation appropriate for t. If
+// no such representation exists, it returns Val{} instead.
+//
+// If explicit is true, then conversions from integer to string are
+// also allowed.
+func convertVal(v Val, t *types.Type, explicit bool) Val {
+       switch ct := v.Ctype(); ct {
+       case CTBOOL:
+               if t.IsBoolean() {
+                       return v
+               }
+
+       case CTSTR:
+               if t.IsString() {
+                       return v
+               }
+
+       case CTINT, CTRUNE:
+               if explicit && t.IsString() {
+                       return tostr(v)
+               }
+               fallthrough
+       case CTFLT, CTCPLX:
+               switch {
+               case t.IsInteger():
+                       v = toint(v)
+                       overflow(v, t)
+                       return v
+               case t.IsFloat():
+                       v = toflt(v)
+                       v = Val{truncfltlit(v.U.(*Mpflt), t)}
+                       return v
+               case t.IsComplex():
+                       v = tocplx(v)
+                       v = Val{trunccmplxlit(v.U.(*Mpcplx), t)}
+                       return v
+               }
        }
-       return n
+
+       return Val{}
 }
 
 func tocplx(v Val) Val {
@@ -609,8 +593,7 @@ func evconst(n *Node) {
 
        case OCONV:
                if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
-                       // TODO(mdempsky): There should be a convval function.
-                       setconst(n, convlit1(nl, n.Type, true, false).Val())
+                       setconst(n, convertVal(nl.Val(), n.Type, true))
                }
 
        case OCONVNOP:
@@ -1128,102 +1111,6 @@ func idealkind(n *Node) Ctype {
        }
 }
 
-// The result of defaultlit MUST be assigned back to n, e.g.
-//     n.Left = defaultlit(n.Left, t)
-func defaultlit(n *Node, t *types.Type) *Node {
-       return defaultlitreuse(n, t, noReuse)
-}
-
-// The result of defaultlitreuse MUST be assigned back to n, e.g.
-//     n.Left = defaultlitreuse(n.Left, t, reuse)
-func defaultlitreuse(n *Node, t *types.Type, reuse canReuseNode) *Node {
-       if n == nil || !n.Type.IsUntyped() {
-               return n
-       }
-
-       if n.Op == OLITERAL && !reuse {
-               n = n.rawcopy()
-               reuse = true
-       }
-
-       lno := setlineno(n)
-       ctype := idealkind(n)
-       var t1 *types.Type
-       switch ctype {
-       default:
-               if t != nil {
-                       n = convlit(n, t)
-                       lineno = lno
-                       return n
-               }
-
-               switch n.Val().Ctype() {
-               case CTNIL:
-                       lineno = lno
-                       if !n.Diag() {
-                               yyerror("use of untyped nil")
-                               n.SetDiag(true)
-                       }
-
-                       n.Type = nil
-               case CTSTR:
-                       t1 := types.Types[TSTRING]
-                       n = convlit1(n, t1, false, reuse)
-               default:
-                       yyerror("defaultlit: unknown literal: %v", n)
-               }
-               lineno = lno
-               return n
-
-       case CTxxx:
-               Fatalf("defaultlit: idealkind is CTxxx: %+v", n)
-
-       case CTBOOL:
-               t1 := types.Types[TBOOL]
-               if t != nil && t.IsBoolean() {
-                       t1 = t
-               }
-               n = convlit1(n, t1, false, reuse)
-               lineno = lno
-               return n
-
-       case CTINT:
-               t1 = types.Types[TINT]
-       case CTRUNE:
-               t1 = types.Runetype
-       case CTFLT:
-               t1 = types.Types[TFLOAT64]
-       case CTCPLX:
-               t1 = types.Types[TCOMPLEX128]
-       }
-
-       // Note: n.Val().Ctype() can be CTxxx (not a constant) here
-       // in the case of an untyped non-constant value, like 1<<i.
-       v1 := n.Val()
-       if t != nil {
-               if t.IsInteger() {
-                       t1 = t
-                       v1 = toint(n.Val())
-               } else if t.IsFloat() {
-                       t1 = t
-                       v1 = toflt(n.Val())
-               } else if t.IsComplex() {
-                       t1 = t
-                       v1 = tocplx(n.Val())
-               }
-               if n.Val().Ctype() != CTxxx {
-                       n.SetVal(v1)
-               }
-       }
-
-       if n.Val().Ctype() != CTxxx {
-               overflow(n.Val(), t1)
-       }
-       n = convlit1(n, t1, false, reuse)
-       lineno = lno
-       return n
-}
-
 // defaultlit on both nodes simultaneously;
 // if they're both ideal going in they better
 // get the same type going out.
@@ -1248,37 +1135,46 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
                return l, r
        }
 
-       if l.Type.IsBoolean() {
-               l = convlit(l, types.Types[TBOOL])
-               r = convlit(r, types.Types[TBOOL])
-       }
-
-       lkind := idealkind(l)
-       rkind := idealkind(r)
-       if lkind == CTCPLX || rkind == CTCPLX {
-               l = convlit(l, types.Types[TCOMPLEX128])
-               r = convlit(r, types.Types[TCOMPLEX128])
+       // Can't mix bool with non-bool, string with non-string, or nil with anything (untyped).
+       if l.Type.IsBoolean() != r.Type.IsBoolean() {
                return l, r
        }
-
-       if lkind == CTFLT || rkind == CTFLT {
-               l = convlit(l, types.Types[TFLOAT64])
-               r = convlit(r, types.Types[TFLOAT64])
+       if l.Type.IsString() != r.Type.IsString() {
                return l, r
        }
-
-       if lkind == CTRUNE || rkind == CTRUNE {
-               l = convlit(l, types.Runetype)
-               r = convlit(r, types.Runetype)
+       if l.isNil() || r.isNil() {
                return l, r
        }
 
-       l = convlit(l, types.Types[TINT])
-       r = convlit(r, types.Types[TINT])
-
+       k := idealkind(l)
+       if rk := idealkind(r); rk > k {
+               k = rk
+       }
+       t := defaultType(k)
+       l = convlit(l, t)
+       r = convlit(r, t)
        return l, r
 }
 
+func defaultType(k Ctype) *types.Type {
+       switch k {
+       case CTBOOL:
+               return types.Types[TBOOL]
+       case CTSTR:
+               return types.Types[TSTRING]
+       case CTINT:
+               return types.Types[TINT]
+       case CTRUNE:
+               return types.Runetype
+       case CTFLT:
+               return types.Types[TFLOAT64]
+       case CTCPLX:
+               return types.Types[TCOMPLEX128]
+       }
+       Fatalf("bad idealkind: %v", k)
+       return nil
+}
+
 // strlit returns the value of a literal string Node as a string.
 func strlit(n *Node) string {
        return n.Val().U.(string)
index 0706d95937dd9bb281ffe32dee96c0317385fb74..6d70cdbdd0c7a0c778242913ea2cb4ff9e13b199 100644 (file)
@@ -1549,11 +1549,25 @@ func (s *state) ssaOp(op Op, t *types.Type) ssa.Op {
 }
 
 func floatForComplex(t *types.Type) *types.Type {
-       if t.Size() == 8 {
+       switch t.Etype {
+       case TCOMPLEX64:
                return types.Types[TFLOAT32]
-       } else {
+       case TCOMPLEX128:
                return types.Types[TFLOAT64]
        }
+       Fatalf("unexpected type: %v", t)
+       return nil
+}
+
+func complexForFloat(t *types.Type) *types.Type {
+       switch t.Etype {
+       case TFLOAT32:
+               return types.Types[TCOMPLEX64]
+       case TFLOAT64:
+               return types.Types[TCOMPLEX128]
+       }
+       Fatalf("unexpected type: %v", t)
+       return nil
 }
 
 type opAndTwoTypes struct {
index 8c72a5928cdb0c20a3c3c64c6b5b3cfc8972fd19..b4be5dcbfbd65f825bcb27ae722f928e47e3abf7 100644 (file)
@@ -798,11 +798,10 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
                yyerror("use of untyped nil")
        }
 
-       old := n
-       od := old.Diag()
-       old.SetDiag(true) // silence errors about n; we'll issue one below
-       n = defaultlit(n, t)
-       old.SetDiag(od)
+       n = convlit1(n, t, false, context)
+       if n.Type == nil {
+               return n
+       }
        if t.Etype == TBLANK {
                return n
        }
@@ -826,9 +825,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
        var why string
        op := assignop(n.Type, t, &why)
        if op == 0 {
-               if !old.Diag() {
-                       yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
-               }
+               yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
                op = OCONV
        }
 
index a18470ea985951fe8dab3fddd1889b21ae9fcf86..e4d1cedd748604d06d6cc3b5a8f1877f4cabb3af 100644 (file)
@@ -709,7 +709,11 @@ func typecheck1(n *Node, top int) (res *Node) {
 
                if t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) {
                        l, r = defaultlit2(l, r, true)
-                       if r.Type.IsInterface() == l.Type.IsInterface() || aop == 0 {
+                       if l.Type == nil || r.Type == nil {
+                               n.Type = nil
+                               return n
+                       }
+                       if l.Type.IsInterface() == r.Type.IsInterface() || aop == 0 {
                                yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
                                n.Type = nil
                                return n
@@ -1049,10 +1053,7 @@ func typecheck1(n *Node, top int) (res *Node) {
                        }
 
                case TMAP:
-                       n.Right = defaultlit(n.Right, t.Key())
-                       if n.Right.Type != nil {
-                               n.Right = assignconv(n.Right, t.Key(), "map index")
-                       }
+                       n.Right = assignconv(n.Right, t.Key(), "map index")
                        n.Type = t.Elem()
                        n.Op = OINDEXMAP
                        n.ResetAux()
@@ -1104,13 +1105,11 @@ func typecheck1(n *Node, top int) (res *Node) {
                        return n
                }
 
-               n.Right = defaultlit(n.Right, t.Elem())
-               r := n.Right
-               if r.Type == nil {
+               n.Right = assignconv(n.Right, t.Elem(), "send")
+               if n.Right.Type == nil {
                        n.Type = nil
                        return n
                }
-               n.Right = assignconv(r, t.Elem(), "send")
                n.Type = nil
 
        case OSLICEHEADER:
@@ -1638,7 +1637,7 @@ func typecheck1(n *Node, top int) (res *Node) {
                ok |= ctxExpr
                checkwidth(n.Type) // ensure width is calculated for backend
                n.Left = typecheck(n.Left, ctxExpr)
-               n.Left = convlit1(n.Left, n.Type, true, noReuse)
+               n.Left = convlit1(n.Left, n.Type, true, nil)
                t := n.Left.Type
                if t == nil || n.Type == nil {
                        n.Type = nil
@@ -2862,7 +2861,6 @@ func typecheckcomplit(n *Node) (res *Node) {
                        r := *vp
                        pushtype(r, t.Elem())
                        r = typecheck(r, ctxExpr)
-                       r = defaultlit(r, t.Elem())
                        *vp = assignconv(r, t.Elem(), "array or slice literal")
 
                        i++
@@ -2900,14 +2898,12 @@ func typecheckcomplit(n *Node) (res *Node) {
                        r := l.Left
                        pushtype(r, t.Key())
                        r = typecheck(r, ctxExpr)
-                       r = defaultlit(r, t.Key())
                        l.Left = assignconv(r, t.Key(), "map key")
                        cs.add(lineno, l.Left, "key", "map literal")
 
                        r = l.Right
                        pushtype(r, t.Elem())
                        r = typecheck(r, ctxExpr)
-                       r = defaultlit(r, t.Elem())
                        l.Right = assignconv(r, t.Elem(), "map value")
                }
 
index 2c8409b3b350e282d8e93bc2ae18cb8dae8f4654..2fcd6057f3da007fef446fadf939f28fe3e36230 100644 (file)
@@ -1281,6 +1281,15 @@ func (t *Type) IsPtrShaped() bool {
                t.Etype == TMAP || t.Etype == TCHAN || t.Etype == TFUNC
 }
 
+// HasNil reports whether the set of values determined by t includes nil.
+func (t *Type) HasNil() bool {
+       switch t.Etype {
+       case TCHAN, TFUNC, TINTER, TMAP, TPTR, TSLICE, TUNSAFEPTR:
+               return true
+       }
+       return false
+}
+
 func (t *Type) IsString() bool {
        return t.Etype == TSTRING
 }
index 904e1e63b138411c6969d76e7589da2a3bf28121..de760542da46e0119695fdbe3d9ffb203714c7ee 100644 (file)
@@ -28,8 +28,8 @@ var _ = int(unsafe.Pointer(uintptr(65)))     // ERROR "convert"
 // implicit conversions merit scrutiny
 var s string
 var bad1 string = 1  // ERROR "conver|incompatible|invalid|cannot"
-var bad2 = s + 1     // ERROR "conver|incompatible|invalid"
-var bad3 = s + 'a'   // ERROR "conver|incompatible|invalid"
+var bad2 = s + 1     // ERROR "conver|incompatible|invalid|cannot"
+var bad3 = s + 'a'   // ERROR "conver|incompatible|invalid|cannot"
 var bad4 = "a" + 1   // ERROR "literals|incompatible|convert|invalid"
 var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid"
 
index b4ad80b687c15506432e0361b4fce1e1b7797571..b582f221b7509b6b5140e2dff6f10ed8878db5f0 100644 (file)
@@ -18,7 +18,7 @@ var (
        _ = sum()
        _ = sum(1.0, 2.0)
        _ = sum(1.5)      // ERROR "integer"
-       _ = sum("hello")  // ERROR ".hello. .type string. as type int|incompatible"
+       _ = sum("hello")  // ERROR ".hello. .type untyped string. as type int|incompatible"
        _ = sum([]int{1}) // ERROR "\[\]int literal.*as type int|incompatible"
 )
 
index ed92c54cfabb305c446b1f8f18a126db9ce3473c..af785eae2a83c7c4596d0981eebe739041b17637 100644 (file)
@@ -12,6 +12,5 @@ type Foo struct {
 
 func main() {
        var s []int
-       var _ string = append(s, Foo{""})  // ERROR "cannot use .. \(type string\) as type int in field value" "cannot use Foo literal \(type Foo\) as type int in append" "cannot use append\(s\, Foo literal\) \(type \[\]int\) as type string in assignment"
+       var _ string = append(s, Foo{""}) // ERROR "cannot use .. \(type untyped string\) as type int in field value" "cannot use Foo literal \(type Foo\) as type int in append" "cannot use append\(s\, Foo literal\) \(type \[\]int\) as type string in assignment"
 }
-
index f238f78e8451353e686a5f523f67071bf627c8dc..215387732b320a87dd0eac9fd10c390978fd891a 100644 (file)
@@ -8,4 +8,4 @@
 
 package p
 
-var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type bool\) as type int in array or slice literal"
+var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type untyped bool\) as type int in array or slice literal"
index 1169fcfbf0b4b5f1384c8ad55aad6d1f3e7e5919..5ae0f1f5282f1a292988bf4a6b0f00dac248808b 100644 (file)
@@ -11,5 +11,5 @@ package main
 func main() {
        _ = copy(nil, []int{}) // ERROR "use of untyped nil"
        _ = copy([]int{}, nil) // ERROR "use of untyped nil"
-       _ = 1+true // ERROR "cannot convert true" "mismatched types int and bool"
+       _ = 1 + true           // ERROR "mismatched types untyped number and untyped bool"
 }
index b28025cdac47eb90a1fface87e93c265187d0ff5..3a4f193b57df33ee3f73413c70c42fc566bee210 100644 (file)
@@ -10,8 +10,8 @@
 package main
 
 func main() {
-       _ = []byte{"foo"}   // ERROR "cannot convert"
-       _ = []int{"foo"}    // ERROR "cannot convert"
-       _ = []rune{"foo"}   // ERROR "cannot convert"
+       _ = []byte{"foo"}   // ERROR "cannot use"
+       _ = []int{"foo"}    // ERROR "cannot use"
+       _ = []rune{"foo"}   // ERROR "cannot use"
        _ = []string{"foo"} // OK
 }
index 568aa13d441c6f3e87eaefbc1cfffe4dd13de708..c49a70a263d11f064c33323c77a5e7838bf0ce80 100644 (file)
@@ -13,7 +13,7 @@ func main() {
        var n byte         // ERROR "not a type|expected type"
        var y = float32(0) // ERROR "cannot call|expected function"
        const (
-               a = 1 + iota // ERROR "invalid operation|incompatible types" "cannot convert iota"
+               a = 1 + iota // ERROR "invalid operation|incompatible types"
        )
 
 }
index 01ecbed53a0b588e423199233a1b7a9bdc64d1e2..df0c032cd5b6955da86b4cf0aafb88f1e2abf9d2 100644 (file)
@@ -18,13 +18,13 @@ func h(x float64) int     { return 0 }
 var (
        s uint    = 33
        u         = 1.0 << s // ERROR "invalid operation|shift of non-integer operand"
-       v float32 = 1 << s   // ERROR "invalid" "as type float32"
+       v float32 = 1 << s   // ERROR "invalid"
 )
 
 // non-constant shift expressions
 var (
-       e1       = g(2.0 << s) // ERROR "invalid|shift of non-integer operand" "as type interface"
-       f1       = h(2 << s)   // ERROR "invalid" "as type float64"
+       e1       = g(2.0 << s) // ERROR "invalid|shift of non-integer operand"
+       f1       = h(2 << s)   // ERROR "invalid"
        g1 int64 = 1.1 << s    // ERROR "truncated"
 )
 
@@ -66,6 +66,7 @@ func _() {
                u2         = 1<<s != 1.0 // ERROR "non-integer|float64"
                v  float32 = 1 << s      // ERROR "non-integer|float32"
                w  int64   = 1.0 << 33   // 1.0<<33 is a constant shift expression
+
                _, _, _, _, _, _, _, _, _, _ = j, k, m, n, o, u, u1, u2, v, w
        )