|
23 | 23 | #include "swift/Basic/StringExtras.h"
|
24 | 24 | #include "swift/Basic/Statistic.h"
|
25 | 25 | #include "swift/AST/AccessScope.h"
|
| 26 | +#include "swift/AST/AccessScopeChecker.h" |
26 | 27 | #include "swift/AST/GenericSignatureBuilder.h"
|
27 | 28 | #include "swift/AST/ASTContext.h"
|
28 | 29 | #include "swift/AST/ASTMangler.h"
|
@@ -2474,11 +2475,46 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
|
2474 | 2475 |
|
2475 | 2476 | // Inject the typealias into the nominal decl that conforms to the protocol.
|
2476 | 2477 | if (auto nominal = DC->getSelfNominalTypeDecl()) {
|
2477 |
| - // FIXME: Ideally this would use the protocol's access too---that is, |
2478 |
| - // a typealias added for an internal protocol shouldn't need to be |
2479 |
| - // public---but that can be problematic if the same type conforms to two |
2480 |
| - // protocols with different access levels. |
2481 |
| - aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/true); |
| 2478 | + AccessScope requiredAccessScope = getRequiredAccessScope(); |
| 2479 | + |
| 2480 | + if (!TC.Context.isSwiftVersionAtLeast(5) && |
| 2481 | + DC->getParentModule()->getResilienceStrategy() != |
| 2482 | + ResilienceStrategy::Resilient) { |
| 2483 | + // HACK: In pre-Swift-5, these typealiases were synthesized with the |
| 2484 | + // same access level as the conforming type, which might be more |
| 2485 | + // visible than the associated type witness. Preserve that behavior |
| 2486 | + // when the underlying type has sufficient access, but only in |
| 2487 | + // non-resilient modules. |
| 2488 | + Optional<AccessScope> underlyingTypeScope = |
| 2489 | + TypeAccessScopeChecker::getAccessScope(type, DC, |
| 2490 | + /*usableFromInline*/false); |
| 2491 | + assert(underlyingTypeScope.hasValue() && |
| 2492 | + "the type is already invalid and we shouldn't have gotten here"); |
| 2493 | + |
| 2494 | + AccessScope nominalAccessScope = nominal->getFormalAccessScope(DC); |
| 2495 | + Optional<AccessScope> widestPossibleScope = |
| 2496 | + underlyingTypeScope->intersectWith(nominalAccessScope); |
| 2497 | + assert(widestPossibleScope.hasValue() && |
| 2498 | + "we found the nominal and the type witness, didn't we?"); |
| 2499 | + requiredAccessScope = widestPossibleScope.getValue(); |
| 2500 | + } |
| 2501 | + |
| 2502 | + // An associated type witness can never be less than fileprivate, since |
| 2503 | + // it must always be at least as visible as the enclosing type. |
| 2504 | + AccessLevel requiredAccess = |
| 2505 | + std::max(requiredAccessScope.accessLevelForDiagnostics(), |
| 2506 | + AccessLevel::FilePrivate); |
| 2507 | + |
| 2508 | + aliasDecl->setAccess(requiredAccess); |
| 2509 | + if (isUsableFromInlineRequired()) { |
| 2510 | + auto *attr = new (TC.Context) UsableFromInlineAttr(/*implicit=*/true); |
| 2511 | + aliasDecl->getAttrs().add(attr); |
| 2512 | + } |
| 2513 | + |
| 2514 | + bool unused; |
| 2515 | + assert(TC.Context.hadError() || |
| 2516 | + !checkWitnessAccess(assocType, aliasDecl, &unused)); |
| 2517 | + (void)unused; |
2482 | 2518 |
|
2483 | 2519 | if (nominal == DC) {
|
2484 | 2520 | nominal->addMember(aliasDecl);
|
|
0 commit comments