Skip to content

Commit c62b750

Browse files
committed
internal/core/export: bug fixes in definitions
- don't print `_` when not appropriate. - print constraint information when appropriate Fixes #882 Change-Id: I474ddf4448b3b7c0ec795688730e9e9b581163dd Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9485 Reviewed-by: CUE cueckoo <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent b5b0429 commit c62b750

File tree

3 files changed

+99
-55
lines changed

3 files changed

+99
-55
lines changed

internal/core/export/export_test.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ func formatNode(t *testing.T, n ast.Node) []byte {
7777
// TestGenerated tests conversions of generated Go structs, which may be
7878
// different from parsed or evaluated CUE, such as having Vertex values.
7979
func TestGenerated(t *testing.T) {
80+
ctx := cuecontext.New()
81+
8082
testCases := []struct {
8183
in func(ctx *adt.OpContext) (adt.Expr, error)
8284
out string
@@ -88,7 +90,7 @@ func TestGenerated(t *testing.T) {
8890
}
8991
return convert.GoValueToValue(ctx, in, false), nil
9092
},
91-
out: `{Terminals: [{Name: "Name", Description: "Desc"}]}`,
93+
out: `Terminals: [{Name: "Name", Description: "Desc"}]`,
9294
}, {
9395
in: func(ctx *adt.OpContext) (adt.Expr, error) {
9496
in := &C{
@@ -134,13 +136,11 @@ func TestGenerated(t *testing.T) {
134136

135137
return n, nil
136138
},
137-
// TODO: should probably print path.
138-
out: `<[l2// undefined field #Terminal] _|_>`,
139+
out: `<[l2// x: undefined field #Terminal] _|_>`,
139140
p: export.Final,
140141
}, {
141-
in: func(ctx *adt.OpContext) (adt.Expr, error) {
142-
c := cuecontext.New()
143-
v := c.CompileString(`
142+
in: func(r *adt.OpContext) (adt.Expr, error) {
143+
v := ctx.CompileString(`
144144
#Provider: {
145145
ID: string
146146
notConcrete: bool
@@ -155,12 +155,28 @@ func TestGenerated(t *testing.T) {
155155

156156
return n, nil
157157
},
158-
out: `{#Provider: {ID: string, notConcrete: bool, a: int, b: a+1}, providers: {foo: {ID: "12345", notConcrete: bool, a: int, b: a+1}}}`,
158+
out: `#Provider: {ID: string, notConcrete: bool, a: int, b: a+1}, providers: {foo: {ID: "12345", notConcrete: bool, a: int, b: a+1}}`,
159+
}, {
160+
// Issue #882
161+
in: func(r *adt.OpContext) (adt.Expr, error) {
162+
valA := ctx.CompileString(`
163+
#One: { version: string }
164+
`)
165+
166+
valB := ctx.CompileString(`
167+
#One: _
168+
ones: {[string]: #One}
169+
`)
170+
v := valB.Unify(valA)
171+
_, n := value.ToInternal(v)
172+
return n, nil
173+
},
174+
out: `#One: {version: string}, ones: {[string]: #One}`,
175+
p: export.All,
159176
}}
160177
for _, tc := range testCases {
161178
t.Run("", func(t *testing.T) {
162-
r := runtime.New()
163-
ctx := adt.NewContext(r, &adt.Vertex{})
179+
ctx := adt.NewContext((*runtime.Runtime)(ctx), &adt.Vertex{})
164180

165181
v, err := tc.in(ctx)
166182
if err != nil {
@@ -172,11 +188,17 @@ func TestGenerated(t *testing.T) {
172188
p = export.Simplified
173189
}
174190

175-
expr, err := p.Expr(ctx, "", v)
191+
var n ast.Node
192+
switch x := v.(type) {
193+
case *adt.Vertex:
194+
n, err = p.Def(ctx, "", x)
195+
default:
196+
n, err = p.Expr(ctx, "", v)
197+
}
176198
if err != nil {
177199
t.Fatal("failed export: ", err)
178200
}
179-
got := astinternal.DebugStr(expr)
201+
got := astinternal.DebugStr(n)
180202
if got != tc.out {
181203
t.Errorf("got: %s\nwant: %s", got, tc.out)
182204
}

internal/core/export/expr.go

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,16 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct,
9797
for _, c := range a {
9898
e.top().upCount = c.up
9999
x := c.c.Expr()
100-
e.addExpr(c.c.Env, x, false)
100+
e.addExpr(c.c.Env, src, x, false)
101+
}
102+
103+
if src != nil {
104+
for _, a := range src.Arcs {
105+
if x, ok := e.fields[a.Label]; ok {
106+
x.arc = a
107+
e.fields[a.Label] = x
108+
}
109+
}
101110
}
102111

103112
s := x.top().scope
@@ -107,9 +116,9 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct,
107116
}
108117

109118
// Unify values only for one level.
110-
if len(e.values.Conjuncts) > 0 {
119+
if a := e.values.Conjuncts; len(a) > 0 {
111120
e.values.Finalize(e.ctx)
112-
e.embed = append(e.embed, e.value(e.values, e.values.Conjuncts...))
121+
e.embed = append(e.embed, e.value(e.values, a...))
113122
}
114123

115124
// Collect and order set of fields.
@@ -196,7 +205,7 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct,
196205
top.fields[f] = fr
197206
}
198207

199-
d.Value = e.mergeValues(f, nil, c, a...)
208+
d.Value = e.mergeValues(f, field.arc, c, a...)
200209

201210
if f.IsDef() {
202211
x.inDefinition--
@@ -218,10 +227,13 @@ func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct,
218227
}
219228
if e.hasEllipsis {
220229
s.Elts = append(s.Elts, &ast.Ellipsis{})
221-
} else if src != nil && src.IsClosedStruct() && e.inDefinition == 0 {
222-
return ast.NewCall(ast.NewIdent("close"), s)
223230
}
224231

232+
// TODO: why was this necessary?
233+
// else if src != nil && src.IsClosedStruct() && e.inDefinition == 0 {
234+
// return ast.NewCall(ast.NewIdent("close"), s)
235+
// }
236+
225237
e.conjuncts = append(e.conjuncts, s)
226238

227239
return ast.NewBinExpr(token.AND, e.conjuncts...)
@@ -240,8 +252,16 @@ type conjuncts struct {
240252
hasEllipsis bool
241253
}
242254

243-
func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) {
255+
func (c *conjuncts) addValueConjunct(src *adt.Vertex, env *adt.Environment, x adt.Expr) {
256+
switch b, ok := x.(adt.BaseValue); {
257+
case ok && src != nil && isTop(b) && !isTop(src.BaseValue):
258+
// drop top
259+
default:
260+
c.values.AddConjunct(adt.MakeRootConjunct(env, x))
261+
}
262+
}
244263

264+
func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) {
245265
x := c.fields[f]
246266
v := adt.MakeRootConjunct(env, n)
247267
x.conjuncts = append(x.conjuncts, conjunct{
@@ -254,6 +274,7 @@ func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node)
254274

255275
type field struct {
256276
docs []*ast.CommentGroup
277+
arc *adt.Vertex
257278
conjuncts []conjunct
258279
}
259280

@@ -262,7 +283,7 @@ type conjunct struct {
262283
up int32
263284
}
264285

265-
func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr, isEmbed bool) {
286+
func (e *conjuncts) addExpr(env *adt.Environment, src *adt.Vertex, x adt.Expr, isEmbed bool) {
266287
switch x := x.(type) {
267288
case *adt.StructLit:
268289
e.top().upCount++
@@ -294,7 +315,7 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr, isEmbed bool) {
294315
e.hasEllipsis = true
295316
continue
296317
case adt.Expr:
297-
e.addExpr(env, f, true)
318+
e.addExpr(env, nil, f, true)
298319
continue
299320

300321
// TODO: also handle dynamic fields
@@ -309,54 +330,44 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr, isEmbed bool) {
309330
switch v := x.(type) {
310331
case nil:
311332
default:
312-
e.values.AddConjunct(adt.MakeRootConjunct(env, x)) // GOBBLE TOP
333+
e.addValueConjunct(src, env, x)
313334

314335
case *adt.Vertex:
315-
e.structs = append(e.structs, v.Structs...)
316-
317-
switch y := v.BaseValue.(type) {
318-
case *adt.ListMarker:
319-
a := []ast.Expr{}
320-
for _, x := range v.Elems() {
321-
a = append(a, e.expr(x))
336+
if b, ok := v.BaseValue.(*adt.Bottom); ok {
337+
if !b.IsIncomplete() || e.cfg.Final {
338+
e.addExpr(env, v, b, false)
339+
return
322340
}
323-
if !v.IsClosedList() {
324-
v := &adt.Vertex{}
325-
v.MatchAndInsert(e.ctx, v)
326-
a = append(a, &ast.Ellipsis{Type: e.expr(v)})
341+
}
342+
343+
switch {
344+
default:
345+
for _, c := range v.Conjuncts {
346+
e.addExpr(c.Env, v, c.Expr(), false)
327347
}
328-
e.embed = append(e.embed, ast.NewList(a...))
329-
return
330348

331-
case *adt.StructMarker:
332-
x = nil
349+
case v.IsData():
350+
e.structs = append(e.structs, v.Structs...)
333351

334-
case adt.Value:
335-
if v.IsData() {
336-
e.values.AddConjunct(adt.MakeRootConjunct(env, y))
337-
break
338-
}
339-
for _, c := range v.Conjuncts {
340-
e.values.AddConjunct(c)
352+
if y, ok := v.BaseValue.(adt.Value); ok {
353+
e.addValueConjunct(src, env, y)
341354
}
342-
}
343355

344-
// generated, only consider arcs.
345-
for _, a := range v.Arcs {
346-
a.Finalize(e.ctx) // TODO: should we do this?
356+
for _, a := range v.Arcs {
357+
a.Finalize(e.ctx) // TODO: should we do this?
347358

348-
e.addConjunct(a.Label, env, a)
359+
e.addConjunct(a.Label, env, a)
360+
}
349361
}
350-
// e.exprs = append(e.exprs, e.value(v, v.Conjuncts...))
351362
}
352363

353364
case *adt.BinaryExpr:
354365
switch {
355366
case x.Op == adt.AndOp && !isEmbed:
356-
e.addExpr(env, x.X, false)
357-
e.addExpr(env, x.Y, false)
367+
e.addExpr(env, src, x.X, false)
368+
e.addExpr(env, src, x.Y, false)
358369
case isSelfContained(x):
359-
e.values.AddConjunct(adt.MakeRootConjunct(env, x))
370+
e.addValueConjunct(src, env, x)
360371
default:
361372
if isEmbed {
362373
e.embed = append(e.embed, e.expr(x))
@@ -368,7 +379,7 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr, isEmbed bool) {
368379
default:
369380
switch {
370381
case isSelfContained(x):
371-
e.values.AddConjunct(adt.MakeRootConjunct(env, x))
382+
e.addValueConjunct(src, env, x)
372383
case isEmbed:
373384
e.embed = append(e.embed, e.expr(x))
374385
default:
@@ -377,6 +388,17 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr, isEmbed bool) {
377388
}
378389
}
379390

391+
func isTop(x adt.BaseValue) bool {
392+
switch v := x.(type) {
393+
case *adt.Top:
394+
return true
395+
case *adt.BasicType:
396+
return v.K == adt.TopKind
397+
default:
398+
return false
399+
}
400+
}
401+
380402
// TODO: find a better way to annotate optionality. Maybe a special conjunct
381403
// or store it in the field information?
382404
func isOptional(a []adt.Conjunct) bool {

internal/filetypes/types.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)