|
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"
|
@@ -2773,6 +2774,74 @@ bool isSubscriptReturningString(const ValueDecl *D, ASTContext &Context) {
|
2773 | 2774 | return resultTy->isString();
|
2774 | 2775 | }
|
2775 | 2776 |
|
| 2777 | +static bool diagnosePotentialParameterizedProtocolUnavailability( |
| 2778 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC, |
| 2779 | + const UnavailabilityReason &Reason) { |
| 2780 | + ASTContext &Context = ReferenceDC->getASTContext(); |
| 2781 | + |
| 2782 | + auto RequiredRange = Reason.getRequiredOSVersionRange(); |
| 2783 | + { |
| 2784 | + auto Err = Context.Diags.diagnose( |
| 2785 | + ReferenceRange.Start, |
| 2786 | + diag::availability_parameterized_protocol_only_version_newer, |
| 2787 | + prettyPlatformString(targetPlatform(Context.LangOpts)), |
| 2788 | + Reason.getRequiredOSVersionRange().getLowerEndpoint()); |
| 2789 | + |
| 2790 | + // Direct a fixit to the error if an existing guard is nearly-correct |
| 2791 | + if (fixAvailabilityByNarrowingNearbyVersionCheck( |
| 2792 | + ReferenceRange, ReferenceDC, RequiredRange, Context, Err)) |
| 2793 | + return true; |
| 2794 | + } |
| 2795 | + fixAvailability(ReferenceRange, ReferenceDC, RequiredRange, Context); |
| 2796 | + return true; |
| 2797 | +} |
| 2798 | + |
| 2799 | +bool swift::diagnoseParameterizedProtocolAvailability( |
| 2800 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC) { |
| 2801 | + // Check the availability of parameterized existential runtime support. |
| 2802 | + ASTContext &ctx = ReferenceDC->getASTContext(); |
| 2803 | + if (ctx.LangOpts.DisableAvailabilityChecking) |
| 2804 | + return false; |
| 2805 | + |
| 2806 | + if (!shouldCheckAvailability(ReferenceDC->getAsDecl())) |
| 2807 | + return false; |
| 2808 | + |
| 2809 | + auto runningOS = TypeChecker::overApproximateAvailabilityAtLocation( |
| 2810 | + ReferenceRange.Start, ReferenceDC); |
| 2811 | + auto availability = ctx.getParameterizedExistentialRuntimeAvailability(); |
| 2812 | + if (!runningOS.isContainedIn(availability)) { |
| 2813 | + return diagnosePotentialParameterizedProtocolUnavailability( |
| 2814 | + ReferenceRange, ReferenceDC, |
| 2815 | + UnavailabilityReason::requiresVersionRange( |
| 2816 | + availability.getOSVersion())); |
| 2817 | + } |
| 2818 | + return false; |
| 2819 | +} |
| 2820 | + |
| 2821 | +static void |
| 2822 | +maybeDiagParameterizedExistentialErasure(ErasureExpr *EE, |
| 2823 | + const ExportContext &Where) { |
| 2824 | + if (auto *OE = dyn_cast<OpaqueValueExpr>(EE->getSubExpr())) { |
| 2825 | + auto *OAT = OE->getType()->getAs<OpenedArchetypeType>(); |
| 2826 | + if (!OAT) |
| 2827 | + return; |
| 2828 | + |
| 2829 | + auto opened = OAT->getGenericEnvironment()->getOpenedExistentialType(); |
| 2830 | + if (!opened || !opened->hasParameterizedExistential()) |
| 2831 | + return; |
| 2832 | + |
| 2833 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2834 | + Where.getDeclContext()); |
| 2835 | + } |
| 2836 | + |
| 2837 | + if (EE->getType() && |
| 2838 | + EE->getType()->isAny() && |
| 2839 | + EE->getSubExpr()->getType()->hasParameterizedExistential()) { |
| 2840 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2841 | + Where.getDeclContext()); |
| 2842 | + } |
| 2843 | +} |
| 2844 | + |
2776 | 2845 | bool swift::diagnoseExplicitUnavailability(
|
2777 | 2846 | const ValueDecl *D,
|
2778 | 2847 | SourceRange R,
|
@@ -2989,6 +3058,17 @@ class ExprAvailabilityWalker : public ASTWalker {
|
2989 | 3058 | diagnoseDeclRefAvailability(Context.getRegexDecl(), Range);
|
2990 | 3059 | diagnoseDeclRefAvailability(RLE->getInitializer(), Range);
|
2991 | 3060 | }
|
| 3061 | + if (auto *EE = dyn_cast<ErasureExpr>(E)) { |
| 3062 | + maybeDiagParameterizedExistentialErasure(EE, Where); |
| 3063 | + } |
| 3064 | + if (auto *CC = dyn_cast<ExplicitCastExpr>(E)) { |
| 3065 | + if (!isa<CoerceExpr>(CC) && |
| 3066 | + CC->getCastType()->hasParameterizedExistential()) { |
| 3067 | + SourceLoc loc = CC->getCastTypeRepr() ? CC->getCastTypeRepr()->getLoc() |
| 3068 | + : E->getLoc(); |
| 3069 | + diagnoseParameterizedProtocolAvailability(loc, Where.getDeclContext()); |
| 3070 | + } |
| 3071 | + } |
2992 | 3072 | if (auto KP = dyn_cast<KeyPathExpr>(E)) {
|
2993 | 3073 | maybeDiagKeyPath(KP);
|
2994 | 3074 | }
|
@@ -3749,7 +3829,12 @@ class ProblematicTypeFinder : public TypeDeclFinder {
|
3749 | 3829 |
|
3750 | 3830 | ModuleDecl *useModule = Where.getDeclContext()->getParentModule();
|
3751 | 3831 | auto subs = ty->getContextSubstitutionMap(useModule, ty->getDecl());
|
3752 |
| - (void) diagnoseSubstitutionMapAvailability(Loc, subs, Where); |
| 3832 | + (void)diagnoseSubstitutionMapAvailability( |
| 3833 | + Loc, subs, Where, |
| 3834 | + /*depTy=*/Type(), |
| 3835 | + /*replacementTy=*/Type(), |
| 3836 | + /*useConformanceAvailabilityErrorsOption=*/false, |
| 3837 | + /*suppressParameterizationCheckForOptional=*/ty->isOptional()); |
3753 | 3838 | return Action::Continue;
|
3754 | 3839 | }
|
3755 | 3840 |
|
@@ -3781,6 +3866,19 @@ class ProblematicTypeFinder : public TypeDeclFinder {
|
3781 | 3866 | }
|
3782 | 3867 | }
|
3783 | 3868 |
|
| 3869 | + if (auto *TT = T->getAs<TupleType>()) { |
| 3870 | + for (auto component : TT->getElementTypes()) { |
| 3871 | + // Let the walker find inner tuple types, we only want to diagnose |
| 3872 | + // non-compound components. |
| 3873 | + if (component->is<TupleType>()) |
| 3874 | + continue; |
| 3875 | + |
| 3876 | + if (component->hasParameterizedExistential()) |
| 3877 | + (void)diagnoseParameterizedProtocolAvailability( |
| 3878 | + Loc, Where.getDeclContext()); |
| 3879 | + } |
| 3880 | + } |
| 3881 | + |
3784 | 3882 | return TypeDeclFinder::walkToTypePost(T);
|
3785 | 3883 | }
|
3786 | 3884 | };
|
@@ -3895,14 +3993,27 @@ swift::diagnoseSubstitutionMapAvailability(SourceLoc loc,
|
3895 | 3993 | SubstitutionMap subs,
|
3896 | 3994 | const ExportContext &where,
|
3897 | 3995 | Type depTy, Type replacementTy,
|
3898 |
| - bool useConformanceAvailabilityErrorsOption) { |
| 3996 | + bool useConformanceAvailabilityErrorsOption, |
| 3997 | + bool suppressParameterizationCheckForOptional) { |
3899 | 3998 | bool hadAnyIssues = false;
|
3900 | 3999 | for (ProtocolConformanceRef conformance : subs.getConformances()) {
|
3901 | 4000 | if (diagnoseConformanceAvailability(loc, conformance, where,
|
3902 | 4001 | depTy, replacementTy,
|
3903 | 4002 | useConformanceAvailabilityErrorsOption))
|
3904 | 4003 | hadAnyIssues = true;
|
3905 | 4004 | }
|
| 4005 | + |
| 4006 | + // If we're looking at \c (any P)? (or any other depth of optional) then |
| 4007 | + // there's no availability problem. |
| 4008 | + if (suppressParameterizationCheckForOptional) |
| 4009 | + return hadAnyIssues; |
| 4010 | + |
| 4011 | + for (auto replacement : subs.getReplacementTypes()) { |
| 4012 | + if (replacement->hasParameterizedExistential()) |
| 4013 | + if (diagnoseParameterizedProtocolAvailability(loc, |
| 4014 | + where.getDeclContext())) |
| 4015 | + hadAnyIssues = true; |
| 4016 | + } |
3906 | 4017 | return hadAnyIssues;
|
3907 | 4018 | }
|
3908 | 4019 |
|
|
0 commit comments