aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2019-09-06 16:05:36 -0700
committerMatthew Dempsky <mdempsky@google.com>2019-09-09 22:12:15 +0000
commite710a1fb2e36b645b103d9f72d47837171336279 (patch)
tree38f1dd43eb1a8e561e3ae5516c6befbdd54887c3 /src
parent51c8d969bd8a9992002a11373f91564c326e6d77 (diff)
downloadgo-e710a1fb2e36b645b103d9f72d47837171336279.tar.xz
cmd/compile: report more precise errors about untyped constants
Previously, we used a single "untyped number" type for all untyped numeric constants. This led to vague error messages like "string(1.0)" reporting that "1 (type untyped number)" can't be converted to string, even though "string(1)" is valid. This CL makes cmd/compile more like go/types by utilizing types.Ideal{int,rune,float,complex} instead of types.Types[TIDEAL], and keeping n.Type in sync with n.Val().Ctype() during constant folding. Thanks to K Heller for looking into this issue, and for the included test case. Fixes #21979. Change-Id: Ibfea88c05704bc3c0a502a455d018a375589754d Reviewed-on: https://go-review.googlesource.com/c/go/+/194019 Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/gc/bimport.go10
-rw-r--r--src/cmd/compile/internal/gc/const.go36
-rw-r--r--src/cmd/compile/internal/gc/fmt.go18
-rw-r--r--src/cmd/compile/internal/gc/iimport.go2
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go30
-rw-r--r--src/cmd/compile/internal/gc/universe.go9
-rw-r--r--src/cmd/compile/internal/types/identity.go7
-rw-r--r--src/cmd/compile/internal/types/type.go5
8 files changed, 60 insertions, 57 deletions
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 7aabae764e..911ac4c0dc 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -5,7 +5,6 @@
package gc
import (
- "cmd/compile/internal/types"
"cmd/internal/src"
)
@@ -15,15 +14,6 @@ import (
// the same name appears in an error message.
var numImport = make(map[string]int)
-func idealType(typ *types.Type) *types.Type {
- switch typ {
- case types.Idealint, types.Idealrune, types.Idealfloat, types.Idealcomplex:
- // canonicalize ideal types
- typ = types.Types[TIDEAL]
- }
- return typ
-}
-
func npos(pos src.XPos, n *Node) *Node {
n.Pos = pos
return n
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 1cd8488ea1..e40c23b8ef 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -998,6 +998,11 @@ func setconst(n *Node, v Val) {
Xoffset: BADWIDTH,
}
n.SetVal(v)
+ if n.Type.IsUntyped() {
+ // TODO(mdempsky): Make typecheck responsible for setting
+ // the correct untyped type.
+ n.Type = idealType(v.Ctype())
+ }
// Check range.
lno := setlineno(n)
@@ -1030,24 +1035,29 @@ func setintconst(n *Node, v int64) {
func nodlit(v Val) *Node {
n := nod(OLITERAL, nil, nil)
n.SetVal(v)
- switch v.Ctype() {
- default:
- Fatalf("nodlit ctype %d", v.Ctype())
+ n.Type = idealType(v.Ctype())
+ return n
+}
+func idealType(ct Ctype) *types.Type {
+ switch ct {
case CTSTR:
- n.Type = types.Idealstring
-
+ return types.Idealstring
case CTBOOL:
- n.Type = types.Idealbool
-
- case CTINT, CTRUNE, CTFLT, CTCPLX:
- n.Type = types.Types[TIDEAL]
-
+ return types.Idealbool
+ case CTINT:
+ return types.Idealint
+ case CTRUNE:
+ return types.Idealrune
+ case CTFLT:
+ return types.Idealfloat
+ case CTCPLX:
+ return types.Idealcomplex
case CTNIL:
- n.Type = types.Types[TNIL]
+ return types.Types[TNIL]
}
-
- return n
+ Fatalf("unexpected Ctype: %v", ct)
+ return nil
}
// idealkind returns a constant kind like consttype
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 782e4cb840..30b4ebd315 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -686,11 +686,21 @@ func typefmt(t *types.Type, flag FmtFlag, mode fmtMode, depth int) string {
}
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
- name := basicnames[t.Etype]
- if t == types.Idealbool || t == types.Idealstring {
- name = "untyped " + name
+ switch t {
+ case types.Idealbool:
+ return "untyped bool"
+ case types.Idealstring:
+ return "untyped string"
+ case types.Idealint:
+ return "untyped int"
+ case types.Idealrune:
+ return "untyped rune"
+ case types.Idealfloat:
+ return "untyped float"
+ case types.Idealcomplex:
+ return "untyped complex"
}
- return name
+ return basicnames[t.Etype]
}
if mode == FDbg {
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 1d4329b4b1..7d134f3a5f 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -374,8 +374,6 @@ func (p *importReader) value() (typ *types.Type, v Val) {
p.float(&x.Imag, typ)
v.U = x
}
-
- typ = idealType(typ)
return
}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index e4d1cedd74..8518efe73a 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -1407,20 +1407,18 @@ func typecheck1(n *Node, top int) (res *Node) {
}
// Determine result type.
- et := t.Etype
- switch et {
+ switch t.Etype {
case TIDEAL:
- // result is ideal
+ n.Type = types.Idealfloat
case TCOMPLEX64:
- et = TFLOAT32
+ n.Type = types.Types[TFLOAT32]
case TCOMPLEX128:
- et = TFLOAT64
+ n.Type = types.Types[TFLOAT64]
default:
yyerror("invalid argument %L for %v", l, n.Op)
n.Type = nil
return n
}
- n.Type = types.Types[et]
case OCOMPLEX:
ok |= ctxExpr
@@ -1457,7 +1455,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
case TIDEAL:
- t = types.Types[TIDEAL]
+ t = types.Idealcomplex
case TFLOAT32:
t = types.Types[TCOMPLEX64]
@@ -2683,20 +2681,20 @@ func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
// e.g in error messages about wrong arguments to return.
func sigrepr(t *types.Type) string {
switch t {
- default:
- return t.String()
-
- case types.Types[TIDEAL]:
- // "untyped number" is not commonly used
- // outside of the compiler, so let's use "number".
- return "number"
-
case types.Idealstring:
return "string"
-
case types.Idealbool:
return "bool"
}
+
+ if t.Etype == TIDEAL {
+ // "untyped number" is not commonly used
+ // outside of the compiler, so let's use "number".
+ // TODO(mdempsky): Revisit this.
+ return "number"
+ }
+
+ return t.String()
}
// retsigerr returns the signature of the types
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index b8260d6525..2077c5639e 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -334,14 +334,7 @@ func typeinit() {
maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
- // for walk to use in error messages
- types.Types[TFUNC] = functype(nil, nil, nil)
-
- // types used in front end
- // types.Types[TNIL] got set early in lexinit
- types.Types[TIDEAL] = types.New(TIDEAL)
-
- types.Types[TINTER] = types.New(TINTER)
+ types.Types[TINTER] = types.New(TINTER) // empty interface
// simple aliases
simtype[TMAP] = TPTR
diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go
index 7c14a03ba1..a77f514df9 100644
--- a/src/cmd/compile/internal/types/identity.go
+++ b/src/cmd/compile/internal/types/identity.go
@@ -53,6 +53,13 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b
assumedEqual[typePair{t1, t2}] = struct{}{}
switch t1.Etype {
+ case TIDEAL:
+ // Historically, cmd/compile used a single "untyped
+ // number" type, so all untyped number types were
+ // identical. Match this behavior.
+ // TODO(mdempsky): Revisit this.
+ return true
+
case TINTER:
if t1.NumFields() != t2.NumFields() {
return false
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 2fcd6057f3..7b2b79c561 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -57,7 +57,7 @@ const (
TUNSAFEPTR
// pseudo-types for literals
- TIDEAL
+ TIDEAL // untyped numeric constants
TNIL
TBLANK
@@ -94,7 +94,6 @@ const (
// It also stores pointers to several special types:
// - Types[TANY] is the placeholder "any" type recognized by substArgTypes.
// - Types[TBLANK] represents the blank variable's type.
-// - Types[TIDEAL] represents untyped numeric constants.
// - Types[TNIL] represents the predeclared "nil" value's type.
// - Types[TUNSAFEPTR] is package unsafe's Pointer type.
var Types [NTYPE]*Type
@@ -112,8 +111,6 @@ var (
Idealbool *Type
// Types to represent untyped numeric constants.
- // Note: Currently these are only used within the binary export
- // data format. The rest of the compiler only uses Types[TIDEAL].
Idealint = New(TIDEAL)
Idealrune = New(TIDEAL)
Idealfloat = New(TIDEAL)