Merge pull request #4579 from aleksgapp/sr-2209-access-scope

[SR-2209] Add real AccessScope type.
This commit is contained in:
Jordan Rose
2016-11-11 11:16:12 -08:00
committed by GitHub
15 changed files with 454 additions and 402 deletions

View File

@@ -3804,19 +3804,6 @@ void swift::performStmtDiagnostics(TypeChecker &TC, const Stmt *S) {
// Utility functions
//===----------------------------------------------------------------------===//
Accessibility
swift::accessibilityFromScopeForDiagnostics(const DeclContext *accessScope) {
if (!accessScope)
return Accessibility::Public;
if (isa<ModuleDecl>(accessScope))
return Accessibility::Internal;
if (accessScope->isModuleScopeContext()) {
return Accessibility::FilePrivate;
}
return Accessibility::Private;
}
void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD,
Accessibility desiredAccess, bool isForSetter) {
StringRef fixItString;

View File

@@ -32,13 +32,6 @@ namespace swift {
class TypeChecker;
class ValueDecl;
/// Returns the access level associated with \p accessScope, for diagnostic
/// purposes.
///
/// \sa ValueDecl::getFormalAccessScope
Accessibility
accessibilityFromScopeForDiagnostics(const DeclContext *accessScope);
/// \brief Emit diagnostics for syntactic restrictions on a given expression.
void performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
const DeclContext *DC,

View File

@@ -20,6 +20,7 @@
#include "TypeChecker.h"
#include "GenericTypeResolver.h"
#include "MiscDiagnostics.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTVisitor.h"
@@ -1190,71 +1191,54 @@ class TypeAccessScopeChecker : private TypeWalker {
using TypeAccessScopeCacheMap = TypeChecker::TypeAccessScopeCacheMap;
TypeAccessScopeCacheMap &Cache;
const SourceFile *File;
SmallVector<intptr_t, 8> RawScopeStack;
static constexpr const intptr_t INVALID = -1;
SmallVector<Optional<AccessScope>, 8> RawScopeStack;
explicit TypeAccessScopeChecker(TypeAccessScopeCacheMap &cache,
const SourceFile *file)
: Cache(cache), File(file) {
// Always have something on the stack.
RawScopeStack.push_back((intptr_t)INVALID);
RawScopeStack.push_back(None);
}
bool shouldVisitOriginalSubstitutedType() override { return true; }
static intptr_t intersectAccess(const intptr_t first, const intptr_t second) {
if (first == INVALID || second == INVALID)
return INVALID;
if (!first)
return second;
if (!second)
return first;
if (first == second)
return first;
auto firstDC = reinterpret_cast<const DeclContext *>(first);
auto secondDC = reinterpret_cast<const DeclContext *>(second);
if (firstDC->isChildContextOf(secondDC))
return first;
if (secondDC->isChildContextOf(firstDC))
return second;
return INVALID;
}
Action walkToTypePre(Type ty) override {
// Assume failure until we post-visit this node.
// This will be correct as long as we don't ever have self-referential
// Types.
auto cached = Cache.find(ty);
if (cached != Cache.end()) {
auto opaqueCached = reinterpret_cast<intptr_t>(cached->second);
RawScopeStack.back() = intersectAccess(RawScopeStack.back(),opaqueCached);
Optional<AccessScope> &last = RawScopeStack.back();
if (last.hasValue())
last = last.getValue().intersectWith(cached->second);
return Action::SkipChildren;
}
const DeclContext *DC;
auto AS = AccessScope::getPublic();
if (auto alias = dyn_cast<NameAliasType>(ty.getPointer()))
DC = alias->getDecl()->getFormalAccessScope(File);
AS = alias->getDecl()->getFormalAccessScope(File);
else if (auto nominal = ty->getAnyNominal())
DC = nominal->getFormalAccessScope(File);
else
DC = nullptr;
RawScopeStack.push_back(reinterpret_cast<intptr_t>(DC));
AS = nominal->getFormalAccessScope(File);
RawScopeStack.push_back(AS);
return Action::Continue;
}
Action walkToTypePost(Type ty) override {
auto last = RawScopeStack.pop_back_val();
if (last != INVALID)
Cache[ty] = reinterpret_cast<const DeclContext *>(last);
RawScopeStack.back() = intersectAccess(RawScopeStack.back(), last);
Optional<AccessScope> last = RawScopeStack.pop_back_val();
if (last.hasValue()) {
Cache.insert(std::make_pair(ty, *last));
Optional<AccessScope> &prev = RawScopeStack.back();
if (prev.hasValue())
prev = prev.getValue().intersectWith(*last);
}
return Action::Continue;
}
public:
static Optional<const DeclContext *>
static Optional<AccessScope>
getAccessScope(Type ty, const DeclContext *useDC,
decltype(TypeChecker::TypeAccessScopeCache) &caches) {
const SourceFile *file = useDC->getParentSourceFile();
@@ -1291,17 +1275,17 @@ void TypeChecker::computeDefaultAccessibility(ExtensionDecl *ED) {
auto getTypeAccess = [this, ED](const TypeLoc &TL) -> Accessibility {
if (!TL.getType())
return Accessibility::Public;
auto scopeDC =
auto accessScope =
TypeAccessScopeChecker::getAccessScope(TL.getType(),
ED->getDeclContext(),
TypeAccessScopeCache);
// This is an error case and will be diagnosed elsewhere.
if (!scopeDC.hasValue())
if (!accessScope.hasValue())
return Accessibility::Public;
if (!scopeDC.getValue())
if (accessScope->isPublic())
return Accessibility::Public;
if (isa<ModuleDecl>(scopeDC.getValue()))
if (isa<ModuleDecl>(accessScope->getDeclContext()))
return Accessibility::Internal;
// Because extensions are always at top-level, they should never
// reference declarations not at the top level. (And any such references
@@ -1436,7 +1420,7 @@ void TypeChecker::computeAccessibility(ValueDecl *D) {
namespace {
class TypeAccessScopeDiagnoser : private ASTWalker {
const DeclContext *accessScope;
AccessScope accessScope;
const DeclContext *useDC;
const ComponentIdentTypeRepr *offendingType = nullptr;
@@ -1465,15 +1449,16 @@ class TypeAccessScopeDiagnoser : private ASTWalker {
return offendingType != nullptr;
}
explicit TypeAccessScopeDiagnoser(const DeclContext *accessScope,
explicit TypeAccessScopeDiagnoser(AccessScope accessScope,
const DeclContext *useDC)
: accessScope(accessScope), useDC(useDC) {}
public:
static const TypeRepr *findTypeWithScope(TypeRepr *TR,
const DeclContext *accessScope,
AccessScope accessScope,
const DeclContext *useDC) {
assert(accessScope && "why would we need to find a public access scope?");
assert(!accessScope.isPublic() &&
"why would we need to find a public access scope?");
TypeAccessScopeDiagnoser diagnoser(accessScope, useDC);
TR->walk(diagnoser);
return diagnoser.offendingType;
@@ -1501,19 +1486,20 @@ enum class DowngradeToWarning: bool {
/// part of the type that caused the problem could not be found. The DeclContext
/// is never null.
static void checkTypeAccessibilityImpl(
TypeChecker &TC, TypeLoc TL, const DeclContext *contextAccessScope,
TypeChecker &TC, TypeLoc TL, AccessScope contextAccessScope,
const DeclContext *useDC,
llvm::function_ref<void(const DeclContext *, const TypeRepr *)> diagnose) {
llvm::function_ref<void(AccessScope, const TypeRepr *)> diagnose) {
if (!TC.getLangOpts().EnableAccessControl)
return;
if (!TL.getType())
return;
// Don't spend time checking local declarations; this is always valid by the
// time we get to this point.
if (contextAccessScope && contextAccessScope->isLocalContext())
if (!contextAccessScope.isPublic() &&
contextAccessScope.getDeclContext()->isLocalContext())
return;
Optional<const DeclContext *> typeAccessScope =
auto typeAccessScope =
TypeAccessScopeChecker::getAccessScope(TL.getType(), useDC,
TC.TypeAccessScopeCache);
@@ -1523,10 +1509,10 @@ static void checkTypeAccessibilityImpl(
if (!typeAccessScope.hasValue())
return;
if (!*typeAccessScope || *typeAccessScope == contextAccessScope ||
contextAccessScope->isChildContextOf(*typeAccessScope)) {
if (typeAccessScope->isPublic() ||
typeAccessScope->hasEqualDeclContextWith(contextAccessScope) ||
contextAccessScope.isChildOf(*typeAccessScope))
return;
}
const TypeRepr *complainRepr = nullptr;
if (TypeRepr *TR = TL.getTypeRepr()) {
@@ -1547,15 +1533,16 @@ static void checkTypeAccessibilityImpl(
/// early versions of Swift 3 not diagnosing certain access violations.
static void checkTypeAccessibility(
TypeChecker &TC, TypeLoc TL, const ValueDecl *context,
llvm::function_ref<void(const DeclContext *, const TypeRepr *,
llvm::function_ref<void(AccessScope, const TypeRepr *,
DowngradeToWarning)> diagnose) {
const DeclContext *contextAccessScope = context->getFormalAccessScope();
AccessScope contextAccessScope = context->getFormalAccessScope();
checkTypeAccessibilityImpl(TC, TL, contextAccessScope,
context->getDeclContext(),
[=](const DeclContext *requiredAccessScope,
[=](AccessScope requiredAccessScope,
const TypeRepr *offendingTR) {
auto downgradeToWarning = DowngradeToWarning::No;
if (contextAccessScope && !isa<ModuleDecl>(contextAccessScope)) {
if (!contextAccessScope.isPublic() &&
!isa<ModuleDecl>(contextAccessScope.getDeclContext())) {
// Swift 3.0.0 mistakenly didn't diagnose any issues when the context
// access scope represented a private or fileprivate level.
downgradeToWarning = DowngradeToWarning::Yes;
@@ -1587,7 +1574,7 @@ static void highlightOffendingType(TypeChecker &TC, InFlightDiagnostic &diag,
static void checkGenericParamAccessibility(TypeChecker &TC,
const GenericParamList *params,
const Decl *owner,
const DeclContext *accessScope,
AccessScope accessScope,
Accessibility contextAccess) {
if (!params)
return;
@@ -1597,12 +1584,13 @@ static void checkGenericParamAccessibility(TypeChecker &TC,
AEK_Parameter = 0,
AEK_Requirement
} accessibilityErrorKind;
const DeclContext *minAccessScope = nullptr;
auto minAccessScope = AccessScope::getPublic();
const TypeRepr *complainRepr = nullptr;
// Swift 3.0.0 mistakenly didn't diagnose any issues when the context access
// scope represented a private or fileprivate level.
bool shouldDowngradeToWarning = accessScope && !isa<ModuleDecl>(accessScope);
bool shouldDowngradeToWarning =
!accessScope.isPublic() && !isa<ModuleDecl>(accessScope.getDeclContext());
for (auto param : *params) {
if (param->getInherited().empty())
@@ -1610,11 +1598,11 @@ static void checkGenericParamAccessibility(TypeChecker &TC,
assert(param->getInherited().size() == 1);
checkTypeAccessibilityImpl(TC, param->getInherited().front(), accessScope,
owner->getDeclContext(),
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
accessibilityErrorKind = AEK_Parameter;
@@ -1623,11 +1611,11 @@ static void checkGenericParamAccessibility(TypeChecker &TC,
}
for (auto &requirement : params->getRequirements()) {
auto callback = [&](const DeclContext *typeAccessScope,
auto callback = [&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
accessibilityErrorKind = AEK_Requirement;
@@ -1653,8 +1641,8 @@ static void checkGenericParamAccessibility(TypeChecker &TC,
}
}
if (minAccessScope) {
auto minAccess = accessibilityFromScopeForDiagnostics(minAccessScope);
if (!minAccessScope.isPublic()) {
auto minAccess = minAccessScope.accessibilityForDiagnostics();
bool isExplicit =
owner->getAttrs().hasAttribute<AccessibilityAttr>() ||
@@ -1665,6 +1653,7 @@ static void checkGenericParamAccessibility(TypeChecker &TC,
auto diag = TC.diagnose(owner, diagID,
owner->getDescriptiveKind(), isExplicit,
contextAccess, minAccess,
isa<FileUnit>(owner->getDeclContext()),
accessibilityErrorKind);
highlightOffendingType(TC, diag, complainRepr);
}
@@ -1727,13 +1716,15 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
checkTypeAccessibility(TC, TypeLoc::withoutLoc(theVar->getType()),
theVar,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess =
accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
bool isExplicit =
theVar->getAttrs().hasAttribute<AccessibilityAttr>();
auto theVarAccess = isExplicit
? theVar->getFormalAccess()
: typeAccessScope.requiredAccessibilityForDiagnostics();
auto diagID = diag::pattern_type_access_inferred;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::pattern_type_access_inferred_warn;
@@ -1741,7 +1732,8 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
theVar->isLet(),
isTypeContext,
isExplicit,
theVar->getFormalAccess(),
theVarAccess,
isa<FileUnit>(theVar->getDeclContext()),
typeAccess,
theVar->getType());
});
@@ -1764,21 +1756,25 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
return;
checkTypeAccessibility(TC, TP->getTypeLoc(), anyVar,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess = accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
bool isExplicit =
anyVar->getAttrs().hasAttribute<AccessibilityAttr>() ||
anyVar->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
auto diagID = diag::pattern_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::pattern_type_access_warn;
auto anyVarAccess = isExplicit
? anyVar->getFormalAccess()
: typeAccessScope.requiredAccessibilityForDiagnostics();
auto diag = TC.diagnose(P->getLoc(), diagID,
anyVar->isLet(),
isTypeContext,
isExplicit,
anyVar->getFormalAccess(),
anyVarAccess,
isa<FileUnit>(anyVar->getDeclContext()),
typeAccess);
highlightOffendingType(TC, diag, complainRepr);
});
@@ -1790,17 +1786,17 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
auto TAD = cast<TypeAliasDecl>(D);
checkTypeAccessibility(TC, TAD->getUnderlyingTypeLoc(), TAD,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess = accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
bool isExplicit = TAD->getAttrs().hasAttribute<AccessibilityAttr>();
auto diagID = diag::type_alias_underlying_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::type_alias_underlying_type_access_warn;
auto diag = TC.diagnose(TAD, diagID,
isExplicit, TAD->getFormalAccess(),
typeAccess);
typeAccess, isa<FileUnit>(TAD->getDeclContext()));
highlightOffendingType(TC, diag, complainRepr);
});
@@ -1815,7 +1811,7 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
AEK_DefaultDefinition = 0,
AEK_Requirement
} accessibilityErrorKind;
const DeclContext *minAccessScope = nullptr;
auto minAccessScope = AccessScope::getPublic();
const TypeRepr *complainRepr = nullptr;
auto downgradeToWarning = DowngradeToWarning::No;
@@ -1823,12 +1819,12 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
assocType->getInherited().end(),
[&](TypeLoc requirement) {
checkTypeAccessibility(TC, requirement, assocType,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
accessibilityErrorKind = AEK_Requirement;
@@ -1837,12 +1833,12 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
});
});
checkTypeAccessibility(TC, assocType->getDefaultDefinitionLoc(), assocType,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
accessibilityErrorKind = AEK_DefaultDefinition;
@@ -1850,8 +1846,8 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
}
});
if (minAccessScope) {
auto minAccess = accessibilityFromScopeForDiagnostics(minAccessScope);
if (!minAccessScope.isPublic()) {
auto minAccess = minAccessScope.accessibilityForDiagnostics();
auto diagID = diag::associated_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::associated_type_access_warn;
@@ -1880,17 +1876,17 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
if (rawTypeLocIter == ED->getInherited().end())
return;
checkTypeAccessibility(TC, *rawTypeLocIter, ED,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess = accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
bool isExplicit = ED->getAttrs().hasAttribute<AccessibilityAttr>();
auto diagID = diag::enum_raw_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::enum_raw_type_access_warn;
auto diag = TC.diagnose(ED, diagID,
isExplicit, ED->getFormalAccess(),
typeAccess);
auto diag = TC.diagnose(ED, diagID, isExplicit,
ED->getFormalAccess(), typeAccess,
isa<FileUnit>(ED->getDeclContext()));
highlightOffendingType(TC, diag, complainRepr);
});
}
@@ -1921,17 +1917,17 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
if (superclassLocIter == CD->getInherited().end())
return;
checkTypeAccessibility(TC, *superclassLocIter, CD,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess = accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
bool isExplicit = CD->getAttrs().hasAttribute<AccessibilityAttr>();
auto diagID = diag::class_super_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::class_super_access_warn;
auto diag = TC.diagnose(CD, diagID,
isExplicit, CD->getFormalAccess(),
typeAccess);
auto diag = TC.diagnose(CD, diagID, isExplicit, CD->getFormalAccess(),
typeAccess,
isa<FileUnit>(CD->getDeclContext()));
highlightOffendingType(TC, diag, complainRepr);
});
}
@@ -1942,7 +1938,7 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
case DeclKind::Protocol: {
auto proto = cast<ProtocolDecl>(D);
const DeclContext *minAccessScope = nullptr;
auto minAccessScope = AccessScope::getPublic();
const TypeRepr *complainRepr = nullptr;
auto downgradeToWarning = DowngradeToWarning::No;
@@ -1950,12 +1946,12 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
proto->getInherited().end(),
[&](TypeLoc requirement) {
checkTypeAccessibility(TC, requirement, proto,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
downgradeToWarning = downgradeDiag;
@@ -1963,14 +1959,15 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
});
});
if (minAccessScope) {
auto minAccess = accessibilityFromScopeForDiagnostics(minAccessScope);
if (!minAccessScope.isPublic()) {
auto minAccess = minAccessScope.accessibilityForDiagnostics();
bool isExplicit = proto->getAttrs().hasAttribute<AccessibilityAttr>();
auto diagID = diag::protocol_refine_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::protocol_refine_access_warn;
auto diag = TC.diagnose(proto, diagID,
isExplicit, proto->getFormalAccess(), minAccess);
isExplicit, proto->getFormalAccess(), minAccess,
isa<FileUnit>(proto->getDeclContext()));
highlightOffendingType(TC, diag, complainRepr);
}
return;
@@ -1979,19 +1976,19 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
case DeclKind::Subscript: {
auto SD = cast<SubscriptDecl>(D);
const DeclContext *minAccessScope = nullptr;
auto minAccessScope = AccessScope::getPublic();
const TypeRepr *complainRepr = nullptr;
auto downgradeToWarning = DowngradeToWarning::No;
bool problemIsElement = false;
for (auto &P : *SD->getIndices()) {
checkTypeAccessibility(TC, P->getTypeLoc(), SD,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
downgradeToWarning = downgradeDiag;
@@ -2000,12 +1997,12 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
}
checkTypeAccessibility(TC, SD->getElementTypeLoc(), SD,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
downgradeToWarning = downgradeDiag;
@@ -2013,17 +2010,20 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
}
});
if (minAccessScope) {
auto minAccess = accessibilityFromScopeForDiagnostics(minAccessScope);
if (!minAccessScope.isPublic()) {
auto minAccess = minAccessScope.accessibilityForDiagnostics();
bool isExplicit =
SD->getAttrs().hasAttribute<AccessibilityAttr>() ||
SD->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
auto diagID = diag::subscript_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::subscript_type_access_warn;
auto subscriptDeclAccess = isExplicit
? SD->getFormalAccess()
: minAccessScope.requiredAccessibilityForDiagnostics();
auto diag = TC.diagnose(SD, diagID,
isExplicit,
SD->getFormalAccess(),
subscriptDeclAccess,
minAccess,
problemIsElement);
highlightOffendingType(TC, diag, complainRepr);
@@ -2048,19 +2048,19 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
FK_Initializer
};
const DeclContext *minAccessScope = nullptr;
auto minAccessScope = AccessScope::getPublic();
const TypeRepr *complainRepr = nullptr;
auto downgradeToWarning = DowngradeToWarning::No;
for (auto *PL : fn->getParameterLists().slice(isTypeContext)) {
for (auto &P : *PL) {
checkTypeAccessibility(TC, P->getTypeLoc(), fn,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
downgradeToWarning = downgradeDiag;
@@ -2072,12 +2072,12 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
bool problemIsResult = false;
if (auto FD = dyn_cast<FuncDecl>(fn)) {
checkTypeAccessibility(TC, FD->getBodyResultTypeLoc(), FD,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *thisComplainRepr,
DowngradeToWarning downgradeDiag) {
if (!minAccessScope ||
typeAccessScope->isChildContextOf(minAccessScope) ||
(!complainRepr && typeAccessScope == minAccessScope)) {
if (typeAccessScope.isChildOf(minAccessScope) ||
(!complainRepr &&
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
minAccessScope = typeAccessScope;
complainRepr = thisComplainRepr;
downgradeToWarning = downgradeDiag;
@@ -2086,20 +2086,26 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
});
}
if (minAccessScope) {
auto minAccess = accessibilityFromScopeForDiagnostics(minAccessScope);
if (!minAccessScope.isPublic()) {
auto minAccess = minAccessScope.accessibilityForDiagnostics();
auto functionKind = isa<ConstructorDecl>(fn)
? FK_Initializer
: isTypeContext ? FK_Method : FK_Function;
bool isExplicit =
fn->getAttrs().hasAttribute<AccessibilityAttr>() ||
D->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
fn->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
auto diagID = diag::function_type_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::function_type_access_warn;
auto fnAccess = isExplicit
? fn->getFormalAccess()
: minAccessScope.requiredAccessibilityForDiagnostics();
auto diag = TC.diagnose(fn, diagID,
isExplicit,
fn->getFormalAccess(),
fnAccess,
isa<FileUnit>(fn->getDeclContext()),
minAccess,
isa<ConstructorDecl>(fn) ? FK_Initializer :
isTypeContext ? FK_Method : FK_Function,
functionKind,
problemIsResult);
highlightOffendingType(TC, diag, complainRepr);
}
@@ -2112,10 +2118,10 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) {
if (!EED->hasArgumentType())
return;
checkTypeAccessibility(TC, EED->getArgumentTypeLoc(), EED,
[&](const DeclContext *typeAccessScope,
[&](AccessScope typeAccessScope,
const TypeRepr *complainRepr,
DowngradeToWarning downgradeToWarning) {
auto typeAccess = accessibilityFromScopeForDiagnostics(typeAccessScope);
auto typeAccess = typeAccessScope.accessibilityForDiagnostics();
auto diagID = diag::enum_case_access;
if (downgradeToWarning == DowngradeToWarning::Yes)
diagID = diag::enum_case_access_warn;
@@ -5695,44 +5701,34 @@ public:
} else {
auto matchAccessScope =
matchDecl->getFormalAccessScope(decl->getDeclContext());
const DeclContext *requiredAccessScope =
classDecl->getFormalAccessScope(decl->getDeclContext());
matchDecl->getFormalAccessScope(decl->getDeclContext());
auto classAccessScope =
classDecl->getFormalAccessScope(decl->getDeclContext());
auto requiredAccessScope =
matchAccessScope.intersectWith(classAccessScope);
// FIXME: This is the same operation as
// TypeAccessScopeChecker::intersectAccess.
if (!requiredAccessScope) {
requiredAccessScope = matchAccessScope;
} else if (matchAccessScope) {
if (matchAccessScope->isChildContextOf(requiredAccessScope)) {
requiredAccessScope = matchAccessScope;
} else {
assert(requiredAccessScope == matchAccessScope ||
requiredAccessScope->isChildContextOf(matchAccessScope));
}
}
bool shouldDiagnose = false;
bool shouldDiagnoseSetter = false;
if (!isa<ConstructorDecl>(decl)) {
shouldDiagnose = !decl->isAccessibleFrom(requiredAccessScope);
auto DC = requiredAccessScope->getDeclContext();
shouldDiagnose = !decl->isAccessibleFrom(DC);
if (!shouldDiagnose && matchDecl->isSettable(decl->getDeclContext())){
auto matchASD = cast<AbstractStorageDecl>(matchDecl);
if (matchASD->isSetterAccessibleFrom(decl->getDeclContext())) {
const auto *ASD = cast<AbstractStorageDecl>(decl);
shouldDiagnoseSetter =
ASD->isSettable(requiredAccessScope) &&
!ASD->isSetterAccessibleFrom(requiredAccessScope);
ASD->isSettable(DC) && !ASD->isSetterAccessibleFrom(DC);
}
}
}
if (shouldDiagnose || shouldDiagnoseSetter) {
bool overriddenForcesAccess =
(requiredAccessScope == matchAccessScope &&
matchAccess != Accessibility::Open);
(requiredAccessScope->hasEqualDeclContextWith(matchAccessScope) &&
matchAccess != Accessibility::Open);
Accessibility requiredAccess =
accessibilityFromScopeForDiagnostics(requiredAccessScope);
requiredAccessScope->requiredAccessibilityForDiagnostics();
{
auto diag = TC.diagnose(decl, diag::override_not_accessible,
shouldDiagnoseSetter,
@@ -6394,25 +6390,28 @@ public:
if (!IsFirstPass) {
TC.computeDefaultAccessibility(ED);
if (auto *AA = ED->getAttrs().getAttribute<AccessibilityAttr>()) {
const DeclContext *desiredAccessScope;
switch (AA->getAccess()) {
const auto access = AA->getAccess();
AccessScope desiredAccessScope = AccessScope::getPublic();
switch (access) {
case Accessibility::Private:
assert(ED->getDeclContext()->isModuleScopeContext() &&
"non-top-level extensions make 'private' != 'fileprivate'");
SWIFT_FALLTHROUGH;
case Accessibility::FilePrivate:
desiredAccessScope = ED->getModuleScopeContext();
case Accessibility::FilePrivate: {
const DeclContext *DC = ED->getModuleScopeContext();
bool isPrivate = access == Accessibility::Private;
desiredAccessScope = AccessScope(DC, isPrivate);
break;
}
case Accessibility::Internal:
desiredAccessScope = ED->getModuleContext();
desiredAccessScope = AccessScope(ED->getModuleContext());
break;
case Accessibility::Public:
case Accessibility::Open:
desiredAccessScope = nullptr;
break;
}
checkGenericParamAccessibility(TC, ED->getGenericParams(), ED,
desiredAccessScope, AA->getAccess());
desiredAccessScope, access);
}
TC.checkConformancesInContext(ED, ED);
}

View File

@@ -20,6 +20,7 @@
#include "TypeChecker.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
@@ -139,7 +140,7 @@ namespace {
unsigned &bestIdx,
bool &doNotDiagnoseMatches);
bool checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
bool checkWitnessAccessibility(AccessScope &requiredAccessScope,
ValueDecl *requirement,
ValueDecl *witness,
bool *isSetter);
@@ -148,7 +149,7 @@ namespace {
ValueDecl *witness,
AvailabilityContext *requirementInfo);
RequirementCheck checkWitness(const DeclContext *requiredAccessScope,
RequirementCheck checkWitness(AccessScope requiredAccessScope,
ValueDecl *requirement,
RequirementMatch match);
};
@@ -466,22 +467,22 @@ namespace {
/// The required access scope, if the check failed due to the
/// witness being less accessible than the requirement.
const DeclContext *RequiredAccessScope;
AccessScope RequiredAccessScope;
/// The required availability, if the check failed due to the
/// witness being less available than the requirement.
AvailabilityContext RequiredAvailability;
RequirementCheck(CheckKind kind)
: Kind(kind), RequiredAccessScope(nullptr),
: Kind(kind), RequiredAccessScope(AccessScope::getPublic()),
RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
RequirementCheck(CheckKind kind, const DeclContext *requiredAccessScope)
RequirementCheck(CheckKind kind, AccessScope requiredAccessScope)
: Kind(kind), RequiredAccessScope(requiredAccessScope),
RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
RequirementCheck(CheckKind kind, AvailabilityContext requiredAvailability)
: Kind(kind), RequiredAccessScope(nullptr),
: Kind(kind), RequiredAccessScope(AccessScope::getPublic()),
RequiredAvailability(requiredAvailability) { }
};
}
@@ -1427,29 +1428,20 @@ bool WitnessChecker::findBestWitness(
}
bool WitnessChecker::
checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
checkWitnessAccessibility(AccessScope &requiredAccessScope,
ValueDecl *requirement,
ValueDecl *witness,
bool *isSetter) {
*isSetter = false;
const DeclContext *protoAccessScope = Proto->getFormalAccessScope(DC);
auto scopeIntersection =
requiredAccessScope.intersectWith(Proto->getFormalAccessScope(DC));
assert(scopeIntersection.hasValue());
// FIXME: This is the same operation as TypeCheckDecl.cpp's
// TypeAccessScopeChecker::intersectAccess.
if (!requiredAccessScope) {
requiredAccessScope = protoAccessScope;
} else if (protoAccessScope) {
if (protoAccessScope->isChildContextOf(requiredAccessScope)) {
requiredAccessScope = protoAccessScope;
} else {
assert(requiredAccessScope == protoAccessScope ||
requiredAccessScope->isChildContextOf(protoAccessScope));
}
}
requiredAccessScope = *scopeIntersection;
const DeclContext *actualScopeToCheck = requiredAccessScope;
if (!witness->isAccessibleFrom(actualScopeToCheck)) {
AccessScope actualScopeToCheck = requiredAccessScope;
if (!witness->isAccessibleFrom(actualScopeToCheck.getDeclContext())) {
// Special case: if we have `@testable import` of the witness's module,
// allow the witness to match if it would have matched for just this file.
// That is, if '@testable' allows us to see the witness here, it should
@@ -1464,7 +1456,7 @@ checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
}
}
if (actualScopeToCheck == requiredAccessScope)
if (actualScopeToCheck.hasEqualDeclContextWith(requiredAccessScope))
return true;
}
@@ -1472,7 +1464,7 @@ checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
*isSetter = true;
auto ASD = cast<AbstractStorageDecl>(witness);
if (!ASD->isSetterAccessibleFrom(actualScopeToCheck))
if (!ASD->isSetterAccessibleFrom(actualScopeToCheck.getDeclContext()))
return true;
}
@@ -1489,7 +1481,7 @@ checkWitnessAvailability(ValueDecl *requirement,
}
RequirementCheck WitnessChecker::
checkWitness(const DeclContext *requiredAccessScope,
checkWitness(AccessScope requiredAccessScope,
ValueDecl *requirement,
RequirementMatch match) {
if (!match.OptionalAdjustments.empty())
@@ -2199,7 +2191,7 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
if (typeDecl) {
// Check access.
const DeclContext *requiredAccessScope =
AccessScope requiredAccessScope =
Adoptee->getAnyNominal()->getFormalAccessScope(DC);
bool isSetter = false;
if (checkWitnessAccessibility(requiredAccessScope, assocType, typeDecl,
@@ -2212,10 +2204,11 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
[DC, typeDecl, requiredAccessScope, assocType](
TypeChecker &tc, NormalProtocolConformance *conformance) {
Accessibility requiredAccess =
accessibilityFromScopeForDiagnostics(requiredAccessScope);
requiredAccessScope.requiredAccessibilityForDiagnostics();
auto proto = conformance->getProtocol();
auto protoAccessScope = proto->getFormalAccessScope(DC);
bool protoForcesAccess =
(requiredAccessScope == proto->getFormalAccessScope(DC));
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
auto diagKind = protoForcesAccess
? diag::type_witness_not_accessible_proto
: diag::type_witness_not_accessible_type;
@@ -2486,7 +2479,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
});
}
const DeclContext *nominalAccessScope =
AccessScope nominalAccessScope =
Adoptee->getAnyNominal()->getFormalAccessScope(DC);
auto check = checkWitness(nominalAccessScope, requirement, best);
@@ -2501,12 +2494,13 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
diagnoseOrDefer(requirement, false,
[DC, witness, check, requirement](
TypeChecker &tc, NormalProtocolConformance *conformance) {
auto requiredAccessScope = check.RequiredAccessScope;
Accessibility requiredAccess =
accessibilityFromScopeForDiagnostics(check.RequiredAccessScope);
requiredAccessScope.requiredAccessibilityForDiagnostics();
auto proto = conformance->getProtocol();
auto protoAccessScope = proto->getFormalAccessScope(DC);
bool protoForcesAccess =
(check.RequiredAccessScope == proto->getFormalAccessScope(DC));
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
auto diagKind = protoForcesAccess
? diag::witness_not_accessible_proto
: diag::witness_not_accessible_type;
@@ -2517,6 +2511,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
witness->getFullName(),
isSetter,
requiredAccess,
protoAccessScope.accessibilityForDiagnostics(),
proto->getName());
fixItAccessibility(diag, witness, requiredAccess, isSetter);
});
@@ -5451,7 +5446,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
// Perform the same checks as conformance witness matching, but silently
// ignore the candidate instead of diagnosing anything.
auto check = checkWitness(/*access: public*/nullptr, requirement, best);
auto check = checkWitness(AccessScope::getPublic(), requirement, best);
if (check.Kind != CheckKind::Success)
return ResolveWitnessResult::ExplicitFailed;

View File

@@ -18,6 +18,7 @@
#define TYPECHECKING_H
#include "swift/Sema/TypeCheckRequest.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/AST.h"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/Availability.h"
@@ -490,7 +491,7 @@ public:
/// during type checking.
llvm::SetVector<NominalTypeDecl *> ValidatedTypes;
using TypeAccessScopeCacheMap = llvm::DenseMap<Type, const DeclContext *>;
using TypeAccessScopeCacheMap = llvm::DenseMap<Type, AccessScope>;
/// Caches the outermost scope where a particular type can be used, relative
/// to a particular file.