Skip to content

Commit 968c5c4

Browse files
committed
Sema: Move type witness access control diagnostics to ensureRequirementsAreSatisfied()
1 parent e9bdade commit 968c5c4

File tree

1 file changed

+82
-87
lines changed

1 file changed

+82
-87
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 82 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,45 +3442,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
34423442

34433443
assert(!type->hasArchetype() && "Got a contextual type here?");
34443444

3445-
checkObjCTypeErasedGenerics(assocType, type, typeDecl);
3446-
3447-
if (typeDecl) {
3448-
// Check access.
3449-
bool isSetter = false;
3450-
if (checkWitnessAccess(assocType, typeDecl, &isSetter)) {
3451-
assert(!isSetter);
3452-
3453-
// Note: you must not capture 'this' in the below closure.
3454-
const DeclContext *DC = this->DC;
3455-
auto requiredAccessScope = getRequiredAccessScope();
3456-
3457-
diagnoseOrDefer(assocType, false,
3458-
[DC, requiredAccessScope, typeDecl](
3459-
NormalProtocolConformance *conformance) {
3460-
AccessLevel requiredAccess =
3461-
requiredAccessScope.requiredAccessForDiagnostics();
3462-
auto proto = conformance->getProtocol();
3463-
auto protoAccessScope = proto->getFormalAccessScope(DC);
3464-
bool protoForcesAccess =
3465-
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
3466-
auto diagKind = protoForcesAccess
3467-
? diag::type_witness_not_accessible_proto
3468-
: diag::type_witness_not_accessible_type;
3469-
auto &diags = DC->getASTContext().Diags;
3470-
diags.diagnose(getLocForDiagnosingWitness(conformance, typeDecl),
3471-
diagKind, typeDecl, requiredAccess, proto);
3472-
diagnoseWitnessFixAccessLevel(diags, typeDecl, requiredAccess);
3473-
});
3474-
}
3475-
3476-
if (isUsableFromInlineRequired()) {
3477-
bool witnessIsUsableFromInline = typeDecl->getFormalAccessScope(
3478-
DC, /*usableFromInlineAsPublic*/true).isPublic();
3479-
if (!witnessIsUsableFromInline)
3480-
diagnoseOrDefer(assocType, false, DiagnoseUsableFromInline(typeDecl));
3481-
}
3482-
} else {
3483-
// If there was no type declaration, synthesize one.
3445+
// If there was no type declaration, synthesize one.
3446+
if (typeDecl == nullptr) {
34843447
auto aliasDecl = new (getASTContext()) TypeAliasDecl(
34853448
SourceLoc(), SourceLoc(), assocType->getName(), SourceLoc(),
34863449
/*genericparams*/ nullptr, DC);
@@ -3490,55 +3453,48 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
34903453
aliasDecl->setSynthesized();
34913454

34923455
// Inject the typealias into the nominal decl that conforms to the protocol.
3493-
if (auto nominal = DC->getSelfNominalTypeDecl()) {
3494-
AccessScope requiredAccessScope = getRequiredAccessScope();
3495-
3496-
if (!getASTContext().isSwiftVersionAtLeast(5) &&
3497-
!DC->getParentModule()->isResilient()) {
3498-
// HACK: In pre-Swift-5, these typealiases were synthesized with the
3499-
// same access level as the conforming type, which might be more
3500-
// visible than the associated type witness. Preserve that behavior
3501-
// when the underlying type has sufficient access, but only in
3502-
// non-resilient modules.
3503-
llvm::Optional<AccessScope> underlyingTypeScope =
3504-
TypeAccessScopeChecker::getAccessScope(type, DC,
3505-
/*usableFromInline*/ false);
3506-
assert(underlyingTypeScope.has_value() &&
3507-
"the type is already invalid and we shouldn't have gotten here");
3508-
3509-
AccessScope nominalAccessScope = nominal->getFormalAccessScope(DC);
3510-
llvm::Optional<AccessScope> widestPossibleScope =
3511-
underlyingTypeScope->intersectWith(nominalAccessScope);
3512-
assert(widestPossibleScope.has_value() &&
3513-
"we found the nominal and the type witness, didn't we?");
3514-
requiredAccessScope = widestPossibleScope.value();
3515-
}
3516-
3517-
// An associated type witness can never be less than fileprivate, since
3518-
// it must always be at least as visible as the enclosing type.
3519-
AccessLevel requiredAccess =
3520-
std::max(requiredAccessScope.accessLevelForDiagnostics(),
3521-
AccessLevel::FilePrivate);
3522-
3523-
aliasDecl->setAccess(requiredAccess);
3524-
if (isUsableFromInlineRequired()) {
3525-
auto *attr =
3526-
new (getASTContext()) UsableFromInlineAttr(/*implicit=*/true);
3527-
aliasDecl->getAttrs().add(attr);
3528-
}
3456+
auto nominal = DC->getSelfNominalTypeDecl();
3457+
AccessScope requiredAccessScope = getRequiredAccessScope();
3458+
3459+
if (!getASTContext().isSwiftVersionAtLeast(5) &&
3460+
!DC->getParentModule()->isResilient()) {
3461+
// HACK: In pre-Swift-5, these typealiases were synthesized with the
3462+
// same access level as the conforming type, which might be more
3463+
// visible than the associated type witness. Preserve that behavior
3464+
// when the underlying type has sufficient access, but only in
3465+
// non-resilient modules.
3466+
llvm::Optional<AccessScope> underlyingTypeScope =
3467+
TypeAccessScopeChecker::getAccessScope(type, DC,
3468+
/*usableFromInline*/ false);
3469+
assert(underlyingTypeScope.has_value() &&
3470+
"the type is already invalid and we shouldn't have gotten here");
3471+
3472+
AccessScope nominalAccessScope = nominal->getFormalAccessScope(DC);
3473+
llvm::Optional<AccessScope> widestPossibleScope =
3474+
underlyingTypeScope->intersectWith(nominalAccessScope);
3475+
assert(widestPossibleScope.has_value() &&
3476+
"we found the nominal and the type witness, didn't we?");
3477+
requiredAccessScope = widestPossibleScope.value();
3478+
}
3479+
3480+
// An associated type witness can never be less than fileprivate, since
3481+
// it must always be at least as visible as the enclosing type.
3482+
AccessLevel requiredAccess =
3483+
std::max(requiredAccessScope.accessLevelForDiagnostics(),
3484+
AccessLevel::FilePrivate);
3485+
3486+
aliasDecl->setAccess(requiredAccess);
3487+
if (isUsableFromInlineRequired()) {
3488+
auto *attr =
3489+
new (getASTContext()) UsableFromInlineAttr(/*implicit=*/true);
3490+
aliasDecl->getAttrs().add(attr);
3491+
}
35293492

3530-
if (nominal == DC) {
3531-
nominal->addMember(aliasDecl);
3532-
} else {
3533-
auto ext = cast<ExtensionDecl>(DC);
3534-
ext->addMember(aliasDecl);
3535-
}
3493+
if (nominal == DC) {
3494+
nominal->addMember(aliasDecl);
35363495
} else {
3537-
// If the declcontext is a Module, then we're in a special error recovery
3538-
// situation. Mark the typealias as an error and don't inject it into any
3539-
// DeclContext.
3540-
assert(isa<ModuleDecl>(DC) && "Not an UnresolvedType conformance?");
3541-
aliasDecl->setInvalid();
3496+
auto ext = cast<ExtensionDecl>(DC);
3497+
ext->addMember(aliasDecl);
35423498
}
35433499

35443500
typeDecl = aliasDecl;
@@ -5186,8 +5142,47 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
51865142
if (where.isImplicit())
51875143
return;
51885144

5189-
Conformance->forEachTypeWitness([&](const AssociatedTypeDecl *assoc,
5145+
Conformance->forEachTypeWitness([&](AssociatedTypeDecl *assocType,
51905146
Type type, TypeDecl *typeDecl) -> bool {
5147+
checkObjCTypeErasedGenerics(assocType, type, typeDecl);
5148+
5149+
if (typeDecl && !typeDecl->isImplicit()) {
5150+
// Check access.
5151+
bool isSetter = false;
5152+
if (checkWitnessAccess(assocType, typeDecl, &isSetter)) {
5153+
assert(!isSetter);
5154+
5155+
// Note: you must not capture 'this' in the below closure.
5156+
const DeclContext *DC = this->DC;
5157+
auto requiredAccessScope = getRequiredAccessScope();
5158+
5159+
diagnoseOrDefer(assocType, false,
5160+
[DC, requiredAccessScope, typeDecl](
5161+
NormalProtocolConformance *conformance) {
5162+
AccessLevel requiredAccess =
5163+
requiredAccessScope.requiredAccessForDiagnostics();
5164+
auto proto = conformance->getProtocol();
5165+
auto protoAccessScope = proto->getFormalAccessScope(DC);
5166+
bool protoForcesAccess =
5167+
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
5168+
auto diagKind = protoForcesAccess
5169+
? diag::type_witness_not_accessible_proto
5170+
: diag::type_witness_not_accessible_type;
5171+
auto &diags = DC->getASTContext().Diags;
5172+
diags.diagnose(getLocForDiagnosingWitness(conformance, typeDecl),
5173+
diagKind, typeDecl, requiredAccess, proto);
5174+
diagnoseWitnessFixAccessLevel(diags, typeDecl, requiredAccess);
5175+
});
5176+
}
5177+
5178+
if (isUsableFromInlineRequired()) {
5179+
bool witnessIsUsableFromInline = typeDecl->getFormalAccessScope(
5180+
DC, /*usableFromInlineAsPublic*/true).isPublic();
5181+
if (!witnessIsUsableFromInline)
5182+
diagnoseOrDefer(assocType, false, DiagnoseUsableFromInline(typeDecl));
5183+
}
5184+
}
5185+
51915186
// Make sure any associated type witnesses don't make reference to a
51925187
// parameterized existential type, or we're going to have trouble at
51935188
// runtime.

0 commit comments

Comments
 (0)