|
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" |
@@ -2781,6 +2782,74 @@ bool isSubscriptReturningString(const ValueDecl *D, ASTContext &Context) { |
2781 | 2782 | return resultTy->isString(); |
2782 | 2783 | } |
2783 | 2784 |
|
| 2785 | +static bool diagnosePotentialParameterizedProtocolUnavailability( |
| 2786 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC, |
| 2787 | + const UnavailabilityReason &Reason) { |
| 2788 | + ASTContext &Context = ReferenceDC->getASTContext(); |
| 2789 | + |
| 2790 | + auto RequiredRange = Reason.getRequiredOSVersionRange(); |
| 2791 | + { |
| 2792 | + auto Err = Context.Diags.diagnose( |
| 2793 | + ReferenceRange.Start, |
| 2794 | + diag::availability_parameterized_protocol_only_version_newer, |
| 2795 | + prettyPlatformString(targetPlatform(Context.LangOpts)), |
| 2796 | + Reason.getRequiredOSVersionRange().getLowerEndpoint()); |
| 2797 | + |
| 2798 | + // Direct a fixit to the error if an existing guard is nearly-correct |
| 2799 | + if (fixAvailabilityByNarrowingNearbyVersionCheck( |
| 2800 | + ReferenceRange, ReferenceDC, RequiredRange, Context, Err)) |
| 2801 | + return true; |
| 2802 | + } |
| 2803 | + fixAvailability(ReferenceRange, ReferenceDC, RequiredRange, Context); |
| 2804 | + return true; |
| 2805 | +} |
| 2806 | + |
| 2807 | +bool swift::diagnoseParameterizedProtocolAvailability( |
| 2808 | + SourceRange ReferenceRange, const DeclContext *ReferenceDC) { |
| 2809 | + // Check the availability of parameterized existential runtime support. |
| 2810 | + ASTContext &ctx = ReferenceDC->getASTContext(); |
| 2811 | + if (ctx.LangOpts.DisableAvailabilityChecking) |
| 2812 | + return false; |
| 2813 | + |
| 2814 | + if (!shouldCheckAvailability(ReferenceDC->getAsDecl())) |
| 2815 | + return false; |
| 2816 | + |
| 2817 | + auto runningOS = TypeChecker::overApproximateAvailabilityAtLocation( |
| 2818 | + ReferenceRange.Start, ReferenceDC); |
| 2819 | + auto availability = ctx.getParameterizedExistentialRuntimeAvailability(); |
| 2820 | + if (!runningOS.isContainedIn(availability)) { |
| 2821 | + return diagnosePotentialParameterizedProtocolUnavailability( |
| 2822 | + ReferenceRange, ReferenceDC, |
| 2823 | + UnavailabilityReason::requiresVersionRange( |
| 2824 | + availability.getOSVersion())); |
| 2825 | + } |
| 2826 | + return false; |
| 2827 | +} |
| 2828 | + |
| 2829 | +static void |
| 2830 | +maybeDiagParameterizedExistentialErasure(ErasureExpr *EE, |
| 2831 | + const ExportContext &Where) { |
| 2832 | + if (auto *OE = dyn_cast<OpaqueValueExpr>(EE->getSubExpr())) { |
| 2833 | + auto *OAT = OE->getType()->getAs<OpenedArchetypeType>(); |
| 2834 | + if (!OAT) |
| 2835 | + return; |
| 2836 | + |
| 2837 | + auto opened = OAT->getGenericEnvironment()->getOpenedExistentialType(); |
| 2838 | + if (!opened || !opened->hasParameterizedExistential()) |
| 2839 | + return; |
| 2840 | + |
| 2841 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2842 | + Where.getDeclContext()); |
| 2843 | + } |
| 2844 | + |
| 2845 | + if (EE->getType() && |
| 2846 | + EE->getType()->isAny() && |
| 2847 | + EE->getSubExpr()->getType()->hasParameterizedExistential()) { |
| 2848 | + (void)diagnoseParameterizedProtocolAvailability(EE->getLoc(), |
| 2849 | + Where.getDeclContext()); |
| 2850 | + } |
| 2851 | +} |
| 2852 | + |
2784 | 2853 | bool swift::diagnoseExplicitUnavailability( |
2785 | 2854 | const ValueDecl *D, |
2786 | 2855 | SourceRange R, |
@@ -2997,6 +3066,17 @@ class ExprAvailabilityWalker : public ASTWalker { |
2997 | 3066 | diagnoseDeclRefAvailability(Context.getRegexDecl(), Range); |
2998 | 3067 | diagnoseDeclRefAvailability(RLE->getInitializer(), Range); |
2999 | 3068 | } |
| 3069 | + if (auto *EE = dyn_cast<ErasureExpr>(E)) { |
| 3070 | + maybeDiagParameterizedExistentialErasure(EE, Where); |
| 3071 | + } |
| 3072 | + if (auto *CC = dyn_cast<ExplicitCastExpr>(E)) { |
| 3073 | + if (!isa<CoerceExpr>(CC) && |
| 3074 | + CC->getCastType()->hasParameterizedExistential()) { |
| 3075 | + SourceLoc loc = CC->getCastTypeRepr() ? CC->getCastTypeRepr()->getLoc() |
| 3076 | + : E->getLoc(); |
| 3077 | + diagnoseParameterizedProtocolAvailability(loc, Where.getDeclContext()); |
| 3078 | + } |
| 3079 | + } |
3000 | 3080 | if (auto KP = dyn_cast<KeyPathExpr>(E)) { |
3001 | 3081 | maybeDiagKeyPath(KP); |
3002 | 3082 | } |
@@ -3762,7 +3842,12 @@ class ProblematicTypeFinder : public TypeDeclFinder { |
3762 | 3842 |
|
3763 | 3843 | ModuleDecl *useModule = Where.getDeclContext()->getParentModule(); |
3764 | 3844 | auto subs = ty->getContextSubstitutionMap(useModule, ty->getDecl()); |
3765 | | - (void) diagnoseSubstitutionMapAvailability(Loc, subs, Where); |
| 3845 | + (void)diagnoseSubstitutionMapAvailability( |
| 3846 | + Loc, subs, Where, |
| 3847 | + /*depTy=*/Type(), |
| 3848 | + /*replacementTy=*/Type(), |
| 3849 | + /*useConformanceAvailabilityErrorsOption=*/false, |
| 3850 | + /*suppressParameterizationCheckForOptional=*/ty->isOptional()); |
3766 | 3851 | return Action::Continue; |
3767 | 3852 | } |
3768 | 3853 |
|
@@ -3794,6 +3879,19 @@ class ProblematicTypeFinder : public TypeDeclFinder { |
3794 | 3879 | } |
3795 | 3880 | } |
3796 | 3881 |
|
| 3882 | + if (auto *TT = T->getAs<TupleType>()) { |
| 3883 | + for (auto component : TT->getElementTypes()) { |
| 3884 | + // Let the walker find inner tuple types, we only want to diagnose |
| 3885 | + // non-compound components. |
| 3886 | + if (component->is<TupleType>()) |
| 3887 | + continue; |
| 3888 | + |
| 3889 | + if (component->hasParameterizedExistential()) |
| 3890 | + (void)diagnoseParameterizedProtocolAvailability( |
| 3891 | + Loc, Where.getDeclContext()); |
| 3892 | + } |
| 3893 | + } |
| 3894 | + |
3797 | 3895 | return TypeDeclFinder::walkToTypePost(T); |
3798 | 3896 | } |
3799 | 3897 | }; |
@@ -3908,14 +4006,27 @@ swift::diagnoseSubstitutionMapAvailability(SourceLoc loc, |
3908 | 4006 | SubstitutionMap subs, |
3909 | 4007 | const ExportContext &where, |
3910 | 4008 | Type depTy, Type replacementTy, |
3911 | | - bool useConformanceAvailabilityErrorsOption) { |
| 4009 | + bool useConformanceAvailabilityErrorsOption, |
| 4010 | + bool suppressParameterizationCheckForOptional) { |
3912 | 4011 | bool hadAnyIssues = false; |
3913 | 4012 | for (ProtocolConformanceRef conformance : subs.getConformances()) { |
3914 | 4013 | if (diagnoseConformanceAvailability(loc, conformance, where, |
3915 | 4014 | depTy, replacementTy, |
3916 | 4015 | useConformanceAvailabilityErrorsOption)) |
3917 | 4016 | hadAnyIssues = true; |
3918 | 4017 | } |
| 4018 | + |
| 4019 | + // If we're looking at \c (any P)? (or any other depth of optional) then |
| 4020 | + // there's no availability problem. |
| 4021 | + if (suppressParameterizationCheckForOptional) |
| 4022 | + return hadAnyIssues; |
| 4023 | + |
| 4024 | + for (auto replacement : subs.getReplacementTypes()) { |
| 4025 | + if (replacement->hasParameterizedExistential()) |
| 4026 | + if (diagnoseParameterizedProtocolAvailability(loc, |
| 4027 | + where.getDeclContext())) |
| 4028 | + hadAnyIssues = true; |
| 4029 | + } |
3919 | 4030 | return hadAnyIssues; |
3920 | 4031 | } |
3921 | 4032 |
|
|
0 commit comments