Skip to content

Commit 8326e67

Browse files
committed
internal/core/adt: allow non-concrete values in builtins
By default, arguments to builtins are checked for concreteness. It will be too much work, not to mention brittle, to change this at this moment, as it would require functions to check the result of the arguments for errors whereas before they did not. Instead, if a function now wants arguments to be able to be non-concrete, it should do so by explicitly setting the NonConcrete flag. It is then subsequently responsible for checking all return arguments. A bit of the non-concrete support is added here, but it will be used and tested in a followup CL. Otherwise, these changes should not result in any test changes. Issue #2741 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I7a61fb93a6976b0b9b9118507ae41acb7fdd2b05 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1199684 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 0a41a20 commit 8326e67

File tree

7 files changed

+80
-24
lines changed

7 files changed

+80
-24
lines changed

internal/core/adt/context.go

+5
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,11 @@ func (c *OpContext) RawElems(v Value) []*Vertex {
11311131
}
11321132

11331133
func (c *OpContext) list(v Value) *Vertex {
1134+
if v != nil {
1135+
if a, ok := c.getDefault(v); ok {
1136+
v = a
1137+
}
1138+
}
11341139
x, ok := v.(*Vertex)
11351140
if !ok || !x.IsList() {
11361141
c.typeError(v, ListKind)

internal/core/adt/expr.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,12 @@ func (x *CallExpr) evaluate(c *OpContext, state combinedFlags) Value {
15201520
cond := state.conditions() | allAncestorsProcessed | concreteKnown
15211521
state = combineMode(cond, runMode).withVertexStatus(state.vertexStatus())
15221522

1523-
expr := c.value(a, state)
1523+
var expr Value
1524+
if b.NonConcrete {
1525+
expr = c.evalState(a, state)
1526+
} else {
1527+
expr = c.value(a, state)
1528+
}
15241529

15251530
switch v := expr.(type) {
15261531
case nil:
@@ -1558,7 +1563,12 @@ type Builtin struct {
15581563
// TODO: make these values for better type checking.
15591564
Params []Param
15601565
Result Kind
1561-
Func func(c *OpContext, args []Value) Expr
1566+
1567+
// NonConcrete should be set to true if a builtin supports non-concrete
1568+
// arguments. By default, all arguments are checked to be concrete.
1569+
NonConcrete bool
1570+
1571+
Func func(c *OpContext, args []Value) Expr
15621572

15631573
Package Feature
15641574
Name string

internal/core/compile/builtin.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var closeBuiltin = &adt.Builtin{
8181
Name: "close",
8282
Params: []adt.Param{structParam},
8383
Result: adt.StructKind,
84+
// Noncrete: true, // TODO: should probably be noncrete
8485
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
8586
s, ok := args[0].(*adt.Vertex)
8687
if !ok {
@@ -98,9 +99,10 @@ var closeBuiltin = &adt.Builtin{
9899
}
99100

100101
var andBuiltin = &adt.Builtin{
101-
Name: "and",
102-
Params: []adt.Param{listParam},
103-
Result: adt.IntKind,
102+
Name: "and",
103+
Params: []adt.Param{listParam},
104+
Result: adt.IntKind,
105+
NonConcrete: true,
104106
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
105107
list := c.RawElems(args[0])
106108
if len(list) == 0 {
@@ -115,9 +117,10 @@ var andBuiltin = &adt.Builtin{
115117
}
116118

117119
var orBuiltin = &adt.Builtin{
118-
Name: "or",
119-
Params: []adt.Param{listParam},
120-
Result: adt.IntKind,
120+
Name: "or",
121+
Params: []adt.Param{listParam},
122+
Result: adt.IntKind,
123+
NonConcrete: true,
121124
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
122125
d := []adt.Disjunct{}
123126
for _, c := range c.RawElems(args[0]) {

internal/pkg/builtin.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ import (
4444
// []T
4545
// map[string]T
4646
type Builtin struct {
47-
Name string
48-
Pkg adt.Feature
49-
Params []Param
50-
Result adt.Kind
51-
Func func(c *CallCtxt)
52-
Const string
47+
Name string
48+
Pkg adt.Feature
49+
Params []Param
50+
Result adt.Kind
51+
NonConcrete bool
52+
Func func(c *CallCtxt)
53+
Const string
5354
}
5455

5556
type Param struct {
@@ -119,10 +120,11 @@ func ToBuiltin(b *Builtin) *adt.Builtin {
119120
}
120121

121122
x := &adt.Builtin{
122-
Params: params,
123-
Result: b.Result,
124-
Package: b.Pkg,
125-
Name: b.Name,
123+
Params: params,
124+
Result: b.Result,
125+
NonConcrete: b.NonConcrete,
126+
Package: b.Pkg,
127+
Name: b.Name,
126128
}
127129
x.Func = func(ctx *adt.OpContext, args []adt.Value) (ret adt.Expr) {
128130
// call, _ := ctx.Source().(*ast.CallExpr)

internal/pkg/context.go

+21-2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,22 @@ func (c *CallCtxt) Do() bool {
4949
return c.Err == nil
5050
}
5151

52+
// Schema returns the ith argument as is, without converting it to a cue.Value.
53+
func (c *CallCtxt) Schema(i int) Schema {
54+
return Schema(value.Make(c.ctx, c.args[i]))
55+
}
56+
57+
// Value returns a finalized cue.Value for the ith argument.
5258
func (c *CallCtxt) Value(i int) cue.Value {
5359
v := value.Make(c.ctx, c.args[i])
54-
// TODO: remove default
55-
// v, _ = v.Default()
60+
if c.builtin.NonConcrete {
61+
// In case NonConcrete is false, the concreteness is already checked
62+
// at call time. We may want to use finalize semantics in both cases,
63+
// though.
64+
_, f := value.ToInternal(v)
65+
f = f.ToDataAll(c.ctx)
66+
v = value.Make(c.ctx, f)
67+
}
5668
if !v.IsConcrete() {
5769
c.errcf(adt.IncompleteError, "non-concrete argument %d", i)
5870
}
@@ -61,6 +73,9 @@ func (c *CallCtxt) Value(i int) cue.Value {
6173

6274
func (c *CallCtxt) Struct(i int) Struct {
6375
x := c.args[i]
76+
if c.builtin.NonConcrete {
77+
x = adt.Default(x)
78+
}
6479
switch v, ok := x.(*adt.Vertex); {
6580
case ok && !v.IsList():
6681
v.CompleteArcs(c.ctx)
@@ -254,6 +269,9 @@ func (c *CallCtxt) Iter(i int) (a cue.Iterator) {
254269

255270
func (c *CallCtxt) getList(i int) *adt.Vertex {
256271
x := c.args[i]
272+
if c.builtin.NonConcrete {
273+
x = adt.Default(x)
274+
}
257275
switch v, ok := x.(*adt.Vertex); {
258276
case ok && v.IsList():
259277
v.Finalize(c.ctx)
@@ -262,6 +280,7 @@ func (c *CallCtxt) getList(i int) *adt.Vertex {
262280
case v != nil:
263281
x = v.Value()
264282
}
283+
265284
if x.Kind()&adt.ListKind == 0 {
266285
var err error
267286
if b, ok := x.(*adt.Bottom); ok {

internal/pkg/types.go

+9
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,18 @@
1515
package pkg
1616

1717
import (
18+
"cuelang.org/go/cue"
1819
"cuelang.org/go/internal/core/adt"
1920
)
2021

22+
// A Schema represents an arbitrary cue.Value that can hold non-concrete values.
23+
// By default function arguments are checked to be concrete.
24+
type Schema cue.Value
25+
26+
func (s Schema) Value() cue.Value {
27+
return cue.Value(s)
28+
}
29+
2130
// List represents a CUE list, which can be open or closed.
2231
type List struct {
2332
runtime adt.Runtime

pkg/gen.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,11 @@ func main() {
123123
}
124124

125125
type generator struct {
126-
dir string
127-
w *bytes.Buffer
128-
cuePkgPath string
129-
first bool
126+
dir string
127+
w *bytes.Buffer
128+
cuePkgPath string
129+
first bool
130+
nonConcrete bool
130131
}
131132

132133
func generate(pkg *packages.Package) error {
@@ -298,6 +299,7 @@ func (g *generator) processGo(pkg *packages.Package) error {
298299
var errorType = types.Universe.Lookup("error").Type()
299300

300301
func (g *generator) genFunc(fn *types.Func) {
302+
g.nonConcrete = false
301303
sign := fn.Type().(*types.Signature)
302304
if sign.Recv() != nil {
303305
return
@@ -334,6 +336,9 @@ func (g *generator) genFunc(fn *types.Func) {
334336
fmt.Fprintf(g.w, "\n},\n")
335337

336338
fmt.Fprintf(g.w, "Result: %s,\n", g.goToCUE(results.At(0).Type()))
339+
if g.nonConcrete {
340+
fmt.Fprintf(g.w, "NonConcrete: true,\n")
341+
}
337342

338343
argList := strings.Join(args, ", ")
339344
valList := strings.Join(vals, ", ")
@@ -378,6 +383,9 @@ func (g *generator) goKind(typ types.Type) string {
378383
return "cueList"
379384
case "cuelang.org/go/internal/pkg.Struct":
380385
return "struct"
386+
case "cuelang.org/go/internal/pkg.Schema":
387+
g.nonConcrete = true
388+
return "schema"
381389
case "[]*github.com/cockroachdb/apd/v3.Decimal":
382390
return "decimalList"
383391
case "cuelang.org/go/cue.Value":

0 commit comments

Comments
 (0)