internal/core/eval: fix interpolation of numbers
Fixes #487
Change-Id: I0a8b0e45cf9d161a8683864764b969d20306fd94
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6948
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/issue315.txt b/cmd/cue/cmd/testdata/script/issue315.txt
index a26a347..7442ffe 100644
--- a/cmd/cue/cmd/testdata/script/issue315.txt
+++ b/cmd/cue/cmd/testdata/script/issue315.txt
@@ -3,7 +3,7 @@
cmp stderr expect-stderr
-- expect-stderr --
-invalid interpolation: incomplete string value 'string':
+invalid interpolation: non-concrete value string (type string):
./file.cue:12:1
-- file.cue --
#X: {
diff --git a/cue/testdata/export/019.txtar b/cue/testdata/export/019.txtar
index ea12d29..eefbf38 100644
--- a/cue/testdata/export/019.txtar
+++ b/cue/testdata/export/019.txtar
@@ -15,16 +15,10 @@
}
}
-- out/eval --
-Errors:
-b: invalid interpolation: cannot use >=0 & <=10 (type number) as type string:
- ./in.cue:1:20
-
-Result:
-(_|_){
- // [eval]
+(struct){
a: (number){ &(>=0, <=10) }
b: (_|_){
- // [eval] b: invalid interpolation: cannot use >=0 & <=10 (type number) as type string:
+ // [incomplete] b: invalid interpolation: non-concrete value >=0 & <=10 (type number):
// ./in.cue:1:20
}
}
diff --git a/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar b/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar
index bcedb40..121daaf 100644
--- a/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar
+++ b/cue/testdata/fulleval/026_dont_convert_incomplete_errors_to_non-incomplete.txtar
@@ -83,7 +83,7 @@
// ./in.cue:11:6
}
s1: (_|_){
- // [incomplete] s1: invalid interpolation: incomplete string value 'string':
+ // [incomplete] s1: invalid interpolation: non-concrete value string (type string):
// ./in.cue:13:5
}
s2: (string){ strings.ContainsAny("dd") }
diff --git a/cue/testdata/interpolation/041_interpolation.txtar b/cue/testdata/interpolation/041_interpolation.txtar
index 06a2adc..f23b618 100644
--- a/cue/testdata/interpolation/041_interpolation.txtar
+++ b/cue/testdata/interpolation/041_interpolation.txtar
@@ -33,7 +33,7 @@
}
-- out/eval --
Errors:
-e: invalid interpolation: cannot use [] (type list) as type string:
+e: invalid interpolation: cannot use [] (type list) as type (string|number):
./in.cue:7:4
Result:
@@ -43,16 +43,16 @@
b: (string){ "one 4 two 4one" }
c: (string){ "one" }
d: (_|_){
- // [incomplete] d: invalid interpolation: incomplete string value '_':
+ // [incomplete] d: invalid interpolation: non-concrete value _ (type _):
// ./in.cue:4:4
}
u: (_|_){
- // [incomplete] u: invalid interpolation: incomplete string value '_':
+ // [incomplete] u: invalid interpolation: non-concrete value _ (type _):
// ./in.cue:5:4
}
r: (_){ _ }
e: (_|_){
- // [eval] e: invalid interpolation: cannot use [] (type list) as type string:
+ // [eval] e: invalid interpolation: cannot use [] (type list) as type (string|number):
// ./in.cue:7:4
}
}
diff --git a/cue/testdata/interpolation/issue487.txtar b/cue/testdata/interpolation/issue487.txtar
new file mode 100644
index 0000000..81a181a
--- /dev/null
+++ b/cue/testdata/interpolation/issue487.txtar
@@ -0,0 +1,66 @@
+-- in.cue --
+t1: {
+ #R: {
+ pos: uint
+ name: "hello_\(pos)"
+ }
+ a: #R & {pos: 67}
+}
+t2: {
+ #R: {
+ pos: string
+ name: "hello_\(pos)"
+ }
+ a: #R & {pos: "a"}
+}
+-- out/eval --
+(struct){
+ t1: (struct){
+ #R: (#struct){
+ pos: (int){ &(>=0, int) }
+ name: (_|_){
+ // [incomplete] t1.#R.name: invalid interpolation: non-concrete value >=0 & int (type int):
+ // ./in.cue:4:9
+ }
+ }
+ a: (#struct){
+ pos: (int){ 67 }
+ name: (string){ "hello_67" }
+ }
+ }
+ t2: (struct){
+ #R: (#struct){
+ pos: (string){ string }
+ name: (_|_){
+ // [incomplete] t2.#R.name: invalid interpolation: non-concrete value string (type string):
+ // ./in.cue:11:9
+ }
+ }
+ a: (#struct){
+ pos: (string){ "a" }
+ name: (string){ "hello_a" }
+ }
+ }
+}
+-- out/compile --
+--- in.cue
+{
+ t1: {
+ #R: {
+ pos: &(int, >=0)
+ name: "hello_\(〈0;pos〉)"
+ }
+ a: (〈0;#R〉 & {
+ pos: 67
+ })
+ }
+ t2: {
+ #R: {
+ pos: string
+ name: "hello_\(〈0;pos〉)"
+ }
+ a: (〈0;#R〉 & {
+ pos: "a"
+ })
+ }
+}
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index 1a26c5c..db385b8 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -738,11 +738,29 @@
return c.stringValue(v, nil)
}
+// ToString returns the string value of a numeric or string value.
+func (c *OpContext) ToString(v Value) string {
+ return c.toStringValue(v, StringKind|NumKind, nil)
+
+}
+
func (c *OpContext) stringValue(v Value, as interface{}) string {
+ return c.toStringValue(v, StringKind, as)
+}
+
+func (c *OpContext) toStringValue(v Value, k Kind, as interface{}) string {
v = Unwrap(v)
if isError(v) {
return ""
}
+ if v.Kind()&k == 0 {
+ if as == nil {
+ c.typeError(v, k)
+ } else {
+ c.typeErrorAs(v, k, as)
+ }
+ return ""
+ }
switch x := v.(type) {
case *String:
return x.Str
@@ -754,11 +772,8 @@
return x.X.String()
default:
- if as == nil {
- c.typeError(v, StringKind)
- } else {
- c.typeErrorAs(v, StringKind, as)
- }
+ c.addErrf(IncompleteError, c.pos(),
+ "non-concrete value %s (type %s)", c.Str(v), v.Kind())
}
return ""
}
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index ece0f98..82df806 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -717,7 +717,7 @@
buf := bytes.Buffer{}
for _, e := range x.Parts {
v := c.value(e)
- s := c.StringValue(v)
+ s := c.ToString(v)
buf.WriteString(s)
}
if err := c.Err(); err != nil {