Skip to content

Commit 3deadce

Browse files
committed
internal/core/adt: fix validators in embeddings
When an embedded validator is added, both evalv2 and evalv3 did not account for the fact that this potentially changes the type of the struct in which they are embedded. This could cause the struct to be marked as type struct before this is actually known. The hasTop field is used as a mechanism to delay the typing of an embedded struct. We use this now for validators to relax the constraints and not have them inadvertently be interpreted as struct types. Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I04fe39464a866874ad4a70683a7e6e74f13d14cb Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1200328 TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Roger Peppe <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 0ffb5d2 commit 3deadce

File tree

3 files changed

+102
-157
lines changed

3 files changed

+102
-157
lines changed

cue/testdata/builtins/matchn.txtar

+94-157
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,15 @@ bare: {
132132
}
133133
}
134134
-- out/eval/stats --
135-
Leaks: 8
136-
Freed: 535
137-
Reused: 530
138-
Allocs: 13
139-
Retain: 52
135+
Leaks: 11
136+
Freed: 520
137+
Reused: 515
138+
Allocs: 16
139+
Retain: 50
140140

141-
Unifications: 531
142-
Conjuncts: 918
143-
Disjuncts: 585
141+
Unifications: 519
142+
Conjuncts: 894
143+
Disjuncts: 570
144144
-- out/eval --
145145
Errors:
146146
match.singleErr: invalid value {a:"foo"} (does not satisfy matchN(1, [{a:int}])): 0 matched, expected 1:
@@ -191,22 +191,6 @@ allOf.multiple1Err3: invalid value 5 (does not satisfy matchN(2, [math.MultipleO
191191
./in.cue:106:20
192192
./in.cue:106:27
193193
./in.cue:110:17
194-
bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
195-
./in.cue:117:7
196-
./in.cue:117:6
197-
./in.cue:117:14
198-
bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
199-
./in.cue:117:7
200-
./in.cue:117:14
201-
./in.cue:118:6
202-
bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
203-
./in.cue:122:7
204-
./in.cue:122:6
205-
./in.cue:122:14
206-
bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
207-
./in.cue:122:7
208-
./in.cue:121:6
209-
./in.cue:122:14
210194

211195
Result:
212196
(_|_){
@@ -375,39 +359,27 @@ Result:
375359
}
376360
multiple1OK1: (int){ 15 }
377361
}
378-
bare: (_|_){
379-
// [eval]
380-
embed: (_|_){
381-
// [eval]
382-
t1: (_|_){
383-
// [eval]
384-
a: (_|_){
385-
// [eval] bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
386-
// ./in.cue:117:7
387-
// ./in.cue:117:6
388-
// ./in.cue:117:14
389-
}
390-
b: (_|_){
391-
// [eval] bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
392-
// ./in.cue:117:7
393-
// ./in.cue:117:14
394-
// ./in.cue:118:6
395-
}
362+
bare: (struct){
363+
embed: (struct){
364+
t1: (struct){
365+
a: (_){ matchN(1, (#list){
366+
0: (_|_){// >10
367+
}
368+
}) }
369+
b: (_){ matchN(1, (#list){
370+
0: (_|_){// >10
371+
}
372+
}) }
396373
}
397-
t2: (_|_){
398-
// [eval]
399-
b: (_|_){
400-
// [eval] bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
401-
// ./in.cue:122:7
402-
// ./in.cue:121:6
403-
// ./in.cue:122:14
404-
}
405-
a: (_|_){
406-
// [eval] bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
407-
// ./in.cue:122:7
408-
// ./in.cue:122:6
409-
// ./in.cue:122:14
410-
}
374+
t2: (struct){
375+
b: (_){ matchN(1, (#list){
376+
0: (_|_){// >10
377+
}
378+
}) }
379+
a: (_){ matchN(1, (#list){
380+
0: (_|_){// >10
381+
}
382+
}) }
411383
}
412384
}
413385
direct: (struct){
@@ -478,18 +450,6 @@ allOf.multiple1Err3: invalid value 5 (does not satisfy matchN(2, [math.MultipleO
478450
./in.cue:106:20
479451
./in.cue:106:27
480452
./in.cue:110:17
481-
bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
482-
./in.cue:117:7
483-
./in.cue:117:14
484-
bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
485-
./in.cue:117:7
486-
./in.cue:117:14
487-
bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
488-
./in.cue:122:7
489-
./in.cue:122:14
490-
bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
491-
./in.cue:122:7
492-
./in.cue:122:14
493453

494454
Result:
495455
(_|_){
@@ -651,35 +611,23 @@ Result:
651611
}
652612
multiple1OK1: (int){ 15 }
653613
}
654-
bare: (_|_){
655-
// [eval]
656-
embed: (_|_){
657-
// [eval]
658-
t1: (_|_){
659-
// [eval]
660-
a: (_|_){
661-
// [eval] bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
662-
// ./in.cue:117:7
663-
// ./in.cue:117:14
664-
}
665-
b: (_|_){
666-
// [eval] bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
667-
// ./in.cue:117:7
668-
// ./in.cue:117:14
669-
}
614+
bare: (struct){
615+
embed: (struct){
616+
t1: (struct){
617+
a: (_){ matchN(1, (#list){
618+
0: (number){ >10 }
619+
}) }
620+
b: (_){ matchN(1, (#list){
621+
0: (number){ >10 }
622+
}) }
670623
}
671-
t2: (_|_){
672-
// [eval]
673-
b: (_|_){
674-
// [eval] bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
675-
// ./in.cue:122:7
676-
// ./in.cue:122:14
677-
}
678-
a: (_|_){
679-
// [eval] bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
680-
// ./in.cue:122:7
681-
// ./in.cue:122:14
682-
}
624+
t2: (struct){
625+
b: (_){ matchN(1, (#list){
626+
0: (number){ >10 }
627+
}) }
628+
a: (_){ matchN(1, (#list){
629+
0: (number){ >10 }
630+
}) }
683631
}
684632
}
685633
direct: (struct){
@@ -735,43 +683,23 @@ diff old new
735683
oneOf.multiple1Err1: invalid value 1 (does not satisfy matchN(1, [math.MultipleOf(3),math.MultipleOf(5)])): 0 matched, expected 1:
736684
./in.cue:84:20
737685
./in.cue:84:27
738-
@@ -49,19 +43,15 @@
739-
./in.cue:110:17
740-
bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
741-
./in.cue:117:7
742-
- ./in.cue:117:6
743-
./in.cue:117:14
744-
bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
745-
./in.cue:117:7
746-
./in.cue:117:14
747-
- ./in.cue:118:6
748-
bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
749-
./in.cue:122:7
750-
- ./in.cue:122:6
751-
./in.cue:122:14
752-
bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
753-
./in.cue:122:7
754-
- ./in.cue:121:6
755-
./in.cue:122:14
756-
757-
Result:
758-
@@ -79,7 +69,6 @@
686+
@@ -63,7 +57,6 @@
759687
// [eval] match.singleErr: invalid value {a:"foo"} (does not satisfy matchN(1, [{a:int}])): 0 matched, expected 1:
760688
// ./in.cue:8:17
761689
// ./in.cue:8:24
762690
- // ./in.cue:10:13
763691
a: (string){ "foo" }
764692
}
765693
incompleteOK: (struct){
766-
@@ -89,7 +78,6 @@
694+
@@ -73,7 +66,6 @@
767695
// [eval] match.incompleteErr: invalid value {a:string} (does not satisfy matchN(1, [{a:int}])): 0 matched, expected 1:
768696
// ./in.cue:12:21
769697
// ./in.cue:12:28
770698
- // ./in.cue:14:17
771699
a: (string){ string }
772700
}
773701
#A: (#struct){
774-
@@ -102,8 +90,7 @@
702+
@@ -86,8 +78,7 @@
775703
0: (int){ 2 }
776704
}), int) }) }
777705
pickTopOK2: (int){ &(matchN(1, (#list){
@@ -781,31 +709,31 @@ diff old new
781709
}), int) }
782710
pickTopErr: (int){ &(matchN(1, (#list){
783711
0: (int){ 2 }
784-
@@ -118,7 +105,6 @@
712+
@@ -102,7 +93,6 @@
785713
// [eval] match.defaults.pickNested1Err: invalid value {a:*3 | int} (does not satisfy matchN(1, [{a:2}])): 0 matched, expected 1:
786714
// ./in.cue:36:23
787715
// ./in.cue:36:30
788716
- // ./in.cue:39:19
789717
a: (int){ |(*(int){ 3 }, (int){ int }) }
790718
}
791719
pickNested2OK1: (struct){
792-
@@ -131,7 +117,6 @@
720+
@@ -115,7 +105,6 @@
793721
// [eval] match.defaults.pickNested2Err: invalid value {a:*3 | int} (does not satisfy matchN(1, [{a:<=2}])): 0 matched, expected 1:
794722
// ./in.cue:41:23
795723
// ./in.cue:41:30
796724
- // ./in.cue:44:19
797725
a: (int){ |(*(int){ 3 }, (int){ int }) }
798726
}
799727
}
800-
@@ -166,7 +151,6 @@
728+
@@ -150,7 +139,6 @@
801729
// [eval] not.singleErr: invalid value {a:2} (does not satisfy matchN(0, [{a:int}])): 1 matched, expected 0:
802730
// ./in.cue:74:17
803731
// ./in.cue:74:24
804732
- // ./in.cue:76:13
805733
a: (int){ 2 }
806734
}
807735
doubleOK: (struct){
808-
@@ -173,10 +157,9 @@
736+
@@ -157,10 +145,9 @@
809737
a: (int){ 2 }
810738
}
811739
doubleErr: (_|_){
@@ -817,38 +745,8 @@ diff old new
817745
a: (string){ "foo" }
818746
}
819747
}
820-
@@ -240,7 +223,6 @@
821-
a: (_|_){
822-
// [eval] bare.embed.t1.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
823-
// ./in.cue:117:7
824-
- // ./in.cue:117:6
825-
// ./in.cue:117:14
826-
}
827-
b: (_|_){
828-
@@ -247,7 +229,6 @@
829-
// [eval] bare.embed.t1.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
830-
// ./in.cue:117:7
831-
// ./in.cue:117:14
832-
- // ./in.cue:118:6
833-
}
834-
}
835-
t2: (_|_){
836-
@@ -255,13 +236,11 @@
837-
b: (_|_){
838-
// [eval] bare.embed.t2.b: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
839-
// ./in.cue:122:7
840-
- // ./in.cue:121:6
841-
// ./in.cue:122:14
842-
}
843-
a: (_|_){
844-
// [eval] bare.embed.t2.a: invalid value {} (does not satisfy matchN(1, [>10])): 0 matched, expected 1:
845-
// ./in.cue:122:7
846-
- // ./in.cue:122:6
847-
// ./in.cue:122:14
848-
}
849-
}
850-
@@ -269,22 +248,18 @@
851-
direct: (struct){
748+
@@ -219,22 +206,18 @@
749+
embed: (struct){
852750
t1: (struct){
853751
a: (_){ matchN(1, (#list){
854752
- 0: (_|_){// >10
@@ -857,14 +755,45 @@ diff old new
857755
- b: (_){ matchN(1, (#list){
858756
- 0: (_|_){// >10
859757
- }
758+
- }) }
759+
- }
760+
- t2: (struct){
761+
- b: (_){ matchN(1, (#list){
762+
- 0: (_|_){// >10
763+
- }
764+
- }) }
765+
- a: (_){ matchN(1, (#list){
766+
- 0: (_|_){// >10
767+
- }
860768
+ 0: (number){ >10 }
861769
+ }) }
862770
+ b: (_){ matchN(1, (#list){
771+
+ 0: (number){ >10 }
772+
+ }) }
773+
+ }
774+
+ t2: (struct){
775+
+ b: (_){ matchN(1, (#list){
776+
+ 0: (number){ >10 }
777+
+ }) }
778+
+ a: (_){ matchN(1, (#list){
863779
+ 0: (number){ >10 }
864780
}) }
865781
}
866-
t2: (struct){
867-
b: (_){ matchN(1, (#list){
782+
}
783+
@@ -241,22 +224,18 @@
784+
direct: (struct){
785+
t1: (struct){
786+
a: (_){ matchN(1, (#list){
787+
- 0: (_|_){// >10
788+
- }
789+
- }) }
790+
- b: (_){ matchN(1, (#list){
791+
- 0: (_|_){// >10
792+
- }
793+
- }) }
794+
- }
795+
- t2: (struct){
796+
- b: (_){ matchN(1, (#list){
868797
- 0: (_|_){// >10
869798
- }
870799
- }) }
@@ -873,6 +802,14 @@ diff old new
873802
- }
874803
+ 0: (number){ >10 }
875804
+ }) }
805+
+ b: (_){ matchN(1, (#list){
806+
+ 0: (number){ >10 }
807+
+ }) }
808+
+ }
809+
+ t2: (struct){
810+
+ b: (_){ matchN(1, (#list){
811+
+ 0: (number){ >10 }
812+
+ }) }
876813
+ a: (_){ matchN(1, (#list){
877814
+ 0: (number){ >10 }
878815
}) }

internal/core/adt/conjunct.go

+7
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,13 @@ func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInf
713713
}
714714
n.checks = append(n.checks, x)
715715

716+
// We use hasTop here to ensure that validation considers the ultimate
717+
// value of embedded validators, rather than assuming that the struct in
718+
// which an expression is embedded is always a struct.
719+
// TODO(validatorType): a more precise alternative would be to determine
720+
// the basic type of the expression and schedule a conjunct for that.
721+
n.hasTop = true
722+
716723
case *Vertex:
717724
// handled above.
718725

internal/core/adt/eval.go

+1
Original file line numberDiff line numberDiff line change
@@ -1976,6 +1976,7 @@ func (n *nodeContext) addValueConjunct(env *Environment, v Value, id CloseInfo)
19761976
}
19771977
n.updateNodeType(x.Kind(), x, id)
19781978
n.checks = append(n.checks, x)
1979+
n.hasTop = true // TODO(validatorType): see namesake TODO in conjunct.go.
19791980

19801981
case *Vertex:
19811982
// handled above.

0 commit comments

Comments
 (0)