this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/core/adt: add cycle detection

In some cases, when definitions mutually refer
to each other, the new typo check algorithm
could get stuck in a loop. The old algorithm
handled this differently (while computing the
sets).

This CL adds cycle detection by simply checking
that an ID that was initially checked isn't
checked again.

Test is added directly here as it caused as
stack overflow on its own.

Fixes #4006

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: I1ff0fa6b6927661e010ef1211ca95c242027472f
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1219239
Reviewed-by: 码畜生活 <likun_power@sina.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>

+139 -68
+129 -64
cue/testdata/definitions/typocheck.txtar
··· 559 559 #Unused: unused: string 560 560 #Used: used: string 561 561 } 562 + -- cycle.cue -- 563 + issue4006: { 564 + #A: { 565 + #B 566 + fieldA: string 567 + } 568 + #B: { #A } 569 + #C: #A & {} 570 + out: #C & #B 571 + } 562 572 -- out/evalalpha/stats -- 563 573 Leaks: 11 564 - Freed: 861 565 - Reused: 802 566 - Allocs: 70 574 + Freed: 870 575 + Reused: 810 576 + Allocs: 71 567 577 Retain: 0 568 578 569 - Unifications: 713 570 - Conjuncts: 1422 579 + Unifications: 722 580 + Conjuncts: 1450 571 581 Disjuncts: 76 572 582 Notifications: 8 573 583 574 - NumCloseIDs: 413 584 + NumCloseIDs: 435 585 + 586 + ConjunctInfos: 1056 587 + MaxConjunctInfos: 5 588 + MaxReqSets: 9 589 + MaxRedirect: 2 575 590 -- diff/-out/evalalpha/stats<==>+out/eval/stats -- 576 591 diff old new 577 592 --- old 578 593 +++ new 579 - @@ -1,11 +1,12 @@ 594 + @@ -1,11 +1,17 @@ 580 595 -Leaks: 47 581 - -Freed: 951 582 - -Reused: 937 596 + -Freed: 960 597 + -Reused: 946 583 598 -Allocs: 61 584 - -Retain: 226 599 + -Retain: 227 585 600 - 586 - -Unifications: 886 587 - -Conjuncts: 1918 588 - -Disjuncts: 1157 601 + -Unifications: 895 602 + -Conjuncts: 1959 603 + -Disjuncts: 1167 589 604 - 590 605 -NumCloseIDs: 3 591 606 +Leaks: 11 592 - +Freed: 861 593 - +Reused: 802 594 - +Allocs: 70 607 + +Freed: 870 608 + +Reused: 810 609 + +Allocs: 71 595 610 +Retain: 0 596 611 + 597 - +Unifications: 713 598 - +Conjuncts: 1422 612 + +Unifications: 722 613 + +Conjuncts: 1450 599 614 +Disjuncts: 76 600 615 +Notifications: 8 601 616 + 602 - +NumCloseIDs: 413 617 + +NumCloseIDs: 435 618 + + 619 + +ConjunctInfos: 1056 620 + +MaxConjunctInfos: 5 621 + +MaxReqSets: 9 622 + +MaxRedirect: 2 603 623 -- out/eval/stats -- 604 624 Leaks: 47 605 - Freed: 951 606 - Reused: 937 625 + Freed: 960 626 + Reused: 946 607 627 Allocs: 61 608 - Retain: 226 628 + Retain: 227 609 629 610 - Unifications: 886 611 - Conjuncts: 1918 612 - Disjuncts: 1157 630 + Unifications: 895 631 + Conjuncts: 1959 632 + Disjuncts: 1167 613 633 614 634 NumCloseIDs: 3 615 635 -- out/evalalpha -- ··· 688 708 e: (int){ 1 } 689 709 f: (int){ int } 690 710 } 711 + } 712 + } 713 + issue4006: (struct){ 714 + #A: (#struct){ 715 + fieldA: (string){ string } 716 + } 717 + #B: (#struct){ 718 + fieldA: (string){ string } 719 + } 720 + #C: (#struct){ 721 + fieldA: (string){ string } 722 + } 723 + out: (#struct){ 724 + fieldA: (string){ string } 691 725 } 692 726 } 693 727 issue3947: (_|_){ ··· 1949 1983 a: (#struct){ 1950 1984 - c?: (string){ string } 1951 1985 b: (string){ "out" } 1952 - + c?: (string){ string } 1953 - } 1954 - } 1955 - #A: (#struct){ 1986 + - } 1987 + - } 1988 + - #A: (#struct){ 1956 1989 - a?: (#struct){ 1957 1990 - c?: (string){ string } 1958 1991 - } 1992 + + c?: (string){ string } 1993 + + } 1994 + + } 1995 + + #A: (#struct){ 1959 1996 + a?: ~(issue3920.#B) 1960 1997 } 1961 1998 #B: (#struct){ 1962 1999 c?: (string){ string } 1963 - @@ -149,10 +90,7 @@ 2000 + @@ -163,10 +104,7 @@ 1964 2001 allowed?: (string){ string } 1965 2002 disallowed: (_|_){ 1966 2003 // [eval] issue3947.full.out.disallowed: field not allowed: ··· 1971 2008 } 1972 2009 } 1973 2010 } 1974 - @@ -164,15 +102,9 @@ 2011 + @@ -178,15 +116,9 @@ 1975 2012 c: (_|_){ 1976 2013 // [eval] 1977 2014 a: (_|_){ ··· 1988 2025 } 1989 2026 b?: (string){ string } 1990 2027 } 1991 - @@ -245,9 +177,6 @@ 2028 + @@ -259,9 +191,6 @@ 1992 2029 } 1993 2030 nestedWithPatterns: (struct){ 1994 2031 out: (#struct){ ··· 1998 2035 objs: (#struct){ 1999 2036 obj1: (#struct){ 2000 2037 extra: (string){ "foo" } 2001 - @@ -254,6 +183,9 @@ 2038 + @@ -268,6 +197,9 @@ 2002 2039 name?: (int){ int } 2003 2040 } 2004 2041 } ··· 2008 2045 } 2009 2046 #Schema: (#struct){ 2010 2047 #meta: (#struct){ 2011 - @@ -344,14 +276,11 @@ 2048 + @@ -358,14 +290,11 @@ 2012 2049 } 2013 2050 a: (_|_){ 2014 2051 // [eval] ··· 2024 2061 } 2025 2062 } 2026 2063 andInStruct: (_|_){ 2027 - @@ -361,14 +290,11 @@ 2064 + @@ -375,14 +304,11 @@ 2028 2065 } 2029 2066 a: (_|_){ 2030 2067 // [eval] ··· 2040 2077 } 2041 2078 } 2042 2079 embedDefWithEmbedding: (_|_){ 2043 - @@ -378,15 +304,11 @@ 2080 + @@ -392,15 +318,11 @@ 2044 2081 } 2045 2082 a: (_|_){ 2046 2083 // [eval] ··· 2057 2094 } 2058 2095 } 2059 2096 embedComprehension: (_|_){ 2060 - @@ -396,16 +318,11 @@ 2097 + @@ -410,16 +332,11 @@ 2061 2098 } 2062 2099 a: (_|_){ 2063 2100 // [eval] ··· 2075 2112 } 2076 2113 } 2077 2114 fieldWithAnd: (_|_){ 2078 - @@ -416,9 +333,6 @@ 2115 + @@ -430,9 +347,6 @@ 2079 2116 // [eval] 2080 2117 err: (_|_){ 2081 2118 // [eval] embed.fieldWithAnd.a.err: field not allowed: ··· 2085 2122 // ./in.cue:20:13 2086 2123 } 2087 2124 } 2088 - @@ -429,20 +343,15 @@ 2125 + @@ -443,20 +357,15 @@ 2089 2126 a: (int){ int } 2090 2127 } 2091 2128 B: (struct){ ··· 2111 2148 } 2112 2149 } 2113 2150 andEmbed: (_|_){ 2114 - @@ -458,17 +367,11 @@ 2151 + @@ -472,17 +381,11 @@ 2115 2152 } 2116 2153 d: (_|_){ 2117 2154 // [eval] ··· 2130 2167 } 2131 2168 } 2132 2169 nonDef: (struct){ 2133 - @@ -477,12 +380,12 @@ 2170 + @@ -491,12 +394,12 @@ 2134 2171 a: (string){ string } 2135 2172 } 2136 2173 #Y: (#struct){ ··· 2147 2184 } 2148 2185 } 2149 2186 } 2150 - @@ -492,12 +395,12 @@ 2187 + @@ -506,12 +409,12 @@ 2151 2188 Name: (string){ string } 2152 2189 } 2153 2190 #Step: (#struct){ ··· 2164 2201 } 2165 2202 out: (#struct){ 2166 2203 Name: (string){ "foo" } 2167 - @@ -507,21 +410,15 @@ 2204 + @@ -521,21 +424,15 @@ 2168 2205 } 2169 2206 withIndirect: (_|_){ 2170 2207 // [eval] ··· 2191 2228 } 2192 2229 normalValidator: (_|_){ 2193 2230 // [eval] 2194 - @@ -531,20 +428,18 @@ 2231 + @@ -545,20 +442,18 @@ 2195 2232 } 2196 2233 x: (_|_){ 2197 2234 // [eval] ··· 2216 2253 #X: (_){ 2217 2254 matchN(0, (#list){ 2218 2255 }) 2219 - @@ -551,17 +446,10 @@ 2256 + @@ -565,17 +460,10 @@ 2220 2257 a?: (int){ int } 2221 2258 b?: (int){ int } 2222 2259 } ··· 2238 2275 } 2239 2276 } 2240 2277 t2: (_|_){ 2241 - @@ -580,10 +468,7 @@ 2278 + @@ -594,10 +482,7 @@ 2242 2279 // [eval] 2243 2280 b: (_|_){ 2244 2281 // [eval] embed.openValidator.t2.a.b: conflicting values 1 and {b?:Y} (mismatched types int and struct): ··· 2249 2286 // ./validators.cue:28:8 2250 2287 // embed.openValidator.t2.a.b: invalid value 1 (does not satisfy matchN): 0 matched, expected 1: 2251 2288 // ./validators.cue:25:5 2252 - @@ -640,16 +525,11 @@ 2289 + @@ -654,16 +539,11 @@ 2253 2290 } 2254 2291 out: (_|_){ 2255 2292 // [eval] ··· 2267 2304 } 2268 2305 } 2269 2306 } 2270 - @@ -682,17 +562,11 @@ 2307 + @@ -696,17 +576,11 @@ 2271 2308 } 2272 2309 out: (_|_){ 2273 2310 // [eval] ··· 2286 2323 } 2287 2324 } 2288 2325 } 2289 - @@ -738,8 +612,8 @@ 2326 + @@ -752,8 +626,8 @@ 2290 2327 // ./issue3832.cue:8:16 2291 2328 } 2292 2329 outFirstName: (_|_){ ··· 2297 2334 } 2298 2335 } 2299 2336 } 2300 - @@ -749,35 +623,27 @@ 2337 + @@ -763,35 +637,27 @@ 2301 2338 }, (#struct){ 2302 2339 pass: (#struct){ 2303 2340 let self#2 = (_|_){ ··· 2343 2380 pass: (#struct){ 2344 2381 let self#2 = (#struct){ 2345 2382 firstName: (string){ "Sam" } 2346 - @@ -784,20 +650,24 @@ 2383 + @@ -798,20 +664,24 @@ 2347 2384 } 2348 2385 outFirstName: (string){ "Sam" } 2349 2386 } ··· 2382 2419 ok: (struct){ 2383 2420 out: (#struct){ 2384 2421 a: (#struct){ 2385 - @@ -818,11 +688,18 @@ 2422 + @@ -832,11 +702,18 @@ 2386 2423 b: (string){ "foo" } 2387 2424 } 2388 2425 } ··· 2406 2443 } 2407 2444 } 2408 2445 #A: (#struct){ 2409 - @@ -893,12 +770,8 @@ 2446 + @@ -907,12 +784,8 @@ 2410 2447 globalField: (string){ string } 2411 2448 } 2412 2449 #Context: (#struct){ ··· 2421 2458 } 2422 2459 out: (struct){ 2423 2460 ingress: (#struct){ 2424 - @@ -926,22 +799,22 @@ 2461 + @@ -940,22 +813,22 @@ 2425 2462 #Z: (#struct){ 2426 2463 } 2427 2464 x: (#struct){ ··· 2460 2497 z: (int){ 1 } 2461 2498 } 2462 2499 } 2463 - @@ -951,22 +824,22 @@ 2500 + @@ -965,22 +838,22 @@ 2464 2501 #Z: (#struct){ 2465 2502 } 2466 2503 x: (#struct){ ··· 2499 2536 z: (int){ 1 } 2500 2537 } 2501 2538 } 2502 - @@ -981,11 +854,7 @@ 2539 + @@ -995,11 +868,7 @@ 2503 2540 } 2504 2541 } 2505 2542 #JobConfig: (#struct){ ··· 2512 2549 job: (#struct){ 2513 2550 image: (string){ "foo:v1" } 2514 2551 vcs: (string){ "git" } 2515 - @@ -1049,7 +918,7 @@ 2552 + @@ -1063,7 +932,7 @@ 2516 2553 } 2517 2554 } 2518 2555 out: (#struct){ ··· 2521 2558 input: (#struct){ 2522 2559 image: (string){ "someimage" } 2523 2560 env: (string){ "FOO" } 2524 - @@ -1081,11 +950,11 @@ 2561 + @@ -1095,11 +964,11 @@ 2525 2562 _in: (_){ _ } 2526 2563 out: (_){ _ } 2527 2564 } ··· 2538 2575 e: (string){ "foo" } 2539 2576 f: (int){ 1 } 2540 2577 } 2541 - @@ -1118,24 +987,16 @@ 2578 + @@ -1132,24 +1001,16 @@ 2542 2579 _in: (_){ _ } 2543 2580 out: (_){ _ } 2544 2581 } ··· 2573 2610 } 2574 2611 } 2575 2612 issue3934: (struct){ 2576 - @@ -1222,7 +1083,7 @@ 2613 + @@ -1236,7 +1097,7 @@ 2577 2614 op: (string){ "add" } 2578 2615 path: (string){ "/metadata" } 2579 2616 value: (_|_){ ··· 2582 2619 // ./large.cue:7:25 2583 2620 // ./large.cue:3:12 2584 2621 } 2585 - @@ -1251,38 +1112,11 @@ 2622 + @@ -1265,38 +1126,11 @@ 2586 2623 #Main: (#struct){ 2587 2624 namespace: (string){ string } 2588 2625 output: (_|_){ ··· 2623 2660 let base#7 = (#struct){ 2624 2661 someMsg: (string){ string } 2625 2662 obs: (#struct){ |(*(#struct){ 2626 - @@ -1301,7 +1135,7 @@ 2663 + @@ -1315,7 +1149,7 @@ 2627 2664 op: (string){ "add" } 2628 2665 path: (string){ "/metadata" } 2629 2666 value: (_|_){ ··· 2632 2669 // ./large.cue:7:25 2633 2670 // ./large.cue:3:12 2634 2671 } 2635 - @@ -1325,6 +1159,19 @@ 2672 + @@ -1339,6 +1173,19 @@ 2636 2673 } 2637 2674 } 2638 2675 } ··· 2652 2689 } 2653 2690 } 2654 2691 out: (#struct){ 2655 - @@ -1354,17 +1201,8 @@ 2692 + @@ -1368,17 +1215,8 @@ 2656 2693 // ./validators.cue:36:17 2657 2694 // disjunction.withErr.t1.out.b1.b2.b3: undefined field: mayExistLater: 2658 2695 // ./validators.cue:33:22 ··· 2815 2852 e: (int){ 1 } 2816 2853 f: (int){ int } 2817 2854 } 2855 + } 2856 + } 2857 + issue4006: (struct){ 2858 + #A: (#struct){ 2859 + fieldA: (string){ string } 2860 + } 2861 + #B: (#struct){ 2862 + fieldA: (string){ string } 2863 + } 2864 + #C: (#struct){ 2865 + fieldA: (string){ string } 2866 + } 2867 + out: (#struct){ 2868 + fieldA: (string){ string } 2818 2869 } 2819 2870 } 2820 2871 issue3947: (_|_){ ··· 4114 4165 e: 1 4115 4166 } 4116 4167 } 4168 + } 4169 + } 4170 + --- cycle.cue 4171 + { 4172 + issue4006: { 4173 + #A: { 4174 + 〈1;#B〉 4175 + fieldA: string 4176 + } 4177 + #B: { 4178 + 〈1;#A〉 4179 + } 4180 + #C: (〈0;#A〉 & {}) 4181 + out: (〈0;#C〉 & 〈0;#B〉) 4117 4182 } 4118 4183 } 4119 4184 --- disjunction.cue
+10 -4
internal/core/adt/typocheck.go
··· 699 699 c.stats.MaxRedirect = int64(len(c.redirectsBuf)) 700 700 } 701 701 702 - return n.containsDefIDRec(node, child) 702 + return n.containsDefIDRec(node, child, child) 703 703 } 704 704 705 - func (n *nodeContext) containsDefIDRec(node, child defID) bool { 705 + func (n *nodeContext) containsDefIDRec(node, child, start defID) bool { 706 706 c := n.ctx 707 707 708 708 // NOTE: this loop is O(H) 709 - for p := child; p != 0; p = c.containments[p] { 709 + for p := child; p != 0; { 710 710 if p == node { 711 711 return true 712 712 } ··· 717 717 // array once. 718 718 for _, r := range c.redirectsBuf { 719 719 if r.to == p && r.from != child { 720 - if n.containsDefIDRec(node, r.from) { 720 + if n.containsDefIDRec(node, r.from, start) { 721 721 return true 722 722 } 723 723 } 724 + } 725 + 726 + p = c.containments[p] 727 + if p == start { 728 + // We won't match node we haven't already after one cycle. 729 + return false 724 730 } 725 731 } 726 732