|
15 | 15 | //===----------------------------------------------------------------------===//
|
16 | 16 |
|
17 | 17 | #include "TypeCheckAccess.h"
|
| 18 | +#include "TypeChecker.h" |
| 19 | +#include "TypeCheckAvailability.h" |
18 | 20 | #include "TypeAccessScopeChecker.h"
|
19 | 21 | #include "swift/AST/ASTVisitor.h"
|
20 | 22 | #include "swift/AST/ASTWalker.h"
|
@@ -1772,7 +1774,11 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
|
1772 | 1774 | checkOverride(VD);
|
1773 | 1775 | }
|
1774 | 1776 |
|
1775 |
| - DeclVisitor<ExportabilityChecker>::visit(D); |
| 1777 | + // Note: references to @_spi and @_implementationOnly declarations from |
| 1778 | + // @inlinable code are diagnosed by DeclAvailabilityChecker below. |
| 1779 | + auto *DC = D->getInnermostDeclContext(); |
| 1780 | + if (DC->getFragileFunctionKind().kind == FragileFunctionKind::None) |
| 1781 | + DeclVisitor<ExportabilityChecker>::visit(D); |
1776 | 1782 | }
|
1777 | 1783 |
|
1778 | 1784 | // Force all kinds to be handled at a lower level.
|
@@ -2035,6 +2041,260 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
|
2035 | 2041 | });
|
2036 | 2042 | }
|
2037 | 2043 | };
|
| 2044 | + |
| 2045 | +/// Diagnose declarations whose signatures refer to unavailable types. |
| 2046 | +class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> { |
| 2047 | + DeclContext *DC; |
| 2048 | + |
| 2049 | + void checkType(Type type, const TypeRepr *typeRepr, const Decl *context, |
| 2050 | + bool allowUnavailableProtocol=false) { |
| 2051 | + // Don't bother checking errors. |
| 2052 | + if (type && type->hasError()) |
| 2053 | + return; |
| 2054 | + |
| 2055 | + // Check the TypeRepr for references to unavailable declarations. |
| 2056 | + if (typeRepr) { |
| 2057 | + DeclAvailabilityFlags flags = None; |
| 2058 | + |
| 2059 | + // We allow a type to conform to a protocol that is less available than |
| 2060 | + // the type itself. This enables a type to retroactively model or directly |
| 2061 | + // conform to a protocol only available on newer OSes and yet still be used on |
| 2062 | + // older OSes. |
| 2063 | + // |
| 2064 | + // To support this, inside inheritance clauses we allow references to |
| 2065 | + // protocols that are unavailable in the current type refinement context. |
| 2066 | + if (allowUnavailableProtocol) |
| 2067 | + flags |= DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol; |
| 2068 | + |
| 2069 | + diagnoseTypeReprAvailability(typeRepr, DC, flags); |
| 2070 | + } |
| 2071 | + |
| 2072 | + // Check the type for references to unavailable conformances. |
| 2073 | + if (type) |
| 2074 | + diagnoseTypeAvailability(type, context->getLoc(), DC); |
| 2075 | + } |
| 2076 | + |
| 2077 | + void checkGenericParams(const GenericContext *ownerCtx, |
| 2078 | + const ValueDecl *ownerDecl) { |
| 2079 | + // FIXME: What if we have a where clause and no generic params? |
| 2080 | + const auto params = ownerCtx->getGenericParams(); |
| 2081 | + if (!params) |
| 2082 | + return; |
| 2083 | + |
| 2084 | + for (auto param : *params) { |
| 2085 | + if (param->getInherited().empty()) |
| 2086 | + continue; |
| 2087 | + assert(param->getInherited().size() == 1); |
| 2088 | + auto inherited = param->getInherited().front(); |
| 2089 | + checkType(inherited.getType(), inherited.getTypeRepr(), ownerDecl); |
| 2090 | + } |
| 2091 | + |
| 2092 | + forAllRequirementTypes(WhereClauseOwner( |
| 2093 | + const_cast<GenericContext *>(ownerCtx)), |
| 2094 | + [&](Type type, TypeRepr *typeRepr) { |
| 2095 | + checkType(type, typeRepr, ownerDecl); |
| 2096 | + }); |
| 2097 | + } |
| 2098 | + |
| 2099 | +public: |
| 2100 | + explicit DeclAvailabilityChecker(Decl *D) |
| 2101 | + : DC(D->getInnermostDeclContext()) {} |
| 2102 | + |
| 2103 | + void visit(Decl *D) { |
| 2104 | + if (D->isImplicit()) |
| 2105 | + return; |
| 2106 | + |
| 2107 | + DeclVisitor<DeclAvailabilityChecker>::visit(D); |
| 2108 | + } |
| 2109 | + |
| 2110 | + // Force all kinds to be handled at a lower level. |
| 2111 | + void visitDecl(Decl *D) = delete; |
| 2112 | + void visitValueDecl(ValueDecl *D) = delete; |
| 2113 | + |
| 2114 | +#define UNREACHABLE(KIND, REASON) \ |
| 2115 | + void visit##KIND##Decl(KIND##Decl *D) { \ |
| 2116 | + llvm_unreachable(REASON); \ |
| 2117 | + } |
| 2118 | + UNREACHABLE(Import, "not applicable") |
| 2119 | + UNREACHABLE(TopLevelCode, "not applicable") |
| 2120 | + UNREACHABLE(Module, "not applicable") |
| 2121 | + |
| 2122 | + UNREACHABLE(Param, "handled by the enclosing declaration") |
| 2123 | + UNREACHABLE(GenericTypeParam, "handled by the enclosing declaration") |
| 2124 | + UNREACHABLE(MissingMember, "handled by the enclosing declaration") |
| 2125 | +#undef UNREACHABLE |
| 2126 | + |
| 2127 | +#define UNINTERESTING(KIND) \ |
| 2128 | + void visit##KIND##Decl(KIND##Decl *D) {} |
| 2129 | + |
| 2130 | + UNINTERESTING(PrefixOperator) // Does not reference other decls. |
| 2131 | + UNINTERESTING(PostfixOperator) // Does not reference other decls. |
| 2132 | + UNINTERESTING(InfixOperator) // Does not reference other decls. |
| 2133 | + UNINTERESTING(IfConfig) // Not applicable. |
| 2134 | + UNINTERESTING(PoundDiagnostic) // Not applicable. |
| 2135 | + UNINTERESTING(EnumCase) // Handled at the EnumElement level. |
| 2136 | + UNINTERESTING(Destructor) // Always correct. |
| 2137 | + UNINTERESTING(Accessor) // Handled by the Var or Subscript. |
| 2138 | + UNINTERESTING(OpaqueType) // TODO |
| 2139 | + UNINTERESTING(PrecedenceGroup) // Doesn't reference anything with availability. |
| 2140 | + |
| 2141 | + // Handled at the PatternBinding level; if the pattern has a simple |
| 2142 | + // "name: TheType" form, we can get better results by diagnosing the TypeRepr. |
| 2143 | + UNINTERESTING(Var) |
| 2144 | + |
| 2145 | + /// \see visitPatternBindingDecl |
| 2146 | + void checkNamedPattern(const NamedPattern *NP, |
| 2147 | + const llvm::DenseSet<const VarDecl *> &seenVars) { |
| 2148 | + const VarDecl *theVar = NP->getDecl(); |
| 2149 | + |
| 2150 | + // Only check the type of individual variables if we didn't check an |
| 2151 | + // enclosing TypedPattern. |
| 2152 | + if (seenVars.count(theVar)) |
| 2153 | + return; |
| 2154 | + |
| 2155 | + checkType(theVar->getValueInterfaceType(), /*typeRepr*/nullptr, theVar); |
| 2156 | + } |
| 2157 | + |
| 2158 | + /// \see visitPatternBindingDecl |
| 2159 | + void checkTypedPattern(PatternBindingDecl *PBD, |
| 2160 | + const TypedPattern *TP, |
| 2161 | + llvm::DenseSet<const VarDecl *> &seenVars) { |
| 2162 | + // FIXME: We need to figure out if this is a stored or computed property, |
| 2163 | + // so we pull out some random VarDecl in the pattern. They're all going to |
| 2164 | + // be the same, but still, ick. |
| 2165 | + const VarDecl *anyVar = nullptr; |
| 2166 | + TP->forEachVariable([&](VarDecl *V) { |
| 2167 | + seenVars.insert(V); |
| 2168 | + anyVar = V; |
| 2169 | + }); |
| 2170 | + |
| 2171 | + checkType(TP->hasType() ? TP->getType() : Type(), |
| 2172 | + TP->getTypeRepr(), PBD); |
| 2173 | + |
| 2174 | + // Check the property wrapper types. |
| 2175 | + if (anyVar) |
| 2176 | + for (auto attr : anyVar->getAttachedPropertyWrappers()) |
| 2177 | + checkType(attr->getType(), attr->getTypeRepr(), anyVar); |
| 2178 | + } |
| 2179 | + |
| 2180 | + void visitPatternBindingDecl(PatternBindingDecl *PBD) { |
| 2181 | + llvm::DenseSet<const VarDecl *> seenVars; |
| 2182 | + for (auto idx : range(PBD->getNumPatternEntries())) { |
| 2183 | + PBD->getPattern(idx)->forEachNode([&](const Pattern *P) { |
| 2184 | + if (auto *NP = dyn_cast<NamedPattern>(P)) { |
| 2185 | + checkNamedPattern(NP, seenVars); |
| 2186 | + return; |
| 2187 | + } |
| 2188 | + |
| 2189 | + auto *TP = dyn_cast<TypedPattern>(P); |
| 2190 | + if (!TP) |
| 2191 | + return; |
| 2192 | + checkTypedPattern(PBD, TP, seenVars); |
| 2193 | + }); |
| 2194 | + seenVars.clear(); |
| 2195 | + } |
| 2196 | + } |
| 2197 | + |
| 2198 | + void visitTypeAliasDecl(TypeAliasDecl *TAD) { |
| 2199 | + checkGenericParams(TAD, TAD); |
| 2200 | + checkType(TAD->getUnderlyingType(), |
| 2201 | + TAD->getUnderlyingTypeRepr(), TAD); |
| 2202 | + } |
| 2203 | + |
| 2204 | + void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) { |
| 2205 | + llvm::for_each(assocType->getInherited(), |
| 2206 | + [&](TypeLoc requirement) { |
| 2207 | + checkType(requirement.getType(), requirement.getTypeRepr(), |
| 2208 | + assocType); |
| 2209 | + }); |
| 2210 | + checkType(assocType->getDefaultDefinitionType(), |
| 2211 | + assocType->getDefaultDefinitionTypeRepr(), assocType); |
| 2212 | + |
| 2213 | + if (assocType->getTrailingWhereClause()) { |
| 2214 | + forAllRequirementTypes(assocType, |
| 2215 | + [&](Type type, TypeRepr *typeRepr) { |
| 2216 | + checkType(type, typeRepr, assocType); |
| 2217 | + }); |
| 2218 | + } |
| 2219 | + } |
| 2220 | + |
| 2221 | + void visitNominalTypeDecl(const NominalTypeDecl *nominal) { |
| 2222 | + checkGenericParams(nominal, nominal); |
| 2223 | + |
| 2224 | + llvm::for_each(nominal->getInherited(), |
| 2225 | + [&](TypeLoc inherited) { |
| 2226 | + checkType(inherited.getType(), inherited.getTypeRepr(), |
| 2227 | + nominal, /*allowUnavailableProtocol=*/true); |
| 2228 | + }); |
| 2229 | + } |
| 2230 | + |
| 2231 | + void visitProtocolDecl(ProtocolDecl *proto) { |
| 2232 | + llvm::for_each(proto->getInherited(), |
| 2233 | + [&](TypeLoc requirement) { |
| 2234 | + checkType(requirement.getType(), requirement.getTypeRepr(), proto, |
| 2235 | + /*allowUnavailableProtocol=*/true); |
| 2236 | + }); |
| 2237 | + |
| 2238 | + if (proto->getTrailingWhereClause()) { |
| 2239 | + forAllRequirementTypes(proto, [&](Type type, TypeRepr *typeRepr) { |
| 2240 | + checkType(type, typeRepr, proto); |
| 2241 | + }); |
| 2242 | + } |
| 2243 | + } |
| 2244 | + |
| 2245 | + void visitSubscriptDecl(SubscriptDecl *SD) { |
| 2246 | + checkGenericParams(SD, SD); |
| 2247 | + |
| 2248 | + for (auto &P : *SD->getIndices()) { |
| 2249 | + checkType(P->getInterfaceType(), P->getTypeRepr(), SD); |
| 2250 | + } |
| 2251 | + checkType(SD->getElementInterfaceType(), SD->getElementTypeRepr(), SD); |
| 2252 | + } |
| 2253 | + |
| 2254 | + void visitAbstractFunctionDecl(AbstractFunctionDecl *fn) { |
| 2255 | + checkGenericParams(fn, fn); |
| 2256 | + |
| 2257 | + for (auto *P : *fn->getParameters()) |
| 2258 | + checkType(P->getInterfaceType(), P->getTypeRepr(), fn); |
| 2259 | + } |
| 2260 | + |
| 2261 | + void visitFuncDecl(FuncDecl *FD) { |
| 2262 | + visitAbstractFunctionDecl(FD); |
| 2263 | + checkType(FD->getResultInterfaceType(), FD->getResultTypeRepr(), FD); |
| 2264 | + } |
| 2265 | + |
| 2266 | + void visitEnumElementDecl(EnumElementDecl *EED) { |
| 2267 | + if (!EED->hasAssociatedValues()) |
| 2268 | + return; |
| 2269 | + for (auto &P : *EED->getParameterList()) |
| 2270 | + checkType(P->getInterfaceType(), P->getTypeRepr(), EED); |
| 2271 | + } |
| 2272 | + |
| 2273 | + void checkConstrainedExtensionRequirements(ExtensionDecl *ED) { |
| 2274 | + if (!ED->getTrailingWhereClause()) |
| 2275 | + return; |
| 2276 | + forAllRequirementTypes(ED, [&](Type type, TypeRepr *typeRepr) { |
| 2277 | + checkType(type, typeRepr, ED); |
| 2278 | + }); |
| 2279 | + } |
| 2280 | + |
| 2281 | + void visitExtensionDecl(ExtensionDecl *ED) { |
| 2282 | + auto extendedType = ED->getExtendedNominal(); |
| 2283 | + assert(extendedType && "valid extension with no extended type?"); |
| 2284 | + if (!extendedType) |
| 2285 | + return; |
| 2286 | + |
| 2287 | + llvm::for_each(ED->getInherited(), |
| 2288 | + [&](TypeLoc inherited) { |
| 2289 | + checkType(inherited.getType(), inherited.getTypeRepr(), |
| 2290 | + ED, /*allowUnavailableProtocol=*/true); |
| 2291 | + }); |
| 2292 | + |
| 2293 | + checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), ED); |
| 2294 | + checkConstrainedExtensionRequirements(ED); |
| 2295 | + } |
| 2296 | +}; |
| 2297 | + |
2038 | 2298 | } // end anonymous namespace
|
2039 | 2299 |
|
2040 | 2300 | static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
|
@@ -2086,4 +2346,5 @@ void swift::checkAccessControl(Decl *D) {
|
2086 | 2346 | }
|
2087 | 2347 |
|
2088 | 2348 | ExportabilityChecker().visit(D);
|
| 2349 | + DeclAvailabilityChecker(D).visit(D); |
2089 | 2350 | }
|
0 commit comments