Skip to content

Commit 2b55328

Browse files
committedNov 28, 2024·
internal/core/adt: add compatibility mode for issue 3534
The OpenInline compatibility mode was previously added to allow ignoring closedness errors when selecting into an inline struct. V2, however, in addition to allowing such errors, would also recursively open up definitions. This change simulates that behavior when OpenInline is enabled by treating the result of selecting into an inline struct as an embedding. Note that this is an orthogonal construct to the one previously introduced with OpenInline. Because they are highly related, however, we will enabled them under the same option. Note that the introduced mechanism also opens up calls to close. This was not the case in V2. This will hopefully not cause any issues in the transition and, given that this is a temporary measure, also not cause issues down the line. Fixes #3534 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I256fcdc7dd7c1b859cafa566b2bf396de9539f09 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1204736 Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 9b8a10c commit 2b55328

File tree

4 files changed

+71
-150
lines changed

4 files changed

+71
-150
lines changed
 

‎cue/testdata/eval/openinline.txtar

+52-148
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ Conjuncts: 141
8888
Disjuncts: 107
8989
-- out/evalalpha --
9090
Errors:
91-
outerErr.extraNesting.t1.version.x.major: field not allowed:
92-
./in.cue:46:25
93-
outerErr.issue3534.t1.version.major: field not allowed:
94-
./in.cue:19:8
95-
./in.cue:25:22
96-
outerErr.usingClose.t1.version.major: field not allowed:
97-
./in.cue:34:17
98-
./in.cue:35:22
9991
#E.b: field not allowed:
10092
./in.cue:57:14
10193
./cue.mod/pkg/foo.com/example/example.cue:4:11
@@ -114,17 +106,15 @@ Result:
114106
x: (int){ 2 }
115107
}
116108
}
117-
outerErr: (_|_){
118-
// [eval]
109+
outerErr: (struct){
119110
_inToOut: (struct){
120111
in: (_){ _ }
121112
out: (_|_){
122113
// [incomplete] outerErr._inToOut.out: in.foo undefined as in is incomplete (type _):
123114
// ./in.cue:19:8
124115
}
125116
}
126-
issue3534: (_|_){
127-
// [eval]
117+
issue3534: (struct){
128118
#Inner: (#struct){
129119
foo: (#struct){
130120
minor: (int){ 2 }
@@ -135,21 +125,14 @@ Result:
135125
major: (int){ 1 }
136126
}
137127
}
138-
t1: (_|_){
139-
// [eval]
140-
version: (_|_){
141-
// [eval]
142-
major: (_|_){
143-
// [eval] outerErr.issue3534.t1.version.major: field not allowed:
144-
// ./in.cue:19:8
145-
// ./in.cue:25:22
146-
}
128+
t1: (#struct){
129+
version: (#struct){
130+
major: (int){ 1 }
147131
minor: (int){ 2 }
148132
}
149133
}
150134
}
151-
usingClose: (_|_){
152-
// [eval]
135+
usingClose: (struct){
153136
#Inner: (#struct){
154137
foo: (#struct){
155138
minor: (int){ 2 }
@@ -160,21 +143,14 @@ Result:
160143
major: (int){ 1 }
161144
}
162145
}
163-
t1: (_|_){
164-
// [eval]
165-
version: (_|_){
166-
// [eval]
167-
major: (_|_){
168-
// [eval] outerErr.usingClose.t1.version.major: field not allowed:
169-
// ./in.cue:34:17
170-
// ./in.cue:35:22
171-
}
146+
t1: (#struct){
147+
version: (#struct){
148+
major: (int){ 1 }
172149
minor: (int){ 2 }
173150
}
174151
}
175152
}
176-
extraNesting: (_|_){
177-
// [eval]
153+
extraNesting: (struct){
178154
#Inner: (#struct){
179155
foo: (#struct){
180156
x: (#struct){
@@ -189,16 +165,10 @@ Result:
189165
}
190166
}
191167
}
192-
t1: (_|_){
193-
// [eval]
194-
version: (_|_){
195-
// [eval]
196-
x: (_|_){
197-
// [eval]
198-
major: (_|_){
199-
// [eval] outerErr.extraNesting.t1.version.x.major: field not allowed:
200-
// ./in.cue:46:25
201-
}
168+
t1: (#struct){
169+
version: (#struct){
170+
x: (#struct){
171+
major: (int){ 1 }
202172
minor: (int){ 2 }
203173
}
204174
}
@@ -238,18 +208,12 @@ Result:
238208
diff old new
239209
--- old
240210
+++ new
241-
@@ -1,10 +1,18 @@
211+
@@ -1,10 +1,10 @@
242212
Errors:
243213
-outerErr.usingClose.t1.version.major: field not allowed:
244-
+outerErr.extraNesting.t1.version.x.major: field not allowed:
245-
+ ./in.cue:46:25
246-
+outerErr.issue3534.t1.version.major: field not allowed:
247-
./in.cue:19:8
214+
- ./in.cue:19:8
248215
- ./in.cue:34:23
249-
+ ./in.cue:25:22
250-
+outerErr.usingClose.t1.version.major: field not allowed:
251-
+ ./in.cue:34:17
252-
./in.cue:35:22
216+
- ./in.cue:35:22
253217
- ./in.cue:37:7
254218
- ./in.cue:38:16
255219
+#E.b: field not allowed:
@@ -261,11 +225,22 @@ diff old new
261225

262226
Result:
263227
(_|_){
264-
@@ -26,20 +34,27 @@
265-
// ./in.cue:19:8
228+
@@ -17,8 +17,7 @@
229+
x: (int){ 2 }
230+
}
231+
}
232+
- outerErr: (_|_){
233+
- // [eval]
234+
+ outerErr: (struct){
235+
_inToOut: (struct){
236+
in: (_){ _ }
237+
out: (_|_){
238+
@@ -44,30 +43,20 @@
239+
}
266240
}
267241
}
268-
- issue3534: (struct){
242+
- usingClose: (_|_){
243+
- // [eval]
269244
- #Inner: (#struct){
270245
- foo: (#struct){
271246
- minor: (int){ 2 }
@@ -276,11 +251,19 @@ diff old new
276251
- major: (int){ 1 }
277252
- }
278253
- }
279-
- t1: (#struct){
280-
- version: (#struct){
281-
- major: (int){ 1 }
282-
+ issue3534: (_|_){
283-
+ // [eval]
254+
- t1: (_|_){
255+
- // [eval]
256+
- version: (_|_){
257+
- // [eval]
258+
- major: (_|_){
259+
- // [eval] outerErr.usingClose.t1.version.major: field not allowed:
260+
- // ./in.cue:19:8
261+
- // ./in.cue:34:23
262+
- // ./in.cue:35:22
263+
- // ./in.cue:37:7
264+
- // ./in.cue:38:16
265+
- }
266+
+ usingClose: (struct){
284267
+ #Inner: (#struct){
285268
+ foo: (#struct){
286269
+ minor: (int){ 2 }
@@ -291,97 +274,18 @@ diff old new
291274
+ major: (int){ 1 }
292275
+ }
293276
+ }
294-
+ t1: (_|_){
295-
+ // [eval]
296-
+ version: (_|_){
297-
+ // [eval]
298-
+ major: (_|_){
299-
+ // [eval] outerErr.issue3534.t1.version.major: field not allowed:
300-
+ // ./in.cue:19:8
301-
+ // ./in.cue:25:22
302-
+ }
277+
+ t1: (#struct){
278+
+ version: (#struct){
279+
+ major: (int){ 1 }
303280
minor: (int){ 2 }
304281
}
305282
}
306-
@@ -62,43 +77,52 @@
307-
// [eval]
308-
major: (_|_){
309-
// [eval] outerErr.usingClose.t1.version.major: field not allowed:
310-
- // ./in.cue:19:8
311-
- // ./in.cue:34:23
312-
+ // ./in.cue:34:17
313-
// ./in.cue:35:22
314-
- // ./in.cue:37:7
315-
- // ./in.cue:38:16
316-
- }
317-
- minor: (int){ 2 }
318-
- }
319-
- }
320-
- }
321-
- extraNesting: (struct){
322-
- #Inner: (#struct){
323-
- foo: (#struct){
324-
- x: (#struct){
325-
- minor: (int){ 2 }
326-
- }
327-
- }
328-
- }
329-
- #Outer: (#struct){
330-
- version: (#struct){
331-
- x: (#struct){
332-
- major: (int){ 1 }
333-
- }
334-
- }
335-
- }
336-
- t1: (#struct){
337-
- version: (#struct){
338-
- x: (#struct){
339-
- major: (int){ 1 }
340-
- minor: (int){ 2 }
341-
- }
342-
- }
343-
- }
344-
- }
345-
- }
283+
@@ -97,8 +86,13 @@
284+
}
285+
}
286+
}
346287
- refFromPkg: (int){ 1 }
347288
- refFromLet: (struct){
348-
+ }
349-
+ minor: (int){ 2 }
350-
+ }
351-
+ }
352-
+ }
353-
+ extraNesting: (_|_){
354-
+ // [eval]
355-
+ #Inner: (#struct){
356-
+ foo: (#struct){
357-
+ x: (#struct){
358-
+ minor: (int){ 2 }
359-
+ }
360-
+ }
361-
+ }
362-
+ #Outer: (#struct){
363-
+ version: (#struct){
364-
+ x: (#struct){
365-
+ major: (int){ 1 }
366-
+ }
367-
+ }
368-
+ }
369-
+ t1: (_|_){
370-
+ // [eval]
371-
+ version: (_|_){
372-
+ // [eval]
373-
+ x: (_|_){
374-
+ // [eval]
375-
+ major: (_|_){
376-
+ // [eval] outerErr.extraNesting.t1.version.x.major: field not allowed:
377-
+ // ./in.cue:46:25
378-
+ }
379-
+ minor: (int){ 2 }
380-
+ }
381-
+ }
382-
+ }
383-
+ }
384-
+ }
385289
+ refFromPkg: (_|_){
386290
+ // [eval] #E.b: field not allowed:
387291
+ // ./in.cue:57:14
@@ -392,7 +296,7 @@ diff old new
392296
let X#1 = (_|_){
393297
// [eval]
394298
#D: (#struct){
395-
@@ -106,15 +130,18 @@
299+
@@ -106,15 +100,18 @@
396300
}
397301
#E: (_|_){
398302
// [eval]

‎internal/core/adt/conjunct.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ func (n *nodeContext) scheduleConjunct(c Conjunct, id CloseInfo) {
7878
if c.CloseInfo.FromDef {
7979
t |= closeDef
8080
}
81-
if c.CloseInfo.FromEmbed {
81+
// NOTE: the check for OpenInline is not strictly necessary, but it
82+
// clarifies that using id.FromEmbed is not used when OpenInline is not
83+
// used.
84+
if c.CloseInfo.FromEmbed || (n.ctx.OpenInline && id.FromEmbed) {
8285
t |= closeEmbed
8386
}
8487
if t != 0 || c.CloseInfo.GroupUnify {

‎internal/core/adt/context.go

+1
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,7 @@ func pos(x Node) token.Pos {
11421142
func (c *OpContext) node(orig Node, x Expr, scalar bool, state combinedFlags) *Vertex {
11431143
if c.OpenInline {
11441144
if _, ok := x.(Resolver); !ok {
1145+
c.ci.FromEmbed = true
11451146
c.inLiteralSelectee++
11461147
defer func() { c.inLiteralSelectee-- }()
11471148
}

‎internal/cuedebug/debug.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,21 @@ type Config struct {
4343
// x: (#D & {b: 2}).b // allow this
4444
//
4545
// This behavior was erroneously permitted in the v2 evaluator and was fixed
46-
// in v3. This allows users that rely on this behavior to use v3.
46+
// in v3. This allows users that rely on this behavior to use v3. This
47+
// option also discards closedness of the resulting expression. As was
48+
// reported in Issue #3534, this was another erroneous behavior in v2 that
49+
// is otherwise fixed in v3.
50+
//
4751
// To aid the transition to v3, this is enabled by default for now.
52+
//
53+
// A possible solution for both incompatibilities would be the introduction
54+
// of an openAll builtin to recursive open up a cue value. For the first
55+
// issue, the example above could be rewritten as:
56+
//
57+
// x: (openAll(#D) & {b: 2}).b
58+
//
59+
// For the second issue, to open up the entire result of an inline struct,
60+
// such an expression could be written as `openAll(expr).out`.
4861
OpenInline bool `envflag:"default:true"`
4962
}
5063

0 commit comments

Comments
 (0)
Please sign in to comment.