Skip to content

Commit 37bf801

Browse files
mpvlmyitcv
authored andcommitted
cue: keep sane references for embedded disjunctions in Expr
In Expr, simulate a struct with just the fields so that embedded disjunctions with references to such fields will direct to the unmerged values of these references. This also addes OpenAPI tests, which relies on this functionality. Change-Id: I5d127fee1389a88a45f3705ad1a0c929ee1c2bb0 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9881 Reviewed-by: Paul Jolly <[email protected]>
1 parent b39a2d0 commit 37bf801

File tree

6 files changed

+268
-18
lines changed

6 files changed

+268
-18
lines changed

cue/types.go

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,38 +2383,34 @@ func (v Value) Expr() (Op, []Value) {
23832383
op = CallOp
23842384

23852385
case *adt.StructLit:
2386-
// Simulate old embeddings.
2387-
envEmbed := &adt.Environment{
2388-
Up: env,
2389-
Vertex: v.v,
2390-
}
2386+
hasEmbed := false
23912387
fields := []adt.Decl{}
2392-
ctx := v.ctx()
23932388
for _, d := range x.Decls {
2394-
switch x := d.(type) {
2389+
switch d.(type) {
23952390
default:
23962391
fields = append(fields, d)
23972392
case adt.Value:
23982393
fields = append(fields, d)
23992394
case adt.Expr:
2400-
// embedding
2401-
n := &adt.Vertex{Label: v.v.Label}
2402-
c := adt.MakeRootConjunct(envEmbed, x)
2403-
n.AddConjunct(c)
2404-
n.Finalize(ctx)
2405-
n.Parent = v.v.Parent
2406-
a = append(a, makeValue(v.idx, n, v.parent_))
2395+
hasEmbed = true
24072396
}
24082397
}
2409-
if len(a) == 0 {
2398+
2399+
if !hasEmbed {
24102400
a = append(a, v)
24112401
break
24122402
}
24132403

2404+
ctx := v.ctx()
2405+
2406+
n := v.v
2407+
24142408
if len(fields) > 0 {
2415-
n := &adt.Vertex{
2416-
Label: v.v.Label,
2409+
n = &adt.Vertex{
2410+
Parent: v.v.Parent,
2411+
Label: v.v.Label,
24172412
}
2413+
24182414
s := &adt.StructLit{}
24192415
if k := v.v.Kind(); k != adt.StructKind && k != BottomKind {
24202416
// TODO: we should also add such a declaration for embeddings
@@ -2428,10 +2424,36 @@ func (v Value) Expr() (Op, []Value) {
24282424
n.AddConjunct(c)
24292425
n.Finalize(ctx)
24302426
n.Parent = v.v.Parent
2427+
}
2428+
2429+
// Simulate old embeddings.
2430+
envEmbed := &adt.Environment{
2431+
Up: env,
2432+
Vertex: n,
2433+
}
2434+
2435+
for _, d := range x.Decls {
2436+
switch x := d.(type) {
2437+
case adt.Value:
2438+
case adt.Expr:
2439+
// embedding
2440+
n := &adt.Vertex{Label: v.v.Label}
2441+
c := adt.MakeRootConjunct(envEmbed, x)
2442+
n.AddConjunct(c)
2443+
n.Finalize(ctx)
2444+
n.Parent = v.v.Parent
2445+
a = append(a, makeValue(v.idx, n, v.parent_))
2446+
}
2447+
}
2448+
2449+
// Could be done earlier, but keep struct with fields at end.
2450+
if len(fields) > 0 {
24312451
a = append(a, makeValue(v.idx, n, v.parent_))
24322452
}
24332453

2434-
op = adt.AndOp
2454+
if len(a) > 1 {
2455+
op = adt.AndOp
2456+
}
24352457

24362458
default:
24372459
a = append(a, v)

cue/types_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,6 +3343,9 @@ func TestExpr(t *testing.T) {
33433343
// Don't split of concrete values.
33443344
input: `v: { "foo", #def: 1 }`,
33453345
want: `{"foo",#def:1}`,
3346+
}, {
3347+
input: `v: { {} | { a: #A, b: #B}, #A: {} | { c: int} }, #B: int | bool`,
3348+
want: `&(|({} {a:#A,b:#B}) {#A:({}|{c:int})})`,
33463349
}, {
33473350
input: `v: { {c: a}, b: a }, a: int`,
33483351
want: `&({c:a} {b:a})`,

encoding/openapi/openapi_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ func TestParseDefinitions(t *testing.T) {
104104
in: "openapi.cue",
105105
out: "openapi-norefs.json",
106106
config: resolveRefs,
107+
}, {
108+
in: "embed.cue",
109+
out: "embed.json",
110+
config: defaultConfig,
111+
}, {
112+
in: "embed.cue",
113+
out: "embed-norefs.json",
114+
config: resolveRefs,
107115
}, {
108116
in: "oneof.cue",
109117
out: "oneof-funcs.json",
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
{
2+
"openapi": "3.0.0",
3+
"info": {
4+
"title": "test",
5+
"version": "v1"
6+
},
7+
"paths": {},
8+
"components": {
9+
"schemas": {
10+
"Foo": {
11+
"type": "string"
12+
},
13+
"LoadBalancerSettings": {
14+
"type": "object",
15+
"properties": {
16+
"consistentHash": {
17+
"type": "object",
18+
"properties": {
19+
"httpHeaderName": {
20+
"type": "string"
21+
}
22+
}
23+
},
24+
"b": {
25+
"type": "string"
26+
}
27+
},
28+
"oneOf": [
29+
{
30+
"not": {
31+
"anyOf": [
32+
{
33+
"required": [
34+
"consistentHash",
35+
"b"
36+
],
37+
"properties": {
38+
"consistentHash": {
39+
"oneOf": [
40+
{
41+
"not": {
42+
"anyOf": [
43+
{
44+
"required": [
45+
"httpHeaderName"
46+
]
47+
}
48+
]
49+
}
50+
},
51+
{
52+
"required": [
53+
"httpHeaderName"
54+
]
55+
}
56+
]
57+
}
58+
}
59+
}
60+
]
61+
}
62+
},
63+
{
64+
"required": [
65+
"consistentHash",
66+
"b"
67+
],
68+
"properties": {
69+
"consistentHash": {
70+
"oneOf": [
71+
{
72+
"not": {
73+
"anyOf": [
74+
{
75+
"required": [
76+
"httpHeaderName"
77+
]
78+
}
79+
]
80+
}
81+
},
82+
{
83+
"required": [
84+
"httpHeaderName"
85+
]
86+
}
87+
]
88+
}
89+
}
90+
}
91+
]
92+
},
93+
"LoadBalancerSettings.ConsistentHashLB": {
94+
"type": "object",
95+
"properties": {
96+
"httpHeaderName": {
97+
"type": "string"
98+
}
99+
},
100+
"oneOf": [
101+
{
102+
"not": {
103+
"anyOf": [
104+
{
105+
"required": [
106+
"httpHeaderName"
107+
]
108+
}
109+
]
110+
}
111+
},
112+
{
113+
"required": [
114+
"httpHeaderName"
115+
]
116+
}
117+
]
118+
}
119+
}
120+
}
121+
}

encoding/openapi/testdata/embed.cue

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#Foo: string
2+
3+
#LoadBalancerSettings: {
4+
{} | {
5+
consistentHash: #ConsistentHashLB
6+
b: #Foo
7+
}
8+
#ConsistentHashLB: {} | {
9+
httpHeaderName: string
10+
}
11+
}

encoding/openapi/testdata/embed.json

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"openapi": "3.0.0",
3+
"info": {
4+
"title": "Generated by cue.",
5+
"version": "no version"
6+
},
7+
"paths": {},
8+
"components": {
9+
"schemas": {
10+
"Foo": {
11+
"type": "string"
12+
},
13+
"LoadBalancerSettings": {
14+
"type": "object",
15+
"oneOf": [
16+
{
17+
"not": {
18+
"anyOf": [
19+
{
20+
"required": [
21+
"consistentHash",
22+
"b"
23+
],
24+
"properties": {
25+
"consistentHash": {
26+
"$ref": "#/components/schemas/LoadBalancerSettings.ConsistentHashLB"
27+
},
28+
"b": {
29+
"$ref": "#/components/schemas/Foo"
30+
}
31+
}
32+
}
33+
]
34+
}
35+
},
36+
{
37+
"required": [
38+
"consistentHash",
39+
"b"
40+
],
41+
"properties": {
42+
"consistentHash": {
43+
"$ref": "#/components/schemas/LoadBalancerSettings.ConsistentHashLB"
44+
},
45+
"b": {
46+
"$ref": "#/components/schemas/Foo"
47+
}
48+
}
49+
}
50+
]
51+
},
52+
"LoadBalancerSettings.ConsistentHashLB": {
53+
"type": "object",
54+
"oneOf": [
55+
{
56+
"not": {
57+
"anyOf": [
58+
{
59+
"required": [
60+
"httpHeaderName"
61+
],
62+
"properties": {
63+
"httpHeaderName": {
64+
"type": "string"
65+
}
66+
}
67+
}
68+
]
69+
}
70+
},
71+
{
72+
"required": [
73+
"httpHeaderName"
74+
],
75+
"properties": {
76+
"httpHeaderName": {
77+
"type": "string"
78+
}
79+
}
80+
}
81+
]
82+
}
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)