Skip to content

Commit 5cebe1b

Browse files
authored
Merge pull request #34310 from slavapestov/refactor-availability-checking
Sema: Pull availability checking out of resolveType()
2 parents 52b847e + 2a678f2 commit 5cebe1b

35 files changed

+622
-169
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4607,7 +4607,9 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
46074607
checkActorIsolation(E, DC);
46084608
}
46094609

4610-
void swift::performStmtDiagnostics(ASTContext &ctx, const Stmt *S) {
4610+
void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) {
4611+
auto &ctx = DC->getASTContext();
4612+
46114613
TypeChecker::checkUnsupportedProtocolType(ctx, const_cast<Stmt *>(S));
46124614

46134615
if (auto switchStmt = dyn_cast<SwitchStmt>(S))
@@ -4619,6 +4621,9 @@ void swift::performStmtDiagnostics(ASTContext &ctx, const Stmt *S) {
46194621
if (auto *lcs = dyn_cast<LabeledConditionalStmt>(S))
46204622
for (const auto &elt : lcs->getCond())
46214623
checkImplicitPromotionsInCondition(elt, ctx);
4624+
4625+
if (!ctx.LangOpts.DisableAvailabilityChecking)
4626+
diagAvailability(S, const_cast<DeclContext*>(DC));
46224627
}
46234628

46244629
//===----------------------------------------------------------------------===//

lib/Sema/MiscDiagnostics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void performSyntacticExprDiagnostics(const Expr *E, const DeclContext *DC,
3838
bool isExprStmt);
3939

4040
/// Emit diagnostics for a given statement.
41-
void performStmtDiagnostics(ASTContext &ctx, const Stmt *S);
41+
void performStmtDiagnostics(const Stmt *S, DeclContext *DC);
4242

4343
void performAbstractFuncDeclDiagnostics(AbstractFunctionDecl *AFD);
4444

lib/Sema/PreCheckExpr.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,11 +1326,8 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
13261326
// Fold 'T.U' into a nested type.
13271327
if (auto *ITR = dyn_cast<IdentTypeRepr>(InnerTypeRepr)) {
13281328
// Resolve the TypeRepr to get the base type for the lookup.
1329-
// Disable availability diagnostics here, because the final
1330-
// TypeRepr will be resolved again when generating constraints.
13311329
const auto options =
1332-
TypeResolutionOptions(TypeResolverContext::InExpression) |
1333-
TypeResolutionFlags::AllowUnavailable;
1330+
TypeResolutionOptions(TypeResolverContext::InExpression);
13341331
const auto resolution =
13351332
TypeResolution::forContextual(DC, options, [](auto unboundTy) {
13361333
// FIXME: Don't let unbound generic types escape type resolution.

lib/Sema/TypeCheckAccess.cpp

Lines changed: 262 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "TypeCheckAccess.h"
18+
#include "TypeChecker.h"
19+
#include "TypeCheckAvailability.h"
1820
#include "TypeAccessScopeChecker.h"
1921
#include "swift/AST/ASTVisitor.h"
2022
#include "swift/AST/ASTWalker.h"
@@ -1772,7 +1774,11 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
17721774
checkOverride(VD);
17731775
}
17741776

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);
17761782
}
17771783

17781784
// Force all kinds to be handled at a lower level.
@@ -2035,6 +2041,260 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
20352041
});
20362042
}
20372043
};
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+
20382298
} // end anonymous namespace
20392299

20402300
static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
@@ -2086,4 +2346,5 @@ void swift::checkAccessControl(Decl *D) {
20862346
}
20872347

20882348
ExportabilityChecker().visit(D);
2349+
DeclAvailabilityChecker(D).visit(D);
20892350
}

0 commit comments

Comments
 (0)