1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556
|
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Typechecking for the core language *)
[@@@ocaml.warning "-60"] module Str = Ast_helper.Str (* For ocamldep *)
[@@@ocaml.warning "+60"]
open Misc
open Asttypes
open Parsetree
open Types
open Data_types
open Typedtree
open Btype
open Ctype
module Style = Misc.Style
type type_forcing_context =
| If_conditional
| If_no_else_branch
| While_loop_conditional
| While_loop_body
| For_loop_start_index
| For_loop_stop_index
| For_loop_body
| Assert_condition
| Sequence_left_hand_side
| When_guard
type type_expected = {
ty: type_expr;
explanation: type_forcing_context option;
}
module Datatype_kind = struct
type t = Record | Variant
let type_name = function
| Record -> "record"
| Variant -> "variant"
let label_name = function
| Record -> "field"
| Variant -> "constructor"
end
type wrong_name = {
type_path: Path.t;
kind: Datatype_kind.t;
name: string loc;
valid_names: string list;
}
type wrong_kind_context =
| Pattern
| Expression of type_forcing_context option
type wrong_kind_sort =
| Constructor
| Record
| Boolean
| List
| Unit
type contains_gadt =
| Contains_gadt
| No_gadt
let wrong_kind_sort_of_constructor (lid : Longident.t) =
match lid with
| Lident "true" | Lident "false"
| Ldot(_, {txt="true"; _}) | Ldot(_, {txt="false"; _}) ->
Boolean
| Lident "[]" | Lident "::"
| Ldot(_, {txt="[]"; _}) | Ldot(_, {txt="::"; _}) -> List
| Lident "()" | Ldot(_, {txt="()"; _}) -> Unit
| _ -> Constructor
type existential_restriction =
| At_toplevel (** no existential types at the toplevel *)
| In_group (** nor with let ... and ... *)
| In_rec (** or recursive definition *)
| With_attributes (** or let[@any_attribute] = ... *)
| In_class_args (** or in class arguments *)
| In_class_def (** or in [class c = let ... in ...] *)
| In_self_pattern (** or in self pattern *)
type existential_binding =
| Bind_already_bound
| Bind_not_in_scope
| Bind_non_locally_abstract
type error =
| Constructor_arity_mismatch of Longident.t * int * int
| Label_mismatch of Longident.t * Errortrace.unification_error
| Pattern_type_clash :
Errortrace.unification_error * Parsetree.pattern_desc option -> error
| Or_pattern_type_clash of Ident.t * Errortrace.unification_error
| Multiply_bound_variable of string
| Orpat_vars of Ident.t * Ident.t list
| Expr_type_clash of
Errortrace.unification_error * type_forcing_context option
* Parsetree.expression option
| Function_arity_type_clash of
{ syntactic_arity : int;
type_constraint : type_expr;
trace : Errortrace.unification_error;
}
(* [Function_arity_type_clash { syntactic_arity = n; type_constraint; trace }]
is the type error for the specific case where an n-ary function is
constrained at a type with an arity less than n, e.g.:
{[
type (_, _) eq = Eq : ('a, 'a) eq
let bad : type a. ?opt:(a, int -> int) eq -> unit -> a =
fun ?opt:(Eq = assert false) () x -> x + 1
]}
[type_constraint] is the user-written polymorphic type (in this example
[?opt:(a, int -> int) eq -> unit -> a]) that causes this type clash, and
[trace] is the unification error that signaled the issue.
*)
| Apply_non_function of {
funct : Typedtree.expression;
func_ty : type_expr;
res_ty : type_expr;
previous_arg_loc : Location.t;
extra_arg_loc : Location.t;
}
| Apply_wrong_label of arg_label * type_expr * bool
| Label_multiply_defined of string
| Label_missing of Ident.t list
| Label_not_mutable of Longident.t
| Wrong_name of string * type_expected * wrong_name
| Name_type_mismatch of
Datatype_kind.t * Longident.t * (Path.t * Path.t) * (Path.t * Path.t) list
| Invalid_format of string
| Not_an_object of type_expr * type_forcing_context option
| Undefined_method of type_expr * string * string list option
| Undefined_self_method of string * string list
| Virtual_class of Longident.t
| Private_type of type_expr
| Private_label of Longident.t * type_expr
| Private_constructor of constructor_description * type_expr
| Unbound_instance_variable of string * string list
| Instance_variable_not_mutable of string
| Not_subtype of Errortrace.Subtype.error
| Outside_class
| Value_multiply_overridden of string
| Coercion_failure of
Errortrace.expanded_type * Errortrace.unification_error * bool
| Not_a_function of type_expr * type_forcing_context option
| Too_many_arguments of type_expr * type_forcing_context option
| Abstract_wrong_label of
{ got : arg_label
; expected : arg_label
; expected_type : type_expr
; explanation : type_forcing_context option
}
| Scoping_let_module of string * type_expr
| Not_a_polymorphic_variant_type of Longident.t
| Incoherent_label_order
| Less_general of string * Errortrace.unification_error
| Modules_not_allowed
| Cannot_infer_signature
| Not_a_packed_module of type_expr
| Unexpected_existential of existential_restriction * string
| Invalid_interval
| Invalid_for_loop_index
| No_value_clauses
| Exception_pattern_disallowed
| Mixed_value_and_exception_patterns_under_guard
| Effect_pattern_below_toplevel
| Invalid_continuation_pattern
| Inlined_record_escape
| Inlined_record_expected
| Unrefuted_pattern of pattern
| Invalid_extension_constructor_payload
| Not_an_extension_constructor
| Invalid_atomic_loc_payload
| Label_not_atomic of Longident.t
| Atomic_in_pattern of Longident.t
| Literal_overflow of string
| Unknown_literal of string * char
| Illegal_letrec_pat
| Illegal_letrec_expr
| Illegal_class_expr
| Letop_type_clash of string * Errortrace.unification_error
| Andop_type_clash of string * Errortrace.unification_error
| Bindings_type_clash of Errortrace.unification_error
| Unbound_existential of Ident.t list * type_expr
| Bind_existential of existential_binding * Ident.t * type_expr
| Missing_type_constraint
| Wrong_expected_kind of wrong_kind_sort * wrong_kind_context * type_expr
| Expr_not_a_record_type of type_expr
| Constructor_labeled_arg
| Partial_tuple_pattern_bad_type
| Extra_tuple_label of string option * type_expr
| Missing_tuple_label of string option * type_expr
| Repeated_tuple_exp_label of string
| Repeated_tuple_pat_label of string
let not_principal fmt =
Format_doc.Doc.kmsg (fun x -> Warnings.Not_principal x) fmt
exception Error of Location.t * Env.t * error
exception Error_forward of Location.error
(* Forward declaration, to be filled in by Typemod.type_module *)
let type_module =
ref ((fun _env _md -> assert false) :
Env.t -> Parsetree.module_expr -> Typedtree.module_expr * Shape.t)
(* Forward declaration, to be filled in by Typemod.type_open *)
let type_open :
(?used_slot:bool ref -> override_flag -> Env.t -> Location.t ->
Longident.t loc -> Path.t * Env.t)
ref =
ref (fun ?used_slot:_ _ -> assert false)
let type_open_decl :
(?used_slot:bool ref -> Env.t -> Parsetree.open_declaration
-> open_declaration * Types.signature * Env.t)
ref =
ref (fun ?used_slot:_ _ -> assert false)
(* Forward declaration, to be filled in by Typemod.type_package *)
let type_package =
ref (fun _ -> assert false)
(* Forward declaration, to be filled in by Typeclass.class_structure *)
let type_object =
ref (fun _env _s -> assert false :
Env.t -> Location.t -> Parsetree.class_structure ->
Typedtree.class_structure * string list)
(*
Saving and outputting type information.
We keep these function names short, because they have to be
called each time we create a record of type [Typedtree.expression]
or [Typedtree.pattern] that will end up in the typed AST.
*)
let re node =
Cmt_format.add_saved_type (Cmt_format.Partial_expression node);
node
let rp node =
Cmt_format.add_saved_type (Cmt_format.Partial_pattern (Value, node));
node
let rcp node =
Cmt_format.add_saved_type (Cmt_format.Partial_pattern (Computation, node));
node
(* Context for inline record arguments; see [type_ident] *)
type recarg =
| Allowed
| Required
| Rejected
let mk_expected ?explanation ty = { ty; explanation; }
let case lhs rhs =
{c_lhs = lhs; c_cont = None; c_guard = None; c_rhs = rhs}
(* Typing of constants *)
let type_constant = function
Const_int _ -> instance Predef.type_int
| Const_char _ -> instance Predef.type_char
| Const_string _ -> instance Predef.type_string
| Const_float _ -> instance Predef.type_float
| Const_int32 _ -> instance Predef.type_int32
| Const_int64 _ -> instance Predef.type_int64
| Const_nativeint _ -> instance Predef.type_nativeint
let constant_desc
: Parsetree.constant_desc -> (Asttypes.constant, error) result =
function
| Pconst_integer (i,None) ->
begin
try Ok (Const_int (Misc.Int_literal_converter.int i))
with Failure _ -> Error (Literal_overflow "int")
end
| Pconst_integer (i,Some 'l') ->
begin
try Ok (Const_int32 (Misc.Int_literal_converter.int32 i))
with Failure _ -> Error (Literal_overflow "int32")
end
| Pconst_integer (i,Some 'L') ->
begin
try Ok (Const_int64 (Misc.Int_literal_converter.int64 i))
with Failure _ -> Error (Literal_overflow "int64")
end
| Pconst_integer (i,Some 'n') ->
begin
try Ok (Const_nativeint (Misc.Int_literal_converter.nativeint i))
with Failure _ -> Error (Literal_overflow "nativeint")
end
| Pconst_integer (i,Some c) -> Error (Unknown_literal (i, c))
| Pconst_char c -> Ok (Const_char c)
| Pconst_string (s,loc,d) -> Ok (Const_string (s,loc,d))
| Pconst_float (f,None)-> Ok (Const_float f)
| Pconst_float (f,Some c) -> Error (Unknown_literal (f, c))
let constant const = constant_desc const.pconst_desc
let constant_or_raise env loc cst =
match constant cst with
| Ok c -> c
| Error err -> raise (Error (loc, env, err))
(* Specific version of type_option, using newty rather than newgenty *)
let type_option ty =
newty (Tconstr(Predef.path_option,[ty], ref Mnil))
let mkexp exp_desc exp_type exp_loc exp_env =
{ exp_desc; exp_type; exp_loc; exp_env; exp_extra = []; exp_attributes = [] }
let option_none env ty loc =
let lid = Longident.Lident "None" in
let cnone = Env.find_ident_constructor Predef.ident_none env in
mkexp (Texp_construct(mknoloc lid, cnone, [])) ty loc env
let option_some env texp =
let lid = Longident.Lident "Some" in
let csome = Env.find_ident_constructor Predef.ident_some env in
mkexp ( Texp_construct(mknoloc lid , csome, [texp]) )
(type_option texp.exp_type) texp.exp_loc texp.exp_env
let extract_option_type env ty =
match get_desc (expand_head env ty) with
Tconstr(path, [ty], _) when Path.same path Predef.path_option -> ty
| _ -> assert false
let is_floatarray_type env ty =
match get_desc (expand_head env ty) with
Tconstr(path, [], _) -> Path.same path Predef.path_floatarray
| _ -> false
let is_iarray_type env ty =
match get_desc (expand_head env ty) with
| Tconstr(path, [_], _) -> Path.same path Predef.path_iarray
| _ -> false
let protect_expansion env ty =
if Env.has_local_constraints env then generic_instance ty else ty
type record_extraction_result =
| Record_type of Path.t * Path.t * Types.label_declaration list
| Not_a_record_type
| Maybe_a_record_type
let extract_concrete_typedecl_protected env ty =
extract_concrete_typedecl env (protect_expansion env ty)
let extract_concrete_record env ty =
match extract_concrete_typedecl_protected env ty with
| Typedecl(p0, p, {type_kind=Type_record (fields, _)}) ->
Record_type (p0, p, fields)
| Has_no_typedecl | Typedecl(_, _, _) -> Not_a_record_type
| May_have_typedecl -> Maybe_a_record_type
type variant_extraction_result =
| Variant_type of Path.t * Path.t * Types.constructor_declaration list
| Not_a_variant_type
| Maybe_a_variant_type
let extract_concrete_variant env ty =
match extract_concrete_typedecl_protected env ty with
| Typedecl(p0, p, {type_kind=Type_variant (cstrs, _)}) ->
Variant_type (p0, p, cstrs)
| Typedecl(p0, p, {type_kind=Type_open}) ->
Variant_type (p0, p, [])
| Has_no_typedecl | Typedecl(_, _, _) -> Not_a_variant_type
| May_have_typedecl -> Maybe_a_variant_type
let extract_label_names env ty =
match extract_concrete_record env ty with
| Record_type (_, _,fields) -> List.map (fun l -> l.Types.ld_id) fields
| Not_a_record_type | Maybe_a_record_type -> assert false
let is_principal ty =
not !Clflags.principal || get_level ty = generic_level
(* Represents information about an array type inferred using type-directed
disambiguation. *)
type array_info =
{ ty_elt : type_expr option;
mut : mutable_flag }
let disambiguate_array_literal ~loc env expected_ty =
let return (ty_elt : type_expr option) (mut : mutable_flag) =
if not (is_principal expected_ty) then
Location.prerr_warning loc
(not_principal "this type-based array disambiguation");
{ ty_elt; mut }
in
if is_floatarray_type env expected_ty then
return (Some (instance Predef.type_float)) Mutable
else if is_iarray_type env expected_ty then
return None Immutable
else
{ ty_elt = None; mut = Mutable }
(* Typing of patterns *)
(* Simplified patterns for effect continuations *)
let type_continuation_pat env expected_ty sp =
let loc = sp.ppat_loc in
match sp.ppat_desc with
| Ppat_any -> None
| Ppat_var name ->
let id = Ident.create_local name.txt in
let desc =
{ val_type = expected_ty; val_kind = Val_reg;
Types.val_loc = loc; val_attributes = [];
val_uid = Uid.mk ~current_unit:(Env.get_current_unit ()); }
in
Some (id, desc)
| Ppat_extension ext ->
raise (Error_forward (Builtin_attributes.error_of_extension ext))
| _ -> raise (Error (loc, env, Invalid_continuation_pattern))
(* unification inside type_exp and type_expect *)
let unify_exp_types loc env ty expected_ty =
(* Format.eprintf "@[%a@ %a@]@." Printtyp.raw_type_expr exp.exp_type
Printtyp.raw_type_expr expected_ty; *)
try
unify env ty expected_ty
with
Unify err ->
raise(Error(loc, env, Expr_type_clash(err, None, None)))
| Tags(l1,l2) ->
raise(Typetexp.Error(loc, env, Typetexp.Variant_tags (l1, l2)))
(* Getting proper location of already typed expressions.
Used to avoid confusing locations on type error messages in presence of
type constraints.
For example:
(* Before patch *)
# let x : string = (5 : int);;
^
(* After patch *)
# let x : string = (5 : int);;
^^^^^^^^^
*)
let proper_exp_loc exp =
let rec aux = function
| [] -> exp.exp_loc
| ((Texp_constraint _ | Texp_coerce _), loc, _) :: _ -> loc
| _ :: rest -> aux rest
in
aux exp.exp_extra
(** [sexp] is used by error messages to report literals in their
original formatting *)
let unify_exp ~sexp env exp expected_ty =
let loc = proper_exp_loc exp in
try
unify_exp_types loc env exp.exp_type expected_ty
with Error(loc, env, Expr_type_clash(err, tfc, None)) ->
raise (Error(loc, env, Expr_type_clash(err, tfc, Some sexp)))
(* helper notation for Pattern_env.t *)
let (!!) (penv : Pattern_env.t) = penv.env
(* Unification inside type_pat *)
(* If [penv] is available, calling this function requires
[penv.in_counterexample = false] *)
let unify_pat_types loc env ty ty' =
try unify env ty ty' with
| Unify err ->
raise(Error(loc, env, Pattern_type_clash(err, None)))
| Tags(l1,l2) ->
raise(Typetexp.Error(loc, env, Typetexp.Variant_tags (l1, l2)))
(* GADT unification inside solve_Ppat_construct and check_counter_example_pat *)
(* We need to distinguish [pat] and [expected] if [refine = true] and
[penv.in_counterexample = false] (see [unify_gadt] for details) *)
let nothing_equated = TypePairs.create 0
let unify_pat_types_return_equated_pairs ~refine loc penv ~pat ~expected =
try
if refine || penv.Pattern_env.in_counterexample
then unify_gadt penv ~pat ~expected
else (unify !!penv pat expected; nothing_equated)
with
| Unify err ->
raise(Error(loc, !!penv, Pattern_type_clash(err, None)))
| Tags(l1,l2) ->
raise(Typetexp.Error(loc, !!penv, Typetexp.Variant_tags (l1, l2)))
(* Unify pattern types in functions that can be called either from
[type_pat] or [check_counter_example_pat].
Since it calls normal unification when [penv.in_counterexample = false],
or [unify_gadt] when [penv.in_counterexample = true],
[ty] and [ty'] always have symmetric roles. *)
let unify_pat_types_penv loc penv ty ty' =
(* [penv.in_counterexample = true] only in calls originating
from [check_counter_example_pat],
which in turn may contain only non-leaking type variables *)
ignore (unify_pat_types_return_equated_pairs ~refine:false loc penv
~pat:ty ~expected:ty')
(** [sdesc_for_hint] is used by error messages to report literals in their
original formatting *)
(* If [penv] is available, calling this function requires
[penv.in_counterexample = false] *)
let unify_pat ?sdesc_for_hint env pat expected_ty =
try unify_pat_types pat.pat_loc env pat.pat_type expected_ty
with Error (loc, env, Pattern_type_clash(err, None)) ->
raise(Error(loc, env, Pattern_type_clash(err, sdesc_for_hint)))
(* unification of a type with a Tconstr with freshly created arguments *)
let unify_head_only loc penv constr ~expected:ty =
let path = cstr_res_type_path constr in
let decl = Env.find_type path !!penv in
let ty' = Ctype.newconstr path (Ctype.instance_list decl.type_params) in
unify_pat_types_penv loc penv ty' ty
(* Creating new conjunctive types is not allowed when typing patterns *)
(* make all Reither present in open variants *)
let finalize_variant pat tag opat r =
let row =
match get_desc (expand_head pat.pat_env pat.pat_type) with
Tvariant row -> r := row; row
| _ -> assert false
in
let f = get_row_field tag row in
begin match row_field_repr f with
| Rabsent -> () (* assert false *)
| Reither (true, [], _) when not (row_closed row) ->
link_row_field_ext ~inside:f (rf_present None)
| Reither (false, ty::tl, _) when not (row_closed row) ->
link_row_field_ext ~inside:f (rf_present (Some ty));
begin match opat with None -> assert false
| Some pat -> List.iter (unify_pat pat.pat_env pat) (ty::tl)
end
| Reither (c, _l, true) when not (has_fixed_explanation row) ->
link_row_field_ext ~inside:f (rf_either [] ~no_arg:c ~matched:false)
| _ -> ()
end
(* Force check of well-formedness WHY? *)
(* unify_pat pat.pat_env pat
(newty(Tvariant{row_fields=[]; row_more=newvar(); row_closed=false;
row_bound=(); row_fixed=false; row_name=None})); *)
let has_variants p =
exists_general_pattern
{ f = fun (type k) (p : k general_pattern) -> match p.pat_desc with
| (Tpat_variant _) -> true
| _ -> false } p
let finalize_variants p =
iter_general_pattern
{ f = fun (type k) (p : k general_pattern) -> match p.pat_desc with
| Tpat_variant(tag, opat, r) ->
finalize_variant p tag opat r
| _ -> () } p
(* [type_pat_state] and related types for pattern environment;
these should not be confused with Pattern_env.t, which is a part of the
interface to unification functions in [Ctype] *)
type pattern_variable_kind =
| Std_var
| As_var
| Continuation_var
type pattern_variable =
{
pv_id: Ident.t;
pv_type: type_expr;
pv_loc: Location.t;
pv_kind: pattern_variable_kind;
pv_attributes: attributes;
pv_uid : Uid.t;
}
type module_variable =
{
mv_id: Ident.t;
mv_name: string Location.loc;
mv_loc: Location.t;
mv_uid: Uid.t
}
(* Whether or not patterns of the form (module M) are accepted. (If they are,
the idents will be created at the provided scope.) When module patterns are
allowed, the caller should take care to check that the introduced module
bindings' types don't escape their scope; see the callsites in [type_let]
and [type_cases] for examples.
[Modules_ignored] indicates that the typing of patterns should not accumulate
a list of module patterns to unpack. It's no different than using
[Modules_allowed] and then ignoring the accumulated [module_variables] list,
but signals more clearly that the module patterns aren't used in an
interesting way.
*)
type module_patterns_restriction =
| Modules_allowed of { scope: int }
| Modules_rejected
| Modules_ignored
(* A parallel type to [module_patterns_restriction], though also
tracking the module variables encountered.
*)
type module_variables =
| Modvars_allowed of
{ scope: int;
module_variables: module_variable list;
}
| Modvars_rejected
| Modvars_ignored
type type_pat_state =
{ mutable tps_pattern_variables: pattern_variable list;
mutable tps_pattern_force: (unit -> unit) list;
mutable tps_module_variables: module_variables;
(* Mutation will not change the constructor of [tps_module_variables], just
the contained [module_variables] list. [module_variables] could be made
mutable instead, but we felt this made the code more awkward.
*)
}
let continuation_variable = function
| None -> []
| Some (id, (desc:Types.value_description)) ->
[{pv_id = id;
pv_type = desc.val_type;
pv_loc = desc.val_loc;
pv_kind = Continuation_var;
pv_attributes = desc.val_attributes;
pv_uid= desc.val_uid}]
let create_type_pat_state ?cont allow_modules =
let tps_module_variables =
match allow_modules with
| Modules_allowed { scope } ->
Modvars_allowed { scope; module_variables = [] }
| Modules_ignored -> Modvars_ignored
| Modules_rejected -> Modvars_rejected
in
{ tps_pattern_variables = continuation_variable cont;
tps_module_variables;
tps_pattern_force = [];
}
(* Copy mutable fields. Used in typechecking or-patterns. *)
let copy_type_pat_state
{ tps_pattern_variables;
tps_module_variables;
tps_pattern_force;
}
=
{ tps_pattern_variables;
tps_module_variables;
tps_pattern_force;
}
let blit_type_pat_state ~src ~dst =
dst.tps_pattern_variables <- src.tps_pattern_variables;
dst.tps_module_variables <- src.tps_module_variables;
dst.tps_pattern_force <- src.tps_pattern_force;
;;
let maybe_add_pattern_variables_ghost loc_let env pv =
List.fold_right
(fun {pv_id; _} env ->
let name = Ident.name pv_id in
if Env.bound_value name env then env
else begin
Env.enter_unbound_value name
(Val_unbound_ghost_recursive loc_let) env
end
) pv env
let enter_variable ?(is_module=false) ?(is_as_variable=false) tps loc name ty
attrs =
if List.exists (fun {pv_id; _} -> Ident.name pv_id = name.txt)
tps.tps_pattern_variables
then raise(Error(loc, Env.empty, Multiply_bound_variable name.txt));
let id =
if is_module then begin
(* Unpack patterns result in both a module declaration and a value
variable of the same name being entered into the environment. (The
module is via [tps_module_variables], and the variable is via
[tps_pattern_variables].) *)
match tps.tps_module_variables with
| Modvars_ignored -> Ident.create_local name.txt
| Modvars_rejected ->
raise (Error (loc, Env.empty, Modules_not_allowed));
| Modvars_allowed { scope; module_variables } ->
let id = Ident.create_scoped name.txt ~scope in
let module_variables =
{ mv_id = id;
mv_name = name;
mv_loc = loc;
mv_uid = Uid.mk ~current_unit:(Env.get_current_unit ());
} :: module_variables
in
tps.tps_module_variables <-
Modvars_allowed { scope; module_variables; };
id
end else
Ident.create_local name.txt
in
let pv_uid = Uid.mk ~current_unit:(Env.get_current_unit ()) in
tps.tps_pattern_variables <-
{pv_id = id;
pv_type = ty;
pv_loc = loc;
pv_kind = if is_as_variable then As_var else Std_var;
pv_attributes = attrs;
pv_uid} :: tps.tps_pattern_variables;
id, pv_uid
let sort_pattern_variables vs =
List.sort
(fun {pv_id = x; _} {pv_id = y; _} ->
Stdlib.compare (Ident.name x) (Ident.name y))
vs
let enter_orpat_variables loc env p1_vs p2_vs =
(* unify_vars operate on sorted lists *)
let p1_vs = sort_pattern_variables p1_vs
and p2_vs = sort_pattern_variables p2_vs in
let rec unify_vars p1_vs p2_vs =
let vars vs = List.map (fun {pv_id; _} -> pv_id) vs in
match p1_vs, p2_vs with
| {pv_id = x1; pv_type = t1; _}::rem1, {pv_id = x2; pv_type = t2; _}::rem2
when Ident.equal x1 x2 ->
if x1==x2 then
unify_vars rem1 rem2
else begin
begin try
unify_var env (newvar ()) t1;
unify env t1 t2
with
| Unify err ->
raise(Error(loc, env, Or_pattern_type_clash(x1, err)))
end;
(x2,x1)::unify_vars rem1 rem2
end
| [],[] -> []
| {pv_id; _}::_, [] | [],{pv_id; _}::_ ->
raise (Error (loc, env, Orpat_vars (pv_id, [])))
| {pv_id = x; _}::_, {pv_id = y; _}::_ ->
let err =
if Ident.name x < Ident.name y
then Orpat_vars (x, vars p2_vs)
else Orpat_vars (y, vars p1_vs) in
raise (Error (loc, env, err)) in
unify_vars p1_vs p2_vs
let rec build_as_type (env : Env.t) p =
build_as_type_extra env p p.pat_extra
and build_as_type_extra env p = function
| [] -> build_as_type_aux env p
| ((Tpat_type _ | Tpat_open _ | Tpat_unpack), _, _) :: rest ->
build_as_type_extra env p rest
| (Tpat_constraint {ctyp_type = ty; _}, _, _) :: rest ->
(* If the type constraint is ground, then this is the best type
we can return, so just return an instance (cf. #12313) *)
if closed_type_expr ty then instance ty else
(* Otherwise we combine the inferred type for the pattern with
then non-ground constraint in a non-ambivalent way *)
let as_ty = build_as_type_extra env p rest in
(* [generic_instance] can only be used if the variables of the original
type ([cty.ctyp_type] here) are not at [generic_level], which they are
here.
If we used [generic_instance] we would lose the sharing between
[instance ty] and [ty]. *)
let ty =
with_local_level_generalize_structure (fun () -> instance ty)
in
(* This call to unify may only fail due to missing GADT equations *)
unify_pat_types p.pat_loc env (instance as_ty) (instance ty);
ty
and build_as_type_aux (env : Env.t) p =
match p.pat_desc with
Tpat_alias(p1,_, _, _, _) -> build_as_type env p1
| Tpat_tuple pl ->
let labeled_tyl =
List.map (fun (label, p) -> label, build_as_type env p) pl in
newty (Ttuple labeled_tyl)
| Tpat_construct(_, cstr, pl, vto) ->
let keep =
cstr.cstr_private = Private || cstr.cstr_existentials <> [] ||
vto <> None (* be lazy and keep the type for node constraints *) in
if keep then p.pat_type else
let tyl = List.map (build_as_type env) pl in
let ty_args, ty_res, _ =
instance_constructor Keep_existentials_flexible cstr
in
List.iter2 (fun (p,ty) -> unify_pat env {p with pat_type = ty})
(List.combine pl tyl) ty_args;
ty_res
| Tpat_variant(l, p', _) ->
let ty = Option.map (build_as_type env) p' in
let fields = [l, rf_present ty] in
newty (Tvariant (create_row ~fields ~more:(newvar())
~name:None ~fixed:None ~closed:false))
| Tpat_record (lpl,_) ->
let lbl = snd3 (List.hd lpl) in
if lbl.lbl_private = Private then p.pat_type else
let ty = newvar () in
let ppl = List.map (fun (_, l, p) -> l.lbl_pos, p) lpl in
let do_label lbl =
let _, ty_arg, ty_res = instance_label ~fixed:false lbl in
unify_pat env {p with pat_type = ty} ty_res;
let refinable =
lbl.lbl_mut = Immutable && List.mem_assoc lbl.lbl_pos ppl &&
match get_desc lbl.lbl_arg with Tpoly _ -> false | _ -> true in
if refinable then begin
let arg = List.assoc lbl.lbl_pos ppl in
unify_pat env {arg with pat_type = build_as_type env arg} ty_arg
end else begin
let _, ty_arg', ty_res' = instance_label ~fixed:false lbl in
unify_pat_types p.pat_loc env ty_arg ty_arg';
unify_pat env p ty_res'
end in
Array.iter do_label lbl.lbl_all;
ty
| Tpat_or(p1, p2, row) ->
begin match row with
None ->
let ty1 = build_as_type env p1 and ty2 = build_as_type env p2 in
unify_pat env {p2 with pat_type = ty2} ty1;
ty1
| Some row ->
let Row {fields; fixed; name} = row_repr row in
newty (Tvariant (create_row ~fields ~fixed ~name
~closed:false ~more:(newvar())))
end
| Tpat_any | Tpat_var _ | Tpat_constant _
| Tpat_array _ | Tpat_lazy _ -> p.pat_type
(* Constraint solving during typing of patterns *)
let solve_Ppat_poly_constraint tps env loc sty expected_ty =
let cty, ty, force = Typetexp.transl_simple_type_delayed env sty in
unify_pat_types loc env ty (instance expected_ty);
tps.tps_pattern_force <- force :: tps.tps_pattern_force;
match get_desc ty with
| Tpoly (body, tyl) ->
let _, ty' =
with_level ~level:generic_level
(fun () -> instance_poly ~keep_names:true ~fixed:false tyl body)
in
(cty, ty, ty')
| _ -> assert false
let solve_Ppat_alias env pat =
with_local_level_generalize (fun () -> build_as_type env pat)
(* Extracts the first element from a list matching a label. Roughly:
pat <- List.assoc_opt label patl;
return (pat, List.remove_assoc label patl)
*)
let extract_pat label patl =
let rec extract_pat_aux acc = function
| [] -> None
| ((label', t) as pat) :: rest ->
if Option.equal String.equal label label' then
Some (t, List.rev_append acc rest)
else
extract_pat_aux (pat::acc) rest
in
extract_pat_aux [] patl
let extract_or_mk_pat label rem closed =
match extract_pat label rem, closed with
(* Take the first match from patl *)
| (Some _ as pat_and_rem), _ -> pat_and_rem
(* No match, but the partial pattern allows us to generate a _ *)
| None, Open -> Some (Ast_helper.Pat.mk Ppat_any, rem)
| None, Closed -> None
(* Reorders [patl] to match the label order in [labeled_tl], erroring if [patl]
is missing a label or has an a extra label (unlabeled components morally
share the same special label).
If [closed] is [Open], then no "missing label" errors are possible; instead,
[_] patterns will be generated for those labels. An unnecessarily [Open]
pattern results in a warning.
*)
let reorder_pat loc penv patl closed labeled_tl expected_ty =
let take_next (taken, rem) (label, _) =
match extract_or_mk_pat label rem closed with
| Some (pat, rem) -> (label, pat) :: taken, rem
| None ->
raise (Error (loc, !!penv, Missing_tuple_label(label, expected_ty)))
in
match List.fold_left take_next ([], patl) labeled_tl with
| taken, [] ->
if closed = Open
&& Int.equal (List.length labeled_tl) (List.length patl) then
Location.prerr_warning loc Warnings.Unnecessarily_partial_tuple_pattern;
List.rev taken
| _, (extra_label, _) :: _ ->
raise
(Error (loc, !!penv, Extra_tuple_label(extra_label, expected_ty)))
(* This assumes the [args] have already been reordered according to the
[expected_ty], if needed. *)
let solve_Ppat_tuple loc env args expected_ty =
let vars = List.map (fun (label, _) -> (label, newgenvar ())) args in
let ty = newgenty (Ttuple vars) in
let expected_ty = generic_instance expected_ty in
unify_pat_types_penv loc env ty expected_ty;
vars
let solve_constructor_annotation
tps (penv : Pattern_env.t) name_list sty ty_args ty_ex unify_res =
assert (not penv.in_counterexample);
let expansion_scope = penv.equations_scope in
(* Introduce fresh type names that expand to type variables.
They should eventually be bound to ground types. *)
let ids_decls =
List.map
(fun name ->
let tv = newvar () in
let decl =
new_local_type ~loc:name.loc Definition
~manifest_and_scope:(tv, Ident.lowest_scope) in
let (id, new_env) =
Env.enter_type ~scope:expansion_scope name.txt decl !!penv in
Pattern_env.set_env penv new_env;
({name with txt = id}, (decl, tv)))
name_list
in
(* Translate the type annotation using these type names. *)
let cty, ty, force =
with_local_level_generalize_structure
(fun () -> Typetexp.transl_simple_type_delayed !!penv sty)
in
tps.tps_pattern_force <- force :: tps.tps_pattern_force;
(* Only unify the return type after generating the ids *)
unify_res ();
let ty_args =
let ty1 = instance ty and ty2 = instance ty in
match ty_args with
[] -> assert false
| [ty_arg] ->
unify_pat_types cty.ctyp_loc !!penv ty1 ty_arg;
[ty2]
| _ ->
unify_pat_types cty.ctyp_loc !!penv ty1
(newty (Ttuple (List.map (fun t -> None, t) ty_args)));
match get_desc (expand_head !!penv ty2) with
Ttuple tyl -> List.map snd tyl
| _ -> assert false
in
if ids_decls <> [] then begin
let ids_decls = List.map (fun (x,dm) -> (x.txt,dm)) ids_decls in
let ids = List.map fst ids_decls in
let rem =
(* First process the existentials introduced by this constructor.
Just need to make their definitions abstract. *)
List.fold_left
(fun rem tv ->
match get_desc tv with
Tconstr(Path.Pident id, [], _) when List.mem_assoc id rem ->
let decl, tv' = List.assoc id ids_decls in
let env =
Env.add_type ~check:false id
{decl with type_manifest = None} !!penv
in
Pattern_env.set_env penv env;
(* We have changed the definition, so clean up *)
Btype.cleanup_abbrev ();
(* Since id is now abstract, this does not create a cycle *)
unify_pat_types cty.ctyp_loc env tv tv';
List.remove_assoc id rem
| _ ->
raise (Error (cty.ctyp_loc, !!penv,
Unbound_existential (ids, ty))))
ids_decls ty_ex
in
(* The other type names should be bound to newly introduced existentials. *)
let bound_ids = ref ids in
List.iter
(fun (id, (decl, tv')) ->
let tv' = expand_head !!penv tv' in
begin match get_desc tv' with
| Tconstr (Path.Pident id', [], _) ->
if List.exists (Ident.same id') !bound_ids then
raise (Error (cty.ctyp_loc, !!penv,
Bind_existential (Bind_already_bound, id, tv')));
(* Both id and id' are Scoped identifiers, so their stamps grow *)
if Ident.scope id' <> penv.equations_scope
|| Ident.compare_stamp id id' > 0 then
raise (Error (cty.ctyp_loc, !!penv,
Bind_existential (Bind_not_in_scope, id, tv')));
bound_ids := id' :: !bound_ids
| _ ->
raise (Error (cty.ctyp_loc, !!penv,
Bind_existential
(Bind_non_locally_abstract, id, tv')));
end;
let env =
Env.add_type ~check:false id
{decl with type_manifest = Some (duplicate_type tv')} !!penv
in
Pattern_env.set_env penv env)
rem;
if rem <> [] then Btype.cleanup_abbrev ();
end;
ty_args, Some (List.map fst ids_decls, cty)
let solve_Ppat_construct tps (penv : Pattern_env.t) loc constr no_existentials
existential_styp expected_ty =
(* if constructor is gadt, we must verify that the expected type has the
correct head *)
if constr.cstr_generalized then
unify_head_only loc penv constr ~expected:(instance expected_ty);
(* PR#7214: do not use gadt unification for toplevel lets *)
let unify_res ty_res expected_ty =
let refine = constr.cstr_generalized && no_existentials = None in
(* Here [ty_res] contains only fresh (non-leaking) type variables,
so the requirement of [unify_gadt] is fulfilled. *)
unify_pat_types_return_equated_pairs ~refine loc penv ~pat:ty_res
~expected:expected_ty
in
let ty_args, equated_types, existential_ctyp =
with_local_level_generalize_structure begin fun () ->
let expected_ty = instance expected_ty in
let ty_args, ty_res, equated_types, existential_ctyp =
match existential_styp with
None ->
let ty_args, ty_res, _ =
instance_constructor (Make_existentials_abstract penv) constr
in
ty_args, ty_res, unify_res ty_res expected_ty, None
| Some (name_list, sty) ->
let existential_treatment =
if name_list = [] then
Make_existentials_abstract penv
else
(* we will unify them (in solve_constructor_annotation) with the
local types provided by the user *)
Keep_existentials_flexible
in
let ty_args, ty_res, ty_ex =
instance_constructor existential_treatment constr
in
let equated_types = lazy (unify_res ty_res expected_ty) in
let ty_args, existential_ctyp =
solve_constructor_annotation tps penv name_list sty ty_args ty_ex
(fun () -> ignore (Lazy.force equated_types))
in
ty_args, ty_res, Lazy.force equated_types, existential_ctyp
in
if constr.cstr_existentials <> [] then
lower_variables_only !!penv penv.Pattern_env.equations_scope ty_res;
(ty_args, equated_types, existential_ctyp)
end
in
if !Clflags.principal && not penv.in_counterexample then begin
(* Do not warn for counter-examples *)
let exception Warn_only_once in
try
TypePairs.iter
(fun (t1, t2) ->
if not (fully_generic t1 && fully_generic t2) then
let msg =
Format_doc.doc_printf
"typing this pattern requires considering@ @[%a@]@ and@ \
@[%a@]@ as@ equal.@ \
But@ the@ knowledge@ of@ these@ types"
(Style.as_inline_code Printtyp.Doc.type_expr) t1
(Style.as_inline_code Printtyp.Doc.type_expr) t2
in
Location.prerr_warning loc (Warnings.Not_principal msg);
raise Warn_only_once)
equated_types
with Warn_only_once -> ()
end;
(ty_args, existential_ctyp)
let solve_Ppat_record_field loc penv label label_lid record_ty =
with_local_level_generalize_structure begin fun () ->
let (_, ty_arg, ty_res) = instance_label ~fixed:false label in
begin try
unify_pat_types_penv loc penv ty_res (instance record_ty)
with Error(_loc, _env, Pattern_type_clash(err, _)) ->
raise(Error(label_lid.loc, !!penv,
Label_mismatch(label_lid.txt, err)))
end;
ty_arg
end
let solve_Ppat_array loc env expected_ty =
let expected_ty = generic_instance expected_ty in
match disambiguate_array_literal ~loc !!env expected_ty with
| { ty_elt = Some ty_elt; mut } -> ty_elt, mut
| { ty_elt = None; mut } ->
let array_type = match mut with
| Immutable -> Predef.type_iarray
| Mutable -> Predef.type_array
in
let ty_elt = newgenvar() in
unify_pat_types_penv loc env (array_type ty_elt) expected_ty;
ty_elt, mut
let solve_Ppat_lazy loc env expected_ty =
let nv = newgenvar () in
unify_pat_types_penv loc env (Predef.type_lazy_t nv)
(generic_instance expected_ty);
nv
let solve_Ppat_constraint tps loc env sty expected_ty =
let cty, ty, force =
with_local_level_generalize_structure
(fun () -> Typetexp.transl_simple_type_delayed env sty)
in
tps.tps_pattern_force <- force :: tps.tps_pattern_force;
let ty, expected_ty' = instance ty, ty in
unify_pat_types loc env ty (instance expected_ty);
(cty, ty, expected_ty')
let solve_Ppat_variant loc env tag no_arg expected_ty =
let arg_type = if no_arg then [] else [newgenvar()] in
let fields = [tag, rf_either ~no_arg arg_type ~matched:true] in
let make_row more =
create_row ~fields ~closed:false ~more ~fixed:None ~name:None
in
let row = make_row (newgenvar ()) in
let expected_ty = generic_instance expected_ty in
(* PR#7404: allow some_private_tag blindly, as it would not unify with
the abstract row variable *)
if tag <> Parmatch.some_private_tag then
unify_pat_types_penv loc env (newgenty(Tvariant row)) expected_ty;
(arg_type, make_row (newvar ()), instance expected_ty)
(* Building the or-pattern corresponding to a polymorphic variant type *)
let build_or_pat env loc lid =
let path, decl = Env.lookup_type ~loc:lid.loc lid.txt env in
let tyl = List.map (fun _ -> newvar()) decl.type_params in
let row0 =
let ty = expand_head env (newty(Tconstr(path, tyl, ref Mnil))) in
match get_desc ty with
Tvariant row when static_row row -> row
| _ -> raise(Error(lid.loc, env, Not_a_polymorphic_variant_type lid.txt))
in
let pats, fields =
List.fold_left
(fun (pats,fields) (l,f) ->
match row_field_repr f with
Rpresent None ->
let f = rf_either [] ~no_arg:true ~matched:true in
(l,None) :: pats,
(l, f) :: fields
| Rpresent (Some ty) ->
let f = rf_either [ty] ~no_arg:false ~matched:true in
(l, Some {pat_desc=Tpat_any; pat_loc=Location.none; pat_env=env;
pat_type=ty; pat_extra=[]; pat_attributes=[]})
:: pats,
(l, f) :: fields
| _ -> pats, fields)
([],[]) (row_fields row0) in
let fields = List.rev fields in
let name = Some (path, tyl) in
let make_row more =
create_row ~fields ~more ~closed:false ~fixed:None ~name in
let ty = newty (Tvariant (make_row (newvar()))) in
let gloc = {loc with Location.loc_ghost=true} in
let row' = ref (make_row (newvar())) in
let pats =
List.map
(fun (l,p) ->
{pat_desc=Tpat_variant(l,p,row'); pat_loc=gloc;
pat_env=env; pat_type=ty; pat_extra=[]; pat_attributes=[]})
pats
in
match pats with
[] ->
(* empty polymorphic variants: not possible with the concrete language
but valid at the ast level *)
raise(Error(lid.loc, env, Not_a_polymorphic_variant_type lid.txt))
| pat :: pats ->
let r =
List.fold_left
(fun pat pat0 ->
{pat_desc=Tpat_or(pat0,pat,Some row0); pat_extra=[];
pat_loc=gloc; pat_env=env; pat_type=ty; pat_attributes=[]})
pat pats in
(path, rp { r with pat_loc = loc })
(* Type paths *)
let rec expand_path env p =
let decl =
try Some (Env.find_type p env) with Not_found -> None
in
match decl with
Some {type_manifest = Some ty} ->
begin match get_desc ty with
Tconstr(p,_,_) -> expand_path env p
| _ -> assert false
end
| _ ->
let p' = Env.normalize_type_path None env p in
if Path.same p p' then p else expand_path env p'
let compare_type_path env tpath1 tpath2 =
Path.same (expand_path env tpath1) (expand_path env tpath2)
(* Records *)
exception Wrong_name_disambiguation of Env.t * wrong_name
let get_constr_type_path ty =
match get_desc ty with
| Tconstr(p, _, _) -> p
| _ -> assert false
module NameChoice(Name : sig
type t
type usage
val kind: Datatype_kind.t
val get_name: t -> string
val get_type: t -> type_expr
val lookup_all_from_type:
Location.t -> usage -> Path.t -> Env.t -> (t * (unit -> unit)) list
(** Some names (for example the fields of inline records) are not
in the typing environment -- they behave as structural labels
rather than nominal labels.*)
val in_env: t -> bool
end) = struct
open Name
let get_type_path d = get_constr_type_path (get_type d)
let lookup_from_type env type_path usage lid =
let descrs = lookup_all_from_type lid.loc usage type_path env in
match lid.txt with
| Longident.Lident name -> begin
match
List.find (fun (nd, _) -> get_name nd = name) descrs
with
| descr, use ->
use ();
descr
| exception Not_found ->
let valid_names = List.map (fun (nd, _) -> get_name nd) descrs in
raise (Wrong_name_disambiguation (env, {
type_path;
name = { lid with txt = name };
kind;
valid_names;
}))
end
| _ -> raise Not_found
let rec unique eq acc = function
[] -> List.rev acc
| x :: rem ->
if List.exists (eq x) acc then unique eq acc rem
else unique eq (x :: acc) rem
let ambiguous_types env lbl others =
let tpath = get_type_path lbl in
let others =
List.map (fun (lbl, _) -> get_type_path lbl) others in
let tpaths = unique (compare_type_path env) [tpath] others in
match tpaths with
[_] -> []
| _ -> let open Printtyp in
wrap_printing_env ~error:true env (fun () ->
Out_type.reset(); strings_of_paths Type tpaths)
let disambiguate_by_type env tpath lbls =
match lbls with
| (Error _ : _ result) -> raise Not_found
| Ok lbls ->
let check_type (lbl, _) =
let lbl_tpath = get_type_path lbl in
compare_type_path env tpath lbl_tpath
in
List.find check_type lbls
(* warn if there are several distinct candidates in scope *)
let warn_if_ambiguous warn lid env lbl rest =
if Warnings.is_active (Ambiguous_name ([],[],false,"")) then begin
Out_type.Ident_conflicts.reset ();
let paths = ambiguous_types env lbl rest in
let expansion = match Out_type.Ident_conflicts.err_msg () with
| None -> ""
| Some msg -> Format_doc.(asprintf "%a" pp_doc) msg
in
if paths <> [] then
warn lid.loc
(Warnings.Ambiguous_name ([Longident.last lid.txt],
paths, false, expansion))
end
(* a non-principal type was used for disambiguation *)
let warn_non_principal warn lid =
let name = Datatype_kind.label_name kind in
warn lid.loc
(not_principal "this type-based %s disambiguation" name)
(* we selected a name out of the lexical scope *)
let warn_out_of_scope warn lid env tpath =
if Warnings.is_active (Name_out_of_scope ("",[],false)) then begin
let path_s =
Printtyp.wrap_printing_env ~error:true env
(fun () -> Format_doc.asprintf "%a" Printtyp.Doc.type_path tpath)
in
warn lid.loc
(Warnings.Name_out_of_scope (path_s, [Longident.last lid.txt], false))
end
(* warn if the selected name is not the last introduced in scope
-- in these cases the resolution is different from pre-disambiguation OCaml
(this warning is not enabled by default, it is specifically for people
wishing to write backward-compatible code).
*)
let warn_if_disambiguated_name warn lid lbl scope =
match scope with
| Ok ((lab1,_) :: _) when lab1 == lbl -> ()
| _ ->
warn lid.loc
(Warnings.Disambiguated_name (get_name lbl))
let force_error : ('a, _) result -> 'a = function
| Ok lbls -> lbls
| Error (loc', env', err) ->
Env.lookup_error loc' env' err
type candidate = t * (unit -> unit)
type nonempty_candidate_filter =
candidate list -> (candidate list, candidate list) result
(** This type is used for candidate filtering functions.
Filtering typically proceeds in several passes, filtering
candidates through increasingly precise conditions.
We assume that the input list is non-empty, and the output is one of
- [Ok result] for a non-empty list [result] of valid candidates
- [Error candidates] with there are no valid candidates,
and [candidates] is a non-empty subset of the input, typically
the result of the last non-empty filtering step.
*)
(** [disambiguate] selects a concrete description for [lid] using
some contextual information:
- An optional [expected_type].
- A list of candidates labels in the current lexical scope,
[candidates_in_scope], that is actually at the type
[(label_descr list, lookup_error) result] so that the
lookup error is only raised when necessary.
- A filtering criterion on candidates in scope [filter_candidates],
representing extra contextual information that can help
candidate selection (see [disambiguate_label_by_ids]).
*)
let disambiguate
?(warn=Location.prerr_warning)
?(filter : nonempty_candidate_filter = Result.ok)
usage lid env
expected_type
candidates_in_scope =
let lbl = match expected_type with
| None ->
(* no expected type => no disambiguation *)
begin match filter (force_error candidates_in_scope) with
| Ok [] | Error [] -> assert false
| Error((lbl, _use) :: _rest) -> lbl (* will fail later *)
| Ok((lbl, use) :: rest) ->
use ();
warn_if_ambiguous warn lid env lbl rest;
lbl
end
| Some(tpath0, tpath, principal) ->
(* If [expected_type] is available, the candidate selected
will correspond to the type-based resolution.
There are two reasons to still check the lexical scope:
- for warning purposes
- for extension types, the type environment does not contain
a list of constructors, so using only type-based selection
would fail.
*)
(* note that [disambiguate_by_type] does not
force [candidates_in_scope]: we just skip this case if there
are no candidates in scope *)
begin match disambiguate_by_type env tpath candidates_in_scope with
| lbl, use ->
use ();
if not principal then begin
(* Check if non-principal type is affecting result *)
match (candidates_in_scope : _ result) with
| Error _ -> warn_non_principal warn lid
| Ok lbls ->
match filter lbls with
| Error _ -> warn_non_principal warn lid
| Ok [] -> assert false
| Ok ((lbl', _use') :: rest) ->
let lbl_tpath = get_type_path lbl' in
(* no principality warning if the non-principal
type-based selection corresponds to the last
definition in scope *)
if not (compare_type_path env tpath lbl_tpath)
then warn_non_principal warn lid
else warn_if_ambiguous warn lid env lbl rest;
end;
lbl
| exception Not_found ->
(* look outside the lexical scope *)
match lookup_from_type env tpath usage lid with
| lbl ->
(* warn only on nominal labels;
structural labels cannot be qualified anyway *)
if in_env lbl then warn_out_of_scope warn lid env tpath;
if not principal then warn_non_principal warn lid;
lbl
| exception Not_found ->
match filter (force_error candidates_in_scope) with
| Ok lbls | Error lbls ->
let tp = (tpath0, expand_path env tpath) in
let tpl =
List.map
(fun (lbl, _) ->
let tp0 = get_type_path lbl in
let tp = expand_path env tp0 in
(tp0, tp))
lbls
in
raise (Error (lid.loc, env,
Name_type_mismatch (kind, lid.txt, tp, tpl)));
end
in
(* warn only on nominal labels *)
if in_env lbl then
warn_if_disambiguated_name warn lid lbl candidates_in_scope;
lbl
end
let wrap_disambiguate msg ty f x =
try f x with
| Wrong_name_disambiguation (env, wrong_name) ->
raise (Error (wrong_name.name.loc, env, Wrong_name (msg, ty, wrong_name)))
module Label = NameChoice (struct
type t = label_description
type usage = Env.label_usage
let kind = Datatype_kind.Record
let get_name lbl = lbl.lbl_name
let get_type lbl = lbl.lbl_res
let lookup_all_from_type loc usage path env =
Env.lookup_all_labels_from_type ~loc usage path env
let in_env lbl =
match lbl.lbl_repres with
| Record_regular | Record_float | Record_unboxed false -> true
| Record_unboxed true | Record_inlined _ | Record_extension _ -> false
end)
(* In record-construction expressions and patterns, we have many labels
at once; find a candidate type in the intersection of the candidates
of each label. In the [closed] expression case, this candidate must
contain exactly all the labels.
If our successive refinements result in an empty list,
return [Error] with the last non-empty list of candidates
for use in error messages.
*)
let disambiguate_label_by_ids closed ids labels : (_, _) result =
let check_ids (lbl, _) =
let lbls = Hashtbl.create 8 in
Array.iter (fun lbl -> Hashtbl.add lbls lbl.lbl_name ()) lbl.lbl_all;
List.for_all (Hashtbl.mem lbls) ids
and check_closed (lbl, _) =
(not closed || List.length ids = Array.length lbl.lbl_all)
in
match List.filter check_ids labels with
| [] -> Error labels
| labels ->
match List.filter check_closed labels with
| [] -> Error labels
| labels ->
Ok labels
(* Only issue warnings once per record constructor/pattern *)
let disambiguate_lid_a_list loc closed env usage expected_type lid_a_list =
let ids = List.map (fun (lid, _) -> Longident.last lid.txt) lid_a_list in
let w_pr = ref false and w_amb = ref []
and w_scope = ref [] and w_scope_ty = ref "" in
let warn loc msg =
let open Warnings in
match msg with
| Not_principal _ -> w_pr := true
| Ambiguous_name([s], l, _, ex) -> w_amb := (s, l, ex) :: !w_amb
| Name_out_of_scope(ty, [s], _) ->
w_scope := s :: !w_scope; w_scope_ty := ty
| _ -> Location.prerr_warning loc msg
in
let process_label lid =
let scope = Env.lookup_all_labels ~loc:lid.loc usage lid.txt env in
let filter : Label.nonempty_candidate_filter =
disambiguate_label_by_ids closed ids in
Label.disambiguate ~warn ~filter usage lid env expected_type scope in
let lbl_a_list =
(* If one label is qualified [{ foo = ...; M.bar = ... }],
we will disambiguate all labels using one of the qualifying modules,
as if the user had written [{ M.foo = ...; M.bar = ... }].
#11630: It is important to process first the
user-qualified labels, instead of processing all labels in
order, so that error messages coming from the lookup of
M (maybe no such module/path exists) are shown to the user
in context of a qualified field [M.bar] they wrote
themselves, instead of the "ghost" qualification [M.foo]
that does not come from the source program. *)
let lbl_list =
List.map (fun (lid, _) ->
match lid.txt with
| Longident.Ldot _ -> Some (process_label lid)
| _ -> None
) lid_a_list
in
(* Find a module prefix (if any) to qualify unqualified labels *)
let qual =
List.find_map (function
| {txt = Longident.Ldot (modname, _); _}, _ -> Some modname
| _ -> None
) lid_a_list
in
(* Prefix unqualified labels with [qual] and resolve them.
Prefixing unqualified labels does not change the final
disambiguation result, it restricts the set of candidates
without removing any valid choice.
It matters if users activated warnings for ambiguous or
out-of-scope resolutions -- they get less warnings by
qualifying at least one of the fields. *)
List.map2 (fun lid_a lbl ->
match lbl, lid_a with
| Some lbl, (lid, a) -> lid, lbl, a
| None, (lid, a) ->
let qual_lid =
match qual, lid.txt with
| Some modname, Longident.Lident s ->
let name = { lid with txt = s } in
{lid with txt = Longident.Ldot (modname, name)}
| _ -> lid
in
lid, process_label qual_lid, a
) lid_a_list lbl_list
in
if !w_pr then
Location.prerr_warning loc
(not_principal "this type-based record disambiguation")
else begin
match List.rev !w_amb with
(_,types,ex)::_ as amb ->
let paths =
List.map (fun (_,lbl,_) -> Label.get_type_path lbl) lbl_a_list in
let path = List.hd paths in
let fst3 (x,_,_) = x in
if List.for_all (compare_type_path env path) (List.tl paths) then
Location.prerr_warning loc
(Warnings.Ambiguous_name (List.map fst3 amb, types, true, ex))
else
List.iter
(fun (s,l,ex) -> Location.prerr_warning loc
(Warnings.Ambiguous_name ([s],l,false, ex)))
amb
| _ -> ()
end;
if !w_scope <> [] then
Location.prerr_warning loc
(Warnings.Name_out_of_scope (!w_scope_ty, List.rev !w_scope, true));
lbl_a_list
let map_fold_cont f xs k =
List.fold_right (fun x k ys -> f x (fun y -> k (y :: ys)))
xs (fun ys -> k (List.rev ys)) []
let type_label_a_list loc closed env usage type_lbl_a expected_type lid_a_list =
let lbl_a_list =
disambiguate_lid_a_list loc closed env usage expected_type lid_a_list
in
(* Invariant: records are sorted in the typed tree *)
let lbl_a_list =
List.sort
(fun (_,lbl1,_) (_,lbl2,_) -> compare lbl1.lbl_pos lbl2.lbl_pos)
lbl_a_list
in
List.map type_lbl_a lbl_a_list
(* Checks over the labels mentioned in a record pattern:
no duplicate definitions (error); properly closed (warning) *)
let check_recordpat_labels loc lbl_pat_list closed =
match lbl_pat_list with
| [] -> () (* should not happen *)
| (_, label1, _) :: _ ->
let all = label1.lbl_all in
let defined = Array.make (Array.length all) false in
let check_defined (_, label, _) =
if defined.(label.lbl_pos)
then raise(Error(loc, Env.empty, Label_multiply_defined label.lbl_name))
else defined.(label.lbl_pos) <- true in
List.iter check_defined lbl_pat_list;
if closed = Closed
&& Warnings.is_active (Warnings.Missing_record_field_pattern "")
then begin
let undefined = ref [] in
for i = 0 to Array.length all - 1 do
if not defined.(i) then undefined := all.(i).lbl_name :: !undefined
done;
if !undefined <> [] then begin
let u = String.concat ", " (List.rev !undefined) in
Location.prerr_warning loc (Warnings.Missing_record_field_pattern u)
end
end
(* Constructors *)
module Constructor = NameChoice (struct
type t = constructor_description
type usage = Env.constructor_usage
let kind = Datatype_kind.Variant
let get_name cstr = cstr.cstr_name
let get_type cstr = cstr.cstr_res
let lookup_all_from_type loc usage path env =
match Env.lookup_all_constructors_from_type ~loc usage path env with
| _ :: _ as x -> x
| [] ->
match (Env.find_type path env).type_kind with
| Type_open ->
(* Extension constructors cannot be found by looking at the type
declaration.
We scan the whole environment to get an accurate spellchecking
hint in the subsequent error message *)
let filter lbl =
compare_type_path env
path (get_constr_type_path @@ get_type lbl) in
let add_valid x acc = if filter x then (x,ignore)::acc else acc in
Env.fold_constructors add_valid None env []
| _ -> []
let in_env _ = true
end)
(* Typing of patterns *)
(* "untyped" cases are prior to checking the pattern. *)
type untyped_case = Parsetree.pattern Parmatch.parmatch_case
(* "half typed" cases are produced in [map_half_typed_cases] when we've just
typechecked the pattern but haven't type-checked the body yet. At this point
we might have added some type equalities to the environment, but haven't yet
added identifiers bound by the pattern. *)
type ('case_pattern, 'case_data) half_typed_case =
{ typed_pat: 'case_pattern;
pat_type_for_unif: type_expr;
untyped_case : untyped_case;
case_data : 'case_data;
branch_env: Env.t;
pat_vars: pattern_variable list;
module_vars: module_variables;
contains_gadt: bool; }
(* Used to split patterns into value cases and exception cases. *)
let split_half_typed_cases env zipped_cases =
let add_case lst htc data = function
| None -> lst
| Some split_pat ->
({ htc.untyped_case with pattern = split_pat }, data) :: lst
in
List.fold_right (fun (htc, data) (vals, exns) ->
let pat = htc.typed_pat in
match split_pattern pat with
| Some _, Some _ when htc.untyped_case.has_guard ->
raise (Error (pat.pat_loc, env,
Mixed_value_and_exception_patterns_under_guard))
| vp, ep -> add_case vals htc data vp, add_case exns htc data ep
) zipped_cases ([], [])
let rec has_literal_pattern p = match p.ppat_desc with
| Ppat_constant _
| Ppat_interval _ ->
true
| Ppat_any
| Ppat_variant (_, None)
| Ppat_construct (_, None)
| Ppat_type _
| Ppat_var _
| Ppat_unpack _
| Ppat_extension _ ->
false
| Ppat_exception p
| Ppat_variant (_, Some p)
| Ppat_construct (_, Some (_, p))
| Ppat_constraint (p, _)
| Ppat_alias (p, _)
| Ppat_lazy p
| Ppat_open (_, p) ->
has_literal_pattern p
| Ppat_array ps ->
List.exists has_literal_pattern ps
| Ppat_tuple (ps, _) ->
List.exists (fun (_,p) -> has_literal_pattern p) ps
| Ppat_record (ps, _) ->
List.exists (fun (_,p) -> has_literal_pattern p) ps
| Ppat_effect (p, q)
| Ppat_or (p, q) ->
has_literal_pattern p || has_literal_pattern q
let check_scope_escape loc env level ty =
try Ctype.check_scope_escape env level ty
with Escape esc ->
(* We don't expand the type here because if we do, we might expand to the
type that escaped, leading to confusing error messages. *)
let trace = Errortrace.[Escape (map_escape trivial_expansion esc)] in
raise (Error(loc,
env,
Pattern_type_clash(Errortrace.unification_error ~trace, None)))
(** The typedtree has two distinct syntactic categories for patterns,
"value" patterns, matching on values, and "computation" patterns
that match on the effect of a computation -- typically, exception
patterns (exception p).
On the other hand, the parsetree has an unstructured representation
where all categories of patterns are mixed together. The
decomposition according to the value/computation structure has to
happen during type-checking.
We don't want to duplicate the type-checking logic in two different
functions, depending on the kind of pattern to be produced. In
particular, there are both value and computation or-patterns, and
the type-checking logic for or-patterns is horribly complex; having
it in two different places would be twice as horirble.
The solution is to pass a GADT tag to [type_pat] to indicate whether
a value or computation pattern is expected. This way, there is a single
place where [Ppat_or] nodes are type-checked, the checking logic is shared,
and only at the end do we inspect the tag to decide to produce a value
or computation pattern.
*)
let pure
: type k . k pattern_category -> value general_pattern -> k general_pattern
= fun category pat ->
match category with
| Value -> pat
| Computation -> as_computation_pattern pat
let only_impure
: type k . k pattern_category ->
computation general_pattern -> k general_pattern
= fun category pat ->
match category with
| Value ->
(* LATER: this exception could be renamed/generalized *)
raise (Error (pat.pat_loc, pat.pat_env,
Exception_pattern_disallowed))
| Computation -> pat
let as_comp_pattern
: type k . k pattern_category ->
k general_pattern -> computation general_pattern
= fun category pat ->
match category with
| Value -> as_computation_pattern pat
| Computation -> pat
let forbid_atomic_field_patterns loc penv (label_lid, label, pat) =
(* Pattern-matching under atomic record fields is not allowed. We
still allow wildcard patterns, so that it is valid to list all
record fields exhaustively. *)
let wildcard pat = match pat.pat_desc with
| Tpat_any -> true
| _ -> false
in
if label.lbl_atomic = Atomic && not (wildcard pat) then
raise (Error (loc, !!penv, Atomic_in_pattern label_lid.txt))
(** [type_pat] propagates the expected type, and
unification may update the typing environment. *)
let rec type_pat
: type k . type_pat_state -> k pattern_category ->
no_existentials: existential_restriction option ->
penv: Pattern_env.t -> Parsetree.pattern -> type_expr ->
k general_pattern
= fun tps category ~no_existentials ~penv sp expected_ty ->
Builtin_attributes.warning_scope sp.ppat_attributes
(fun () ->
type_pat_aux tps category ~no_existentials ~penv sp expected_ty
)
and type_pat_aux
: type k . type_pat_state -> k pattern_category -> no_existentials:_ ->
penv:Pattern_env.t -> _ -> _ -> k general_pattern
= fun tps category ~no_existentials ~penv sp expected_ty ->
assert (penv.in_counterexample = false);
let type_pat tps category ?(penv=penv) =
type_pat tps category ~no_existentials ~penv
in
let loc = sp.ppat_loc in
let solve_expected (x : pattern) : pattern =
unify_pat ~sdesc_for_hint:sp.ppat_desc !!penv x (instance expected_ty);
x
in
let crp (x : k general_pattern) : k general_pattern =
match category with
| Value -> rp x
| Computation -> rcp x
in
(* record {general,value,computation} pattern *)
let rp = crp
and rvp x = crp (pure category x)
and rcp x = crp (only_impure category x) in
match sp.ppat_desc with
Ppat_any ->
rvp {
pat_desc = Tpat_any;
pat_loc = loc; pat_extra=[];
pat_type = instance expected_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_var name ->
let ty = instance expected_ty in
let id, uid = enter_variable tps loc name ty sp.ppat_attributes in
rvp {
pat_desc = Tpat_var (id, name, uid);
pat_loc = loc; pat_extra=[];
pat_type = ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_unpack name ->
let t = instance expected_ty in
begin match name.txt with
| None ->
rvp {
pat_desc = Tpat_any;
pat_loc = sp.ppat_loc;
pat_extra=[Tpat_unpack, name.loc, sp.ppat_attributes];
pat_type = t;
pat_attributes = [];
pat_env = !!penv }
| Some s ->
let v = { name with txt = s } in
(* We're able to pass ~is_module:true here without an error because
[Ppat_unpack] is a case identified by [may_contain_modules]. See
the comment on [may_contain_modules]. *)
let id, uid =
enter_variable tps loc v t ~is_module:true sp.ppat_attributes
in
rvp {
pat_desc = Tpat_var (id, v, uid);
pat_loc = sp.ppat_loc;
pat_extra=[Tpat_unpack, loc, sp.ppat_attributes];
pat_type = t;
pat_attributes = [];
pat_env = !!penv }
end
| Ppat_constraint(
{ppat_desc=Ppat_var name; ppat_loc=lloc; ppat_attributes = attrs},
({ptyp_desc=Ptyp_poly _} as sty)) ->
(* explicitly polymorphic type *)
let cty, ty, ty' =
solve_Ppat_poly_constraint tps !!penv lloc sty expected_ty in
let id, uid = enter_variable tps lloc name ty' attrs in
rvp { pat_desc = Tpat_var (id, name, uid);
pat_loc = lloc;
pat_extra = [Tpat_constraint cty, loc, sp.ppat_attributes];
pat_type = ty;
pat_attributes = [];
pat_env = !!penv }
| Ppat_alias(sq, name) ->
let q = type_pat tps Value sq expected_ty in
let ty_var = solve_Ppat_alias !!penv q in
let id, uid =
enter_variable
~is_as_variable:true tps name.loc name ty_var sp.ppat_attributes
in
rvp { pat_desc = Tpat_alias(q, id, name, uid, ty_var);
pat_loc = loc; pat_extra=[];
pat_type = q.pat_type;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_constant cst ->
let cst = constant_or_raise !!penv loc cst in
rvp @@ solve_expected {
pat_desc = Tpat_constant cst;
pat_loc = loc; pat_extra=[];
pat_type = type_constant cst;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_interval (c1, c2) ->
let open Ast_helper in
let get_bound = function
| {pconst_desc = Pconst_char c; _} -> c
| {pconst_loc = loc; _} ->
raise (Error (loc, !!penv, Invalid_interval))
in
let c1 = get_bound c1 in
let c2 = get_bound c2 in
let gloc = {loc with Location.loc_ghost=true} in
let rec loop c1 c2 =
if c1 = c2 then Pat.constant ~loc:gloc (Const.char ~loc:gloc c1)
else
Pat.or_ ~loc:gloc
(Pat.constant ~loc:gloc (Const.char ~loc:gloc c1))
(loop (Char.chr(Char.code c1 + 1)) c2)
in
let p = if c1 <= c2 then loop c1 c2 else loop c2 c1 in
let p = {p with ppat_loc=loc} in
type_pat tps category p expected_ty
(* TODO: record 'extra' to remember about interval *)
| Ppat_tuple (spl, closed) ->
assert (closed = Open || List.length spl >= 2);
Option.iter
(fun l -> raise (Error (loc, !!penv, Repeated_tuple_pat_label l)))
(Misc.repeated_label spl);
let args =
match get_desc (expand_head !!penv expected_ty) with
(* If it's a principally-known tuple pattern, try to reorder *)
| Ttuple labeled_tl when is_principal expected_ty ->
reorder_pat loc penv spl closed labeled_tl expected_ty
(* If not, it's not allowed to be open (partial) *)
| _ ->
match closed with
| Open -> raise (Error (loc, !!penv, Partial_tuple_pattern_bad_type))
| Closed -> spl
in
let expected_tys =
solve_Ppat_tuple loc penv args expected_ty
in
let pl =
List.map2 (fun (lbl, t) (_, p) -> lbl, type_pat tps Value p t)
expected_tys args
in
rvp {
pat_desc = Tpat_tuple pl;
pat_loc = loc; pat_extra=[];
pat_type =
newty (Ttuple (List.map (fun (lbl, p) -> lbl, p.pat_type) pl));
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_construct(lid, sarg) ->
let expected_type =
match extract_concrete_variant !!penv expected_ty with
| Variant_type(p0, p, _) ->
Some (p0, p, is_principal expected_ty)
| Maybe_a_variant_type -> None
| Not_a_variant_type ->
let srt = wrong_kind_sort_of_constructor lid.txt in
let error = Wrong_expected_kind(srt, Pattern, expected_ty) in
raise (Error (loc, !!penv, error))
in
let constr =
let candidates =
Env.lookup_all_constructors Env.Pattern ~loc:lid.loc lid.txt !!penv in
wrap_disambiguate "This variant pattern is expected to have"
(mk_expected expected_ty)
(Constructor.disambiguate Env.Pattern lid !!penv expected_type)
candidates
in
begin match no_existentials, constr.cstr_existentials with
| None, _ | _, [] -> ()
| Some r, (_ :: _) ->
let name = constr.cstr_name in
raise (Error (loc, !!penv, Unexpected_existential (r, name)))
end;
let sarg', existential_styp =
match sarg with
None -> None, None
| Some (vl, {ppat_desc = Ppat_constraint (sp, sty)})
when vl <> [] || constr.cstr_arity > 1 ->
Some sp, Some (vl, sty)
| Some ([], sp) ->
Some sp, None
| Some (_, sp) ->
raise (Error (sp.ppat_loc, !!penv, Missing_type_constraint))
in
let sargs =
match sarg' with
None -> []
| Some {ppat_desc = Ppat_tuple (spl, _)} when
constr.cstr_arity > 1 ||
Builtin_attributes.explicit_arity sp.ppat_attributes
->
List.map (fun (l, sp) ->
match l with
| Some _ -> raise (Error(loc, !!penv, Constructor_labeled_arg))
| None -> sp
) spl
| Some({ppat_desc = Ppat_any} as sp) when
constr.cstr_arity = 0 && existential_styp = None
->
Location.prerr_warning sp.ppat_loc
Warnings.Wildcard_arg_to_constant_constr;
[]
| Some({ppat_desc = Ppat_any} as sp) when constr.cstr_arity > 1 ->
replicate_list sp constr.cstr_arity
| Some sp -> [sp] in
if Builtin_attributes.warn_on_literal_pattern constr.cstr_attributes then
begin match List.filter has_literal_pattern sargs with
| sp :: _ ->
Location.prerr_warning sp.ppat_loc Warnings.Fragile_literal_pattern
| _ -> ()
end;
if List.length sargs <> constr.cstr_arity then
raise(Error(loc, !!penv, Constructor_arity_mismatch(lid.txt,
constr.cstr_arity, List.length sargs)));
let (ty_args, existential_ctyp) =
solve_Ppat_construct tps penv loc constr no_existentials
existential_styp expected_ty
in
let rec check_non_escaping p =
match p.ppat_desc with
| Ppat_or (p1, p2) ->
check_non_escaping p1;
check_non_escaping p2
| Ppat_alias (p, _) ->
check_non_escaping p
| Ppat_constraint _ ->
raise (Error (p.ppat_loc, !!penv, Inlined_record_escape))
| _ ->
()
in
if constr.cstr_inlined <> None then begin
List.iter check_non_escaping sargs;
Option.iter (fun (_, sarg) -> check_non_escaping sarg) sarg
end;
let args = List.map2 (type_pat tps Value) sargs ty_args in
rvp { pat_desc=Tpat_construct(lid, constr, args, existential_ctyp);
pat_loc = loc; pat_extra=[];
pat_type = instance expected_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_variant(tag, sarg) ->
assert (tag <> Parmatch.some_private_tag);
let constant = (sarg = None) in
let arg_type, row, pat_type =
solve_Ppat_variant loc penv tag constant expected_ty in
let arg =
(* PR#6235: propagate type information *)
match sarg, arg_type with
Some sp, [ty] -> Some (type_pat tps Value sp ty)
| _ -> None
in
rvp {
pat_desc = Tpat_variant(tag, arg, ref row);
pat_loc = loc; pat_extra = [];
pat_type = pat_type;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_record(lid_sp_list, closed) ->
assert (lid_sp_list <> []);
let expected_type, record_ty =
match extract_concrete_record !!penv expected_ty with
| Record_type(p0, p, _) ->
let ty = generic_instance expected_ty in
Some (p0, p, is_principal expected_ty), ty
| Maybe_a_record_type -> None, newvar ()
| Not_a_record_type ->
let error = Wrong_expected_kind(Record, Pattern, expected_ty) in
raise (Error (loc, !!penv, error))
in
let type_label_pat (label_lid, label, sarg) =
let ty_arg =
solve_Ppat_record_field loc penv label label_lid record_ty in
(label_lid, label, type_pat tps Value sarg ty_arg)
in
let make_record_pat lbl_pat_list =
check_recordpat_labels loc lbl_pat_list closed;
List.iter (forbid_atomic_field_patterns loc penv) lbl_pat_list;
{
pat_desc = Tpat_record (lbl_pat_list, closed);
pat_loc = loc; pat_extra=[];
pat_type = instance record_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv;
}
in
let lbl_a_list =
wrap_disambiguate "This record pattern is expected to have"
(mk_expected expected_ty)
(type_label_a_list loc false !!penv Env.Projection
type_label_pat expected_type)
lid_sp_list
in
rvp @@ solve_expected (make_record_pat lbl_a_list)
| Ppat_array(spl) ->
let ty_elt, expected_mutability = solve_Ppat_array loc penv expected_ty in
let pl = List.map (fun p -> type_pat tps Value p ty_elt) spl in
rvp {
pat_desc = Tpat_array (expected_mutability, pl);
pat_loc = loc; pat_extra=[];
pat_type = instance expected_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_or(sp1, sp2) ->
(* Reset pattern forces for just [tps2] because later we append [tps1] and
[tps2]'s pattern forces, and we don't want to duplicate [tps]'s pattern
forces. *)
let tps1 = copy_type_pat_state tps in
let tps2 = {(copy_type_pat_state tps) with tps_pattern_force = []} in
(* Introduce a new level to avoid keeping nodes at intermediate levels *)
let pat_desc = with_local_level_generalize begin fun () ->
(* Introduce a new scope using with_local_level without generalizations *)
let env1, p1, env2, p2 =
with_local_level begin fun () ->
let type_pat_rec tps penv sp =
type_pat tps category sp expected_ty ~penv
in
let penv1 =
Pattern_env.copy ~equations_scope:(get_current_level ()) penv in
let penv2 = Pattern_env.copy penv1 in
let p1 = type_pat_rec tps1 penv1 sp1 in
let p2 = type_pat_rec tps2 penv2 sp2 in
(penv1.env, p1, penv2.env, p2)
end
in
let p1_variables = tps1.tps_pattern_variables in
let p2_variables = tps2.tps_pattern_variables in
(* Make sure no variable with an ambiguous type gets added to the
environment. *)
let outer_lev = get_current_level () in
List.iter (fun { pv_type; pv_loc; _ } ->
check_scope_escape pv_loc env1 outer_lev pv_type
) p1_variables;
List.iter (fun { pv_type; pv_loc; _ } ->
check_scope_escape pv_loc env2 outer_lev pv_type
) p2_variables;
let alpha_env =
enter_orpat_variables loc !!penv p1_variables p2_variables in
(* Propagate the outcome of checking the or-pattern back to
the type_pat_state that the caller passed in.
*)
blit_type_pat_state
~src:
{ tps_pattern_variables = tps1.tps_pattern_variables;
(* We want to propagate all pattern forces, regardless of
which branch they were found in.
*)
tps_pattern_force =
tps2.tps_pattern_force @ tps1.tps_pattern_force;
tps_module_variables = tps1.tps_module_variables;
}
~dst:tps;
let p2 = alpha_pat alpha_env p2 in
Tpat_or (p1, p2, None)
end
in
rp { pat_desc = pat_desc;
pat_loc = loc; pat_extra = [];
pat_type = instance expected_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_lazy sp1 ->
let nv = solve_Ppat_lazy loc penv expected_ty in
let p1 = type_pat tps Value sp1 nv in
rvp {
pat_desc = Tpat_lazy p1;
pat_loc = loc; pat_extra=[];
pat_type = instance expected_ty;
pat_attributes = sp.ppat_attributes;
pat_env = !!penv }
| Ppat_constraint(sp, sty) ->
(* Pretend separate = true *)
let cty, ty, expected_ty' =
solve_Ppat_constraint tps loc !!penv sty expected_ty in
let p = type_pat tps category sp expected_ty' in
let extra = (Tpat_constraint cty, loc, sp.ppat_attributes) in
begin match category, (p : k general_pattern) with
| Value, {pat_desc = Tpat_var (id,s,uid); _} ->
{ p with
pat_type = ty;
pat_desc =
Tpat_alias
({p with pat_desc = Tpat_any; pat_attributes = []},
id, s, uid, ty);
pat_extra = [extra];
}
| _, p ->
{ p with pat_type = ty; pat_extra = extra::p.pat_extra }
end
| Ppat_type lid ->
let (path, p) = build_or_pat !!penv loc lid in
pure category @@ solve_expected
{ p with pat_extra = (Tpat_type (path, lid), loc, sp.ppat_attributes)
:: p.pat_extra }
| Ppat_open (lid,p) ->
let path, new_env =
!type_open Asttypes.Fresh !!penv sp.ppat_loc lid in
Pattern_env.set_env penv new_env;
let p = type_pat tps category ~penv p expected_ty in
let new_env = !!penv in
begin match Env.remove_last_open path new_env with
| None -> assert false
| Some closed_env -> Pattern_env.set_env penv closed_env
end;
{ p with pat_extra = (Tpat_open (path,lid,new_env),
loc, sp.ppat_attributes) :: p.pat_extra }
| Ppat_exception p ->
let p_exn = type_pat tps Value p Predef.type_exn in
rcp {
pat_desc = Tpat_exception p_exn;
pat_loc = sp.ppat_loc;
pat_extra = [];
pat_type = expected_ty;
pat_env = !!penv;
pat_attributes = sp.ppat_attributes;
}
| Ppat_effect _ ->
raise (Error (loc, !!penv, Effect_pattern_below_toplevel))
| Ppat_extension ext ->
raise (Error_forward (Builtin_attributes.error_of_extension ext))
let iter_pattern_variables_type f : pattern_variable list -> unit =
List.iter (fun {pv_type; _} -> f pv_type)
let add_pattern_variables ?check ?check_as env pv =
List.fold_right
(fun {pv_id; pv_type; pv_loc; pv_kind; pv_attributes; pv_uid} env ->
let check = if pv_kind=As_var then check_as else check in
Env.add_value ?check pv_id
{val_type = pv_type; val_kind = Val_reg; Types.val_loc = pv_loc;
val_attributes = pv_attributes;
val_uid = pv_uid;
} env
)
pv env
let add_module_variables env module_variables =
let module_variables_as_list =
match module_variables with
| Modvars_allowed mvs -> mvs.module_variables
| Modvars_ignored | Modvars_rejected -> []
in
List.fold_left (fun env { mv_id; mv_loc; mv_name; mv_uid } ->
Typetexp.TyVarEnv.with_local_scope begin fun () ->
(* This code is parallel to the typing of Pexp_letmodule. However we
omit the call to [Mtype.lower_nongen] as it's not necessary here.
For Pexp_letmodule, the call to [type_module] is done in a raised
level and so needs to be modified to have the correct, outer level.
Here, on the other hand, we're calling [type_module] outside the
raised level, so there's no extra step to take.
*)
let modl, md_shape =
!type_module env
Ast_helper.(
Mod.unpack ~loc:mv_loc
(Exp.ident ~loc:mv_name.loc
(mkloc (Longident.Lident mv_name.txt)
mv_name.loc)))
in
let pres =
match modl.mod_type with
| Mty_alias _ -> Mp_absent
| _ -> Mp_present
in
let md =
{ md_type = modl.mod_type; md_attributes = [];
md_loc = mv_name.loc;
md_uid = mv_uid; }
in
Env.add_module_declaration ~shape:md_shape ~check:true mv_id pres md env
end
) env module_variables_as_list
let type_pat tps category ?no_existentials penv =
type_pat tps category ~no_existentials ~penv
let type_pattern category ~lev env spat expected_ty ?cont allow_modules =
let tps = create_type_pat_state ?cont allow_modules in
let new_penv = Pattern_env.make env
~equations_scope:lev ~in_counterexample:false in
let pat = type_pat tps category new_penv spat expected_ty in
let { tps_pattern_variables = pvs;
tps_module_variables = mvs;
tps_pattern_force = pattern_forces;
} = tps in
(pat, !!new_penv, pattern_forces, pvs, mvs)
let type_pattern_list
category no_existentials env spatl expected_tys allow_modules
=
let tps = create_type_pat_state allow_modules in
let equations_scope = get_current_level () in
let new_penv = Pattern_env.make env
~equations_scope ~in_counterexample:false in
let type_pat (attrs, pat) ty =
Builtin_attributes.warning_scope ~ppwarning:false attrs
(fun () ->
type_pat tps category ~no_existentials new_penv pat ty
)
in
let patl = List.map2 type_pat spatl expected_tys in
let { tps_pattern_variables = pvs;
tps_module_variables = mvs;
tps_pattern_force = pattern_forces;
} = tps in
(patl, !!new_penv, pattern_forces, pvs, mvs)
let type_class_arg_pattern cl_num val_env met_env l spat =
let tps = create_type_pat_state Modules_rejected in
let nv = newvar () in
let equations_scope = get_current_level () in
let new_penv = Pattern_env.make val_env
~equations_scope ~in_counterexample:false in
let pat =
type_pat tps Value ~no_existentials:In_class_args new_penv spat nv in
if has_variants pat then begin
Parmatch.pressure_variants val_env [pat];
finalize_variants pat;
end;
List.iter (fun f -> f()) tps.tps_pattern_force;
if is_optional l then unify_pat val_env pat (type_option (newvar ()));
let (pv, val_env, met_env) =
List.fold_right
(fun {pv_id; pv_type; pv_loc; pv_kind; pv_attributes}
(pv, val_env, met_env) ->
let check s =
if pv_kind = As_var then Warnings.Unused_var s
else Warnings.Unused_var_strict s in
let id' = Ident.rename pv_id in
let val_uid = Uid.mk ~current_unit:(Env.get_current_unit ()) in
let val_env =
Env.add_value pv_id
{ val_type = pv_type
; val_kind = Val_reg
; val_attributes = pv_attributes
; val_loc = pv_loc
; val_uid
}
val_env
in
let met_env =
Env.add_value id' ~check
{ val_type = pv_type
; val_kind = Val_ivar (Immutable, cl_num)
; val_attributes = pv_attributes
; val_loc = pv_loc
; val_uid
}
met_env
in
((id', pv_id, pv_type)::pv, val_env, met_env))
tps.tps_pattern_variables ([], val_env, met_env)
in
(pat, pv, val_env, met_env)
let type_self_pattern env spat =
let open Ast_helper in
let spat = Pat.mk(Ppat_alias (spat, mknoloc "selfpat-*")) in
let tps = create_type_pat_state Modules_rejected in
let nv = newvar() in
let equations_scope = get_current_level () in
let new_penv = Pattern_env.make env
~equations_scope ~in_counterexample:false in
let pat =
type_pat tps Value ~no_existentials:In_self_pattern new_penv spat nv in
List.iter (fun f -> f()) tps.tps_pattern_force;
pat, tps.tps_pattern_variables
(** In [check_counter_example_pat], we will check a counter-example candidate
produced by Parmatch. This is a pattern that represents a set of values by
using or-patterns (p_1 | ... | p_n) to enumerate all alternatives in the
counter-example search. These or-patterns occur at every choice point,
possibly deep inside the pattern.
Parmatch does not use type information, so this pattern may
exhibit two issues:
- some parts of the pattern may be ill-typed due to GADTs, and
- some wildcard patterns may not match any values: their type is
empty.
The aim of [check_counter_example_pat] is to refine this untyped pattern
into a well-typed pattern, and ensure that it matches at least one
concrete value.
- It filters ill-typed branches of or-patterns.
(see {!splitting_mode} below)
- It tries to check that wildcard patterns are non-empty.
(see {!explosion_fuel})
*)
type counter_example_checking_info = {
explosion_fuel: int;
splitting_mode: splitting_mode;
}
(**
[explosion_fuel] controls the checking of wildcard patterns. We
eliminate potentially-empty wildcard patterns by exploding them
into concrete sub-patterns, for example (K1 _ | K2 _) or
{ l1: _; l2: _ }. [explosion_fuel] is the depth limit on wildcard
explosion. Such depth limit is required to avoid non-termination
and compilation-time blowups.
[splitting_mode] controls the handling of or-patterns. In
[Counter_example] mode, we only need to select one branch that
leads to a well-typed pattern. Checking all branches is expensive,
we use different search strategies (see {!splitting_mode}) to
reduce the number of explored alternatives.
*)
(** Due to GADT constraints, an or-pattern produced within
a counter-example may have ill-typed branches. Consider for example
{[
type _ tag = Int : int tag | Bool : bool tag
]}
then [Parmatch] will propose the or-pattern [Int | Bool] whenever
a pattern of type [tag] is required to form a counter-example. For
example, a function expects a (int tag option) and only [None] is
handled by the user-written pattern. [Some (Int | Bool)] is not
well-typed in this context, only the sub-pattern [Some Int] is.
In this example, the expected type coming from the context
suffices to know which or-pattern branch must be chosen.
In the general case, choosing a branch can have non-local effects
on the typability of the term. For example, consider a tuple type
['a tag * ...'a...], where the first component is a GADT. All
constructor choices for this GADT lead to a well-typed branch in
isolation (['a] is unconstrained), but choosing one of them adds
a constraint on ['a] that may make the other tuple elements
ill-typed.
In general, after choosing each possible branch of the or-pattern,
[check_counter_example_pat] has to check the rest of the pattern to
tell if this choice leads to a well-typed term. This may lead to an
explosion of typing/search work -- the rest of the term may in turn
contain alternatives.
We use careful strategies to try to limit counterexample-checking
time; [splitting_mode] represents those strategies.
*)
and splitting_mode =
| Backtrack_or
(** Always backtrack in or-patterns.
[Backtrack_or] selects a single alternative from an or-pattern
by using backtracking, trying to choose each branch in turn, and
to complete it into a valid sub-pattern. We call this
"splitting" the or-pattern.
We use this mode when looking for unused patterns or sub-patterns,
in particular to check a refutation clause (p -> .).
*)
| Refine_or of { inside_nonsplit_or: bool; }
(** Only backtrack when needed.
[Refine_or] tries another approach for refining or-pattern.
Instead of always splitting each or-pattern, It first attempts to
find branches that do not introduce new constraints (because they
do not contain GADT constructors). Those branches are such that,
if they fail, all other branches will fail.
If we find one such branch, we attempt to complete the subpattern
(checking what's outside the or-pattern), ignoring other
branches -- we never consider another branch choice again. If all
branches are constrained, it falls back to splitting the
or-pattern.
We use this mode when checking exhaustivity of pattern matching.
*)
(** This exception is only used internally within [check_counter_example_pat],
to jump back to the parent or-pattern in the [Refine_or] strategy.
Such a parent exists precisely when [inside_nonsplit_or = true];
it's an invariant that we always setup an exception handler for
[Need_backtrack] when we set this flag. *)
exception Need_backtrack
(** This exception is only used internally within [check_counter_example_pat].
We use it to discard counter-example candidates that do not match any
value. *)
exception Empty_branch
type abort_reason = Adds_constraints | Empty
(** Remember current typing state for backtracking.
No variable information, as we only backtrack on
patterns without variables (cf. assert statements).
In the GADT mode, [env] may be extended by unification,
and therefore it needs to be saved along with a [snapshot]. *)
type unification_state =
{ snapshot: snapshot;
env: Env.t; }
let save_state penv =
{ snapshot = Btype.snapshot ();
env = !!penv; }
let set_state s penv =
Btype.backtrack s.snapshot;
Pattern_env.set_env penv s.env
(** Find the first alternative in the tree of or-patterns for which
[f] does not raise an error. If all fail, the last error is
propagated *)
let rec find_valid_alternative f pat =
match pat.pat_desc with
| Tpat_or(p1,p2,_) ->
(try find_valid_alternative f p1 with
| Empty_branch | Error _ -> find_valid_alternative f p2
)
| _ -> f pat
let no_explosion info = { info with explosion_fuel = 0 }
let enter_nonsplit_or info =
let splitting_mode = match info.splitting_mode with
| Backtrack_or ->
(* in Backtrack_or mode, or-patterns are always split *)
assert false
| Refine_or _ ->
Refine_or {inside_nonsplit_or = true}
in { info with splitting_mode }
let rec check_counter_example_pat
~info ~(penv : Pattern_env.t) type_pat_state tp expected_ty k =
assert (penv.in_counterexample = true);
let check_rec ?(info=info) ?(penv=penv) =
check_counter_example_pat ~info ~penv type_pat_state in
let loc = tp.pat_loc in
let solve_expected (x : pattern) : pattern =
unify_pat_types_penv x.pat_loc penv x.pat_type
(instance expected_ty);
x
in
(* "make pattern" and "make pattern then continue" *)
let mp ?(pat_type = expected_ty) desc =
{ pat_desc = desc; pat_loc = loc; pat_extra=[];
pat_type = instance pat_type; pat_attributes = []; pat_env = !!penv } in
let mkp k ?pat_type desc = k (mp ?pat_type desc) in
let must_backtrack_on_gadt =
match info.splitting_mode with
| Backtrack_or -> false
| Refine_or {inside_nonsplit_or} -> inside_nonsplit_or
in
match tp.pat_desc with
Tpat_any | Tpat_var _ ->
let k' () = mkp k tp.pat_desc in
if info.explosion_fuel <= 0 then k' () else
let decrease n = {info with explosion_fuel = info.explosion_fuel - n} in
begin match Parmatch.pats_of_type !!penv expected_ty with
| [] -> raise Empty_branch
| [{pat_desc = Tpat_any}] -> k' ()
| [tp] -> check_rec ~info:(decrease 1) tp expected_ty k
| tp :: tpl ->
if must_backtrack_on_gadt then raise Need_backtrack;
let tp =
List.fold_left
(fun tp tp' -> {tp with pat_desc = Tpat_or (tp, tp', None)})
tp tpl
in
check_rec ~info:(decrease 5) tp expected_ty k
end
| Tpat_alias (p, _, _, _, _) -> check_rec ~info p expected_ty k
| Tpat_constant cst ->
let cst = constant_or_raise !!penv loc (Untypeast.constant cst) in
k @@ solve_expected (mp (Tpat_constant cst) ~pat_type:(type_constant cst))
| Tpat_tuple tpl ->
assert (List.length tpl >= 2);
let expected_tys = solve_Ppat_tuple loc penv tpl expected_ty in
let tpl_ann = List.combine tpl expected_tys in
map_fold_cont (fun ((l,p),(_,t)) k -> check_rec p t (fun p -> k (l, p)))
tpl_ann
(fun pl ->
let pat_type =
newty (Ttuple(List.map (fun (l, p) -> l, p.pat_type) pl))
in
mkp k (Tpat_tuple pl) ~pat_type)
| Tpat_construct(cstr_lid, constr, targs, _) ->
if constr.cstr_generalized && must_backtrack_on_gadt then
raise Need_backtrack;
let (ty_args, existential_ctyp) =
solve_Ppat_construct
type_pat_state penv loc constr None None expected_ty
in
map_fold_cont
(fun (p,t) -> check_rec p t)
(List.combine targs ty_args)
(fun args ->
mkp k (Tpat_construct(cstr_lid, constr, args, existential_ctyp)))
| Tpat_variant(tag, targ, _) ->
let constant = (targ = None) in
let arg_type, row, pat_type =
solve_Ppat_variant loc penv tag constant expected_ty in
let k arg =
mkp k ~pat_type (Tpat_variant(tag, arg, ref row))
in begin
(* PR#6235: propagate type information *)
match targ, arg_type with
Some p, [ty] -> check_rec p ty (fun p -> k (Some p))
| _ -> k None
end
| Tpat_record(fields, closed) ->
let record_ty = generic_instance expected_ty in
let type_label_pat (label_lid, label, targ) k =
let ty_arg =
solve_Ppat_record_field loc penv label label_lid record_ty in
check_rec targ ty_arg (fun arg -> k (label_lid, label, arg))
in
map_fold_cont type_label_pat fields
(fun fields -> mkp k (Tpat_record (fields, closed)))
| Tpat_array (mutability, tpl) ->
let ty_elt, _ = solve_Ppat_array loc penv expected_ty in
map_fold_cont (fun p -> check_rec p ty_elt) tpl
(fun pl -> mkp k (Tpat_array (mutability, pl)))
| Tpat_or(tp1, tp2, _) ->
(* We are in counter-example mode, but try to avoid backtracking *)
let must_split =
match info.splitting_mode with
| Backtrack_or -> true
| Refine_or _ -> false in
let state = save_state penv in
let split_or tp =
let type_alternative pat =
set_state state penv; check_rec pat expected_ty k in
find_valid_alternative type_alternative tp
in
if must_split then split_or tp else
let check_rec_result penv tp : (_, abort_reason) result =
let info = enter_nonsplit_or info in
match check_rec ~info tp expected_ty ~penv (fun x -> x) with
| res -> Ok res
| exception Need_backtrack -> Error Adds_constraints
| exception Empty_branch -> Error Empty
in
let p1 = check_rec_result (Pattern_env.copy penv) tp1 in
let p2 = check_rec_result (Pattern_env.copy penv) tp2 in
begin match p1, p2 with
| Error Empty, Error Empty ->
raise Empty_branch
| Error Adds_constraints, Error _
| Error _, Error Adds_constraints ->
let inside_nonsplit_or =
match info.splitting_mode with
| Backtrack_or -> false
| Refine_or {inside_nonsplit_or} -> inside_nonsplit_or in
if inside_nonsplit_or
then raise Need_backtrack
else split_or tp
| Ok p, Error _
| Error _, Ok p ->
k p
| Ok p1, Ok p2 ->
mkp k (Tpat_or (p1, p2, None))
end
| Tpat_lazy tp1 ->
let nv = solve_Ppat_lazy loc penv expected_ty in
(* do not explode under lazy: PR#7421 *)
check_rec ~info:(no_explosion info) tp1 nv
(fun p1 -> mkp k (Tpat_lazy p1))
let check_counter_example_pat ~counter_example_args penv tp expected_ty =
(* [check_counter_example_pat] doesn't use [type_pat_state] in an interesting
way -- one of the functions it calls writes an entry into
[tps_pattern_forces] -- so we can just ignore module patterns. *)
let type_pat_state = create_type_pat_state Modules_ignored in
wrap_trace_gadt_instances ~force:true !!penv
(check_counter_example_pat ~info:counter_example_args ~penv
type_pat_state tp expected_ty)
(fun x -> x)
(* this function is passed to Partial.parmatch
to type check gadt nonexhaustiveness *)
let partial_pred ~lev ~splitting_mode ?(explode=0) env expected_ty p =
let penv = Pattern_env.make env
~equations_scope:lev ~in_counterexample:true in
let state = save_state penv in
let counter_example_args =
{
splitting_mode;
explosion_fuel = explode;
} in
try
let typed_p =
check_counter_example_pat ~counter_example_args penv p expected_ty
in
set_state state penv;
(* types are invalidated but we don't need them here *)
Some typed_p
with Error _ | Empty_branch ->
set_state state penv;
None
let check_partial
?(lev=get_current_level ()) env expected_ty loc cases
=
let explode = match cases with [_] -> 5 | _ -> 0 in
let splitting_mode = Refine_or {inside_nonsplit_or = false} in
Parmatch.check_partial
(partial_pred ~lev ~splitting_mode ~explode env expected_ty)
loc cases
let check_unused
?(lev=get_current_level ()) env expected_ty cases
=
Parmatch.check_unused
(fun refute pat ->
match
partial_pred ~lev ~splitting_mode:Backtrack_or ~explode:5
env expected_ty pat
with
Some pat' when refute ->
raise (Error (pat.pat_loc, env, Unrefuted_pattern pat'))
| r -> r)
cases
(** Some delayed checks, to be executed after typing the whole
compilation unit or toplevel phrase *)
let delayed_checks = ref []
let reset_delayed_checks () = delayed_checks := []
let add_delayed_check f =
delayed_checks := (f, Warnings.backup ()) :: !delayed_checks
let force_delayed_checks () =
(* checks may change type levels *)
let snap = Btype.snapshot () in
let w_old = Warnings.backup () in
List.iter
(fun (f, w) -> Warnings.restore w; f ())
(List.rev !delayed_checks);
Warnings.restore w_old;
reset_delayed_checks ();
Btype.backtrack snap
let rec final_subexpression exp =
match exp.exp_desc with
Texp_let (_, _, e)
| Texp_sequence (_, e)
| Texp_try (e, _, _)
| Texp_ifthenelse (_, e, _)
| Texp_match (_, {c_rhs=e} :: _, _, _)
| Texp_letmodule (_, _, _, _, e)
| Texp_letexception (_, e)
| Texp_open (_, e)
-> final_subexpression e
| _ -> exp
let is_prim ~name funct =
match funct.exp_desc with
| Texp_ident (_, _, {val_kind=Val_prim{Primitive.prim_name; _}}) ->
prim_name = name
| _ -> false
(* List labels in a function type, and whether return type is a variable *)
let rec list_labels_aux env visited ls ty_fun =
let ty = expand_head env ty_fun in
if TypeSet.mem ty visited then
List.rev ls, false
else match get_desc ty with
| Tarrow (l, _, ty_res, _) ->
list_labels_aux env (TypeSet.add ty visited) (l::ls) ty_res
| _ ->
List.rev ls, is_Tvar ty
let list_labels env ty =
let snap = Btype.snapshot () in
let result =
wrap_trace_gadt_instances env (list_labels_aux env TypeSet.empty []) ty
in
Btype.backtrack snap;
result
(* Collecting arguments for function applications. *)
type untyped_apply_arg =
| Known_arg of
{
sarg : Parsetree.expression;
ty_arg : type_expr;
ty_arg0 : type_expr;
wrapped_in_some : bool;
}
(* [arg] is a [Known_arg] in:
- [f arg] when is known to be a function (f : _ -> _)
- [f ~lab:arg] when (f : lab:_ -> _)
- [f ?lab:arg] when (f : ?lab:_ -> _)
In these cases we have [wrapped_in_some = false].
- [f ~lab:arg] when (f : ?lab:_ -> _)
In this case [wrapped_in_some = true].
[ty_arg] is the (possibly generic) expected type of the argument,
and [ty_arg0] is an instance of [ty_arg]. *)
| Unknown_arg of
{
sarg : Parsetree.expression;
ty_arg : type_expr;
}
(* [arg] is an [Unknown_arg] in:
[f arg] when [f] is not known (either a type variable,
or the [commu_ok] case where a function type is known
but not principally).
[ty_arg] is the expected type of the argument, usually just
a fresh type variable. *)
| Eliminated_optional_arg of
{
ty_arg : type_expr;
level: int;
}
(* When [f : ?foo:ty -> _ -> _], [~foo] is an [Eliminated_optional_arg]
in [f x] ([foo] is an optional argument that was not passed, but a
following positional argument was passed).
[level] is the level of the function arrow. *)
type untyped_omitted_param =
{
ty_arg : type_expr;
level: int;
}
let remaining_function_type_for_error ty_ret rev_args =
List.fold_left
(fun ty_ret (lbl, arg) ->
match arg with
| Arg (Unknown_arg _ | Known_arg _) -> ty_ret
| Arg (Eliminated_optional_arg { ty_arg; level })
| Omitted { ty_arg; level } ->
let ty_ret =
newty2 ~level
(Tarrow (lbl, ty_arg, ty_ret, commu_ok))
in
ty_ret)
ty_ret rev_args
let previous_arg_loc rev_args ~funct =
(* [rev_args] is the arguments typed until now, in reverse
order of appearance. Not all arguments have a location
attached (eg. an optional argument that is not passed). *)
rev_args
|> List.find_map (function
| _, Arg (Known_arg { sarg = {pexp_loc = loc; _ }}
| Unknown_arg { sarg = {pexp_loc = loc; _}}) ->
Some loc
| _ -> None)
|> Option.value ~default:funct.exp_loc
let collect_unknown_apply_args env funct ty_fun0 rev_args sargs =
let labels_match ~param ~arg =
param = arg
|| !Clflags.classic && arg = Nolabel && not (is_optional param)
in
let has_label l ty_fun =
let ls, tvar = list_labels env ty_fun in
tvar || List.mem l ls
in
let rec loop ty_fun rev_args sargs =
match sargs with
| [] -> ty_fun, List.rev rev_args
| (lbl, sarg) :: rest ->
let (ty_arg, ty_res) =
let ty_fun = expand_head env ty_fun in
match get_desc ty_fun with
| Tvar _ ->
let ty_arg = newvar () in
let ty_res = newvar () in
if get_level ty_fun >= get_level ty_arg &&
not (is_prim ~name:"%identity" funct)
then
Location.prerr_warning sarg.pexp_loc
Warnings.Ignored_extra_argument;
unify env ty_fun (newty (Tarrow(lbl,ty_arg,ty_res,commu_var ())));
(ty_arg, ty_res)
| Tarrow (l, ty_arg, ty_res, _) when labels_match ~param:l ~arg:lbl ->
(ty_arg, ty_res)
| td ->
let ty_fun = match td with Tarrow _ -> newty td | _ -> ty_fun in
let ty_res = remaining_function_type_for_error ty_fun rev_args in
match get_desc ty_res with
| Tarrow _ ->
if !Clflags.classic || not (has_label lbl ty_fun) then
raise (Error(sarg.pexp_loc, env,
Apply_wrong_label(lbl, ty_res, false)))
else
raise (Error(funct.exp_loc, env, Incoherent_label_order))
| _ ->
raise(Error(funct.exp_loc, env, Apply_non_function {
funct;
func_ty = expand_head env funct.exp_type;
res_ty = expand_head env ty_res;
previous_arg_loc = previous_arg_loc rev_args ~funct;
extra_arg_loc = sarg.pexp_loc; }))
in
let arg = Unknown_arg { sarg; ty_arg } in
loop ty_res ((lbl, Arg arg) :: rev_args) rest
in
loop ty_fun0 rev_args sargs
let collect_apply_args env funct ignore_labels ty_fun ty_fun0 sargs =
let warned = ref false in
let rec loop ty_fun ty_fun0 rev_args sargs =
if sargs = [] then
collect_unknown_apply_args env funct ty_fun0 rev_args sargs
else
let ty_fun' = expand_head env ty_fun in
let lv = get_level ty_fun' in
let may_warn loc w =
if not !warned && !Clflags.principal && lv <> generic_level
then begin
warned := true;
Location.prerr_warning loc w
end
in
let lopt =
match get_desc ty_fun', get_desc (expand_head env ty_fun0) with
| Tarrow (l, ty_arg, ty_ret, com), Tarrow (_, ty_arg0, ty_ret0, _)
when is_commu_ok com ->
Some (l, `Arrow (ty_arg, ty_ret, ty_arg0, ty_ret0))
| _ -> None
in
match lopt with
| None ->
(* We're not looking at a *known* function type anymore. *)
collect_unknown_apply_args env funct ty_fun0 rev_args sargs
| Some (l, arrow_kind) ->
begin
let name = label_name l
and optional = is_optional l in
let remaining_sargs, arg_opt =
if ignore_labels then begin
(* No reordering is allowed, process arguments in order *)
match sargs with
| [] -> assert false
| (l', sarg) :: remaining_sargs ->
if name = label_name l' || (not optional && l' = Nolabel) then
(remaining_sargs, Some (sarg, l'))
else if
optional &&
not (List.exists (fun (l, _) -> name = label_name l)
remaining_sargs) &&
List.exists (function (Nolabel, _) -> true | _ -> false)
sargs
then
(sargs, None)
else
raise(Error(sarg.pexp_loc, env,
Apply_wrong_label(l', ty_fun', optional)))
end else
(* Arguments can be commuted, try to fetch the argument
corresponding to the first parameter. *)
match extract_label name sargs with
| Some (l', sarg, commuted, remaining_sargs) ->
if commuted then begin
may_warn sarg.pexp_loc
(not_principal "commuting this argument")
end;
if not optional && is_optional l' then
Location.prerr_warning sarg.pexp_loc
(Warnings.Nonoptional_label (Asttypes.string_of_label l));
remaining_sargs, Some (sarg, l')
| None ->
sargs, None
in
match arrow_kind with
| `Arrow (ty_arg, ty_ret, ty_arg0, ty_ret0) ->
let arg =
match arg_opt with
| Some (sarg, l') ->
let wrapped_in_some = optional && not (is_optional l') in
if wrapped_in_some then
may_warn sarg.pexp_loc
(not_principal "using an optional argument here");
Arg (Known_arg { sarg; ty_arg; ty_arg0; wrapped_in_some })
| None ->
if optional && List.mem_assoc Nolabel sargs then begin
may_warn funct.exp_loc (Warnings.Non_principal_labels
"eliminated optional argument");
Arg (Eliminated_optional_arg { ty_arg; level = lv })
end else begin
(* No argument was given for this parameter, we abstract
over it. *)
may_warn funct.exp_loc
(Warnings.Non_principal_labels "commuted an argument");
Omitted { ty_arg; level = lv }
end
in
loop ty_ret ty_ret0 ((l, arg) :: rev_args) remaining_sargs
end
in
loop ty_fun ty_fun0 [] sargs
let type_omitted_parameters_and_build_result_type ty_ret args =
let ty_ret, args =
List.fold_left
(fun (ty_ret, args) (lbl, arg) ->
match arg with
| Arg _exp as arg ->
let args = (lbl, arg) :: args in
(ty_ret, args)
| Omitted { ty_arg; level } ->
let ty_ret =
newty2 ~level
(Tarrow ((lbl, ty_arg, ty_ret, commu_ok)))
in
let args = (lbl, Omitted ()) :: args in
(ty_ret, args))
(ty_ret, []) (List.rev args)
in
ty_ret, args
(* Generalization criterion for expressions *)
let rec is_nonexpansive exp =
match exp.exp_desc with
| Texp_ident _
| Texp_constant _
| Texp_unreachable
| Texp_function _
| Texp_array (_, []) -> true
| Texp_let(_rec_flag, pat_exp_list, body) ->
List.for_all (fun vb -> is_nonexpansive vb.vb_expr) pat_exp_list &&
is_nonexpansive body
| Texp_apply(e, (_,Omitted ())::el) ->
is_nonexpansive e && List.for_all is_nonexpansive_arg (List.map snd el)
| Texp_match(e, cases, _, _) ->
(* Not sure this is necessary, if [e] is nonexpansive then we shouldn't
care if there are exception patterns. But the previous version enforced
that there be none, so... *)
let contains_exception_pat pat =
exists_general_pattern { f = fun (type k) (p : k general_pattern) ->
match p.pat_desc with
| Tpat_exception _ -> true
| _ -> false } pat
in
is_nonexpansive e &&
List.for_all
(fun {c_lhs; c_guard; c_rhs} ->
is_nonexpansive_opt c_guard && is_nonexpansive c_rhs
&& not (contains_exception_pat c_lhs)
) cases
| Texp_tuple el ->
List.for_all (fun (_, e) -> is_nonexpansive e) el
| Texp_construct( _, _, el) ->
List.for_all is_nonexpansive el
| Texp_variant(_, arg) -> is_nonexpansive_opt arg
| Texp_record { fields; extended_expression } ->
Array.for_all
(fun (lbl, definition) ->
match definition with
| Overridden (_, exp) ->
lbl.lbl_mut = Immutable && is_nonexpansive exp
| Kept _ -> true)
fields
&& is_nonexpansive_opt extended_expression
| Texp_atomic_loc(exp, _, _) -> is_nonexpansive exp
| Texp_field(exp, _, _) -> is_nonexpansive exp
| Texp_ifthenelse(_cond, ifso, ifnot) ->
is_nonexpansive ifso && is_nonexpansive_opt ifnot
| Texp_sequence (_e1, e2) -> is_nonexpansive e2 (* PR#4354 *)
| Texp_new (_, _, cl_decl) -> Btype.class_type_arity cl_decl.cty_type > 0
(* Note: nonexpansive only means no _observable_ side effects *)
| Texp_lazy e -> is_nonexpansive e
| Texp_object ({cstr_fields=fields; cstr_type = { csig_vars=vars}}, _) ->
let count = ref 0 in
List.for_all
(fun field -> match field.cf_desc with
Tcf_method _ -> true
| Tcf_val (_, _, _, Tcfk_concrete (_, e), _) ->
incr count; is_nonexpansive e
| Tcf_val (_, _, _, Tcfk_virtual _, _) ->
incr count; true
| Tcf_initializer e -> is_nonexpansive e
| Tcf_constraint _ -> true
| Tcf_inherit _ -> false
| Tcf_attribute _ -> true)
fields &&
Vars.fold (fun _ (mut,_,_) b -> decr count; b && mut = Immutable)
vars true &&
!count = 0
| Texp_letmodule (_, _, _, mexp, e)
| Texp_open ({ open_expr = mexp; _}, e) ->
is_nonexpansive_mod mexp && is_nonexpansive e
| Texp_pack mexp ->
is_nonexpansive_mod mexp
(* Computations which raise exceptions are nonexpansive, since (raise e) is
equivalent to (raise e; diverge), and a nonexpansive "diverge" can be
produced using lazy values or the relaxed value restriction.
See GPR#1142 *)
| Texp_assert (exp, _) ->
is_nonexpansive exp
| Texp_apply (
{ exp_desc = Texp_ident (_, _, {val_kind =
Val_prim {Primitive.prim_name =
("%raise" | "%reraise" | "%raise_notrace")}}) },
[Nolabel, Arg e]) ->
is_nonexpansive e
| Texp_array (_, _ :: _)
| Texp_apply _
| Texp_try _
| Texp_setfield _
| Texp_while _
| Texp_for _
| Texp_send _
| Texp_instvar _
| Texp_setinstvar _
| Texp_override _
| Texp_letexception _
| Texp_letop _
| Texp_extension_constructor _ ->
false
and is_nonexpansive_mod mexp =
match mexp.mod_desc with
| Tmod_ident _
| Tmod_functor _ -> true
| Tmod_unpack (e, _) -> is_nonexpansive e
| Tmod_constraint (m, _, _, _) -> is_nonexpansive_mod m
| Tmod_structure str ->
List.for_all
(fun item -> match item.str_desc with
| Tstr_eval _ | Tstr_primitive _ | Tstr_type _
| Tstr_modtype _ | Tstr_class_type _ -> true
| Tstr_value (_, pat_exp_list) ->
List.for_all (fun vb -> is_nonexpansive vb.vb_expr) pat_exp_list
| Tstr_module {mb_expr=m;_}
| Tstr_open {open_expr=m;_}
| Tstr_include {incl_mod=m;_} -> is_nonexpansive_mod m
| Tstr_recmodule id_mod_list ->
List.for_all (fun {mb_expr=m;_} -> is_nonexpansive_mod m)
id_mod_list
| Tstr_exception {tyexn_constructor = {ext_kind = Text_decl _}} ->
false (* true would be unsound *)
| Tstr_exception {tyexn_constructor = {ext_kind = Text_rebind _}} ->
true
| Tstr_typext te ->
List.for_all
(function {ext_kind = Text_decl _} -> false
| {ext_kind = Text_rebind _} -> true)
te.tyext_constructors
| Tstr_class _ -> false (* could be more precise *)
| Tstr_attribute _ -> true
)
str.str_items
| Tmod_apply _ | Tmod_apply_unit _ -> false
and is_nonexpansive_opt = function
| None -> true
| Some e -> is_nonexpansive e
and is_nonexpansive_arg = function
| Omitted () -> true
| Arg e -> is_nonexpansive e
let maybe_expansive e = not (is_nonexpansive e)
let annotate_recursive_bindings env valbinds =
let ids = let_bound_idents valbinds in
List.map
(fun {vb_pat; vb_expr; vb_rec_kind = _; vb_attributes; vb_loc} ->
match (Value_rec_check.is_valid_recursive_expression ids vb_expr) with
| None ->
raise(Error(vb_expr.exp_loc, env, Illegal_letrec_expr))
| Some vb_rec_kind ->
{ vb_pat; vb_expr; vb_rec_kind; vb_attributes; vb_loc})
valbinds
let check_recursive_class_bindings env ids exprs =
List.iter
(fun expr ->
if not (Value_rec_check.is_valid_class_expr ids expr) then
raise(Error(expr.cl_loc, env, Illegal_class_expr)))
exprs
(* Approximate the type of an expression, for better recursion *)
let rec approx_type env sty =
match sty.ptyp_desc with
Ptyp_arrow (p, _, sty) ->
let ty1 = if is_optional p then type_option (newvar ()) else newvar () in
newty (Tarrow (p, ty1, approx_type env sty, commu_ok))
| Ptyp_tuple args ->
newty (Ttuple (List.map (fun (l, t) -> l, approx_type env t) args))
| Ptyp_constr (lid, ctl) ->
let path, decl = Env.lookup_type ~use:false ~loc:lid.loc lid.txt env in
if List.length ctl <> decl.type_arity then newvar ()
else begin
let tyl = List.map (approx_type env) ctl in
newconstr path tyl
end
| Ptyp_poly (_, sty) ->
approx_type env sty
| _ -> newvar ()
let type_pattern_approx env spat =
match spat.ppat_desc with
| Ppat_constraint (_, sty) -> approx_type env sty
| _ -> newvar ()
let type_approx_fun env label default spat ret_ty =
let ty = type_pattern_approx env spat in
let ty =
match label, default with
| (Nolabel | Labelled _), _ -> ty
| Optional _, None ->
unify_pat_types spat.ppat_loc env ty (type_option (newvar ()));
ty
| Optional _, Some _ ->
type_option ty
in
newty (Tarrow (label, ty, ret_ty, commu_ok))
let type_approx_constraint env ty constraint_ ~loc =
match constraint_ with
| Pconstraint constrain ->
let ty_constrain = approx_type env constrain in
begin try unify env ty ty_constrain with Unify err ->
raise (Error (loc, env, Expr_type_clash (err, None, None)))
end;
ty_constrain
| Pcoerce (constrain, coerce) ->
let approx_ty_opt = function
| None -> newvar ()
| Some sty -> approx_type env sty
in
let ty_constrain = approx_ty_opt constrain
and ty_coerce = approx_type env coerce in
begin try unify env ty ty_constrain with Unify err ->
raise (Error (loc, env, Expr_type_clash (err, None, None)))
end;
ty_coerce
let type_approx_constraint_opt env ty constraint_ ~loc =
match constraint_ with
| None -> ty
| Some constraint_ -> type_approx_constraint env ty constraint_ ~loc
let rec type_approx env sexp =
let loc = sexp.pexp_loc in
match sexp.pexp_desc with
Pexp_let (_, _, e) -> type_approx env e
| Pexp_function (params, c, body) ->
type_approx_function env params c body ~loc
| Pexp_match (_, {pc_rhs=e}::_) -> type_approx env e
| Pexp_try (e, _) -> type_approx env e
| Pexp_tuple l ->
let labeled_tys = List.map (fun (label, l) -> label, type_approx env l) l in
newty (Ttuple labeled_tys)
| Pexp_ifthenelse (_,e,_) -> type_approx env e
| Pexp_sequence (_,e) -> type_approx env e
| Pexp_constraint (e, sty) ->
let ty = type_approx env e in
type_approx_constraint env ty (Pconstraint sty) ~loc
| Pexp_coerce (e, sty1, sty2) ->
let ty = type_approx env e in
type_approx_constraint env ty (Pcoerce (sty1, sty2)) ~loc
| Pexp_pack (_, Some ptyp) ->
let ty = newvar () in
let sty = Ast_helper.Typ.package ~loc ptyp in
type_approx_constraint env ty (Pconstraint sty) ~loc
| _ -> newvar ()
and type_approx_function env params c body ~loc =
(* We can approximate types up to the first newtype parameter, whereupon
we give up.
*)
match params with
| { pparam_desc = Pparam_val (label, default, pat) } :: params ->
type_approx_fun env label default pat
(type_approx_function env params c body ~loc)
| { pparam_desc = Pparam_newtype _ } :: _ ->
newvar ()
| [] ->
let body_ty =
match body with
| Pfunction_body body ->
type_approx env body
| Pfunction_cases ({pc_rhs = e} :: _, _, _) ->
newty (Tarrow (Nolabel, newvar (), type_approx env e, commu_ok))
| Pfunction_cases ([], _, _) ->
newvar ()
in
type_approx_constraint_opt env body_ty c ~loc
(* Check that all univars are safe in a type. Both exp.exp_type and
ty_expected should already be generalized. *)
let check_univars env kind exp ty_expected vars =
let pty = instance ty_expected in
let exp_ty, vars =
with_local_level_generalize begin fun () ->
match get_desc pty with
Tpoly (body, tl) ->
(* Enforce scoping for type_let:
since body is not generic, instance_poly only makes
copies of nodes that have a Tunivar as descendant *)
let _, ty' = instance_poly ~fixed:true tl body in
let vars, exp_ty = instance_parameterized_type vars exp.exp_type in
unify_exp_types exp.exp_loc env exp_ty ty';
(exp_ty, vars)
| _ -> assert false
end
in
let ty, complete = polyfy env exp_ty vars in
if not complete then
let ty_expected = instance ty_expected in
raise (Error(exp.exp_loc,
env,
Less_general(kind,
Errortrace.unification_error
~trace:[Ctype.expanded_diff env
~got:ty ~expected:ty_expected])))
(* [check_statement] implements the [non-unit-statement] check.
This check is called in contexts where the value of the expression is known
to be discarded (eg. the lhs of a sequence). We check that [exp] has type
unit, or has an explicit type annotation; otherwise we raise the
[non-unit-statement] warning. *)
let check_statement exp =
let ty = get_desc (expand_head exp.exp_env exp.exp_type) in
match ty with
| Tconstr (p, _, _) when Path.same p Predef.path_unit -> ()
| Tvar _ -> ()
| _ ->
let rec loop {exp_loc; exp_desc; exp_extra; _} =
match exp_desc with
| Texp_let (_, _, e)
| Texp_sequence (_, e)
| Texp_letexception (_, e)
| Texp_letmodule (_, _, _, _, e) ->
loop e
| _ ->
let loc =
match List.find_opt (function
| (Texp_constraint _, _, _) -> true
| _ -> false) exp_extra
with
| Some (_, loc, _) -> loc
| None -> exp_loc
in
Location.prerr_warning loc Warnings.Non_unit_statement
in
loop exp
(* [check_partial_application] implements the [ignored-partial-application]
warning (and if [statement] is [true], also [non-unit-statement]).
If [exp] has a function type, we check that it is not syntactically the
result of a function application, as this is often a bug in certain contexts
(eg the rhs of a let-binding or in the argument of [ignore]). For example,
[ignore (List.map print_int)] written by mistake instead of [ignore (List.map
print_int li)].
The check can be disabled by explicitly annotating the expression with a type
constraint, eg [(e : _ -> _)].
If [statement] is [true] and the [ignored-partial-application] is {em not}
triggered, then the [non-unit-statement] check is performed (see
[check_statement]).
If the type of [exp] is not known at the time this function is called, the
check is retried again after typechecking. *)
let check_partial_application ~statement exp =
let check_statement () = if statement then check_statement exp in
let doit () =
let ty = get_desc (expand_head exp.exp_env exp.exp_type) in
match ty with
| Tarrow _ ->
let rec check {exp_desc; exp_loc; exp_extra; _} =
if List.exists (function
| (Texp_constraint _, _, _) -> true
| _ -> false) exp_extra then check_statement ()
else begin
match exp_desc with
| Texp_ident _ | Texp_constant _ | Texp_tuple _
| Texp_construct _ | Texp_variant _ | Texp_record _
| Texp_atomic_loc _ | Texp_field _ | Texp_setfield _ | Texp_array _
| Texp_while _ | Texp_for _ | Texp_instvar _
| Texp_setinstvar _ | Texp_override _ | Texp_assert _
| Texp_lazy _ | Texp_object _ | Texp_pack _ | Texp_unreachable
| Texp_extension_constructor _ | Texp_ifthenelse (_, _, None)
| Texp_function _ ->
check_statement ()
| Texp_match (_, cases, eff_cases, _) ->
List.iter (fun {c_rhs; _} -> check c_rhs) cases;
List.iter (fun {c_rhs; _} -> check c_rhs) eff_cases
| Texp_try (e, cases, eff_cases) ->
check e;
List.iter (fun {c_rhs; _} -> check c_rhs) cases;
List.iter (fun {c_rhs; _} -> check c_rhs) eff_cases
| Texp_ifthenelse (_, e1, Some e2) ->
check e1; check e2
| Texp_let (_, _, e) | Texp_sequence (_, e) | Texp_open (_, e)
| Texp_letexception (_, e) | Texp_letmodule (_, _, _, _, e) ->
check e
| Texp_apply _ | Texp_send _ | Texp_new _ | Texp_letop _ ->
Location.prerr_warning exp_loc
Warnings.Ignored_partial_application
end
in
check exp
| _ ->
check_statement ()
in
let ty = get_desc (expand_head exp.exp_env exp.exp_type) in
match ty with
| Tvar _ ->
(* The type of [exp] is not known. Delay the check until after
typechecking in order to give a chance for the type to become known
through unification. *)
add_delayed_check doit
| _ ->
doit ()
let pattern_needs_partial_application_check p =
let rec check : type a. a general_pattern -> bool = fun p ->
not (List.exists (function (Tpat_constraint _, _, _) -> true | _ -> false)
p.pat_extra) &&
match p.pat_desc with
| Tpat_any -> true
| Tpat_exception _ -> true
| Tpat_or (p1, p2, _) -> check p1 && check p2
| Tpat_value p -> check (p :> value general_pattern)
| _ -> false
in
check p
(* Check that a type is generalizable at some level *)
let generalizable level ty =
with_type_mark begin fun mark ->
let rec check ty =
if try_mark_node mark ty then
if get_level ty <= level then raise Exit else iter_type_expr check ty
in
try check ty; true with Exit -> false
end
(* Hack to allow coercion of self. Will clean-up later. *)
let self_coercion = ref ([] : (Path.t * Location.t list ref) list)
(* Helpers for type_cases *)
let contains_variant_either ty =
with_type_mark begin fun mark ->
let rec loop ty =
if try_mark_node mark ty then
begin match get_desc ty with
Tvariant row ->
if not (is_fixed row) then
List.iter
(fun (_,f) ->
match row_field_repr f with Reither _ -> raise Exit | _ -> ())
(row_fields row);
iter_row loop row
| _ ->
iter_type_expr loop ty
end
in
try loop ty; false with Exit -> true
end
let shallow_iter_ppat f p =
match p.ppat_desc with
| Ppat_any | Ppat_var _ | Ppat_constant _ | Ppat_interval _
| Ppat_construct (_, None)
| Ppat_extension _
| Ppat_type _ | Ppat_unpack _ -> ()
| Ppat_array pats -> List.iter f pats
| Ppat_or (p1,p2)
| Ppat_effect(p1, p2) -> f p1; f p2
| Ppat_variant (_, arg) -> Option.iter f arg
| Ppat_tuple (lst, _) -> List.iter (fun (_, p) -> f p) lst
| Ppat_construct (_, Some (_, p))
| Ppat_exception p | Ppat_alias (p,_)
| Ppat_open (_,p)
| Ppat_constraint (p,_) | Ppat_lazy p -> f p
| Ppat_record (args, _flag) -> List.iter (fun (_,p) -> f p) args
let exists_ppat f p =
let exception Found in
let rec loop p =
if f p then raise Found else ();
shallow_iter_ppat loop p in
match loop p with
| exception Found -> true
| () -> false
let contains_polymorphic_variant p =
exists_ppat
(function
| {ppat_desc = (Ppat_variant _ | Ppat_type _)} -> true
| _ -> false)
p
let contains_gadt p =
exists_general_pattern { f = fun (type k) (p : k general_pattern) ->
match p.pat_desc with
| Tpat_construct (_, cd, _, _) when cd.cstr_generalized -> true
| _ -> false } p
(* There are various things that we need to do in presence of GADT constructors
that aren't required if there are none.
However, because of disambiguation, we can't know for sure whether the
patterns contain some GADT constructors. So we conservatively assume that
any constructor might be a GADT constructor. *)
let may_contain_gadts p =
exists_ppat
(function
| {ppat_desc = Ppat_construct _} -> true
| _ -> false)
p
(* One of the things we do in the presence of GADT constructors (see above
definition) is treat `let p = e in ...` as a match `match e with p -> ...`.
This changes the way type inference works to check the expression first, and
use its type in the checking of the pattern. We want that behavior for
labeled tuple patterns as well. *)
let turn_let_into_match p =
exists_ppat
(fun p ->
match p.ppat_desc with
| Ppat_construct _ -> true
| Ppat_tuple (_, Open) -> true
| Ppat_tuple (spl, Closed) ->
List.exists (fun (l, _) -> Option.is_some l) spl
| _ -> false)
p
(* There are various things that we need to do in presence of module patterns
that aren't required if there are none. Most notably, we need to ensure the
modules are entered at the appropriate scope. The caller should use
[may_contain_modules] as an indication to set up the proper scope handling
code (via [allow_modules]) to permit module patterns.
The class of patterns identified here should stay in sync with the patterns
whose typing involves [enter_variable ~is_module:true], as these calls
will error if the scope handling isn't set up.
*)
let may_contain_modules p =
exists_ppat
(function
| {ppat_desc = Ppat_unpack _} -> true
| _ -> false)
p
let check_absent_variant env =
iter_general_pattern { f = fun (type k) (pat : k general_pattern) ->
match pat.pat_desc with
| Tpat_variant (s, arg, row) ->
let row = !row in
if List.exists (fun (s',fi) -> s = s' && row_field_repr fi <> Rabsent)
(row_fields row)
|| not (is_fixed row) && not (static_row row) (* same as Ctype.poly *)
then () else
let ty_arg =
match arg with None -> [] | Some p -> [duplicate_type p.pat_type] in
let fields = [s, rf_either ty_arg ~no_arg:(arg=None) ~matched:true] in
let row' =
create_row ~fields
~more:(newvar ()) ~closed:false ~fixed:None ~name:None in
(* Should fail *)
unify_pat env {pat with pat_type = newty (Tvariant row')}
(duplicate_type pat.pat_type)
| _ -> () }
(* To find reasonable names for let-bound and lambda-bound idents *)
let rec name_pattern default = function
[] -> Ident.create_local default
| p :: rem ->
match p.pat_desc with
Tpat_var (id, _, _) -> id
| Tpat_alias(_, id, _, _, _) -> id
| _ -> name_pattern default rem
let name_cases default lst =
name_pattern default (List.map (fun c -> c.c_lhs) lst)
(* Typing of expressions *)
(* If [is_inferred e] is true, [e] will be typechecked without using
the "expected type" provided by the context. *)
let rec is_inferred sexp =
match sexp.pexp_desc with
| Pexp_ident _ | Pexp_apply _ | Pexp_field _ | Pexp_constraint _
| Pexp_coerce _ | Pexp_send _ | Pexp_new _ | Pexp_pack (_, Some _) -> true
| Pexp_sequence (_, e) | Pexp_open (_, e) -> is_inferred e
| Pexp_ifthenelse (_, e1, Some e2) -> is_inferred e1 && is_inferred e2
| _ -> false
(* check if the type of %apply or %revapply matches the type expected by
the specialized typing rule for those primitives.
*)
type apply_prim =
| Apply
| Revapply
let check_apply_prim_type prim typ =
match get_desc typ with
| Tarrow (Nolabel,a,b,_) ->
begin match get_desc b with
| Tarrow(Nolabel,c,d,_) ->
let f, x, res =
match prim with
| Apply -> a, c, d
| Revapply -> c, a, d
in
begin match get_desc f with
| Tarrow(Nolabel,fl,fr,_) ->
is_Tvar fl && is_Tvar fr && is_Tvar x && is_Tvar res
&& Types.eq_type fl x && Types.eq_type fr res
| _ -> false
end
| _ -> false
end
| _ -> false
(* Merge explanation to type clash error *)
let with_explanation explanation f =
match explanation with
| None -> f ()
| Some explanation ->
try f ()
with Error (loc', env', Expr_type_clash(err', None, exp'))
when not loc'.Location.loc_ghost ->
let err = Expr_type_clash(err', Some explanation, exp') in
raise (Error (loc', env', err))
(* Generalize expressions *)
let may_lower_contravariant env exp =
if maybe_expansive exp then lower_contravariant env exp.exp_type
(* value binding elaboration *)
let vb_exp_constraint {pvb_expr=expr; pvb_pat=pat; pvb_constraint=ct; _ } =
let open Ast_helper in
match ct with
| None -> expr
| Some (Pvc_constraint { locally_abstract_univars=[]; typ }) ->
begin match typ.ptyp_desc with
| Ptyp_poly _ -> expr
| _ ->
let loc = { expr.pexp_loc with Location.loc_ghost = true } in
Exp.constraint_ ~loc expr typ
end
| Some (Pvc_coercion { ground; coercion}) ->
let loc = { expr.pexp_loc with Location.loc_ghost = true } in
Exp.coerce ~loc expr ground coercion
| Some (Pvc_constraint { locally_abstract_univars=vars;typ}) ->
let loc_start = pat.ppat_loc.Location.loc_start in
let loc = { expr.pexp_loc with loc_start; loc_ghost=true } in
let expr = Exp.constraint_ ~loc expr typ in
List.fold_right (Exp.newtype ~loc) vars expr
let vb_pat_constraint ({pvb_pat=pat; pvb_expr = exp; _ } as vb) =
vb.pvb_attributes,
let open Ast_helper in
match vb.pvb_constraint, pat.ppat_desc, exp.pexp_desc with
| Some (Pvc_constraint {locally_abstract_univars=[]; typ}
| Pvc_coercion { coercion=typ; _ }),
_, _ ->
Pat.constraint_ ~loc:{pat.ppat_loc with Location.loc_ghost=true} pat typ
| Some (Pvc_constraint {locally_abstract_univars=vars; typ }), _, _ ->
let varified = Typ.varify_constructors vars typ in
let t = Typ.poly ~loc:typ.ptyp_loc vars varified in
let loc_end = typ.ptyp_loc.Location.loc_end in
let loc = { pat.ppat_loc with loc_end; loc_ghost=true } in
Pat.constraint_ ~loc pat t
| None, (Ppat_any | Ppat_constraint _), _ -> pat
| None, _, Pexp_coerce (_, _, sty)
| None, _, Pexp_constraint (_, sty) when !Clflags.principal ->
(* propagate type annotation to pattern,
to allow it to be generalized in -principal mode *)
Pat.constraint_ ~loc:{pat.ppat_loc with Location.loc_ghost=true} pat sty
| _ -> pat
(** The body of a constraint or coercion. The "body" may be either an expression
or a list of function cases. This type is polymorphic in the data returned
out of typing so that typing an expression body can return an expression
and typing a function cases body can return the cases.
*)
type 'ret constraint_arg =
{ type_without_constraint: Env.t -> 'ret * type_expr;
(** [type_without_constraint] types a body (e :> t) where there is no
constraint.
*)
type_with_constraint: Env.t -> type_expr -> 'ret;
(** [type_with_constraint] types a body (e : t) or (e : t :> t') in
the presence of a constraint.
*)
is_self: 'ret -> bool;
(** Whether the thing being constrained is a [Val_self] ident. *)
}
let rec type_exp ?recarg env sexp =
(* We now delegate everything to type_expect *)
type_expect ?recarg env sexp (mk_expected (newvar ()))
(* Typing of an expression with an expected type.
This provide better error messages, and allows controlled
propagation of return type information.
In the principal case, structural nodes of [type_expected_explained] may be
at [generic_level] (but its variables no higher than [!current_level]).
*)
and type_expect ?recarg env sexp ty_expected_explained =
let previous_saved_types = Cmt_format.get_saved_types () in
let exp =
Builtin_attributes.warning_scope sexp.pexp_attributes
(fun () ->
type_expect_ ?recarg env sexp ty_expected_explained
)
in
Cmt_format.set_saved_types
(Cmt_format.Partial_expression exp :: previous_saved_types);
exp
and type_expect_
?(recarg=Rejected)
env sexp ty_expected_explained =
let { ty = ty_expected; explanation } = ty_expected_explained in
let loc = sexp.pexp_loc in
(* Record the expression type before unifying it with the expected type *)
let with_explanation = with_explanation explanation in
(* Unify the result with [ty_expected], enforcing the current level *)
let rue exp =
with_explanation (fun () ->
unify_exp ~sexp env (re exp) (instance ty_expected));
exp
in
match sexp.pexp_desc with
| Pexp_ident lid ->
let path, desc = type_ident env ~recarg lid in
let exp_desc =
match desc.val_kind with
| Val_ivar (_, cl_num) ->
let (self_path, _) =
Env.find_value_by_name
(Longident.Lident ("self-" ^ cl_num)) env
in
Texp_instvar(self_path, path,
match lid.txt with
Longident.Lident txt -> { txt; loc = lid.loc }
| _ -> assert false)
| Val_self (_, _, _, cl_num) ->
let (path, _) =
Env.find_value_by_name (Longident.Lident ("self-" ^ cl_num)) env
in
Texp_ident(path, lid, desc)
| _ ->
Texp_ident(path, lid, desc)
in
rue {
exp_desc; exp_loc = loc; exp_extra = [];
exp_type = instance desc.val_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_constant({pconst_desc = Pconst_string (str, _, _); _} as cst) -> (
let cst = constant_or_raise env loc cst in
(* Terrible hack for format strings *)
let ty_exp = expand_head env (protect_expansion env ty_expected) in
let fmt6_path =
Path.(Pdot (Pident (Ident.create_persistent "CamlinternalFormatBasics"),
"format6"))
in
let is_format = match get_desc ty_exp with
| Tconstr(path, _, _) when Path.same path fmt6_path ->
if !Clflags.principal && get_level ty_exp <> generic_level then
Location.prerr_warning loc
(not_principal "this coercion to format6");
true
| _ -> false
in
if is_format then
let format_parsetree =
{ (type_format loc str env) with pexp_loc = sexp.pexp_loc } in
type_expect env format_parsetree ty_expected_explained
else
rue {
exp_desc = Texp_constant cst;
exp_loc = loc; exp_extra = [];
exp_type = instance Predef.type_string;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
)
| Pexp_constant cst ->
let cst = constant_or_raise env loc cst in
rue {
exp_desc = Texp_constant cst;
exp_loc = loc; exp_extra = [];
exp_type = type_constant cst;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_let(Nonrecursive,
[{pvb_pat=spat; pvb_attributes=[]; _ } as vb], sbody)
when turn_let_into_match spat ->
(* TODO: allow non-empty attributes? *)
let sval = vb_exp_constraint vb in
type_expect env
{sexp with
pexp_desc = Pexp_match (sval, [Ast_helper.Exp.case spat sbody])}
ty_expected_explained
| Pexp_let(rec_flag, spat_sexp_list, sbody) ->
let existential_context =
if rec_flag = Recursive then In_rec
else if List.compare_length_with spat_sexp_list 1 > 0 then In_group
else With_attributes in
let may_contain_modules =
List.exists (fun pvb -> may_contain_modules pvb.pvb_pat) spat_sexp_list
in
let outer_level = get_current_level () in
let (pat_exp_list, body, _new_env) =
(* If the patterns contain module unpacks, there is a possibility that
the types of the let body or bound expressions mention types
introduced by those unpacks. The below code checks for scope escape
via both of these pathways (body, bound expressions).
*)
with_local_level_generalize_if may_contain_modules begin fun () ->
let allow_modules =
if may_contain_modules
then
let scope = create_scope () in
Modules_allowed { scope }
else Modules_rejected
in
let (pat_exp_list, new_env) =
type_let existential_context env rec_flag spat_sexp_list
allow_modules
in
let body = type_expect new_env sbody ty_expected_explained in
let pat_exp_list = match rec_flag with
| Recursive -> annotate_recursive_bindings env pat_exp_list
| Nonrecursive -> pat_exp_list
in
(* The "bound expressions" component of the scope escape check.
This kind of scope escape is relevant only for recursive
module definitions.
*)
if rec_flag = Recursive && may_contain_modules then begin
List.iter
(fun vb ->
(* [type_let] already generalized bound expressions' types
in-place. We first take an instance before checking scope
escape at the outer level to avoid losing generality of
types added to [new_env].
*)
let bound_exp = vb.vb_expr in
let bound_exp_type = Ctype.instance bound_exp.exp_type in
let loc = proper_exp_loc bound_exp in
let outer_var = newvar2 outer_level in
(* Checking unification within an environment extended with the
module bindings allows us to correctly accept more programs.
This environment allows unification to identify more cases
where a type introduced by the module is equal to a type
introduced at an outer scope. *)
unify_exp_types loc new_env bound_exp_type outer_var)
pat_exp_list
end;
(pat_exp_list, body, new_env)
end
~before_generalize:(fun (_pat_exp_list, body, new_env) ->
(* The "body" component of the scope escape check. *)
unify_exp ~sexp new_env body (newvar ()))
in
re {
exp_desc = Texp_let(rec_flag, pat_exp_list, body);
exp_loc = loc; exp_extra = [];
exp_type = body.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_function (params, body_constraint, body) ->
let in_function = ty_expected_explained, loc in
let exp_type, params, body, newtypes, contains_gadt =
type_function env params body_constraint body ty_expected ~in_function
~first:true
in
(* Require that the n-ary function is known to have at least n arrows
in the type. This prevents GADT equations introduced by the parameters
from hiding arrows from the resulting type.
Performance hack: Only do this check when any of [params] contains a
GADT, as this is the only opportunity for arrows to be hidden from the
resulting type.
*)
begin match contains_gadt with
| No_gadt -> ()
| Contains_gadt ->
let ty_function =
List.fold_right
(fun param rest_ty ->
newty
(Tarrow (param.fp_arg_label, newvar (), rest_ty, commu_ok)))
params
(match body with
| Tfunction_body _ -> newvar ()
| Tfunction_cases _ ->
newty (Tarrow (Nolabel, newvar (), newvar (), commu_ok)))
in
try unify env ty_function exp_type
with Unify trace ->
let syntactic_arity =
List.length params +
(match body with
| Tfunction_body _ -> 0
| Tfunction_cases _ -> 1)
in
let err =
Function_arity_type_clash
{ syntactic_arity;
type_constraint = exp_type;
trace;
}
in
raise (Error (loc, env, err))
end;
re
{ exp_desc = Texp_function (params, body);
exp_loc = loc;
exp_extra =
List.map (fun { txt; loc } -> Texp_newtype txt, loc, []) newtypes;
exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_apply(sfunct, sargs) ->
assert (sargs <> []);
let outer_level = get_current_level () in
let rec lower_args seen ty_fun =
let ty = expand_head env ty_fun in
if TypeSet.mem ty seen then () else
match get_desc ty with
Tarrow (_l, ty_arg, ty_fun, _com) ->
(try Ctype.unify_var env (newvar2 outer_level) ty_arg
with Unify _ -> assert false);
lower_args (TypeSet.add ty seen) ty_fun
| _ -> ()
in
(* one more level for warning on non-returning functions *)
with_local_level_generalize begin fun () ->
let type_sfunct sfunct =
let funct =
with_local_level_generalize_structure_if_principal
(fun () -> type_exp env sfunct)
in
let ty = instance funct.exp_type in
wrap_trace_gadt_instances env (lower_args TypeSet.empty) ty;
funct
in
let funct, sargs =
let funct = type_sfunct sfunct in
match funct.exp_desc, sargs with
| Texp_ident (_, _,
{val_kind = Val_prim {prim_name="%revapply"}; val_type}),
[Nolabel, sarg; Nolabel, actual_sfunct]
when is_inferred actual_sfunct
&& check_apply_prim_type Revapply val_type ->
type_sfunct actual_sfunct, [Nolabel, sarg]
| Texp_ident (_, _,
{val_kind = Val_prim {prim_name="%apply"}; val_type}),
[Nolabel, actual_sfunct; Nolabel, sarg]
when check_apply_prim_type Apply val_type ->
type_sfunct actual_sfunct, [Nolabel, sarg]
| _ ->
funct, sargs
in
let (args, ty_res) = type_application env funct sargs in
rue {
exp_desc = Texp_apply(funct, args);
exp_loc = loc; exp_extra = [];
exp_type = ty_res;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
end
| Pexp_match(sarg, caselist) ->
let arg =
with_local_level_generalize (fun () -> type_exp env sarg)
~before_generalize:(may_lower_contravariant env)
in
let rec split_cases valc effc conts = function
| [] -> List.rev valc, List.rev effc, List.rev conts
| {pc_lhs = {ppat_desc=Ppat_effect(p1, p2)}} as c :: rest ->
split_cases valc
(({c with pc_lhs = p1}) :: effc) (p2 :: conts) rest
| c :: rest ->
split_cases (c :: valc) effc conts rest
in
let val_caselist, eff_caselist, eff_conts =
split_cases [] [] [] caselist
in
if val_caselist = [] && eff_caselist <> [] then
raise (Error (loc, env, No_value_clauses));
let val_cases, partial =
type_cases Computation env arg.exp_type ty_expected_explained
~check_if_total:true loc val_caselist
in
let eff_cases =
match eff_caselist with
| [] -> []
| eff_caselist ->
type_effect_cases Value env ty_expected_explained loc eff_caselist
eff_conts
in
if
List.for_all (fun c -> pattern_needs_partial_application_check c.c_lhs)
val_cases
then check_partial_application ~statement:false arg;
re {
exp_desc = Texp_match(arg, val_cases, eff_cases, partial);
exp_loc = loc; exp_extra = [];
exp_type = instance ty_expected;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_try(sbody, caselist) ->
let body = type_expect env sbody ty_expected_explained in
let rec split_cases exnc effc conts = function
| [] -> List.rev exnc, List.rev effc, List.rev conts
| {pc_lhs = {ppat_desc=Ppat_effect(p1, p2)}} as c :: rest ->
split_cases exnc
(({c with pc_lhs = p1}) :: effc) (p2 :: conts) rest
| c :: rest ->
split_cases (c :: exnc) effc conts rest
in
let exn_caselist, eff_caselist, eff_conts =
split_cases [] [] [] caselist
in
let exn_cases, _ =
type_cases Value env Predef.type_exn ty_expected_explained
~check_if_total:false loc exn_caselist
in
let eff_cases =
match eff_caselist with
| [] -> []
| eff_caselist ->
type_effect_cases Value env ty_expected_explained loc eff_caselist
eff_conts
in
re {
exp_desc = Texp_try(body, exn_cases, eff_cases);
exp_loc = loc; exp_extra = [];
exp_type = body.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_tuple sexpl ->
assert (List.length sexpl >= 2);
Option.iter
(fun l -> raise (Error (loc, env, Repeated_tuple_exp_label l)))
(Misc.repeated_label sexpl);
let labeled_subtypes = List.map (fun (l, _) -> l, newgenvar ()) sexpl in
let to_unify = newgenty (Ttuple labeled_subtypes) in
with_explanation (fun () ->
unify_exp_types loc env to_unify (generic_instance ty_expected));
let expl =
List.map2
(fun (l, body) (_, ty) ->
(l, type_expect env body (mk_expected ty)))
sexpl labeled_subtypes
in
re {
exp_desc = Texp_tuple expl;
exp_loc = loc; exp_extra = [];
(* Keep sharing *)
exp_type = newty (Ttuple (List.map (fun (l, e) -> l, e.exp_type) expl));
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_construct(lid, sarg) ->
type_construct env ~sexp lid sarg ty_expected_explained
| Pexp_variant(l, sarg) ->
(* Keep sharing *)
let ty_expected1 = protect_expansion env ty_expected in
let ty_expected0 = instance ty_expected in
begin try match
sarg, get_desc (expand_head env ty_expected1),
get_desc (expand_head env ty_expected0)
with
| Some sarg, Tvariant row, Tvariant row0 ->
begin match
row_field_repr (get_row_field l row),
row_field_repr (get_row_field l row0)
with
Rpresent (Some ty), Rpresent (Some ty0) ->
let arg = type_argument env sarg ty ty0 in
re { exp_desc = Texp_variant(l, Some arg);
exp_loc = loc; exp_extra = [];
exp_type = ty_expected0;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ -> raise Exit
end
| _ -> raise Exit
with Exit ->
let arg = Option.map (type_exp env) sarg in
let arg_type = Option.map (fun arg -> arg.exp_type) arg in
let row =
create_row
~fields: [l, rf_present arg_type]
~more: (newvar ())
~closed: false
~fixed: None
~name: None
in
rue {
exp_desc = Texp_variant(l, arg);
exp_loc = loc; exp_extra = [];
exp_type = newty (Tvariant row);
exp_attributes = sexp.pexp_attributes;
exp_env = env }
end
| Pexp_record(lid_sexp_list, opt_sexp) ->
assert (lid_sexp_list <> []);
let opt_exp =
match opt_sexp with
None -> None
| Some sexp ->
let exp =
with_local_level_generalize_structure_if_principal
(fun () -> type_exp ~recarg env sexp)
in
Some exp
in
let ty_record, expected_type =
let expected_opath =
match extract_concrete_record env ty_expected with
| Record_type (p0, p, _) -> Some (p0, p, is_principal ty_expected)
| Maybe_a_record_type -> None
| Not_a_record_type ->
let error =
Wrong_expected_kind(Record, Expression explanation, ty_expected)
in
raise (Error (loc, env, error))
in
let opt_exp_opath =
match opt_exp with
| None -> None
| Some exp ->
match extract_concrete_record env exp.exp_type with
| Record_type (p0, p, _) -> Some (p0, p, is_principal exp.exp_type)
| Maybe_a_record_type -> None
| Not_a_record_type ->
let error = Expr_not_a_record_type exp.exp_type in
raise (Error (exp.exp_loc, env, error))
in
match expected_opath, opt_exp_opath with
| None, None -> newvar (), None
| Some _, None -> ty_expected, expected_opath
| Some(_, _, true), Some _ -> ty_expected, expected_opath
| (None | Some (_, _, false)), Some (_, p', _) ->
let decl = Env.find_type p' env in
let ty =
with_local_level_generalize_structure
(fun () -> newconstr p' (instance_list decl.type_params))
in
ty, opt_exp_opath
in
let closed = (opt_sexp = None) in
let lbl_exp_list =
wrap_disambiguate "This record expression is expected to have"
(mk_expected ty_record)
(type_label_a_list loc closed env Env.Construct
(type_label_exp true env loc ty_record)
expected_type)
lid_sexp_list
in
with_explanation (fun () ->
unify_exp_types loc env (instance ty_record) (instance ty_expected));
(* type_label_a_list returns a list of labels sorted by lbl_pos *)
(* note: check_duplicates would better be implemented in
type_label_a_list directly *)
let rec check_duplicates = function
| (_, lbl1, _) :: (_, lbl2, _) :: _ when lbl1.lbl_pos = lbl2.lbl_pos ->
raise(Error(loc, env, Label_multiply_defined lbl1.lbl_name))
| _ :: rem ->
check_duplicates rem
| [] -> ()
in
check_duplicates lbl_exp_list;
let opt_exp, label_definitions =
let (_lid, lbl, _lbl_exp) = List.hd lbl_exp_list in
let matching_label lbl =
List.find
(fun (_, lbl',_) -> lbl'.lbl_pos = lbl.lbl_pos)
lbl_exp_list
in
match opt_exp with
None ->
let label_definitions =
Array.map (fun lbl ->
match matching_label lbl with
| (lid, _lbl, lbl_exp) ->
Overridden (lid, lbl_exp)
| exception Not_found ->
let present_indices =
List.map (fun (_, lbl, _) -> lbl.lbl_pos) lbl_exp_list
in
let label_names = extract_label_names env ty_expected in
let rec missing_labels n = function
[] -> []
| lbl :: rem ->
if List.mem n present_indices
then missing_labels (n + 1) rem
else lbl :: missing_labels (n + 1) rem
in
let missing = missing_labels 0 label_names in
raise(Error(loc, env, Label_missing missing)))
lbl.lbl_all
in
None, label_definitions
| Some exp ->
let ty_exp = instance exp.exp_type in
let unify_kept lbl =
let _, ty_arg1, ty_res1 = instance_label ~fixed:false lbl in
unify_exp_types exp.exp_loc env ty_exp ty_res1;
match matching_label lbl with
| lid, _lbl, lbl_exp ->
(* do not connect result types for overridden labels *)
Overridden (lid, lbl_exp)
| exception Not_found -> begin
let _, ty_arg2, ty_res2 = instance_label ~fixed:false lbl in
unify_exp_types loc env ty_arg1 ty_arg2;
with_explanation (fun () ->
unify_exp_types loc env (instance ty_expected) ty_res2);
Kept (ty_arg1, lbl.lbl_mut)
end
in
let label_definitions = Array.map unify_kept lbl.lbl_all in
Some {exp with exp_type = ty_exp}, label_definitions
in
let num_fields =
match lbl_exp_list with [] -> assert false
| (_, lbl,_)::_ -> Array.length lbl.lbl_all in
if opt_sexp <> None && List.length lid_sexp_list = num_fields then
Location.prerr_warning loc Warnings.Useless_record_with;
let label_descriptions, representation =
let (_, { lbl_all; lbl_repres }, _) = List.hd lbl_exp_list in
lbl_all, lbl_repres
in
let fields =
Array.map2 (fun descr def -> descr, def)
label_descriptions label_definitions
in
re {
exp_desc = Texp_record {
fields; representation;
extended_expression = opt_exp
};
exp_loc = loc; exp_extra = [];
exp_type = instance ty_expected;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_field(srecord, lid) ->
let record, label, ty_arg =
solve_Pexp_field ~label_usage:Env.Projection env sexp srecord lid
in
rue {
exp_desc = Texp_field(record, lid, label);
exp_loc = loc; exp_extra = [];
exp_type = ty_arg;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_setfield(srecord, lid, snewval) ->
let (record, label, expected_type) =
type_label_access env srecord Env.Mutation lid in
let ty_record =
if expected_type = None then newvar () else record.exp_type in
let (label_loc, label, newval) =
type_label_exp false env loc ty_record (lid, label, snewval) in
unify_exp ~sexp env record ty_record;
if label.lbl_mut = Immutable then
raise(Error(loc, env, Label_not_mutable lid.txt));
rue {
exp_desc = Texp_setfield(record, label_loc, label, newval);
exp_loc = loc; exp_extra = [];
exp_type = instance Predef.type_unit;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_array(sargl) ->
let ty_elt, mutability =
let ty_expected = generic_instance ty_expected in
match disambiguate_array_literal ~loc env ty_expected with
| { ty_elt = Some ty; mut } -> ty, mut
| { ty_elt = None; mut } ->
let ty = newgenvar () in
let to_unify =
match mut with
| Mutable -> Predef.type_array ty
| Immutable -> Predef.type_iarray ty
in
with_explanation (fun () ->
unify_exp_types loc env to_unify ty_expected);
ty, mut
in
let argl =
List.map (fun sarg -> type_expect env sarg (mk_expected ty_elt)) sargl
in
re {
exp_desc = Texp_array (mutability, argl);
exp_loc = loc; exp_extra = [];
exp_type = instance ty_expected;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_ifthenelse(scond, sifso, sifnot) ->
let cond = type_expect env scond
(mk_expected ~explanation:If_conditional Predef.type_bool) in
begin match sifnot with
None ->
let ifso = type_expect env sifso
(mk_expected ~explanation:If_no_else_branch Predef.type_unit) in
rue {
exp_desc = Texp_ifthenelse(cond, ifso, None);
exp_loc = loc; exp_extra = [];
exp_type = ifso.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Some sifnot ->
let ifso = type_expect env sifso ty_expected_explained in
let ifnot = type_expect env sifnot ty_expected_explained in
(* Keep sharing *)
unify_exp ~sexp env ifnot ifso.exp_type;
re {
exp_desc = Texp_ifthenelse(cond, ifso, Some ifnot);
exp_loc = loc; exp_extra = [];
exp_type = ifso.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
end
| Pexp_sequence(sexp1, sexp2) ->
let exp1 = type_statement ~explanation:Sequence_left_hand_side
env sexp1 in
let exp2 = type_expect env sexp2 ty_expected_explained in
re {
exp_desc = Texp_sequence(exp1, exp2);
exp_loc = loc; exp_extra = [];
exp_type = exp2.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_while(scond, sbody) ->
let cond = type_expect env scond
(mk_expected ~explanation:While_loop_conditional Predef.type_bool) in
let exp_type =
match cond.exp_desc with
| Texp_construct(_, {cstr_name="true"}, _) -> instance ty_expected
| _ -> instance Predef.type_unit
in
let body = type_statement ~explanation:While_loop_body env sbody in
rue {
exp_desc = Texp_while(cond, body);
exp_loc = loc; exp_extra = [];
exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_for(param, slow, shigh, dir, sbody) ->
let low = type_expect env slow
(mk_expected ~explanation:For_loop_start_index Predef.type_int) in
let high = type_expect env shigh
(mk_expected ~explanation:For_loop_stop_index Predef.type_int) in
let id, new_env =
match param.ppat_desc with
| Ppat_any -> Ident.create_local "_for", env
| Ppat_var {txt} ->
Env.enter_value txt
{val_type = instance Predef.type_int;
val_attributes = [];
val_kind = Val_reg;
val_loc = loc;
val_uid = Uid.mk ~current_unit:(Env.get_current_unit ());
} env
~check:(fun s -> Warnings.Unused_for_index s)
| _ ->
raise (Error (param.ppat_loc, env, Invalid_for_loop_index))
in
let body = type_statement ~explanation:For_loop_body new_env sbody in
rue {
exp_desc = Texp_for(id, param, low, high, dir, body);
exp_loc = loc; exp_extra = [];
exp_type = instance Predef.type_unit;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_constraint (sarg, sty) ->
let (ty, exp_extra) = type_constraint env sty in
let arg = type_argument env sarg ty (instance ty) in
rue {
exp_desc = arg.exp_desc;
exp_loc = arg.exp_loc;
exp_type = instance ty;
exp_attributes = arg.exp_attributes;
exp_env = env;
exp_extra = (exp_extra, loc, sexp.pexp_attributes) :: arg.exp_extra;
}
| Pexp_coerce(sarg, sty, sty') ->
let arg, ty', exp_extra =
type_coerce (expression_constraint sarg) env loc sty sty'
~loc_arg:sarg.pexp_loc
in
rue {
exp_desc = arg.exp_desc;
exp_loc = arg.exp_loc;
exp_type = ty';
exp_attributes = arg.exp_attributes;
exp_env = env;
exp_extra = (exp_extra, loc, sexp.pexp_attributes) :: arg.exp_extra;
}
| Pexp_send (e, {txt=met}) ->
let (obj,meth,typ) =
with_local_level_generalize_structure_if_principal
(fun () -> type_send env loc explanation e met)
in
let typ =
match get_desc typ with
| Tpoly (ty, []) ->
instance ty
| Tpoly (ty, tl) ->
if !Clflags.principal && get_level typ <> generic_level then
Location.prerr_warning loc
(not_principal "this use of a polymorphic method");
snd (instance_poly ~fixed:false tl ty)
| Tvar _ ->
let ty' = newvar () in
unify env (instance typ) (newty(Tpoly(ty',[])));
(* if not !Clflags.nolabels then
Location.prerr_warning loc (Warnings.Unknown_method met); *)
ty'
| _ ->
assert false
in
rue {
exp_desc = Texp_send(obj, meth);
exp_loc = loc; exp_extra = [];
exp_type = typ;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_new cl ->
let (cl_path, cl_decl) = Env.lookup_class ~loc:cl.loc cl.txt env in
begin match cl_decl.cty_new with
None ->
raise(Error(loc, env, Virtual_class cl.txt))
| Some ty ->
rue {
exp_desc = Texp_new (cl_path, cl, cl_decl);
exp_loc = loc; exp_extra = [];
exp_type = instance ty;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
end
| Pexp_setinstvar (lab, snewval) -> begin
let (path, mut, cl_num, ty) =
Env.lookup_instance_variable ~loc lab.txt env
in
match mut with
| Mutable ->
let newval =
type_expect env snewval (mk_expected (instance ty))
in
let (path_self, _) =
Env.find_value_by_name (Longident.Lident ("self-" ^ cl_num)) env
in
rue {
exp_desc = Texp_setinstvar(path_self, path, lab, newval);
exp_loc = loc; exp_extra = [];
exp_type = instance Predef.type_unit;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ ->
raise(Error(loc, env, Instance_variable_not_mutable lab.txt))
end
| Pexp_override lst ->
let _ =
List.fold_right
(fun (lab, _) l ->
if List.exists (fun l -> l.txt = lab.txt) l then
raise(Error(loc, env,
Value_multiply_overridden lab.txt));
lab::l)
lst
[] in
begin match
try
Env.find_value_by_name (Longident.Lident "selfpat-*") env,
Env.find_value_by_name (Longident.Lident "self-*") env
with Not_found ->
raise(Error(loc, env, Outside_class))
with
(_, {val_type = self_ty; val_kind = Val_self (sign, _, vars, _)}),
(path_self, _) ->
let type_override (lab, snewval) =
begin try
let id = Vars.find lab.txt vars in
let ty = Btype.instance_variable_type lab.txt sign in
(id, lab, type_expect env snewval (mk_expected (instance ty)))
with
Not_found ->
let vars = Vars.fold (fun var _ li -> var::li) vars [] in
raise(Error(loc, env,
Unbound_instance_variable (lab.txt, vars)))
end
in
let modifs = List.map type_override lst in
rue {
exp_desc = Texp_override(path_self, modifs);
exp_loc = loc; exp_extra = [];
exp_type = self_ty;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ ->
assert false
end
| Pexp_letmodule(name, smodl, sbody) ->
let lv = get_current_level () in
let (id, pres, modl, _, body) =
with_local_level_generalize begin fun () ->
let modl, pres, id, new_env =
Typetexp.TyVarEnv.with_local_scope begin fun () ->
let modl, md_shape = !type_module env smodl in
Mtype.lower_nongen lv modl.mod_type;
let pres =
match modl.mod_type with
| Mty_alias _ -> Mp_absent
| _ -> Mp_present
in
let scope = create_scope () in
let md_uid = Uid.mk ~current_unit:(Env.get_current_unit ()) in
let md_shape = Shape.set_uid_if_none md_shape md_uid in
let md =
{ md_type = modl.mod_type; md_attributes = [];
md_loc = name.loc;
md_uid; }
in
let (id, new_env) =
match name.txt with
| None -> None, env
| Some name ->
let id, env =
Env.enter_module_declaration
~scope ~shape:md_shape name pres md env
in
Some id, env
in
modl, pres, id, new_env
end
in
(* Ideally, we should catch Expr_type_clash errors
in type_expect triggered by escaping identifiers
from the local module and refine them into
Scoping_let_module errors
*)
let body = type_expect new_env sbody ty_expected_explained in
(id, pres, modl, new_env, body)
end
~before_generalize: begin fun (_id, _pres, _modl, new_env, body) ->
(* Ensure that local definitions do not leak. *)
(* required for implicit unpack *)
enforce_current_level new_env body.exp_type
end
in
re {
exp_desc = Texp_letmodule(id, name, pres, modl, body);
exp_loc = loc; exp_extra = [];
exp_type = body.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_letexception(cd, sbody) ->
let (cd, newenv, _shape) = Typedecl.transl_exception env cd in
let body = type_expect newenv sbody ty_expected_explained in
re {
exp_desc = Texp_letexception(cd, body);
exp_loc = loc; exp_extra = [];
exp_type = body.exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| Pexp_assert (e) ->
let cond = type_expect env e
(mk_expected ~explanation:Assert_condition Predef.type_bool) in
let exp_type =
match cond.exp_desc with
| Texp_construct(_, {cstr_name="false"}, _) ->
instance ty_expected
| _ ->
instance Predef.type_unit
in
let rec innermost_location loc_stack =
match loc_stack with
| [] -> loc
| [l] -> l
| _ :: s -> innermost_location s
in
rue {
exp_desc = Texp_assert (cond, innermost_location sexp.pexp_loc_stack);
exp_loc = loc; exp_extra = [];
exp_type;
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_lazy e ->
let ty = newgenvar () in
let to_unify = Predef.type_lazy_t ty in
with_explanation (fun () ->
unify_exp_types loc env to_unify (generic_instance ty_expected));
let arg = type_expect env e (mk_expected ty) in
re {
exp_desc = Texp_lazy arg;
exp_loc = loc; exp_extra = [];
exp_type = instance ty_expected;
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_object s ->
let desc, meths = !type_object env loc s in
rue {
exp_desc = Texp_object (desc, meths);
exp_loc = loc; exp_extra = [];
exp_type = desc.cstr_type.csig_self;
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_poly(sbody, sty) ->
let ty, cty =
with_local_level_generalize_structure_if_principal
begin fun () ->
match sty with None -> protect_expansion env ty_expected, None
| Some sty ->
let sty = Ast_helper.Typ.force_poly sty in
let cty = Typetexp.transl_simple_type env ~closed:false sty in
cty.ctyp_type, Some cty
end
in
if sty <> None then
with_explanation (fun () ->
unify_exp_types loc env (instance ty) (instance ty_expected));
let exp =
match get_desc (expand_head env ty) with
Tpoly (ty', []) ->
let exp = type_expect env sbody (mk_expected ty') in
{ exp with exp_type = instance ty }
| Tpoly (ty', tl) ->
(* One more level to generalize locally *)
let (exp, vars) =
with_local_level_generalize begin fun () ->
let vars, ty'' =
with_local_level_generalize_structure_if_principal
(fun () -> instance_poly ~fixed:true tl ty')
in
let exp = type_expect env sbody (mk_expected ty'') in
(exp, vars)
end
in
check_univars env "method" exp ty_expected vars;
{ exp with exp_type = instance ty }
| Tvar _ ->
let exp = type_exp env sbody in
let exp = {exp with exp_type = newty (Tpoly (exp.exp_type, []))} in
unify_exp ~sexp env exp ty;
exp
| _ -> assert false
in
re { exp with exp_extra =
(Texp_poly cty, loc, sexp.pexp_attributes) :: exp.exp_extra }
| Pexp_newtype(name, sbody) ->
let body, ety = type_newtype env name (fun env ->
let expr = type_exp env sbody in
expr, expr.exp_type)
in
(* non-expansive if the body is non-expansive, so we don't introduce
any new extra node in the typed AST. *)
rue { body with exp_loc = loc; exp_type = ety;
exp_extra =
(Texp_newtype name.txt, loc, sexp.pexp_attributes) :: body.exp_extra
}
| Pexp_pack (m, optyp) ->
begin match optyp with
| Some ptyp ->
let t = Ast_helper.Typ.package ~loc:ptyp.ppt_loc ptyp in
let pty, exp_extra = type_constraint env t in
begin match get_desc (instance pty) with
| Tpackage pack ->
let (modl, pack') = !type_package env m pack in
let ty = newty (Tpackage pack') in
unify_exp_types m.pmod_loc env (instance pty) ty;
rue {
exp_desc = Texp_pack modl;
exp_loc = loc; exp_extra = [exp_extra, loc, []];
exp_type = instance pty;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ ->
fatal_error "[type_expect] Package not translated to a package"
end
| None ->
let pack =
match get_desc (Ctype.expand_head env (instance ty_expected)) with
Tpackage pack ->
if !Clflags.principal &&
get_level (Ctype.expand_head env
(protect_expansion env ty_expected))
< Btype.generic_level
then
Location.prerr_warning loc
(not_principal "this module packing");
pack
| Tvar _ ->
raise (Error (loc, env, Cannot_infer_signature))
| _ ->
raise (Error (loc, env, Not_a_packed_module ty_expected))
in
let (modl, pack') = !type_package env m pack in
rue {
exp_desc = Texp_pack modl;
exp_loc = loc; exp_extra = [];
exp_type = newty (Tpackage pack');
exp_attributes = sexp.pexp_attributes;
exp_env = env }
end
| Pexp_open (od, e) ->
let tv = newvar () in
let (od, _, newenv) = !type_open_decl env od in
let exp = type_expect newenv e ty_expected_explained in
(* Force the return type to be well-formed in the original
environment. *)
unify_var newenv tv exp.exp_type;
re {
exp_desc = Texp_open (od, exp);
exp_type = exp.exp_type;
exp_loc = loc;
exp_extra = [];
exp_attributes = sexp.pexp_attributes;
exp_env = env;
}
| Pexp_letop{ let_ = slet; ands = sands; body = sbody } ->
let rec loop spat_acc ty_acc sands =
match sands with
| [] -> spat_acc, ty_acc
| { pbop_pat = spat; _} :: rest ->
let ty = newvar () in
let loc = { slet.pbop_op.loc with Location.loc_ghost = true } in
let spat_acc =
Ast_helper.Pat.tuple ~loc [None, spat_acc; None, spat] Closed
in
let ty_acc = newty (Ttuple [None, ty_acc; None, ty]) in
loop spat_acc ty_acc rest
in
let op_path, op_desc, op_type, spat_params, ty_params,
ty_func_result, ty_result, ty_andops =
with_local_level_generalize_structure_if_principal begin fun () ->
let let_loc = slet.pbop_op.loc in
let op_path, op_desc = type_binding_op_ident env slet.pbop_op in
let op_type = instance op_desc.val_type in
let spat_params, ty_params = loop slet.pbop_pat (newvar ()) sands in
let ty_func_result = newvar () in
let ty_func =
newty (Tarrow(Nolabel, ty_params, ty_func_result, commu_ok)) in
let ty_result = newvar () in
let ty_andops = newvar () in
let ty_op =
newty (Tarrow(Nolabel, ty_andops,
newty (Tarrow(Nolabel, ty_func, ty_result, commu_ok)), commu_ok))
in
begin try
unify env op_type ty_op
with Unify err ->
raise(Error(let_loc, env, Letop_type_clash(slet.pbop_op.txt, err)))
end;
(op_path, op_desc, op_type, spat_params, ty_params,
ty_func_result, ty_result, ty_andops)
end
in
let exp, ands = type_andops env slet.pbop_exp sands ty_andops in
let scase = Ast_helper.Exp.case spat_params sbody in
let cases, partial =
type_cases Value env
ty_params (mk_expected ty_func_result)
~check_if_total:true loc [scase]
in
let body =
match cases with
| [case] -> case
| _ -> assert false
in
let param = name_cases "param" cases in
let let_ =
{ bop_op_name = slet.pbop_op;
bop_op_path = op_path;
bop_op_val = op_desc;
bop_op_type = op_type;
bop_exp = exp;
bop_loc = slet.pbop_loc; }
in
let desc =
Texp_letop{let_; ands; param; body; partial}
in
rue { exp_desc = desc;
exp_loc = sexp.pexp_loc;
exp_extra = [];
exp_type = instance ty_result;
exp_env = env;
exp_attributes = sexp.pexp_attributes; }
| Pexp_extension ({ txt = ("ocaml.extension_constructor"
|"extension_constructor"); _ },
payload) ->
begin match payload with
| PStr [ { pstr_desc =
Pstr_eval ({ pexp_desc = Pexp_construct (lid, None); _ }, _)
} ] ->
let path =
let cd =
Env.lookup_constructor Env.Positive ~loc:lid.loc lid.txt env
in
match cd.cstr_tag with
| Cstr_extension (path, _) -> path
| _ -> raise (Error (lid.loc, env, Not_an_extension_constructor))
in
rue {
exp_desc = Texp_extension_constructor (lid, path);
exp_loc = loc; exp_extra = [];
exp_type = instance Predef.type_extension_constructor;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ ->
raise (Error (loc, env, Invalid_extension_constructor_payload))
end
| Pexp_extension ({ txt = ("ocaml.atomic.loc"
|"atomic.loc"); _ },
payload) ->
begin match payload with
| PStr [ { pstr_desc =
Pstr_eval (
{ pexp_desc = Pexp_field (srecord, lid); _ } as sexp, _
)
} ] ->
let record, label, ty_arg =
solve_Pexp_field ~label_usage:Env.Mutation env sexp srecord lid
in
Env.mark_label_used Env.Projection label.lbl_uid;
if label.lbl_atomic = Nonatomic then
raise (Error (loc, env, Label_not_atomic lid.txt)) ;
rue {
exp_desc = Texp_atomic_loc (record, lid, label);
exp_loc = loc; exp_extra = [];
exp_type = instance (Predef.type_atomic_loc ty_arg);
exp_attributes = sexp.pexp_attributes;
exp_env = env }
| _ ->
raise (Error (loc, env, Invalid_atomic_loc_payload))
end
| Pexp_extension ext ->
raise (Error_forward (Builtin_attributes.error_of_extension ext))
| Pexp_unreachable ->
re { exp_desc = Texp_unreachable;
exp_loc = loc; exp_extra = [];
exp_type = instance ty_expected;
exp_attributes = sexp.pexp_attributes;
exp_env = env }
and expression_constraint pexp =
{ type_without_constraint = (fun env ->
let expr = type_exp env pexp in
expr, expr.exp_type);
type_with_constraint =
(fun env ty -> type_argument env pexp ty (instance ty));
is_self =
(fun expr ->
match expr.exp_desc with
| Texp_ident (_, _, { val_kind = Val_self _ }) -> true
| _ -> false);
}
(** Types a body in the scope of a coercion (with an optional constraint)
and returns the inferred type. See the comment on {!constraint_arg} for
an explanation of how this typechecking is polymorphic in the body.
*)
and type_coerce
: type a. a constraint_arg -> _ -> _ -> _ -> _ -> loc_arg:_
-> a * type_expr * exp_extra =
fun constraint_arg env loc sty sty' ~loc_arg ->
(* Pretend separate = true, 1% slowdown for lablgtk *)
(* Also see PR#7199 for a problem with the following:
let separate = !Clflags.principal || Env.has_local_constraints env in*)
let { is_self; type_with_constraint; type_without_constraint } =
constraint_arg
in
match sty with
| None ->
let (cty', ty', force) =
with_local_level_generalize_structure begin fun () ->
Typetexp.transl_simple_type_delayed env sty'
end
in
let arg, arg_type, gen =
let lv = get_current_level () in
with_local_level_generalize begin fun () ->
let arg, arg_type = type_without_constraint env in
arg, arg_type, generalizable lv arg_type
end
~before_generalize:
(fun (_, arg_type, _) -> enforce_current_level env arg_type)
in
begin match !self_coercion, get_desc ty' with
| ((path, r) :: _, Tconstr (path', _, _))
when is_self arg && Path.same path path' ->
(* prerr_endline "self coercion"; *)
r := loc :: !r;
force ()
| _ when closed_type_expr ~env arg_type
&& closed_type_expr ~env ty' ->
if not gen && (* first try a single coercion *)
let snap = snapshot () in
let ty, _b = enlarge_type env (generic_instance ty') in
try
force (); Ctype.unify env arg_type ty; true
with Unify _ ->
backtrack snap; false
then ()
else begin try
let force' = subtype env arg_type (generic_instance ty') in
force (); force' ();
if not gen && !Clflags.principal then
Location.prerr_warning loc
(not_principal "this ground coercion");
with Subtype err ->
(* prerr_endline "coercion failed"; *)
raise (Error (loc, env, Not_subtype err))
end;
| _ ->
let ty, b = enlarge_type env (generic_instance ty') in
force ();
begin try Ctype.unify env arg_type ty with Unify err ->
let expanded = full_expand ~may_forget_scope:true env ty' in
raise(Error(loc_arg, env,
Coercion_failure ({ ty = ty'; expanded }, err, b)))
end
end;
(arg, ty', Texp_coerce (None, cty'))
| Some sty ->
let cty, ty, force, cty', ty', force' =
with_local_level_generalize_structure begin fun () ->
let (cty, ty, force) =
Typetexp.transl_simple_type_delayed env sty
and (cty', ty', force') =
Typetexp.transl_simple_type_delayed env sty'
in
(cty, ty, force, cty', ty', force')
end
in
begin try
let force'' =
subtype env (generic_instance ty) (generic_instance ty')
in
force (); force' (); force'' ()
with Subtype err ->
raise (Error (loc, env, Not_subtype err))
end;
(type_with_constraint env ty,
instance ty', Texp_coerce (Some cty, cty'))
and type_constraint env sty =
(* Pretend separate = true, 1% slowdown for lablgtk *)
let cty =
with_local_level_generalize_structure begin fun () ->
Typetexp.transl_simple_type env ~closed:false sty
end
in
cty.ctyp_type, Texp_constraint cty
(** Types a body in the scope of a coercion (:>) or a constraint (:), and
unifies the inferred type with the expected type.
@param loc the location of the overall constraint
@param loc_arg the location of the thing being constrained
*)
and type_constraint_expect
: type a. a constraint_arg -> _ -> _ -> loc_arg:_ -> _ -> _ -> a * _ * _ =
fun constraint_arg env loc ~loc_arg constraint_ ty_expected ->
let ret, ty, exp_extra =
match constraint_ with
| Pcoerce (ty_constrain, ty_coerce) ->
type_coerce constraint_arg env loc ty_constrain ty_coerce ~loc_arg
| Pconstraint ty_constrain ->
let ty, exp_extra = type_constraint env ty_constrain in
constraint_arg.type_with_constraint env ty, ty, exp_extra
in
unify_exp_types loc env ty (instance ty_expected);
ret, ty, exp_extra
(** Typecheck the body of a newtype. The "body" of a newtype may be:
- an expression
- a suffix of function parameters together with a function body
That's why this function is polymorphic over the body.
@param type_body A function that produces a type for the body given the
environment. When typechecking an expression, this is [type_exp].
@return The type returned by [type_body] but with the Tconstr
nodes for the newtype properly linked.
*)
and type_newtype
: type a. _ -> _ -> (Env.t -> a * type_expr) -> a * type_expr =
fun env { txt = name; loc = name_loc } type_body ->
let ty =
if Typetexp.valid_tyvar_name name then
newvar ~name ()
else
newvar ()
in
(* Use [with_local_level_generalize] just for scoping *)
with_local_level_generalize begin fun () ->
(* Create a fake abstract type declaration for [name]. *)
let decl = new_local_type ~loc:name_loc Definition in
let scope = create_scope () in
let (id, new_env) = Env.enter_type ~scope name decl env in
let result, exp_type = type_body new_env in
(* Replace every instance of this type constructor in the resulting
type. *)
let seen = Hashtbl.create 8 in
let rec replace t =
if Hashtbl.mem seen (get_id t) then ()
else begin
Hashtbl.add seen (get_id t) ();
match get_desc t with
| Tconstr (Path.Pident id', _, _) when id == id' -> link_type t ty
| _ -> Btype.iter_type_expr replace t
end
in
let ety = Subst.type_expr Subst.identity exp_type in
replace ety;
(result, ety)
end
~before_generalize:(fun (_,ety) -> enforce_current_level env ety)
and type_ident env ?(recarg=Rejected) lid =
let (path, desc) = Env.lookup_value ~loc:lid.loc lid.txt env in
let is_recarg =
match get_desc desc.val_type with
| Tconstr(p, _, _) -> Path.is_constructor_typath p
| _ -> false
in
begin match is_recarg, recarg, get_desc desc.val_type with
| _, Allowed, _
| true, Required, _
| false, Rejected, _ -> ()
| true, Rejected, _
| false, Required, (Tvar _ | Tconstr _) ->
raise (Error (lid.loc, env, Inlined_record_escape))
| false, Required, _ -> () (* will fail later *)
end;
path, desc
and type_binding_op_ident env s =
let loc = s.loc in
let lid = Location.mkloc (Longident.Lident s.txt) loc in
let path, desc = type_ident env lid in
let path =
match desc.val_kind with
| Val_ivar _ ->
fatal_error "Illegal name for instance variable"
| Val_self (_, _, _, cl_num) ->
let path, _ =
Env.find_value_by_name (Longident.Lident ("self-" ^ cl_num)) env
in
path
| _ -> path
in
path, desc
(** Returns the argument type and then the return type.
@param first Whether the parameter corresponding to the argument of
[ty_expected] is the first parameter to the (n-ary) function. This only
affects error messages.
@param in_function Information about the [Pexp_function] node that's in the
process of being typechecked (its overall type and its location). Again,
this is only used to improve error messages.
*)
and split_function_ty env ty_expected ~arg_label ~first ~in_function =
let { ty = ty_fun; explanation }, loc = in_function in
let separate = !Clflags.principal || Env.has_local_constraints env in
with_local_level_generalize_structure_if separate begin fun () ->
let ty_arg, ty_res =
try filter_arrow env (instance ty_expected) arg_label
with Filter_arrow_failed err ->
let err = match err with
| Unification_error unif_err ->
Expr_type_clash (unif_err, explanation, None)
| Label_mismatch { got; expected; expected_type } ->
Abstract_wrong_label { got; expected; expected_type; explanation }
| Not_a_function ->
if first
then Not_a_function (ty_fun, explanation)
else Too_many_arguments (ty_fun, explanation)
in
raise (Error(loc, env, err))
in
let ty_arg =
if is_optional arg_label then
let tv = newvar () in
begin
try unify env ty_arg (type_option tv)
with Unify _ -> assert false
end;
type_option tv
else ty_arg
in
(ty_arg, ty_res)
end
(* Typecheck parameters one at a time followed by the body. Later parameters
are checked in the scope of earlier ones. That's necessary to support
constructs like [fun (type a) (x : a) -> ...] and
[fun (module M : S) (x : M.t) -> ...].
Operates like [type_expect] in that it unifies the "type of the remaining
function params + body" with [ty_expected], and returns out the inferred
type.
See [split_function_ty] for the meaning of [first] and [in_function].
Returns (inferred_ty, params, body, newtypes, contains_gadt), where:
- [newtypes] are the newtypes immediately bound by the prefix of function
parameters. These should be added to an [exp_extra] node.
- [contains_gadt] is whether any of [params] contains a GADT. Note
this does not indicate whether [body] contains a GADT (if it's
[Tfunction_cases]).
*)
and type_function
env params_suffix body_constraint body ty_expected ~first ~in_function
=
let ty_fun, (loc_function : Location.t) = in_function in
(* The "rest of the function" extends from the start of the first parameter
to the end of the overall function. The parser does not construct such
a location so we forge one for type errors.
*)
let loc : Location.t =
match params_suffix, body with
| param :: _, _ ->
{ loc_start = param.pparam_loc.loc_start;
loc_end = loc_function.loc_end;
loc_ghost = true;
}
| [], Pfunction_body pexp -> pexp.pexp_loc
| [], Pfunction_cases (_, loc_cases, _) -> loc_cases
in
match params_suffix with
| { pparam_desc = Pparam_newtype newtype; pparam_loc = _ } :: rest ->
(* Check everything else in the scope of (type a). *)
let (params, body, newtypes, contains_gadt), exp_type =
type_newtype env newtype (fun env ->
let exp_type, params, body, newtypes, contains_gadt =
(* mimic the typing of Pexp_newtype by minting a new type var,
like [type_exp].
*)
type_function env rest body_constraint body (newvar ())
~first:false ~in_function
in
(params, body, newtypes, contains_gadt), exp_type)
in
with_explanation ty_fun.explanation (fun () ->
unify_exp_types loc env exp_type (instance ty_expected));
exp_type, params, body, newtype :: newtypes, contains_gadt
| { pparam_desc = Pparam_val (arg_label, default_arg, pat); pparam_loc }
:: rest
->
let ty_arg, ty_res =
split_function_ty env ty_expected ~arg_label ~first ~in_function
in
(* [ty_arg_internal] is the type of the parameter viewed internally
to the function. This is different than [ty_arg] exactly for
optional arguments with defaults, where the external [ty_arg]
is optional and the internal view is not optional.
*)
let ty_arg_internal, default_arg =
match default_arg with
| None -> ty_arg, None
| Some default ->
assert (is_optional arg_label);
let ty_default = newvar () in
begin
try unify env (type_option ty_default) ty_arg
with Unify _ -> assert false;
end;
(* Issue#12668: Retain type-directed disambiguation of
?x:(y : Variant.t = Constr)
*)
let default =
match pat.ppat_desc with
| Ppat_constraint (_, sty) ->
let gloc = { default.pexp_loc with loc_ghost = true } in
Ast_helper.Exp.constraint_ default sty ~loc:gloc
| _ -> default
in
let default = type_expect env default (mk_expected ty_default) in
ty_default, Some default
in
let (pat, params, body, newtypes, contains_gadt), partial =
(* Check everything else in the scope of the parameter. *)
map_half_typed_cases Value env ty_arg_internal ty_res pat.ppat_loc
~check_if_total:true
(* We don't make use of [case_data] here so we pass unit. *)
[ { pattern = pat; has_guard = false; needs_refute = false }, () ]
~type_body:begin
fun () pat ~when_env:_ ~ext_env ~cont:_ ~ty_expected ~ty_infer:_
~contains_gadt:param_contains_gadt ->
let _, params, body, newtypes, suffix_contains_gadt =
type_function ext_env rest body_constraint body
ty_expected ~first:false ~in_function
in
let contains_gadt =
if param_contains_gadt then
Contains_gadt
else
suffix_contains_gadt
in
(pat, params, body, newtypes, contains_gadt)
end
|> function
(* The result must be a singleton because we passed a singleton
list above. *)
| [ result ], partial -> result, partial
| ([] | _ :: _ :: _), _ -> assert false
in
let exp_type =
instance (newgenty (Tarrow (arg_label, ty_arg, ty_res, commu_ok)))
in
(* This is quadratic, as it operates over the entire tail of the
type for each new parameter. Now that functions are n-ary, we
could possibly run this once.
*)
with_explanation ty_fun.explanation (fun () ->
unify_exp_types loc env exp_type (instance ty_expected));
(* This is quadratic, as it extracts all of the parameters from an arrow
type for each parameter that's added. Now that functions are n-ary,
there might be an opportunity to improve this.
*)
let not_nolabel_function ty =
let ls, tvar = list_labels env ty in
List.for_all (( <> ) Nolabel) ls && not tvar
in
if is_optional arg_label && not_nolabel_function ty_res
then
Location.prerr_warning
pat.pat_loc
Warnings.Unerasable_optional_argument;
let fp_kind, fp_param =
match default_arg with
| None ->
let param = name_pattern "param" [ pat ] in
Tparam_pat pat, param
| Some default_arg ->
let param = Ident.create_local "*opt*" in
Tparam_optional_default (pat, default_arg), param
in
let param =
{ fp_kind;
fp_arg_label = arg_label;
fp_param;
fp_partial = partial;
fp_newtypes = newtypes;
fp_loc = pparam_loc;
}
in
exp_type, param :: params, body, [], contains_gadt
| [] ->
let exp_type, body =
match body with
| Pfunction_body body ->
let body =
match body_constraint with
| None -> type_expect env body (mk_expected ty_expected)
| Some constraint_ ->
let body_loc = body.pexp_loc in
let body, exp_type, exp_extra =
type_constraint_expect (expression_constraint body)
env body_loc ~loc_arg:body_loc constraint_ ty_expected
in
{ body with
exp_extra = (exp_extra, body_loc, []) :: body.exp_extra;
exp_type;
}
in
body.exp_type, Tfunction_body body
| Pfunction_cases (cases, _, attributes) ->
let type_cases_expect env ty_expected =
type_function_cases_expect
env ty_expected loc cases attributes ~first ~in_function
in
let (cases, partial, exp_type), exp_extra =
match body_constraint with
| None -> type_cases_expect env ty_expected, None
| Some constraint_ ->
(* The typing of function case coercions/constraints is
analogous to the typing of expression coercions/constraints.
- [type_with_constraint]: If there is a constraint, then call
[type_argument] on the cases, and discard the cases'
inferred type in favor of the constrained type. (Function
cases aren't inferred, so [type_argument] would just call
[type_expect] straight away, so we do the same here.)
- [type_without_constraint]: If there is just a coercion and
no constraint, call [type_exp] on the cases and surface the
cases' inferred type to [type_constraint_expect]. *)
let function_cases_constraint_arg =
{ is_self = (fun _ -> false);
type_with_constraint = (fun env ty ->
let cases, partial, _ = type_cases_expect env ty in
cases, partial);
type_without_constraint = (fun env ->
let cases, partial, ty_fun =
(* The analogy to [type_exp] for expressions. *)
type_cases_expect env (newvar ())
in
(cases, partial), ty_fun);
}
in
let (cases, partial), exp_type, exp_extra =
type_constraint_expect function_cases_constraint_arg
env loc constraint_ ty_expected ~loc_arg:loc
in
(cases, partial, exp_type), Some exp_extra
in
let param = name_cases "param" cases in
let body =
Tfunction_cases
{ cases; partial; param; loc; exp_extra; attributes }
in
exp_type, body
in
(* [No_gadt] is fine because this return value is only meant to indicate
whether [params] (here, the empty list) contains any GADT, not whether
the body is a [Tfunction_cases] whose patterns include a GADT.
*)
exp_type, [], body, [], No_gadt
and type_label_access env srecord usage lid =
let record =
with_local_level_generalize_structure_if_principal
(fun () -> type_exp ~recarg:Allowed env srecord)
in
let ty_exp = record.exp_type in
let expected_type =
match extract_concrete_record env ty_exp with
| Record_type(p0, p, _) ->
Some(p0, p, is_principal ty_exp)
| Maybe_a_record_type -> None
| Not_a_record_type ->
let error = Expr_not_a_record_type ty_exp in
raise (Error (record.exp_loc, env, error))
in
let labels = Env.lookup_all_labels ~loc:lid.loc usage lid.txt env in
let label =
wrap_disambiguate "This expression has" (mk_expected ty_exp)
(Label.disambiguate usage lid env expected_type) labels in
(record, label, expected_type)
and solve_Pexp_field ~label_usage env sexp srecord lid =
let (record, label, _) =
type_label_access env srecord label_usage lid
in
let (_, ty_arg, ty_res) = instance_label ~fixed:false label in
unify_exp ~sexp env record ty_res;
(record, label, ty_arg)
(* Typing format strings for printing or reading.
These formats are used by functions in modules Printf, Format, and Scanf.
(Handling of * modifiers contributed by Thorsten Ohl.) *)
and type_format loc str env =
let loc = {loc with Location.loc_ghost = true} in
try
CamlinternalFormatBasics.(CamlinternalFormat.(
let mk_exp_loc pexp_desc = {
pexp_desc = pexp_desc;
pexp_loc = loc;
pexp_loc_stack = [];
pexp_attributes = [];
} and mk_lid_loc lid = {
txt = lid;
loc = loc;
} in
let mk_constr name args =
let lid =
Longident.(Ldot(mknoloc (Lident "CamlinternalFormatBasics"),
mknoloc name))
in
let arg = match args with
| [] -> None
| [ e ] -> Some e
| _ :: _ :: _ ->
Some (mk_exp_loc (Pexp_tuple (List.map (fun e -> None, e) args)))
in
mk_exp_loc (Pexp_construct (mk_lid_loc lid, arg)) in
let mk_cst cst =
mk_exp_loc (Pexp_constant {pconst_desc = cst; pconst_loc = loc})
in
let mk_int n = mk_cst (Pconst_integer (Int.to_string n, None))
and mk_string str = mk_cst (Pconst_string (str, loc, None))
and mk_char chr = mk_cst (Pconst_char chr) in
let rec mk_formatting_lit fmting = match fmting with
| Close_box ->
mk_constr "Close_box" []
| Close_tag ->
mk_constr "Close_tag" []
| Break (org, ns, ni) ->
mk_constr "Break" [ mk_string org; mk_int ns; mk_int ni ]
| FFlush ->
mk_constr "FFlush" []
| Force_newline ->
mk_constr "Force_newline" []
| Flush_newline ->
mk_constr "Flush_newline" []
| Magic_size (org, sz) ->
mk_constr "Magic_size" [ mk_string org; mk_int sz ]
| Escaped_at ->
mk_constr "Escaped_at" []
| Escaped_percent ->
mk_constr "Escaped_percent" []
| Scan_indic c ->
mk_constr "Scan_indic" [ mk_char c ]
and mk_formatting_gen : type a b c d e f .
(a, b, c, d, e, f) formatting_gen -> Parsetree.expression =
fun fmting -> match fmting with
| Open_tag (Format (fmt', str')) ->
mk_constr "Open_tag" [ mk_format fmt' str' ]
| Open_box (Format (fmt', str')) ->
mk_constr "Open_box" [ mk_format fmt' str' ]
and mk_format : type a b c d e f .
(a, b, c, d, e, f) CamlinternalFormatBasics.fmt -> string ->
Parsetree.expression = fun fmt str ->
mk_constr "Format" [ mk_fmt fmt; mk_string str ]
and mk_side side = match side with
| Left -> mk_constr "Left" []
| Right -> mk_constr "Right" []
| Zeros -> mk_constr "Zeros" []
and mk_iconv iconv = match iconv with
| Int_d -> mk_constr "Int_d" [] | Int_pd -> mk_constr "Int_pd" []
| Int_sd -> mk_constr "Int_sd" [] | Int_i -> mk_constr "Int_i" []
| Int_pi -> mk_constr "Int_pi" [] | Int_si -> mk_constr "Int_si" []
| Int_x -> mk_constr "Int_x" [] | Int_Cx -> mk_constr "Int_Cx" []
| Int_X -> mk_constr "Int_X" [] | Int_CX -> mk_constr "Int_CX" []
| Int_o -> mk_constr "Int_o" [] | Int_Co -> mk_constr "Int_Co" []
| Int_u -> mk_constr "Int_u" [] | Int_Cd -> mk_constr "Int_Cd" []
| Int_Ci -> mk_constr "Int_Ci" [] | Int_Cu -> mk_constr "Int_Cu" []
and mk_fconv fconv =
let flag = match fst fconv with
| Float_flag_ -> mk_constr "Float_flag_" []
| Float_flag_p -> mk_constr "Float_flag_p" []
| Float_flag_s -> mk_constr "Float_flag_s" [] in
let kind = match snd fconv with
| Float_f -> mk_constr "Float_f" []
| Float_e -> mk_constr "Float_e" []
| Float_E -> mk_constr "Float_E" []
| Float_g -> mk_constr "Float_g" []
| Float_G -> mk_constr "Float_G" []
| Float_h -> mk_constr "Float_h" []
| Float_H -> mk_constr "Float_H" []
| Float_F -> mk_constr "Float_F" []
| Float_CF -> mk_constr "Float_CF" [] in
mk_exp_loc (Pexp_tuple [None, flag; None, kind])
and mk_counter cnt = match cnt with
| Line_counter -> mk_constr "Line_counter" []
| Char_counter -> mk_constr "Char_counter" []
| Token_counter -> mk_constr "Token_counter" []
and mk_int_opt n_opt = match n_opt with
| None ->
let lid_loc = mk_lid_loc (Longident.Lident "None") in
mk_exp_loc (Pexp_construct (lid_loc, None))
| Some n ->
let lid_loc = mk_lid_loc (Longident.Lident "Some") in
mk_exp_loc (Pexp_construct (lid_loc, Some (mk_int n)))
and mk_fmtty : type a b c d e f g h i j k l .
(a, b, c, d, e, f, g, h, i, j, k, l) fmtty_rel -> Parsetree.expression
=
fun fmtty -> match fmtty with
| Char_ty rest -> mk_constr "Char_ty" [ mk_fmtty rest ]
| String_ty rest -> mk_constr "String_ty" [ mk_fmtty rest ]
| Int_ty rest -> mk_constr "Int_ty" [ mk_fmtty rest ]
| Int32_ty rest -> mk_constr "Int32_ty" [ mk_fmtty rest ]
| Nativeint_ty rest -> mk_constr "Nativeint_ty" [ mk_fmtty rest ]
| Int64_ty rest -> mk_constr "Int64_ty" [ mk_fmtty rest ]
| Float_ty rest -> mk_constr "Float_ty" [ mk_fmtty rest ]
| Bool_ty rest -> mk_constr "Bool_ty" [ mk_fmtty rest ]
| Alpha_ty rest -> mk_constr "Alpha_ty" [ mk_fmtty rest ]
| Theta_ty rest -> mk_constr "Theta_ty" [ mk_fmtty rest ]
| Any_ty rest -> mk_constr "Any_ty" [ mk_fmtty rest ]
| Reader_ty rest -> mk_constr "Reader_ty" [ mk_fmtty rest ]
| Ignored_reader_ty rest ->
mk_constr "Ignored_reader_ty" [ mk_fmtty rest ]
| Format_arg_ty (sub_fmtty, rest) ->
mk_constr "Format_arg_ty" [ mk_fmtty sub_fmtty; mk_fmtty rest ]
| Format_subst_ty (sub_fmtty1, sub_fmtty2, rest) ->
mk_constr "Format_subst_ty"
[ mk_fmtty sub_fmtty1; mk_fmtty sub_fmtty2; mk_fmtty rest ]
| End_of_fmtty -> mk_constr "End_of_fmtty" []
and mk_ignored : type a b c d e f .
(a, b, c, d, e, f) ignored -> Parsetree.expression =
fun ign -> match ign with
| Ignored_char ->
mk_constr "Ignored_char" []
| Ignored_caml_char ->
mk_constr "Ignored_caml_char" []
| Ignored_string pad_opt ->
mk_constr "Ignored_string" [ mk_int_opt pad_opt ]
| Ignored_caml_string pad_opt ->
mk_constr "Ignored_caml_string" [ mk_int_opt pad_opt ]
| Ignored_int (iconv, pad_opt) ->
mk_constr "Ignored_int" [ mk_iconv iconv; mk_int_opt pad_opt ]
| Ignored_int32 (iconv, pad_opt) ->
mk_constr "Ignored_int32" [ mk_iconv iconv; mk_int_opt pad_opt ]
| Ignored_nativeint (iconv, pad_opt) ->
mk_constr "Ignored_nativeint" [ mk_iconv iconv; mk_int_opt pad_opt ]
| Ignored_int64 (iconv, pad_opt) ->
mk_constr "Ignored_int64" [ mk_iconv iconv; mk_int_opt pad_opt ]
| Ignored_float (pad_opt, prec_opt) ->
mk_constr "Ignored_float" [ mk_int_opt pad_opt; mk_int_opt prec_opt ]
| Ignored_bool pad_opt ->
mk_constr "Ignored_bool" [ mk_int_opt pad_opt ]
| Ignored_format_arg (pad_opt, fmtty) ->
mk_constr "Ignored_format_arg" [ mk_int_opt pad_opt; mk_fmtty fmtty ]
| Ignored_format_subst (pad_opt, fmtty) ->
mk_constr "Ignored_format_subst" [
mk_int_opt pad_opt; mk_fmtty fmtty ]
| Ignored_reader ->
mk_constr "Ignored_reader" []
| Ignored_scan_char_set (width_opt, char_set) ->
mk_constr "Ignored_scan_char_set" [
mk_int_opt width_opt; mk_string char_set ]
| Ignored_scan_get_counter counter ->
mk_constr "Ignored_scan_get_counter" [
mk_counter counter
]
| Ignored_scan_next_char ->
mk_constr "Ignored_scan_next_char" []
and mk_padding : type x y . (x, y) padding -> Parsetree.expression =
fun pad -> match pad with
| No_padding -> mk_constr "No_padding" []
| Lit_padding (s, w) -> mk_constr "Lit_padding" [ mk_side s; mk_int w ]
| Arg_padding s -> mk_constr "Arg_padding" [ mk_side s ]
and mk_precision : type x y . (x, y) precision -> Parsetree.expression =
fun prec -> match prec with
| No_precision -> mk_constr "No_precision" []
| Lit_precision w -> mk_constr "Lit_precision" [ mk_int w ]
| Arg_precision -> mk_constr "Arg_precision" []
and mk_fmt : type a b c d e f .
(a, b, c, d, e, f) fmt -> Parsetree.expression =
fun fmt -> match fmt with
| Char rest ->
mk_constr "Char" [ mk_fmt rest ]
| Caml_char rest ->
mk_constr "Caml_char" [ mk_fmt rest ]
| String (pad, rest) ->
mk_constr "String" [ mk_padding pad; mk_fmt rest ]
| Caml_string (pad, rest) ->
mk_constr "Caml_string" [ mk_padding pad; mk_fmt rest ]
| Int (iconv, pad, prec, rest) ->
mk_constr "Int" [
mk_iconv iconv; mk_padding pad; mk_precision prec; mk_fmt rest ]
| Int32 (iconv, pad, prec, rest) ->
mk_constr "Int32" [
mk_iconv iconv; mk_padding pad; mk_precision prec; mk_fmt rest ]
| Nativeint (iconv, pad, prec, rest) ->
mk_constr "Nativeint" [
mk_iconv iconv; mk_padding pad; mk_precision prec; mk_fmt rest ]
| Int64 (iconv, pad, prec, rest) ->
mk_constr "Int64" [
mk_iconv iconv; mk_padding pad; mk_precision prec; mk_fmt rest ]
| Float (fconv, pad, prec, rest) ->
mk_constr "Float" [
mk_fconv fconv; mk_padding pad; mk_precision prec; mk_fmt rest ]
| Bool (pad, rest) ->
mk_constr "Bool" [ mk_padding pad; mk_fmt rest ]
| Flush rest ->
mk_constr "Flush" [ mk_fmt rest ]
| String_literal (s, rest) ->
mk_constr "String_literal" [ mk_string s; mk_fmt rest ]
| Char_literal (c, rest) ->
mk_constr "Char_literal" [ mk_char c; mk_fmt rest ]
| Format_arg (pad_opt, fmtty, rest) ->
mk_constr "Format_arg" [
mk_int_opt pad_opt; mk_fmtty fmtty; mk_fmt rest ]
| Format_subst (pad_opt, fmtty, rest) ->
mk_constr "Format_subst" [
mk_int_opt pad_opt; mk_fmtty fmtty; mk_fmt rest ]
| Alpha rest ->
mk_constr "Alpha" [ mk_fmt rest ]
| Theta rest ->
mk_constr "Theta" [ mk_fmt rest ]
| Formatting_lit (fmting, rest) ->
mk_constr "Formatting_lit" [ mk_formatting_lit fmting; mk_fmt rest ]
| Formatting_gen (fmting, rest) ->
mk_constr "Formatting_gen" [ mk_formatting_gen fmting; mk_fmt rest ]
| Reader rest ->
mk_constr "Reader" [ mk_fmt rest ]
| Scan_char_set (width_opt, char_set, rest) ->
mk_constr "Scan_char_set" [
mk_int_opt width_opt; mk_string char_set; mk_fmt rest ]
| Scan_get_counter (cnt, rest) ->
mk_constr "Scan_get_counter" [ mk_counter cnt; mk_fmt rest ]
| Scan_next_char rest ->
mk_constr "Scan_next_char" [ mk_fmt rest ]
| Ignored_param (ign, rest) ->
mk_constr "Ignored_param" [ mk_ignored ign; mk_fmt rest ]
| End_of_format ->
mk_constr "End_of_format" []
| Custom _ ->
(* Custom formatters have no syntax so they will never appear
in formats parsed from strings. *)
assert false
in
let legacy_behavior = not !Clflags.strict_formats in
let Fmt_EBB fmt = fmt_ebb_of_string ~legacy_behavior str in
mk_constr "Format" [ mk_fmt fmt; mk_string str ]
))
with Failure msg ->
raise (Error (loc, env, Invalid_format msg))
and type_label_exp create env loc ty_expected
(lid, label, sarg) =
(* Here also ty_expected may be at generic_level *)
let separate = !Clflags.principal || Env.has_local_constraints env in
let is_poly = is_poly_Tpoly label.lbl_arg in
let (vars, arg) =
(* raise level to check univars *)
with_local_level_generalize_if is_poly begin fun () ->
let (vars, ty_arg) =
with_local_level_generalize_structure_if separate begin fun () ->
let (vars, ty_arg, ty_res) =
with_local_level_generalize_structure_if separate
(fun () -> instance_label ~fixed:true label)
in
begin try
unify env (instance ty_res) (instance ty_expected)
with Unify err ->
raise (Error(lid.loc, env, Label_mismatch(lid.txt, err)))
end;
(* Instantiate so that we can generalize internal nodes *)
let ty_arg = instance ty_arg in
(vars, ty_arg)
end
in
if label.lbl_private = Private then
if create then
raise (Error(loc, env, Private_type ty_expected))
else
raise (Error(lid.loc, env, Private_label(lid.txt, ty_expected)));
(vars, type_argument env sarg ty_arg (instance ty_arg))
end
~before_generalize:(fun (_,arg) -> may_lower_contravariant env arg)
in
if is_poly then check_univars env "field value" arg label.lbl_arg vars;
(lid, label, {arg with exp_type = instance arg.exp_type})
and type_argument ?explanation ?recarg env sarg ty_expected' ty_expected =
(* ty_expected' may be generic *)
let no_labels ty =
let ls, tvar = list_labels env ty in
not tvar && List.for_all ((=) Nolabel) ls
in
let may_coerce =
if not (is_inferred sarg) then None else
let work () =
let te = expand_head env ty_expected' in
match get_desc te with
Tarrow(Nolabel,_,ty_res0,_) ->
Some (no_labels ty_res0, get_level te)
| _ -> None
in
(* Need to be careful not to expand local constraints here *)
if Env.has_local_constraints env then
let snap = Btype.snapshot () in
try_finally ~always:(fun () -> Btype.backtrack snap) work
else work ()
in
match may_coerce with
Some (safe_expect, lv) ->
(* apply optional arguments when expected type is "" *)
(* we must be very careful about not breaking the semantics *)
let texp =
with_local_level_generalize_structure_if_principal
(fun () -> type_exp env sarg)
in
let rec make_args args ty_fun =
match get_desc (expand_head env ty_fun) with
| Tarrow (l,ty_arg,ty_fun,_) when is_optional l ->
let ty = option_none env (instance ty_arg) sarg.pexp_loc in
make_args ((l, Arg ty) :: args) ty_fun
| Tarrow (l,_,ty_res',_) when l = Nolabel || !Clflags.classic ->
List.rev args, ty_fun, no_labels ty_res'
| Tvar _ -> List.rev args, ty_fun, false
| _ -> [], texp.exp_type, false
in
let args, ty_fun', simple_res = make_args [] texp.exp_type
and texp = {texp with exp_type = instance texp.exp_type} in
if not (simple_res || safe_expect) then begin
unify_exp ~sexp:sarg env texp ty_expected;
texp
end else begin
let warn = !Clflags.principal &&
(lv <> generic_level || get_level ty_fun' <> generic_level)
and ty_fun = instance ty_fun' in
let ty_arg, ty_res =
match get_desc (expand_head env ty_expected) with
Tarrow(Nolabel,ty_arg,ty_res,_) -> ty_arg, ty_res
| _ -> assert false
in
unify_exp ~sexp:sarg env {texp with exp_type = ty_fun} ty_expected;
if args = [] then texp else
(* eta-expand to avoid side effects *)
let var_pair name ty =
let id = Ident.create_local name in
let desc =
{ val_type = ty; val_kind = Val_reg;
val_attributes = [];
val_loc = Location.none;
val_uid = Uid.mk ~current_unit:(Env.get_current_unit ());
}
in
let exp_env = Env.add_value id desc env in
{pat_desc =
Tpat_var (id, mknoloc name, desc.val_uid);
pat_type = ty;
pat_extra=[];
pat_attributes = [];
pat_loc = Location.none; pat_env = env},
{exp_type = ty; exp_loc = Location.none; exp_env = exp_env;
exp_extra = []; exp_attributes = [];
exp_desc =
Texp_ident(Path.Pident id, mknoloc (Longident.Lident name), desc)}
in
let eta_pat, eta_var = var_pair "eta" ty_arg in
let func texp =
let e =
{texp with exp_type = ty_res; exp_desc =
Texp_apply
(texp,
args @ [Nolabel, Arg eta_var])}
in
let cases = [ case eta_pat e ] in
let cases_loc = { texp.exp_loc with loc_ghost = true } in
let param = name_cases "param" cases in
{ texp with exp_type = ty_fun; exp_desc =
Texp_function ([],
Tfunction_cases
{ cases; partial = Total; param; loc = cases_loc;
exp_extra = None; attributes = [];
})
}
in
Location.prerr_warning texp.exp_loc
(Warnings.Eliminated_optional_arguments
(List.map (fun (l, _) -> Asttypes.string_of_label l) args));
if warn then Location.prerr_warning texp.exp_loc
(Warnings.Non_principal_labels "eliminated optional argument");
(* let-expand to have side effects *)
let let_pat, let_var = var_pair "arg" texp.exp_type in
re { texp with exp_type = ty_fun; exp_desc =
Texp_let (Nonrecursive,
[{vb_pat=let_pat; vb_expr=texp; vb_attributes=[];
vb_loc=Location.none; vb_rec_kind = Dynamic;
}],
func let_var) }
end
| None ->
let texp = type_expect ?recarg env sarg
(mk_expected ?explanation ty_expected') in
unify_exp ~sexp:sarg env texp ty_expected;
texp
and type_apply_arg env (lbl, arg) =
match arg with
| Arg (Unknown_arg { sarg; ty_arg }) ->
let arg = type_expect env sarg (mk_expected ty_arg) in
if is_optional lbl then
unify_exp ~sexp:sarg env arg (type_option(newvar()));
(lbl, Arg arg)
| Arg (Known_arg { sarg; ty_arg; ty_arg0; wrapped_in_some }) ->
let arg =
if wrapped_in_some then
option_some env
(type_argument env sarg
(extract_option_type env ty_arg)
(extract_option_type env ty_arg0))
else
type_argument env sarg ty_arg ty_arg0
in
(lbl, Arg arg)
| Arg (Eliminated_optional_arg { ty_arg; _ }) ->
let arg =
option_none env (instance ty_arg) Location.none
in
(lbl, Arg arg)
| Omitted _ as arg -> (lbl, arg)
and type_application env funct sargs =
let is_ignore funct =
is_prim ~name:"%ignore" funct &&
(try ignore (filter_arrow env (instance funct.exp_type) Nolabel); true
with Filter_arrow_failed _ -> false)
in
match sargs with
| (* Special case for ignore: avoid discarding warning *)
[Nolabel, sarg] when is_ignore funct ->
let ty_arg, ty_res =
filter_arrow env (instance funct.exp_type) Nolabel in
let exp = type_expect env sarg (mk_expected ty_arg) in
check_partial_application ~statement:false exp;
([Nolabel, Arg exp], ty_res)
| _ ->
let ty = funct.exp_type in
let ignore_labels =
!Clflags.classic ||
begin
let ls, tvar = list_labels env ty in
not tvar &&
let labels = List.filter (fun l -> not (is_optional l)) ls in
List.length labels = List.length sargs &&
List.for_all (fun (l,_) -> l = Nolabel) sargs &&
List.exists (fun l -> l <> Nolabel) labels &&
(Location.prerr_warning
funct.exp_loc
(Warnings.Labels_omitted
(List.map Asttypes.string_of_label
(List.filter ((<>) Nolabel) labels)));
true)
end
in
(* Consider for example the application
[f n]
with
[f : a:bar -> ?opt:baz -> int -> unit] *)
let ty_ret, args =
collect_apply_args env funct ignore_labels ty (instance ty) sargs
in
(* example: [collect_apply_args] returns
[ty_ret = unit] and
[args = [(Label "a", Omitted bar);
(Optional "opt", Arg (Eliminated_optional_arg baz));
(Nolabel, Arg (Known_arg n))]] *)
let args = List.map (fun arg -> type_apply_arg env arg) args in
(* example: type-check [n] and generate [None] for [?opt].
[args] becomes [(Label "a", Omitted bar);
(Optional "opt", Arg None);
(Nolabel, Arg n)] *)
let ty_ret, args =
type_omitted_parameters_and_build_result_type ty_ret args in
(* example:
[ty_ret] becomes [a:bar -> unit]
[args] becomes [(Label "a", Omitted ());
(Optional "opt", Arg None);
(Nolabel, Arg n)] *)
args, instance ty_ret
and type_construct env ~sexp lid sarg ty_expected_explained =
let { ty = ty_expected; explanation } = ty_expected_explained in
let expected_type =
match extract_concrete_variant env ty_expected with
| Variant_type(p0, p,_) ->
Some(p0, p, is_principal ty_expected)
| Maybe_a_variant_type -> None
| Not_a_variant_type ->
let srt = wrong_kind_sort_of_constructor lid.txt in
let ctx = Expression explanation in
let error = Wrong_expected_kind(srt, ctx, ty_expected) in
raise (Error (sexp.pexp_loc, env, error))
in
let constrs =
Env.lookup_all_constructors ~loc:lid.loc Env.Positive lid.txt env
in
let constr =
wrap_disambiguate "This variant expression is expected to have"
ty_expected_explained
(Constructor.disambiguate Env.Positive lid env expected_type) constrs
in
let sargs =
match sarg with
None -> []
| Some {pexp_desc = Pexp_tuple sel} when
constr.cstr_arity > 1
|| Builtin_attributes.explicit_arity sexp.pexp_attributes
->
List.map (fun (l, se) ->
match l with
| Some _ ->
raise (Error(sexp.pexp_loc, env, Constructor_labeled_arg))
| None -> se
) sel
| Some se -> [se] in
if List.length sargs <> constr.cstr_arity then
raise(Error(sexp.pexp_loc, env,
Constructor_arity_mismatch
(lid.txt, constr.cstr_arity, List.length sargs)));
let separate = !Clflags.principal || Env.has_local_constraints env in
let ty_args, ty_res, texp =
with_local_level_generalize_structure_if separate begin fun () ->
let ty_args, ty_res, texp =
with_local_level_generalize_structure_if separate begin fun () ->
let (ty_args, ty_res, _) =
instance_constructor Keep_existentials_flexible constr
in
let texp =
re {
exp_desc = Texp_construct(lid, constr, []);
exp_loc = sexp.pexp_loc; exp_extra = [];
exp_type = ty_res;
exp_attributes = sexp.pexp_attributes;
exp_env = env } in
(ty_args, ty_res, texp)
end
in
with_explanation explanation (fun () ->
unify_exp ~sexp env {texp with exp_type = instance ty_res}
(instance ty_expected));
(ty_args, ty_res, texp)
end
in
let ty_args0, ty_res =
match instance_list (ty_res :: ty_args) with
t :: tl -> tl, t
| _ -> assert false
in
let texp = {texp with exp_type = ty_res} in
if not separate then unify_exp ~sexp env texp (instance ty_expected);
let recarg =
match constr.cstr_inlined with
| None -> Rejected
| Some _ ->
begin match sargs with
| [{pexp_desc =
Pexp_ident _ |
Pexp_record (_, (Some {pexp_desc = Pexp_ident _}| None))}] ->
Required
| _ ->
raise (Error(sexp.pexp_loc, env, Inlined_record_expected))
end
in
let args =
List.map2 (fun e (t,t0) -> type_argument ~recarg env e t t0) sargs
(List.combine ty_args ty_args0) in
if constr.cstr_private = Private then
begin match constr.cstr_tag with
| Cstr_extension _ ->
raise(Error(sexp.pexp_loc, env, Private_constructor (constr, ty_res)))
| Cstr_constant _ | Cstr_block _ | Cstr_unboxed ->
raise (Error(sexp.pexp_loc, env, Private_type ty_res));
end;
(* NOTE: shouldn't we call "re" on this final expression? -- AF *)
{ texp with
exp_desc = Texp_construct(lid, constr, args) }
(* Typing of statements (expressions whose values are discarded) *)
and type_statement ?explanation env sexp =
(* OCaml 5.2.0 changed the type of 'while' to give 'while true do e done'
a polymorphic type. The change has the potential to trigger a
nonreturning-statement warning in existing code that follows
'while true' with some other statement, e.g.
while true do e done; assert false
To avoid this issue, we disable the warning in this particular case.
We might consider re-enabling it at a point when most users have
migrated to OCaml 5.2.0 or later. *)
let allow_polymorphic e = match e.exp_desc with
| Texp_while _ -> true
| _ -> false
in
(* Raise the current level to detect non-returning functions *)
with_local_level_generalize (fun () -> type_exp env sexp)
~before_generalize: begin fun exp ->
let subexp = final_subexpression exp in
let ty = expand_head env exp.exp_type in
if is_Tvar ty
&& get_level ty > get_current_level ()
&& not (allow_polymorphic subexp) then
Location.prerr_warning
subexp.exp_loc
Warnings.Nonreturning_statement;
if !Clflags.strict_sequence then
let expected_ty = instance Predef.type_unit in
with_explanation explanation (fun () ->
unify_exp ~sexp env exp expected_ty)
else begin
check_partial_application ~statement:true exp;
enforce_current_level env ty
end
end
(* Most of the arguments are the same as [type_cases].
Takes a callback which is responsible for typing the body of the case.
The arguments are documented inline in the type signature.
It takes a callback rather than returning the half-typed cases directly
because the typing of the body must take place at an increased level.
The overall function returns:
- The data returned by the callback
- Whether the cases' patterns are partial or total
*)
and map_half_typed_cases
: type k ret case_data.
?additional_checks_for_split_cases:((_ * ret) list -> unit) -> ?conts:_
-> k pattern_category -> _ -> _ -> _ -> _
-> (untyped_case * case_data) list
-> type_body:(
case_data
-> k general_pattern (* the typed pattern *)
-> when_env:_ (* environment with module/pattern variables *)
-> ext_env:_ (* when_env + continuation var*)
-> cont:_
-> ty_expected:_ (* type to check body in scope of *)
-> ty_infer:_ (* type to infer for body *)
-> contains_gadt:_ (* whether the pattern contains a GADT *)
-> ret)
-> check_if_total:bool (* if false, assume Partial right away *)
-> ret list * partial
= fun ?additional_checks_for_split_cases ?conts
category env ty_arg ty_res loc caselist ~type_body ~check_if_total ->
(* ty_arg is _fully_ generalized *)
let patterns = List.map (fun ((x : untyped_case), _) -> x.pattern) caselist in
let contains_polyvars = List.exists contains_polymorphic_variant patterns in
let erase_either = contains_polyvars && contains_variant_either ty_arg in
let may_contain_gadts = List.exists may_contain_gadts patterns in
let may_contain_modules = List.exists may_contain_modules patterns in
let create_inner_level = may_contain_gadts || may_contain_modules in
let ty_arg =
if (may_contain_gadts || erase_either) && not !Clflags.principal
then duplicate_type ty_arg else ty_arg
in
let rec is_var spat =
match spat.ppat_desc with
Ppat_any | Ppat_var _ -> true
| Ppat_alias (spat, _) -> is_var spat
| _ -> false in
let needs_exhaust_check =
match caselist with
[ ({ needs_refute = true }, _) ] -> true
| [ ({ pattern }, _) ] when is_var pattern -> false
| _ -> true
in
let outer_level = get_current_level () in
with_local_level_iter_if create_inner_level begin fun () ->
let lev = get_current_level () in
let allow_modules =
if may_contain_modules
then
(* The corresponding check for scope escape is done together with
the check for GADT-induced existentials by
[with_local_level_iter_if create_inner_level].
*)
Modules_allowed { scope = lev }
else Modules_rejected
in
let take_partial_instance =
if erase_either
then Some false else None
in
let map_conts f conts caselist = match conts with
| None -> List.map (fun c -> f c None) caselist
| Some conts -> List.map2 f caselist conts
in
let half_typed_cases, ty_res, do_copy_types, ty_arg' =
(* propagation of the argument *)
with_local_level_generalize begin fun () ->
let pattern_force = ref [] in
(* Format.printf "@[%i %i@ %a@]@." lev (get_current_level())
Printtyp.raw_type_expr ty_arg; *)
let half_typed_cases =
map_conts
(fun ({ Parmatch.pattern; _ } as untyped_case, case_data) cont ->
let htc =
with_local_level_generalize_structure_if_principal begin fun () ->
let ty_arg =
(* propagation of pattern *)
with_local_level_generalize_structure
(fun () -> instance ?partial:take_partial_instance ty_arg)
in
let (pat, ext_env, force, pvs, mvs) =
type_pattern ?cont category ~lev env pattern ty_arg
allow_modules
in
pattern_force := force @ !pattern_force;
{ typed_pat = pat;
pat_type_for_unif = ty_arg;
untyped_case;
case_data;
branch_env = ext_env;
pat_vars = pvs;
module_vars = mvs;
contains_gadt = contains_gadt (as_comp_pattern category pat);
}
end
in
(* Ensure that no ambivalent pattern type escapes its branch *)
check_scope_escape htc.typed_pat.pat_loc env outer_level
htc.pat_type_for_unif;
let pat = htc.typed_pat in
{htc with typed_pat = { pat with pat_type = instance pat.pat_type }}
)
conts caselist in
let patl =
List.map (fun { typed_pat; _ } -> typed_pat) half_typed_cases in
let does_contain_gadt =
List.exists (fun { contains_gadt; _ } -> contains_gadt) half_typed_cases
in
let ty_res, do_copy_types =
if does_contain_gadt && not !Clflags.principal then
duplicate_type ty_res, Env.make_copy_of_types env
else ty_res, (fun env -> env)
in
(* Unify all cases (delayed to keep it order-free) *)
let ty_arg' = newvar () in
let unify_pats ty =
List.iter (fun { typed_pat = pat; pat_type_for_unif = pat_ty; _ } ->
unify_pat_types pat.pat_loc env pat_ty ty
) half_typed_cases
in
unify_pats ty_arg';
(* Check for polymorphic variants to close *)
if List.exists has_variants patl then begin
Parmatch.pressure_variants_in_computation_pattern env
(List.map (as_comp_pattern category) patl);
List.iter finalize_variants patl
end;
(* `Contaminating' unifications start here *)
List.iter (fun f -> f()) !pattern_force;
(* Post-processing and generalization *)
if take_partial_instance <> None then unify_pats (instance ty_arg);
List.iter (fun { pat_vars; _ } ->
iter_pattern_variables_type (enforce_current_level env) pat_vars
) half_typed_cases;
(half_typed_cases, ty_res, do_copy_types, ty_arg')
end
in
(* type bodies *)
let ty_res' = instance ty_res in
(* Why is it needed to keep the level of result raised ? *)
let result = with_local_level_if_principal ~post:ignore begin fun () ->
map_conts
(fun { typed_pat = pat; branch_env = ext_env;
pat_vars = pvs; module_vars = mvs;
case_data; contains_gadt; _ } cont
->
let ext_env =
if contains_gadt then
do_copy_types ext_env
else
ext_env
in
(* Before handing off the cases to the callback, first set up the the
branch environments by adding the variables (and module variables)
from the patterns.
*)
let cont_vars, pvs =
List.partition (fun pv -> pv.pv_kind = Continuation_var) pvs in
let add_pattern_vars = add_pattern_variables
~check:(fun s -> Warnings.Unused_var_strict s)
~check_as:(fun s -> Warnings.Unused_var s)
in
let when_env = add_pattern_vars ext_env pvs in
let when_env = add_module_variables when_env mvs in
let ext_env = add_pattern_vars when_env cont_vars in
let ty_expected =
if contains_gadt && not !Clflags.principal then
(* Take a generic copy of [ty_res] again to allow propagation of
type information from preceding branches *)
duplicate_type ty_res
else ty_res in
type_body case_data pat ~when_env ~ext_env ~cont ~ty_expected
~ty_infer:ty_res' ~contains_gadt)
conts half_typed_cases
end in
let do_init = may_contain_gadts || needs_exhaust_check in
let ty_arg_check =
if do_init then
(* Hack: use for_saving to copy variables too *)
Subst.type_expr (Subst.for_saving Subst.identity) ty_arg'
else ty_arg'
in
(* Split the cases into val and exn cases so we can do the appropriate checks
for exhaustivity and unused variables.
The caller of this function can define custom checks. For some of these
checks, the half-typed case doesn't provide enough info on its own -- for
instance, the check for ambiguous bindings in when guards needs to know the
case body's expression -- so the code pairs each case with its
corresponding element in [result] before handing it off to the caller's
custom checks.
*)
let val_cases_with_result, exn_cases_with_result =
match category with
| Value ->
let val_cases =
List.map2
(fun htc res ->
{ htc.untyped_case with pattern = htc.typed_pat }, res)
half_typed_cases
result
in
(val_cases : (pattern Parmatch.parmatch_case * ret) list), []
| Computation ->
split_half_typed_cases env (List.combine half_typed_cases result)
in
let val_cases = List.map fst val_cases_with_result in
let exn_cases = List.map fst exn_cases_with_result in
if val_cases = [] && exn_cases <> [] then
raise (Error (loc, env, No_value_clauses));
let partial =
if check_if_total then
check_partial ~lev env ty_arg_check loc val_cases
else
Partial
in
let unused_check delayed =
List.iter (fun { typed_pat; branch_env; _ } ->
check_absent_variant branch_env (as_comp_pattern category typed_pat)
) half_typed_cases;
with_level_if delayed ~level:lev begin fun () ->
check_unused ~lev env ty_arg_check val_cases ;
check_unused ~lev env Predef.type_exn exn_cases ;
end;
in
if contains_polyvars then
add_delayed_check (fun () -> unused_check true)
else
(* Check for unused cases, do not delay because of gadts *)
unused_check false;
begin
match additional_checks_for_split_cases with
| None -> ()
| Some check ->
check val_cases_with_result;
check exn_cases_with_result;
end;
(result, partial), [ty_res']
end
(* Ensure that existential types do not escape *)
~post:(fun ty_res' -> unify_exp_types loc env ty_res' (newvar ()))
(* Typing of match cases *)
and type_cases
: type k . k pattern_category -> _ -> _ -> _ -> ?conts:_ ->
check_if_total:bool -> _ -> Parsetree.case list ->
k case list * partial
= fun category env
ty_arg ty_res_explained ?conts ~check_if_total loc caselist ->
let { ty = ty_res; explanation } = ty_res_explained in
let caselist =
List.map (fun case -> Parmatch.untyped_case case, case) caselist
in
(* Most of the work is done by [map_half_typed_cases]. All that's left
is to typecheck the guards and the cases, and then to check for some
warnings that can fire in the presence of guards.
*)
map_half_typed_cases ?conts category env ty_arg ty_res loc caselist
~check_if_total
~type_body:begin
fun { pc_guard; pc_rhs } pat ~when_env ~ext_env ~cont ~ty_expected
~ty_infer ~contains_gadt:_ ->
let cont = Option.map (fun (id,_) -> id) cont in
let guard =
match pc_guard with
| None -> None
| Some scond ->
(* It is crucial that the continuation is not used in the
`when' expression as the extent of the continuation is
yet to be determined. We make the continuation
inaccessible by typing the `when' expression using the
environment `ext_env' which does not bind the
continuation variable. *)
Some
(type_expect when_env scond
(mk_expected ~explanation:When_guard Predef.type_bool))
in
let exp =
type_expect ext_env pc_rhs (mk_expected ?explanation ty_expected)
in
{
c_lhs = pat;
c_cont = cont;
c_guard = guard;
c_rhs = {exp with exp_type = ty_infer}
}
end
~additional_checks_for_split_cases:(fun cases ->
let cases =
List.map
(fun (case_with_pat, case) ->
{ case with c_lhs = case_with_pat.Parmatch.pattern }) cases
in
Parmatch.check_ambiguous_bindings cases)
(** A version of [type_expect], but that operates over function cases instead
of expressions. The input type is like the [ty_expected] argument to
[type_expect], and the returned type is like the [exp_type] of the
expression returned by [type_expect].
See [split_function_ty] for the meaning of [first] and [in_function].
*)
and type_function_cases_expect
env ty_expected loc cases attrs ~first ~in_function =
Builtin_attributes.warning_scope attrs begin fun () ->
let ty_arg, ty_res =
split_function_ty env ty_expected ~arg_label:Nolabel ~first ~in_function
in
let cases, partial =
type_cases Value env ty_arg (mk_expected ty_res)
~check_if_total:true loc cases
in
let ty_fun =
instance (newgenty (Tarrow (Nolabel, ty_arg, ty_res, commu_ok)))
in
unify_exp_types loc env ty_fun (instance ty_expected);
cases, partial, ty_fun
end
and type_effect_cases
: type k . k pattern_category -> _ -> _ -> _ -> Parsetree.case list -> _
-> k case list
= fun category env ty_res_explained loc caselist conts ->
let { ty = ty_res; explanation = _ } = ty_res_explained in
let _ = newvar () in
(* remember original level *)
with_local_level begin fun () ->
(* Create a locally type abstract type for effect type. *)
let new_env, ty_arg, ty_cont =
let decl = Ctype.new_local_type ~loc Definition in
let scope = create_scope () in
let name = Ctype.get_new_abstract_name env "%eff" in
let id = Ident.create_scoped ~scope name in
let new_env = Env.add_type ~check:false id decl env in
let ty_eff = newgenty (Tconstr (Path.Pident id,[],ref Mnil)) in
new_env,
Predef.type_eff ty_eff,
Predef.type_continuation ty_eff ty_res
in
let conts = List.map (type_continuation_pat env ty_cont) conts in
let cases, _ = type_cases category new_env ty_arg
ty_res_explained ~conts ~check_if_total:false loc caselist
in
cases
end
(* Typing of let bindings *)
and type_let ?check ?check_strict
existential_context env rec_flag spat_sexp_list allow_modules =
let spatl = List.map vb_pat_constraint spat_sexp_list in
let attrs_list = List.map fst spatl in
let is_recursive = (rec_flag = Recursive) in
let (pat_list, exp_list, new_env, mvs) =
with_local_level_generalize begin fun () ->
if existential_context = At_toplevel then Typetexp.TyVarEnv.reset ();
let (pat_list, new_env, force, pvs, mvs) =
with_local_level_generalize_structure_if_principal begin fun () ->
let nvs = List.map (fun _ -> newvar ()) spatl in
let (pat_list, _new_env, _force, _pvs, _mvs as res) =
type_pattern_list
Value existential_context env spatl nvs allow_modules in
(* If recursive, first unify with an approximation of the
expression *)
if is_recursive then
List.iter2
(fun pat binding ->
let pat =
match get_desc pat.pat_type with
| Tpoly (ty, tl) ->
{pat with pat_type =
snd (instance_poly ~keep_names:true ~fixed:false tl ty)}
| _ -> pat
in
let bound_expr = vb_exp_constraint binding in
unify_pat env pat (type_approx env bound_expr))
pat_list spat_sexp_list;
(* Polymorphic variant processing *)
List.iter
(fun pat ->
if has_variants pat then begin
Parmatch.pressure_variants env [pat];
finalize_variants pat
end)
pat_list;
res
end
in
(* Note [add_module_variables after checking expressions]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Don't call [add_module_variables] here, because its use of
[type_module] will fail until after we have type-checked the expression
of the let. Example: [let m : (module S) = ... in let (module M) = m in
...] We learn the signature [S] from the type of [m] in the RHS of the
second let, and we need that knowledge for [type_module] to succeed. If
we type-checked expressions before patterns, then we could call
[add_module_variables] here.
*)
let new_env = add_pattern_variables new_env pvs in
let pat_list =
List.map
(fun pat -> {pat with pat_type = instance pat.pat_type}, pat.pat_type)
pat_list
in
(* Only bind pattern variables after generalizing *)
List.iter (fun f -> f()) force;
let exp_list =
(* See Note [add_module_variables after checking expressions]
We can't defer type-checking module variables with recursive
definitions, so things like [let rec (module M) = m in ...] always
fail, even if the type of [m] is known.
*)
let exp_env =
if is_recursive then add_module_variables new_env mvs else env
in
type_let_def_wrap_warnings ?check ?check_strict ~is_recursive
~exp_env ~new_env ~spat_sexp_list ~attrs_list ~pat_list ~pvs
(fun exp_env ({pvb_attributes; _} as vb) expected_ty ->
let sexp = vb_exp_constraint vb in
match get_desc expected_ty with
| Tpoly (ty, tl) ->
let vars, ty' =
with_local_level_generalize_structure_if_principal
(fun () -> instance_poly ~keep_names:true ~fixed:true tl ty)
in
let exp =
Builtin_attributes.warning_scope pvb_attributes (fun () ->
type_expect exp_env sexp (mk_expected ty'))
in
exp, Some vars
| _ ->
let exp =
Builtin_attributes.warning_scope pvb_attributes (fun () ->
type_expect exp_env sexp (mk_expected expected_ty))
in
exp, None)
in
List.iter2
(fun (pat, _) (attrs, exp) ->
Builtin_attributes.warning_scope ~ppwarning:false attrs
(fun () ->
let case = Parmatch.typed_case (case pat exp) in
ignore(check_partial env pat.pat_type pat.pat_loc
[case] : Typedtree.partial)
)
)
pat_list
(List.map2 (fun (attrs, _) (e, _) -> attrs, e) spatl exp_list);
(pat_list, exp_list, new_env, mvs)
end
~before_generalize: begin fun (pat_list, exp_list, _, _) ->
List.iter2 (fun (pat, _) (exp, vars) ->
if maybe_expansive exp then begin
lower_contravariant env pat.pat_type;
if vars <> None then lower_contravariant env exp.exp_type
end)
pat_list exp_list
end
in
List.iter2
(fun (_, expected_ty) (exp, vars) ->
Option.iter (check_univars env "definition" exp expected_ty) vars)
pat_list exp_list;
let l = List.combine pat_list exp_list in
let l =
List.map2
(fun ((p, _), (e, _)) pvb ->
(* vb_rec_kind will be computed later for recursive bindings *)
{vb_pat=p; vb_expr=e; vb_attributes=pvb.pvb_attributes;
vb_loc=pvb.pvb_loc; vb_rec_kind = Dynamic;
})
l spat_sexp_list
in
if is_recursive then
List.iter
(fun {vb_pat=pat} -> match pat.pat_desc with
Tpat_var _ -> ()
| Tpat_alias ({pat_desc=Tpat_any}, _, _, _, _) -> ()
| _ -> raise(Error(pat.pat_loc, env, Illegal_letrec_pat)))
l;
List.iter (fun vb ->
if pattern_needs_partial_application_check vb.vb_pat then
check_partial_application ~statement:false vb.vb_expr
) l;
(* See Note [add_module_variables after checking expressions] *)
let new_env = add_module_variables new_env mvs in
(l, new_env)
and type_let_def_wrap_warnings
?(check = fun s -> Warnings.Unused_var s)
?(check_strict = fun s -> Warnings.Unused_var_strict s)
~is_recursive ~exp_env ~new_env ~spat_sexp_list ~attrs_list ~pat_list ~pvs
type_def =
let is_fake_let =
match spat_sexp_list with
| [{pvb_expr={pexp_desc=Pexp_match(
{pexp_desc=Pexp_ident({ txt = Longident.Lident "*opt*"})},_)}}] ->
true (* the fake let-declaration introduced by fun ?(x = e) -> ... *)
| _ ->
false
in
let check = if is_fake_let then check_strict else check in
let warn_about_unused_bindings =
List.exists
(fun attrs ->
Builtin_attributes.warning_scope ~ppwarning:false attrs (fun () ->
Warnings.is_active (check "") || Warnings.is_active (check_strict "")
|| (is_recursive && (Warnings.is_active Warnings.Unused_rec_flag))))
attrs_list
in
let sexp_is_fun { pvb_expr = sexp; _ } =
match sexp.pexp_desc with
| Pexp_function _ -> true
| _ -> false
in
let exp_env =
if not is_recursive && List.for_all sexp_is_fun spat_sexp_list then begin
(* Add ghost bindings to help detecting missing "rec" keywords.
We only add those if the body of the definition is obviously a
function. The rationale is that, in other cases, the hint is probably
wrong (and the user is using "advanced features" anyway (lazy,
recursive values...)).
[pvb_loc] (below) is the location of the first let-binding (in case of
a let .. and ..), and is where the missing "rec" hint suggests to add a
"rec" keyword. *)
match spat_sexp_list with
| {pvb_loc; _} :: _ ->
maybe_add_pattern_variables_ghost pvb_loc exp_env pvs
| _ -> assert false
end
else exp_env
in
(* Algorithm to detect unused declarations in recursive bindings:
- During type checking of the definitions, we capture the 'value_used'
events on the bound identifiers and record them in a slot corresponding
to the current definition (!current_slot).
In effect, this creates a dependency graph between definitions.
- After type checking the definition (!current_slot = None),
when one of the bound identifier is effectively used, we trigger
again all the events recorded in the corresponding slot.
The effect is to traverse the transitive closure of the graph created
in the first step.
We also keep track of whether *all* variables in a given pattern
are unused. If this is the case, for local declarations, the issued
warning is 26, not 27.
*)
let current_slot = ref None in
let rec_needed = ref false in
let typ_slot_list =
List.map2
(fun attrs (pat, expected_ty) ->
Builtin_attributes.warning_scope ~ppwarning:false attrs (fun () ->
if not warn_about_unused_bindings then expected_ty, None
else
let some_used = ref false in
(* has one of the identifier of this pattern been used? *)
let slot = ref [] in
List.iter
(fun id ->
let vd = Env.find_value (Path.Pident id) new_env in
(* note: Env.find_value does not trigger the value_used
event *)
let name = Ident.name id in
let used = ref false in
if not (name = "" || name.[0] = '_' || name.[0] = '#') then
add_delayed_check
(fun () ->
if not !used then
Location.prerr_warning vd.Types.val_loc
((if !some_used then check_strict else check) name)
);
Env.set_value_used_callback
vd
(fun () ->
match !current_slot with
| Some slot ->
slot := vd.val_uid :: !slot; rec_needed := true
| None ->
List.iter Env.mark_value_used (get_ref slot);
used := true;
some_used := true
)
)
(Typedtree.pat_bound_idents pat);
expected_ty, Some slot
))
attrs_list
pat_list
in
let exp_list =
List.map2
(fun case (pat, slot) ->
if is_recursive then current_slot := slot;
type_def exp_env case pat)
spat_sexp_list typ_slot_list
in
current_slot := None;
if is_recursive && not !rec_needed then begin
let {pvb_pat; pvb_attributes} = List.hd spat_sexp_list in
(* See PR#6677 *)
Builtin_attributes.warning_scope ~ppwarning:false pvb_attributes
(fun () ->
Location.prerr_warning pvb_pat.ppat_loc Warnings.Unused_rec_flag
)
end;
exp_list
and type_andops env sarg sands expected_ty =
let rec loop env let_sarg rev_sands expected_ty =
match rev_sands with
| [] -> type_expect env let_sarg (mk_expected expected_ty), []
| { pbop_op = sop; pbop_exp = sexp; pbop_loc = loc; _ } :: rest ->
let op_path, op_desc, op_type, ty_arg, ty_rest, ty_result =
with_local_level_generalize_structure_if_principal begin fun () ->
let op_path, op_desc = type_binding_op_ident env sop in
let op_type = instance op_desc.val_type in
let ty_arg = newvar () in
let ty_rest = newvar () in
let ty_result = newvar() in
let ty_rest_fun =
newty (Tarrow(Nolabel, ty_arg, ty_result, commu_ok)) in
let ty_op =
newty (Tarrow(Nolabel, ty_rest, ty_rest_fun, commu_ok)) in
begin try
unify env op_type ty_op
with Unify err ->
raise(Error(sop.loc, env, Andop_type_clash(sop.txt, err)))
end;
(op_path, op_desc, op_type, ty_arg, ty_rest, ty_result)
end
in
let let_arg, rest = loop env let_sarg rest ty_rest in
let exp = type_expect env sexp (mk_expected ty_arg) in
begin try
unify env (instance ty_result) (instance expected_ty)
with Unify err ->
raise(Error(loc, env, Bindings_type_clash(err)))
end;
let andop =
{ bop_op_name = sop;
bop_op_path = op_path;
bop_op_val = op_desc;
bop_op_type = op_type;
bop_exp = exp;
bop_loc = loc }
in
let_arg, andop :: rest
in
let let_arg, rev_ands = loop env sarg (List.rev sands) expected_ty in
let_arg, List.rev rev_ands
(* Typing of method call *)
and type_send env loc explanation e met =
let obj = type_exp env e in
let (meth, typ) =
match obj.exp_desc with
| Texp_ident(_, _, {val_kind = Val_self(sign, meths, _, _)}) ->
let id, typ =
match meths with
| Self_concrete meths ->
let id =
match Meths.find met meths with
| id -> id
| exception Not_found ->
let valid_methods =
Meths.fold (fun lab _ acc -> lab :: acc) meths []
in
raise (Error(e.pexp_loc, env,
Undefined_self_method (met, valid_methods)))
in
let typ = Btype.method_type met sign in
id, typ
| Self_virtual meths_ref -> begin
match Meths.find met !meths_ref with
| id -> id, Btype.method_type met sign
| exception Not_found ->
let id = Ident.create_local met in
let ty = newvar () in
meths_ref := Meths.add met id !meths_ref;
add_method env met Private Virtual ty sign;
Location.prerr_warning loc
(Warnings.Undeclared_virtual_method met);
id, ty
end
in
Tmeth_val id, typ
| Texp_ident(_, _, {val_kind = Val_anc (sign, meths, cl_num)}) ->
let id =
match Meths.find met meths with
| id -> id
| exception Not_found ->
let valid_methods =
Meths.fold (fun lab _ acc -> lab :: acc) meths []
in
raise (Error(e.pexp_loc, env,
Undefined_self_method (met, valid_methods)))
in
let typ = Btype.method_type met sign in
let (self_path, _) =
Env.find_value_by_name
(Longident.Lident ("self-" ^ cl_num)) env
in
Tmeth_ancestor(id, self_path), typ
| _ ->
let ty =
match filter_method env met obj.exp_type with
| ty -> ty
| exception Filter_method_failed err ->
let error =
match err with
| Unification_error err ->
Expr_type_clash(err, explanation, None)
| Not_an_object ty ->
Not_an_object(ty, explanation)
| Not_a_method ->
let valid_methods =
match get_desc (expand_head env obj.exp_type) with
| Tobject (fields, _) ->
let (fields, _) = Ctype.flatten_fields fields in
let collect_fields li (meth, meth_kind, _meth_ty) =
if field_kind_repr meth_kind = Fpublic
then meth::li else li
in
Some (List.fold_left collect_fields [] fields)
| _ -> None
in
Undefined_method(obj.exp_type, met, valid_methods)
in
raise (Error(e.pexp_loc, env, error))
in
Tmeth_name met, ty
in
(obj,meth,typ)
(* Typing of toplevel bindings *)
let type_binding env rec_flag spat_sexp_list =
let (pat_exp_list, new_env) =
type_let
~check:(fun s -> Warnings.Unused_value_declaration s)
~check_strict:(fun s -> Warnings.Unused_value_declaration s)
At_toplevel
env rec_flag spat_sexp_list Modules_rejected
in
(pat_exp_list, new_env)
let type_let existential_ctx env rec_flag spat_sexp_list =
let (pat_exp_list, new_env) =
type_let existential_ctx env rec_flag spat_sexp_list Modules_rejected in
(pat_exp_list, new_env)
(* Typing of toplevel expressions *)
let type_expression env sexp =
let exp =
with_local_level_generalize begin fun () ->
Typetexp.TyVarEnv.reset();
type_exp env sexp
end
~before_generalize:(may_lower_contravariant env)
in
match sexp.pexp_desc with
Pexp_ident lid ->
let loc = sexp.pexp_loc in
(* Special case for keeping type variables when looking-up a variable *)
let (_path, desc) = Env.lookup_value ~use:false ~loc lid.txt env in
{exp with exp_type = desc.val_type}
| _ -> exp
(* Error report *)
let spellcheck unbound_name valid_names =
Misc.did_you_mean (Misc.spellcheck valid_names unbound_name)
let spellcheck_idents unbound valid_idents =
spellcheck (Ident.name unbound) (List.map Ident.name valid_idents)
open Format_doc
module Fmt = Format_doc
module Printtyp = Printtyp.Doc
let quoted_longident = Style.as_inline_code Pprintast.Doc.longident
let quoted_constr = Style.as_inline_code Pprintast.Doc.constr
let tuple_component ~print_article ppf lbl =
let article =
match print_article, lbl with
| true, Some _ -> "a "
| true, None -> "an "
| false, _ -> ""
in
match lbl with
| Some s ->
fprintf ppf "%scomponent with label %a" article Style.inline_code s
| None -> fprintf ppf "%sunlabeled component" article
(* Returns the first diff of the trace *)
let type_clash_of_trace trace =
Errortrace.(explain trace (fun ~prev:_ -> function
| Diff diff -> Some diff
| _ -> None
))
(** More precise denomination for type errors. Used by messages:
- [This <denom> ...]
- [The <denom> "foo" ...] *)
let pp_exp_denom ppf pexp =
let d = pp_print_string ppf in
let d_expression = fprintf ppf "%a expression" Style.inline_code in
match pexp.pexp_desc with
| Pexp_constant _ -> d "constant"
| Pexp_ident _ -> d "value"
| Pexp_construct _ | Pexp_variant _ -> d "constructor"
| Pexp_field _ -> d "field access"
| Pexp_send _ -> d "method call"
| Pexp_while _ -> d_expression "while"
| Pexp_for _ -> d_expression "for"
| Pexp_ifthenelse _ -> d_expression "if-then-else"
| Pexp_match _ -> d_expression "match"
| Pexp_try _ -> d_expression "try-with"
| _ -> d "expression"
(** Implements the "This expression" message, printing the expression if it
should be according to {!Parsetree.Doc.nominal_exp}. *)
let report_this_pexp_has_type denom ppf exp =
let denom ppf =
match denom, exp with
| Some d, _ -> fprintf ppf "%s" d
| None, Some exp -> pp_exp_denom ppf exp
| None, None -> fprintf ppf "expression"
in
let nexp = Option.bind exp Pprintast.Doc.nominal_exp in
match nexp with
| Some nexp ->
fprintf ppf "The %t %a has type" denom (Style.as_inline_code pp_doc) nexp
| _ -> fprintf ppf "This %t has type" denom
let report_this_texp_has_type denom ppf texp =
report_this_pexp_has_type denom ppf (Some (Untypeast.untype_expression texp))
(* Hint on type error on integer literals
To avoid confusion, it is disabled on float literals
and when the expected type is `int` *)
let report_literal_type_constraint expected_type const =
let const_str = match const.pconst_desc with
| Pconst_integer (s, _) -> Some s
| _ -> None
in
let suffix =
if Path.same expected_type Predef.path_int32 then
Some 'l'
else if Path.same expected_type Predef.path_int64 then
Some 'L'
else if Path.same expected_type Predef.path_nativeint then
Some 'n'
else if Path.same expected_type Predef.path_float then
Some '.'
else None
in
let pp_const ppf (c,s) = Fmt.fprintf ppf "%s%c" c s in
match const_str, suffix with
| Some c, Some s -> [
Location.msg
"@[@{<hint>Hint@}: Did you mean %a?@]"
(Style.as_inline_code pp_const) (c,s)
]
| _, _ -> []
let report_literal_type_constraint const = function
| Some tr ->
begin match get_desc Errortrace.(tr.expected.ty) with
Tconstr (typ, [], _) ->
report_literal_type_constraint typ const
| _ -> []
end
| None -> []
let report_partial_application = function
| Some tr -> begin
match get_desc tr.Errortrace.got.Errortrace.expanded with
| Tarrow _ ->
[ Location.msg
"@[@{<hint>Hint@}:@ This function application is partial,@ \
maybe@ some@ arguments@ are missing.@]" ]
| _ -> []
end
| None -> []
let report_expr_type_clash_hints exp diff =
match exp with
| Some exp -> begin
match exp.pexp_desc with
| Pexp_constant const -> report_literal_type_constraint const diff
| Pexp_apply _ -> report_partial_application diff
| _ -> []
end
| None -> []
let report_pattern_type_clash_hints pat diff =
match pat with
| Some (Ppat_constant const) -> report_literal_type_constraint const diff
| _ -> []
let report_type_expected_explanation expl =
let because expl_str = doc_printf "@ because it is in %s" expl_str in
match expl with
| If_conditional ->
because "the condition of an if-statement"
| If_no_else_branch ->
because "the result of a conditional with no else branch"
| While_loop_conditional ->
because "the condition of a while-loop"
| While_loop_body ->
because "the body of a while-loop"
| For_loop_start_index ->
because "a for-loop start index"
| For_loop_stop_index ->
because "a for-loop stop index"
| For_loop_body ->
because "the body of a for-loop"
| Assert_condition ->
because "the condition of an assertion"
| Sequence_left_hand_side ->
because "the left-hand side of a sequence"
| When_guard ->
because "a when-guard"
let report_type_expected_explanation_opt expl =
match expl with
| None -> Format_doc.Doc.empty
| Some expl -> report_type_expected_explanation expl
let report_unification_error ~loc ?sub env err
?type_expected_explanation txt1 txt2 =
Location.error_of_printer ~loc ?sub (fun ppf () ->
Errortrace_report.unification ppf env err
?type_expected_explanation txt1 txt2
) ()
let report_too_many_arg_error ~funct ~func_ty ~previous_arg_loc
~extra_arg_loc ~returns_unit loc =
let open Location in
let cnum_offset off (pos : Lexing.position) =
{ pos with pos_cnum = pos.pos_cnum + off }
in
let app_loc =
(* Span the application, including the extra argument. *)
{ loc_start = loc.loc_start;
loc_end = extra_arg_loc.loc_end;
loc_ghost = false }
and tail_loc =
(* Possible location for a ';'. The location is widened to overlap the end
of the argument. *)
let arg_end = previous_arg_loc.loc_end in
{ loc_start = cnum_offset ~-1 arg_end;
loc_end = cnum_offset ~+1 arg_end;
loc_ghost = false }
in
errorf ~loc:app_loc
"@[<v>@[<2>%a@ %a@]\
@ It is applied to too many arguments@]"
(report_this_texp_has_type (Some "function")) funct
Printtyp.type_expr func_ty
~sub:(
let semicolon =
if returns_unit then
[msg ~loc:tail_loc "@{<hint>Hint@}: Did you forget a ';'?"]
else []
in
semicolon @
[msg ~loc:extra_arg_loc "This extra argument is not expected."]
)
let msg = Fmt.doc_printf
let report_error ~loc env = function
| Constructor_arity_mismatch(lid, expected, provided) ->
Location.errorf ~loc
"@[The constructor %a@ expects %i argument(s),@ \
but is applied here to %i argument(s)@]"
quoted_constr lid expected provided
| Constructor_labeled_arg ->
Location.errorf ~loc
"Constructors cannot have labeled arguments.@ \
Consider using an inline record instead."
| Partial_tuple_pattern_bad_type ->
Location.errorf ~loc
"Could not determine the type of this partial tuple pattern."
| Extra_tuple_label (lbl, typ) ->
Location.errorf ~loc
"This pattern was expected to match values of type@ %a,@ but it \
contains an extra %a."
(Style.as_inline_code Printtyp.type_expr) typ
(tuple_component ~print_article:false) lbl;
| Missing_tuple_label (lbl, typ) ->
let hint ppf () =
(* We only hint if the missing component is labeled. This is
unlikely to be a correct fix for traditional tuples. *)
match lbl with
| Some _ -> fprintf ppf "@ Hint: use .. to ignore some components."
| None -> ()
in
Location.errorf ~loc
"This pattern was expected to match values of type@ %a,@ but it is \
missing %a.%a"
(Style.as_inline_code Printtyp.type_expr) typ
(tuple_component ~print_article:true) lbl
hint ()
| Label_mismatch(lid, err) ->
report_unification_error ~loc env err
(msg "The record field %a@ belongs to the type" quoted_longident lid)
(msg "but is mixed here with fields of type")
| Pattern_type_clash (err, pat) ->
let diff = type_clash_of_trace err.trace in
let sub = report_pattern_type_clash_hints pat diff in
report_unification_error ~loc ~sub env err
(msg "This pattern matches values of type")
(msg "but a pattern was expected which matches values of type");
| Or_pattern_type_clash (id, err) ->
report_unification_error ~loc env err
(msg "The variable %a on the left-hand side of this \
or-pattern has type" Style.inline_code (Ident.name id))
(msg "but on the right-hand side it has type")
| Multiply_bound_variable name ->
Location.errorf ~loc
"Variable %a is bound several times in this matching"
Style.inline_code name
| Orpat_vars (id, valid_idents) ->
Location.aligned_error_hint ~loc
"@{<ralign>Variable @}%a must occur on both sides of this %a pattern"
Style.inline_code (Ident.name id)
Style.inline_code "|"
(spellcheck_idents id valid_idents)
| Expr_type_clash (err, explanation, exp) ->
let diff = type_clash_of_trace err.trace in
let sub = report_expr_type_clash_hints exp diff in
report_unification_error ~loc ~sub env err
~type_expected_explanation:
(report_type_expected_explanation_opt explanation)
(msg "%a" (report_this_pexp_has_type None) exp)
(msg "but an expression was expected of type");
| Function_arity_type_clash {
syntactic_arity; type_constraint; trace = { trace };
} ->
(* The last diff's expected type will be the locally-abstract type
that the GADT pattern introduced an equation on.
*)
let type_with_local_equation =
let last_diff =
List.find_map
(function Errortrace.Diff diff -> Some diff | _ -> None)
(List.rev trace)
in
match last_diff with
| None -> None
| Some diff -> Some diff.expected.ty
in
(* [syntactic_arity>1] for this error, so "arguments" is always plural. *)
Location.errorf ~loc
"@[\
@[\
The syntactic arity of the function doesn't match the type constraint:@ \
@[<2>\
This function has %d syntactic arguments, but its type is constrained \
to@ %a.\
@]@ \
@]@ \
@[\
@[<2>@{<hint>Hint@}: \
consider splitting the function definition into@ %a@ \
where %a is the pattern with the GADT constructor that@ \
introduces the local type equation%t.\
@]"
syntactic_arity
(Style.as_inline_code Printtyp.type_expr) type_constraint
Style.inline_code "fun ... gadt_pat -> fun ..."
Style.inline_code "gadt_pat"
(fun ppf ->
Option.iter
(fprintf ppf " on %a" (Style.as_inline_code Printtyp.type_expr))
type_with_local_equation)
| Apply_non_function {
funct; func_ty; res_ty; previous_arg_loc; extra_arg_loc
} ->
begin match get_desc func_ty with
Tarrow _ ->
let returns_unit = match get_desc res_ty with
| Tconstr (p, _, _) -> Path.same p Predef.path_unit
| _ -> false
in
report_too_many_arg_error ~funct ~func_ty ~previous_arg_loc
~extra_arg_loc ~returns_unit loc
| _ ->
Location.errorf ~loc "@[<v>@[<2>This expression has type@ %a@]@ %s@]"
(Style.as_inline_code Printtyp.type_expr) func_ty
"This is not a function; it cannot be applied."
end
| Apply_wrong_label (l, ty, extra_info) ->
let print_label ppf = function
| Nolabel -> fprintf ppf "without label"
| l ->
fprintf ppf "with label %a"
Style.inline_code (prefixed_label_name l)
in
let extra_info =
if not extra_info then
[]
else
[ Location.msg
"Since OCaml 4.11, optional arguments do not commute when \
-nolabels is given" ]
in
Location.errorf ~loc ~sub:extra_info
"@[<v>@[<2>The function applied to this argument has type@ %a@]@.\
This argument cannot be applied %a@]"
Printtyp.type_expr ty print_label l
| Label_multiply_defined s ->
Location.errorf ~loc "The record field label %s is defined several times"
s
| Label_missing labels ->
let print_label ppf lbl = Style.inline_code ppf (Ident.name lbl) in
let print_labels ppf = List.iter (fprintf ppf "@ %a" print_label) in
Location.errorf ~loc "@[<hov>Some record fields are undefined:%a@]"
print_labels labels
| Label_not_mutable lid ->
Location.errorf ~loc "The record field %a is not mutable"
quoted_longident lid
| Wrong_name (eorp, ty_expected, { type_path; kind; name; valid_names; }) ->
Printtyp.wrap_printing_env ~error:true env (fun () ->
let { ty; explanation } = ty_expected in
if Path.is_constructor_typath type_path then
Location.aligned_error_hint ~loc
"@{<ralign>The field @}%a is not part of the record argument \
for the %a constructor"
Style.inline_code name.txt
(Style.as_inline_code Printtyp.type_path) type_path
(spellcheck name.txt valid_names)
else
let intro ppf = Fmt.fprintf ppf "@[%s type@;<1 2>%a%a@]@\n"
eorp (Style.as_inline_code Printtyp.type_expr) ty
pp_doc (report_type_expected_explanation_opt explanation)
in
let main =
Fmt.doc_printf "@{<ralign>There is no %s @}%a within type %a"
(Datatype_kind.label_name kind)
Style.inline_code name.txt
(Style.as_inline_code Printtyp.type_path) type_path
in
let main, sub =
match spellcheck name.txt valid_names with
| None -> main, []
| Some hint ->
let main, hint = Misc.align_error_hint ~main ~hint in
main, [Location.mknoloc hint]
in
Location.errorf ~loc ~sub "%t%a" intro pp_doc main
)
| Name_type_mismatch (kind, lid, tp, tpl) ->
let type_name = Datatype_kind.type_name kind in
let name = Datatype_kind.label_name kind in
let pr = match kind with
| Datatype_kind.Record -> quoted_longident
| Datatype_kind.Variant -> quoted_constr
in
Location.errorf ~loc "%t" (fun ppf ->
Errortrace_report.ambiguous_type ppf env tp tpl
(msg "The %s %a@ belongs to the %s type"
name pr lid type_name)
(msg "The %s %a@ belongs to one of the following %s types:"
name pr lid type_name)
(msg "but a %s was expected belonging to the %s type"
name type_name)
)
| Invalid_format msg ->
Location.errorf ~loc "%s" msg
| Not_an_object (ty, explanation) ->
Location.errorf ~loc
"This expression is not an object;@ it has type %a%a"
(Style.as_inline_code Printtyp.type_expr) ty
pp_doc (report_type_expected_explanation_opt explanation)
| Undefined_method (ty, me, valid_methods) ->
Printtyp.wrap_printing_env ~error:true env (fun () ->
let intro ppf =
Fmt.fprintf ppf
"@[<v>@[This expression has type@;<1 2>%a@]@,@]"
(Style.as_inline_code Printtyp.type_expr) ty
in
let main =
Fmt.doc_printf "@{<ralign>It has no method @}%a"
Style.inline_code me
in
let main, sub =
match Option.bind valid_methods (spellcheck me) with
| None -> main, []
| Some hint ->
let main, hint = Misc.align_error_hint ~main ~hint in
main, [Location.mknoloc hint]
in
Location.errorf ~sub ~loc "%t%a" intro pp_doc main
)
| Undefined_self_method (me, valid_methods) ->
Location.aligned_error_hint ~loc
"@{<ralign>This expression has no method @}%a"
Style.inline_code me
(spellcheck me valid_methods)
| Virtual_class cl ->
Location.errorf ~loc "Cannot instantiate the virtual class %a"
quoted_longident cl
| Unbound_instance_variable (var, valid_vars) ->
Location.aligned_error_hint ~loc
"@{<ralign>Unbound instance variable @}%a" Style.inline_code var
(spellcheck var valid_vars)
| Instance_variable_not_mutable v ->
Location.errorf ~loc "The instance variable %a is not mutable"
Style.inline_code v
| Not_subtype err ->
Location.errorf ~loc "%t" (fun ppf ->
Errortrace_report.subtype ppf env err "is not a subtype of"
)
| Outside_class ->
Location.errorf ~loc
"This object duplication occurs outside a method definition"
| Value_multiply_overridden v ->
Location.errorf ~loc
"The instance variable %a is overridden several times"
Style.inline_code v
| Coercion_failure (ty_exp, err, b) ->
let intro =
let ty_exp = Out_type.prepare_expansion ty_exp in
doc_printf "This expression cannot be coerced to type@;<1 2>%a;@ \
it has type"
(Style.as_inline_code @@ Printtyp.type_expansion Type) ty_exp
in
Location.errorf ~loc "%t" (fun ppf ->
Errortrace_report.unification ppf env err
intro
(Fmt.Doc.msg "but is here used with type")
)
~sub:(
if not b then [] else
[ Location.msg "This simple coercion was not fully general";
Location.msg
"@{<hint>Hint@}: Consider using a fully explicit coercion@ \
of the form: %a"
Style.inline_code "(foo : ty1 :> ty2)"
]
)
| Not_a_function (ty, explanation) ->
Location.errorf ~loc
"This expression should not be a function,@ \
the expected type is@ %a%a"
(Style.as_inline_code Printtyp.type_expr) ty
pp_doc (report_type_expected_explanation_opt explanation)
| Too_many_arguments (ty, explanation) ->
Location.errorf ~loc
"This function expects too many arguments,@ \
it should have type@ %a%a"
(Style.as_inline_code Printtyp.type_expr) ty
pp_doc (report_type_expected_explanation_opt explanation)
| Abstract_wrong_label {got; expected; expected_type; explanation} ->
let label ~long ppf = function
| Nolabel -> fprintf ppf "unlabeled"
| l ->
if long then
fprintf ppf "labeled %a" Style.inline_code (prefixed_label_name l)
else
Style.inline_code ppf (prefixed_label_name l)
in
let second_long = match got, expected with
| Nolabel, _ | _, Nolabel -> true
| _ -> false
in
Location.errorf ~loc
"@[<v>@[<2>This function should have type@ %a%a@]@,\
@[but its first argument is %a@ instead of %s%a@]@]"
(Style.as_inline_code Printtyp.type_expr) expected_type
pp_doc (report_type_expected_explanation_opt explanation)
(label ~long:true) got
(if second_long then "being " else "")
(label ~long:second_long) expected
| Scoping_let_module(id, ty) ->
Location.errorf ~loc
"This %a expression has type@ %a@ \
In this type, the locally bound module name %a escapes its scope"
Style.inline_code "let module"
(Style.as_inline_code Printtyp.type_expr) ty
Style.inline_code id
| Private_type ty ->
Location.errorf ~loc "Cannot create values of the private type %a"
(Style.as_inline_code Printtyp.type_expr) ty
| Private_label (lid, ty) ->
Location.errorf ~loc "Cannot assign field %a of the private type %a"
quoted_longident lid
(Style.as_inline_code Printtyp.type_expr) ty
| Private_constructor (constr, ty) ->
Location.errorf ~loc
"Cannot use private constructor %a to create values of type %a"
Style.inline_code constr.cstr_name
(Style.as_inline_code Printtyp.type_expr) ty
| Not_a_polymorphic_variant_type lid ->
Location.errorf ~loc "The type %a@ is not a variant type"
quoted_longident lid
| Incoherent_label_order ->
Location.errorf ~loc
"This function is applied to arguments@ \
in an order different from other calls.@ \
This is only allowed when the real type is known."
| Less_general (kind, err) ->
report_unification_error ~loc env err
(Fmt.doc_printf "This %s has type" kind)
(Fmt.doc_printf "which is less general than")
| Modules_not_allowed ->
Location.errorf ~loc "Modules are not allowed in this pattern."
| Cannot_infer_signature ->
Location.errorf ~loc
"The signature for this packaged module couldn't be inferred."
| Not_a_packed_module ty ->
Location.errorf ~loc
"This expression is packed module, but the expected type is@ %a"
(Style.as_inline_code Printtyp.type_expr) ty
| Unexpected_existential (reason, name) ->
let reason_str =
match reason with
| In_class_args ->
dprintf "Existential types are not allowed in class arguments"
| In_class_def ->
dprintf "Existential types are not allowed in bindings inside \
class definition"
| In_self_pattern ->
dprintf "Existential types are not allowed in self patterns"
| At_toplevel ->
dprintf "Existential types are not allowed in toplevel bindings"
| In_group ->
dprintf "Existential types are not allowed in grouped (%a) bindings"
Style.inline_code "let ... and ..."
| In_rec ->
dprintf "Existential types are not allowed in recursive bindings"
| With_attributes ->
dprintf
"Existential types are not allowed in presence of attributes"
in
Location.errorf ~loc
"%t,@ but the constructor %a introduces existential types."
reason_str Style.inline_code name
| Invalid_interval ->
Location.errorf ~loc
"@[Only character intervals are supported in patterns.@]"
| Invalid_for_loop_index ->
Location.errorf ~loc
"@[Invalid for-loop index: only variables and %a are allowed.@]"
Style.inline_code "_"
| No_value_clauses ->
Location.errorf ~loc
"None of the patterns in this %a expression match values."
Style.inline_code "match"
| Exception_pattern_disallowed ->
Location.errorf ~loc
"@[Exception patterns are not allowed in this position.@]"
| Mixed_value_and_exception_patterns_under_guard ->
Location.errorf ~loc
"@[Mixing value and exception patterns under when-guards is not \
supported.@]"
| Effect_pattern_below_toplevel ->
Location.errorf ~loc
"@[Effect patterns must be at the top level of a match case.@]"
| Invalid_continuation_pattern ->
Location.errorf ~loc
"@[Invalid continuation pattern: only variables and _ are allowed .@]"
| Inlined_record_escape ->
Location.errorf ~loc
"@[This form is not allowed as the type of the inlined record could \
escape.@]"
| Inlined_record_expected ->
Location.errorf ~loc
"@[This constructor expects an inlined record argument.@]"
| Unrefuted_pattern pat ->
Location.errorf ~loc
"@[%s@ %s@ @[%a@]@]"
"This match case could not be refuted."
"Here is an example of a value that would reach it:"
(Style.as_inline_code Printpat.top_pretty) pat
| Invalid_extension_constructor_payload ->
Location.errorf ~loc
"Invalid %a payload, a constructor is expected."
Style.inline_code "[%extension_constructor]"
| Not_an_extension_constructor ->
Location.errorf ~loc
"This constructor is not an extension constructor."
| Invalid_atomic_loc_payload ->
Location.errorf ~loc
"Invalid %a payload, a record field access is expected."
Style.inline_code "[%atomic.loc]"
| Label_not_atomic lid ->
Location.errorf ~loc "The record field %a is not atomic"
quoted_longident lid
| Atomic_in_pattern lid ->
Location.errorf ~loc
"Atomic fields (here %a) are forbidden in patterns,@ \
as it is difficult to reason about when the atomic read@ \
will happen during pattern matching:@ the field may be read@ \
zero, one or several times depending on the patterns around it."
quoted_longident lid
| Literal_overflow ty ->
Location.errorf ~loc
"Integer literal exceeds the range of representable integers of type %a"
Style.inline_code ty
| Unknown_literal (n, m) ->
let pp_lit ppf (n,m) = fprintf ppf "%s%c" n m in
Location.errorf ~loc "Unknown modifier %a for literal %a"
(Style.as_inline_code pp_print_char) m
(Style.as_inline_code pp_lit) (n,m)
| Illegal_letrec_pat ->
Location.errorf ~loc
"Only variables are allowed as left-hand side of %a"
Style.inline_code "let rec"
| Illegal_letrec_expr ->
Location.errorf ~loc
"This kind of expression is not allowed as right-hand side of %a"
Style.inline_code "let rec"
| Illegal_class_expr ->
Location.errorf ~loc
"This kind of recursive class expression is not allowed"
| Letop_type_clash(name, err) ->
report_unification_error ~loc env err
(msg "The operator %a has type" Style.inline_code name)
(msg "but it was expected to have type")
| Andop_type_clash(name, err) ->
report_unification_error ~loc env err
(msg "The operator %a has type" Style.inline_code name)
(msg "but it was expected to have type")
| Bindings_type_clash(err) ->
report_unification_error ~loc env err
(Fmt.doc_printf "These bindings have type")
(Fmt.doc_printf "but bindings were expected of type")
| Unbound_existential (ids, ty) ->
let pp_ident ppf id = pp_print_string ppf (Ident.name id) in
let pp_type ppf (ids,ty)=
fprintf ppf "@[type %a.@ %a@]@]"
(pp_print_list ~pp_sep:pp_print_space pp_ident) ids
Printtyp.type_expr ty
in
Location.errorf ~loc
"@[<2>%s:@ %a@]"
"This type does not bind all existentials in the constructor"
(Style.as_inline_code pp_type) (ids, ty)
| Bind_existential (reason, id, ty) ->
let reason1, reason2 = match reason with
| Bind_already_bound -> "the name", "that is already bound"
| Bind_not_in_scope -> "the name", "that was defined before"
| Bind_non_locally_abstract -> "the type",
"that is not a locally abstract type"
in
Location.errorf ~loc
"@[<hov0>The local name@ %a@ %s@ %s.@ %s@ %s@ %a@ %s.@]"
(Style.as_inline_code Printtyp.ident) id
"can only be given to an existential variable"
"introduced by this GADT constructor"
"The type annotation tries to bind it to"
reason1 (Style.as_inline_code Printtyp.type_expr) ty reason2
| Missing_type_constraint ->
Location.errorf ~loc
"@[%s@ %s@]"
"Existential types introduced in a constructor pattern"
"must be bound by a type constraint on the argument."
| Wrong_expected_kind(sort, ctx, ty) ->
let ctx, explanation =
match ctx with
| Expression explanation -> "expression", explanation
| Pattern -> "pattern", None
in
let sort =
match sort with
| Constructor -> "constructor"
| Boolean -> "boolean literal"
| List -> "list literal"
| Unit -> "unit literal"
| Record -> "record"
in
Location.errorf ~loc
"This %s should not be a %s,@ \
the expected type is@ %a%a"
ctx sort (Style.as_inline_code Printtyp.type_expr) ty
pp_doc (report_type_expected_explanation_opt explanation)
| Expr_not_a_record_type ty ->
Location.errorf ~loc
"This expression has type %a@ \
which is not a record type."
(Style.as_inline_code Printtyp.type_expr) ty
| Repeated_tuple_exp_label l ->
Location.errorf ~loc
"@[This tuple expression has two labels named %a@]"
Style.inline_code l
| Repeated_tuple_pat_label l ->
Location.errorf ~loc
"@[This tuple pattern has two labels named %a@]"
Style.inline_code l
let report_error ~loc env err =
Printtyp.wrap_printing_env ~error:true env
(fun () -> report_error ~loc env err)
let () =
Location.register_error_of_exn
(function
| Error (loc, env, err) ->
Some (report_error ~loc env err)
| Error_forward err ->
Some err
| _ ->
None
)
let () =
Persistent_env.add_delayed_check_forward := add_delayed_check;
Env.add_delayed_check_forward := add_delayed_check;
()
(* drop the need to call [Parmatch.typed_case] from the external API *)
let check_partial ?lev a b c cases =
check_partial ?lev a b c (List.map Parmatch.typed_case cases)
(* drop ?recarg argument from the external API *)
let type_expect env e ty = type_expect env e ty
let type_exp env e = type_exp env e
let type_argument env e t1 t2 = type_argument env e t1 t2
|