|
18 | 18 |
|
19 | 19 | #include "MiscDiagnostics.h"
|
20 | 20 | #include "TypeChecker.h"
|
| 21 | +#include "TypeCheckAvailability.h" |
21 | 22 | #include "swift/Sema/ConstraintSystem.h"
|
| 23 | +#include "swift/Sema/IDETypeChecking.h" |
22 | 24 |
|
23 | 25 | using namespace swift;
|
24 | 26 | using namespace swift::constraints;
|
@@ -1688,12 +1690,15 @@ class SyntacticElementSolutionApplication
|
1688 | 1690 | };
|
1689 | 1691 |
|
1690 | 1692 | class ResultBuilderRewriter : public SyntacticElementSolutionApplication {
|
| 1693 | + const AppliedBuilderTransform &Transform; |
| 1694 | + |
1691 | 1695 | public:
|
1692 | 1696 | ResultBuilderRewriter(Solution &solution, AnyFunctionRef context,
|
1693 | 1697 | const AppliedBuilderTransform &transform,
|
1694 | 1698 | RewriteTargetFn rewriteTarget)
|
1695 | 1699 | : SyntacticElementSolutionApplication(
|
1696 |
| - solution, context, transform.bodyResultType, rewriteTarget) {} |
| 1700 | + solution, context, transform.bodyResultType, rewriteTarget), |
| 1701 | + Transform(transform) {} |
1697 | 1702 |
|
1698 | 1703 | bool apply() {
|
1699 | 1704 | auto body = visit(context.getBody());
|
@@ -1767,6 +1772,9 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication {
|
1767 | 1772 |
|
1768 | 1773 | NullablePtr<Stmt> transformIf(IfStmt *ifStmt, TypeJoinExpr *join,
|
1769 | 1774 | unsigned index) {
|
| 1775 | + // FIXME: Turn this into a condition once warning is an error. |
| 1776 | + (void)diagnoseMissingBuildWithAvailability(ifStmt); |
| 1777 | + |
1770 | 1778 | auto *joinVar = join->getVar();
|
1771 | 1779 |
|
1772 | 1780 | // First, let's add assignment to the end of `then` branch
|
@@ -1855,6 +1863,109 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication {
|
1855 | 1863 | ASTContext &getASTContext() const {
|
1856 | 1864 | return context.getAsDeclContext()->getASTContext();
|
1857 | 1865 | }
|
| 1866 | + |
| 1867 | +private: |
| 1868 | + /// Look for a #available condition. If there is one, we need to check |
| 1869 | + /// that the resulting type of the "then" doesn't refer to any types that |
| 1870 | + /// are unavailable in the enclosing context. |
| 1871 | + /// |
| 1872 | + /// Note that this is for staging in support for buildLimitedAvailability(); |
| 1873 | + /// the diagnostic is currently a warning, so that existing code that |
| 1874 | + /// compiles today will continue to compile. Once result builder types |
| 1875 | + /// have had the chance to adopt buildLimitedAvailability(), we'll upgrade |
| 1876 | + /// this warning to an error. |
| 1877 | + LLVM_NODISCARD |
| 1878 | + bool diagnoseMissingBuildWithAvailability(IfStmt *ifStmt) { |
| 1879 | + auto findAvailabilityCondition = |
| 1880 | + [](StmtCondition stmtCond) -> const StmtConditionElement * { |
| 1881 | + for (const auto &cond : stmtCond) { |
| 1882 | + switch (cond.getKind()) { |
| 1883 | + case StmtConditionElement::CK_Boolean: |
| 1884 | + case StmtConditionElement::CK_PatternBinding: |
| 1885 | + continue; |
| 1886 | + |
| 1887 | + case StmtConditionElement::CK_Availability: |
| 1888 | + return &cond; |
| 1889 | + break; |
| 1890 | + } |
| 1891 | + } |
| 1892 | + |
| 1893 | + return nullptr; |
| 1894 | + }; |
| 1895 | + |
| 1896 | + auto availabilityCond = findAvailabilityCondition(ifStmt->getCond()); |
| 1897 | + if (!availabilityCond) |
| 1898 | + return false; |
| 1899 | + |
| 1900 | + SourceLoc loc = availabilityCond->getStartLoc(); |
| 1901 | + Type bodyType; |
| 1902 | + if (availabilityCond->getAvailability()->isUnavailability()) { |
| 1903 | + BraceStmt *elseBody = nullptr; |
| 1904 | + // For #unavailable, we need to check the "else". |
| 1905 | + if (auto *innerIf = getAsStmt<IfStmt>(ifStmt->getElseStmt())) { |
| 1906 | + elseBody = castToStmt<BraceStmt>(innerIf->getThenStmt()); |
| 1907 | + } else { |
| 1908 | + elseBody = castToStmt<BraceStmt>(ifStmt->getElseStmt()); |
| 1909 | + } |
| 1910 | + |
| 1911 | + Type elseBodyType = |
| 1912 | + solution.simplifyType(solution.getType(elseBody->getLastElement())); |
| 1913 | + bodyType = elseBodyType; |
| 1914 | + } else { |
| 1915 | + auto *thenBody = castToStmt<BraceStmt>(ifStmt->getThenStmt()); |
| 1916 | + Type thenBodyType = |
| 1917 | + solution.simplifyType(solution.getType(thenBody->getLastElement())); |
| 1918 | + bodyType = thenBodyType; |
| 1919 | + } |
| 1920 | + |
| 1921 | + auto builderType = solution.simplifyType(Transform.builderType); |
| 1922 | + |
| 1923 | + return bodyType.findIf([&](Type type) { |
| 1924 | + auto nominal = type->getAnyNominal(); |
| 1925 | + if (!nominal) |
| 1926 | + return false; |
| 1927 | + |
| 1928 | + ExportContext where = |
| 1929 | + ExportContext::forFunctionBody(context.getAsDeclContext(), loc); |
| 1930 | + if (auto reason = |
| 1931 | + TypeChecker::checkDeclarationAvailability(nominal, where)) { |
| 1932 | + auto &ctx = getASTContext(); |
| 1933 | + ctx.Diags.diagnose(loc, |
| 1934 | + diag::result_builder_missing_limited_availability, |
| 1935 | + builderType); |
| 1936 | + |
| 1937 | + // Add a note to the result builder with a stub for |
| 1938 | + // buildLimitedAvailability(). |
| 1939 | + if (auto builder = builderType->getAnyNominal()) { |
| 1940 | + SourceLoc buildInsertionLoc; |
| 1941 | + std::string stubIndent; |
| 1942 | + Type componentType; |
| 1943 | + std::tie(buildInsertionLoc, stubIndent, componentType) = |
| 1944 | + determineResultBuilderBuildFixItInfo(builder); |
| 1945 | + if (buildInsertionLoc.isValid()) { |
| 1946 | + std::string fixItString; |
| 1947 | + { |
| 1948 | + llvm::raw_string_ostream out(fixItString); |
| 1949 | + printResultBuilderBuildFunction( |
| 1950 | + builder, componentType, |
| 1951 | + ResultBuilderBuildFunction::BuildLimitedAvailability, |
| 1952 | + stubIndent, out); |
| 1953 | + |
| 1954 | + builder |
| 1955 | + ->diagnose( |
| 1956 | + diag::result_builder_missing_build_limited_availability, |
| 1957 | + builderType) |
| 1958 | + .fixItInsert(buildInsertionLoc, fixItString); |
| 1959 | + } |
| 1960 | + } |
| 1961 | + } |
| 1962 | + |
| 1963 | + return true; |
| 1964 | + } |
| 1965 | + |
| 1966 | + return false; |
| 1967 | + }); |
| 1968 | + } |
1858 | 1969 | };
|
1859 | 1970 | } // namespace
|
1860 | 1971 |
|
|
0 commit comments