aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/gc/const.go470
-rw-r--r--src/cmd/compile/internal/gc/ssa.go18
-rw-r--r--src/cmd/compile/internal/gc/subr.go13
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go22
-rw-r--r--src/cmd/compile/internal/types/type.go9
5 files changed, 222 insertions, 310 deletions
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index d8e68bf25d..47601ecf5f 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -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
+ }
+
+ if t == nil || !okforconst[t.Etype] {
+ t = defaultType(idealkind(n))
+ }
+
+ switch n.Op {
+ default:
+ Fatalf("unexpected untyped expression: %v", 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)
+ v := convertVal(n.Val(), t, explicit)
+ if v.U == nil {
+ break
}
+ n.SetVal(v)
+ n.Type = t
+ return 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
+ 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
- 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 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
+ }
- case TCOMPLEX64:
- n.Type = t
- n.Left = convlit(n.Left, types.Types[TFLOAT32])
- n.Right = convlit(n.Right, types.Types[TFLOAT32])
- }
+ 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
+ }
+ 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
+ return n
}
+ n.Type = t
return n
- }
- // avoid repeated calculations, errors
- if types.Identical(n.Type, t) {
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ if !t.IsBoolean() {
+ break
+ }
+ n.Type = t
return n
- }
- ct := consttype(n)
- var et types.EType
- if ct == 0 {
- 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
+ }
+ return n
}
- et = t.Etype
- if et == TINTER {
- if ct == CTNIL && n.Type == types.Types[TNIL] {
- n.Type = t
- return n
+ 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)
+ }
}
- return defaultlitreuse(n, nil, reuse)
+ n.SetDiag(true)
}
+ n.Type = nil
+ return n
+}
- switch ct {
+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:
- goto bad
-
- case CTNIL:
- switch et {
- default:
- n.Type = nil
- goto bad
-
- // let normal conversion code handle it
- case TSTRING:
- return n
-
- case TARRAY:
- goto bad
-
- case TCHAN, TFUNC, TINTER, TMAP, TPTR, TSLICE, TUNSAFEPTR:
- break
+ if okfor[op][t.Etype] {
+ return t
}
+ }
+ return nil
+}
- case CTSTR, CTBOOL:
- if et != n.Type.Etype {
- goto bad
+// 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 CTINT, CTRUNE, CTFLT, CTCPLX:
- if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
- goto bad
+ case CTSTR:
+ if t.IsString() {
+ return v
}
- 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
-
- case CTCPLX:
- n.SetVal(Val{trunccmplxlit(n.Val().U.(*Mpcplx), t)})
- }
- } else if et == types.TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
- n.SetVal(tostr(n.Val()))
- } else {
- goto bad
+ case CTINT, CTRUNE:
+ if explicit && t.IsString() {
+ return tostr(v)
}
- }
-
- n.Type = t
- return n
-
-bad:
- if !n.Diag() {
- if !t.Broke() {
- yyerror("cannot convert %L to type %v", n, t)
+ 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
}
- n.SetDiag(true)
}
- if n.Type.IsUntyped() {
- n = defaultlitreuse(n, nil, reuse)
- }
- 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)
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 0706d95937..6d70cdbdd0 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -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 {
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 8c72a5928c..b4be5dcbfb 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -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
}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index a18470ea98..e4d1cedd74 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -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")
}
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 2c8409b3b3..2fcd6057f3 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -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
}