|
15 | 15 | //===----------------------------------------------------------------------===//
|
16 | 16 |
|
17 | 17 | #include "TypeCheckAvailability.h"
|
| 18 | +#include "MiscDiagnostics.h" |
18 | 19 | #include "TypeCheckConcurrency.h"
|
19 |
| -#include "TypeChecker.h" |
20 | 20 | #include "TypeCheckObjC.h"
|
21 |
| -#include "MiscDiagnostics.h" |
| 21 | +#include "TypeChecker.h" |
22 | 22 | #include "swift/AST/ASTWalker.h"
|
| 23 | +#include "swift/AST/GenericEnvironment.h" |
23 | 24 | #include "swift/AST/Initializer.h"
|
24 | 25 | #include "swift/AST/NameLookup.h"
|
25 | 26 | #include "swift/AST/Pattern.h"
|
@@ -2749,6 +2750,74 @@ bool isSubscriptReturningString(const ValueDecl *D, ASTContext &Context) {
|
2749 | 2750 | return resultTy->isString();
|
2750 | 2751 | }
|
2751 | 2752 |
|
| 2753 | +static bool diagnosePotentialParameterizedProtocolUnavailability( |
| 2754 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC, |
| 2755 | + const UnavailabilityReason &Reason) { |
| 2756 | + ASTContext &Context = ReferenceDC->getASTContext(); |
| 2757 | + |
| 2758 | + auto RequiredRange = Reason.getRequiredOSVersionRange(); |
| 2759 | + { |
| 2760 | + auto Err = Context.Diags.diagnose( |
| 2761 | + ReferenceRange.Start, |
| 2762 | + diag::availability_parameterized_protocol_only_version_newer, |
| 2763 | + prettyPlatformString(targetPlatform(Context.LangOpts)), |
| 2764 | + Reason.getRequiredOSVersionRange().getLowerEndpoint()); |
| 2765 | + |
| 2766 | + // Direct a fixit to the error if an existing guard is nearly-correct |
| 2767 | + if (fixAvailabilityByNarrowingNearbyVersionCheck( |
| 2768 | + ReferenceRange, ReferenceDC, RequiredRange, Context, Err)) |
| 2769 | + return true; |
| 2770 | + } |
| 2771 | + fixAvailability(ReferenceRange, ReferenceDC, RequiredRange, Context); |
| 2772 | + return true; |
| 2773 | +} |
| 2774 | + |
| 2775 | +bool swift::diagnoseParameterizedProtocolAvailability( |
| 2776 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC) { |
| 2777 | + // Check the availability of parameterized existential runtime support. |
| 2778 | + ASTContext &ctx = ReferenceDC->getASTContext(); |
| 2779 | + if (ctx.LangOpts.DisableAvailabilityChecking) |
| 2780 | + return false; |
| 2781 | + |
| 2782 | + if (!shouldCheckAvailability(ReferenceDC->getAsDecl())) |
| 2783 | + return false; |
| 2784 | + |
| 2785 | + auto runningOS = TypeChecker::overApproximateAvailabilityAtLocation( |
| 2786 | + ReferenceRange.Start, ReferenceDC); |
| 2787 | + auto availability = ctx.getParameterizedExistentialRuntimeAvailability(); |
| 2788 | + if (!runningOS.isContainedIn(availability)) { |
| 2789 | + return diagnosePotentialParameterizedProtocolUnavailability( |
| 2790 | + ReferenceRange, ReferenceDC, |
| 2791 | + UnavailabilityReason::requiresVersionRange( |
| 2792 | + availability.getOSVersion())); |
| 2793 | + } |
| 2794 | + return false; |
| 2795 | +} |
| 2796 | + |
| 2797 | +static void |
| 2798 | +maybeDiagParameterizedExistentialErasure(ErasureExpr *EE, |
| 2799 | + const ExportContext &Where) { |
| 2800 | + if (auto *OE = dyn_cast<OpaqueValueExpr>(EE->getSubExpr())) { |
| 2801 | + auto *OAT = OE->getType()->getAs<OpenedArchetypeType>(); |
| 2802 | + if (!OAT) |
| 2803 | + return; |
| 2804 | + |
| 2805 | + auto opened = OAT->getGenericEnvironment()->getOpenedExistentialType(); |
| 2806 | + if (!opened || !opened->hasParameterizedExistential()) |
| 2807 | + return; |
| 2808 | + |
| 2809 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2810 | + Where.getDeclContext()); |
| 2811 | + } |
| 2812 | + |
| 2813 | + if (EE->getType() && |
| 2814 | + EE->getType()->isAny() && |
| 2815 | + EE->getSubExpr()->getType()->hasParameterizedExistential()) { |
| 2816 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2817 | + Where.getDeclContext()); |
| 2818 | + } |
| 2819 | +} |
| 2820 | + |
2752 | 2821 | bool swift::diagnoseExplicitUnavailability(
|
2753 | 2822 | const ValueDecl *D,
|
2754 | 2823 | SourceRange R,
|
@@ -2965,6 +3034,17 @@ class ExprAvailabilityWalker : public ASTWalker {
|
2965 | 3034 | diagnoseDeclRefAvailability(Context.getRegexDecl(), Range);
|
2966 | 3035 | diagnoseDeclRefAvailability(RLE->getInitializer(), Range);
|
2967 | 3036 | }
|
| 3037 | + if (auto *EE = dyn_cast<ErasureExpr>(E)) { |
| 3038 | + maybeDiagParameterizedExistentialErasure(EE, Where); |
| 3039 | + } |
| 3040 | + if (auto *CC = dyn_cast<ExplicitCastExpr>(E)) { |
| 3041 | + if (!isa<CoerceExpr>(CC) && |
| 3042 | + CC->getCastType()->hasParameterizedExistential()) { |
| 3043 | + SourceLoc loc = CC->getCastTypeRepr() ? CC->getCastTypeRepr()->getLoc() |
| 3044 | + : E->getLoc(); |
| 3045 | + diagnoseParameterizedProtocolAvailability(loc, Where.getDeclContext()); |
| 3046 | + } |
| 3047 | + } |
2968 | 3048 | if (auto KP = dyn_cast<KeyPathExpr>(E)) {
|
2969 | 3049 | maybeDiagKeyPath(KP);
|
2970 | 3050 | }
|
@@ -3739,7 +3819,12 @@ class ProblematicTypeFinder : public TypeDeclFinder {
|
3739 | 3819 |
|
3740 | 3820 | ModuleDecl *useModule = Where.getDeclContext()->getParentModule();
|
3741 | 3821 | auto subs = ty->getContextSubstitutionMap(useModule, ty->getDecl());
|
3742 |
| - (void) diagnoseSubstitutionMapAvailability(Loc, subs, Where); |
| 3822 | + (void)diagnoseSubstitutionMapAvailability( |
| 3823 | + Loc, subs, Where, |
| 3824 | + /*depTy=*/Type(), |
| 3825 | + /*replacementTy=*/Type(), |
| 3826 | + /*useConformanceAvailabilityErrorsOption=*/false, |
| 3827 | + /*suppressParameterizationCheckForOptional=*/ty->isOptional()); |
3743 | 3828 | return Action::Continue;
|
3744 | 3829 | }
|
3745 | 3830 |
|
@@ -3771,6 +3856,19 @@ class ProblematicTypeFinder : public TypeDeclFinder {
|
3771 | 3856 | }
|
3772 | 3857 | }
|
3773 | 3858 |
|
| 3859 | + if (auto *TT = T->getAs<TupleType>()) { |
| 3860 | + for (auto component : TT->getElementTypes()) { |
| 3861 | + // Let the walker find inner tuple types, we only want to diagnose |
| 3862 | + // non-compound components. |
| 3863 | + if (component->is<TupleType>()) |
| 3864 | + continue; |
| 3865 | + |
| 3866 | + if (component->hasParameterizedExistential()) |
| 3867 | + (void)diagnoseParameterizedProtocolAvailability( |
| 3868 | + Loc, Where.getDeclContext()); |
| 3869 | + } |
| 3870 | + } |
| 3871 | + |
3774 | 3872 | return TypeDeclFinder::walkToTypePost(T);
|
3775 | 3873 | }
|
3776 | 3874 | };
|
@@ -3885,14 +3983,27 @@ swift::diagnoseSubstitutionMapAvailability(SourceLoc loc,
|
3885 | 3983 | SubstitutionMap subs,
|
3886 | 3984 | const ExportContext &where,
|
3887 | 3985 | Type depTy, Type replacementTy,
|
3888 |
| - bool useConformanceAvailabilityErrorsOption) { |
| 3986 | + bool useConformanceAvailabilityErrorsOption, |
| 3987 | + bool suppressParameterizationCheckForOptional) { |
3889 | 3988 | bool hadAnyIssues = false;
|
3890 | 3989 | for (ProtocolConformanceRef conformance : subs.getConformances()) {
|
3891 | 3990 | if (diagnoseConformanceAvailability(loc, conformance, where,
|
3892 | 3991 | depTy, replacementTy,
|
3893 | 3992 | useConformanceAvailabilityErrorsOption))
|
3894 | 3993 | hadAnyIssues = true;
|
3895 | 3994 | }
|
| 3995 | + |
| 3996 | + // If we're looking at \c (any P)? (or any other depth of optional) then |
| 3997 | + // there's no availability problem. |
| 3998 | + if (suppressParameterizationCheckForOptional) |
| 3999 | + return hadAnyIssues; |
| 4000 | + |
| 4001 | + for (auto replacement : subs.getReplacementTypes()) { |
| 4002 | + if (replacement->hasParameterizedExistential()) |
| 4003 | + if (diagnoseParameterizedProtocolAvailability(loc, |
| 4004 | + where.getDeclContext())) |
| 4005 | + hadAnyIssues = true; |
| 4006 | + } |
3896 | 4007 | return hadAnyIssues;
|
3897 | 4008 | }
|
3898 | 4009 |
|
|
0 commit comments