From e07fda5c43b5e91c781a0df57449af2b42a93e72 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 28 Oct 2024 15:42:54 +0000 Subject: [PATCH 1/2] [Sema] Factor out callback version of `TypeChecker::checkAvailability` Allow the caller to use their own diagnostic logic. --- lib/Sema/TypeCheckAvailability.cpp | 34 +++++++++++++++++++++--------- lib/Sema/TypeChecker.h | 6 ++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 9bcf3c83034e6..df40644c85787 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2098,15 +2098,15 @@ static void fixAvailability(SourceRange ReferenceRange, } static void diagnosePotentialUnavailability( - SourceRange ReferenceRange, Diag Diag, + SourceRange ReferenceRange, + llvm::function_ref + Diagnose, const DeclContext *ReferenceDC, const AvailabilityRange &Availability) { ASTContext &Context = ReferenceDC->getASTContext(); { - auto Err = Context.Diags.diagnose( - ReferenceRange.Start, Diag, - Context.getTargetPlatformStringForDiagnostics(), - Availability.getRawMinimumVersion()); + auto Err = Diagnose(Context.getTargetPlatformStringForDiagnostics(), + Availability.getRawMinimumVersion()); // Direct a fixit to the error if an existing guard is nearly-correct if (fixAvailabilityByNarrowingNearbyVersionCheck( @@ -2116,10 +2116,11 @@ static void diagnosePotentialUnavailability( fixAvailability(ReferenceRange, ReferenceDC, Availability, Context); } -bool TypeChecker::checkAvailability(SourceRange ReferenceRange, - AvailabilityRange RequiredAvailability, - Diag Diag, - const DeclContext *ReferenceDC) { +bool TypeChecker::checkAvailability( + SourceRange ReferenceRange, AvailabilityRange RequiredAvailability, + const DeclContext *ReferenceDC, + llvm::function_ref + Diagnose) { ASTContext &ctx = ReferenceDC->getASTContext(); if (ctx.LangOpts.DisableAvailabilityChecking) return false; @@ -2128,7 +2129,7 @@ bool TypeChecker::checkAvailability(SourceRange ReferenceRange, TypeChecker::overApproximateAvailabilityAtLocation(ReferenceRange.Start, ReferenceDC); if (!availabilityAtLocation.isContainedIn(RequiredAvailability)) { - diagnosePotentialUnavailability(ReferenceRange, Diag, ReferenceDC, + diagnosePotentialUnavailability(ReferenceRange, Diagnose, ReferenceDC, RequiredAvailability); return true; } @@ -2136,6 +2137,19 @@ bool TypeChecker::checkAvailability(SourceRange ReferenceRange, return false; } +bool TypeChecker::checkAvailability(SourceRange ReferenceRange, + AvailabilityRange RequiredAvailability, + Diag Diag, + const DeclContext *ReferenceDC) { + auto &Diags = ReferenceDC->getASTContext().Diags; + return TypeChecker::checkAvailability( + ReferenceRange, RequiredAvailability, ReferenceDC, + [&](StringRef platformName, llvm::VersionTuple version) { + return Diags.diagnose(ReferenceRange.Start, Diag, platformName, + version); + }); +} + void TypeChecker::checkConcurrencyAvailability(SourceRange ReferenceRange, const DeclContext *ReferenceDC) { checkAvailability( diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b156fdd72edec..de724d973626f 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1052,6 +1052,12 @@ checkConformanceAvailability(const RootProtocolConformance *Conf, const ExtensionDecl *Ext, const ExportContext &Where); +bool checkAvailability( + SourceRange ReferenceRange, AvailabilityRange RequiredAvailability, + const DeclContext *ReferenceDC, + llvm::function_ref + Diagnose); + bool checkAvailability(SourceRange ReferenceRange, AvailabilityRange RequiredAvailability, Diag Diag, From 9d4a78678ae91cc81c9a1456e710c36ea33d157b Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 28 Oct 2024 15:42:54 +0000 Subject: [PATCH 2/2] [Sema] Add logic to diagnose regex feature availability Add the necessary compiler-side logic to allow the regex parsing library to hand back a set of features for a regex literal, which can then be diagnosed by ExprAvailabilityWalker if the availability context isn't sufficient. No tests as this only adds the necessary infrastructure, we don't yet hand back the features from the regex parsing library. --- include/swift/AST/ASTBridging.h | 68 +++++++++++++++++++++ include/swift/AST/ASTBridgingImpl.h | 36 +++++++++++ include/swift/AST/DiagnosticEngine.h | 3 + include/swift/AST/DiagnosticsSema.def | 4 ++ include/swift/AST/Expr.h | 47 ++++++++++++++ include/swift/AST/TypeCheckRequests.h | 42 +++++++++++++ include/swift/AST/TypeCheckerTypeIDZone.def | 6 ++ include/swift/Basic/BasicBridging.h | 19 ++++++ include/swift/Basic/BasicBridgingImpl.h | 12 ++++ include/swift/Bridging/ASTGen.h | 22 +++++-- lib/AST/DiagnosticEngine.cpp | 7 +++ lib/AST/Expr.cpp | 22 +++++++ lib/AST/TypeCheckRequests.cpp | 9 +++ lib/ASTGen/Sources/ASTGen/Regex.swift | 33 ++++++++++ lib/Sema/TypeCheckAvailability.cpp | 18 ++++++ lib/Sema/TypeCheckRegex.cpp | 43 ++++++++++++- 16 files changed, 383 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 56c66893d039d..e3ba7b44ac738 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -28,6 +28,10 @@ SWIFT_BEGIN_NULLABILITY_ANNOTATIONS +namespace llvm { +template class ArrayRef; +} + namespace swift { class Argument; class ASTContext; @@ -42,6 +46,8 @@ class Identifier; class IfConfigClauseRangeInfo; struct LabeledStmtInfo; class ProtocolConformanceRef; +class RegexLiteralPatternFeature; +class RegexLiteralPatternFeatureKind; class Type; class CanType; class TypeBase; @@ -1351,6 +1357,68 @@ BridgedPrefixUnaryExpr BridgedPrefixUnaryExpr_createParsed(BridgedASTContext cContext, BridgedExpr oper, BridgedExpr operand); +class BridgedRegexLiteralPatternFeatureKind final { + unsigned RawValue; + +public: + BRIDGED_INLINE + SWIFT_NAME("init(rawValue:)") + BridgedRegexLiteralPatternFeatureKind(SwiftInt rawValue); + + using UnbridgedTy = swift::RegexLiteralPatternFeatureKind; + + BRIDGED_INLINE + BridgedRegexLiteralPatternFeatureKind(UnbridgedTy kind); + + BRIDGED_INLINE + UnbridgedTy unbridged() const; +}; + +class BridgedRegexLiteralPatternFeature final { + BridgedCharSourceRange Range; + BridgedRegexLiteralPatternFeatureKind Kind; + +public: + SWIFT_NAME("init(kind:at:)") + BridgedRegexLiteralPatternFeature(BridgedRegexLiteralPatternFeatureKind kind, + BridgedCharSourceRange range) + : Range(range), Kind(kind) {} + + using UnbridgedTy = swift::RegexLiteralPatternFeature; + + BRIDGED_INLINE + BridgedRegexLiteralPatternFeature(UnbridgedTy feature); + + BRIDGED_INLINE + UnbridgedTy unbridged() const; +}; + +class BridgedRegexLiteralPatternFeatures final { + BridgedRegexLiteralPatternFeature *_Nullable Data; + SwiftInt Count; + +public: + BridgedRegexLiteralPatternFeatures() : Data(nullptr), Count(0) {} + + SWIFT_NAME("init(baseAddress:count:)") + BridgedRegexLiteralPatternFeatures( + BridgedRegexLiteralPatternFeature *_Nullable data, SwiftInt count) + : Data(data), Count(count) {} + + using UnbridgedTy = llvm::ArrayRef; + + BRIDGED_INLINE + UnbridgedTy unbridged() const; + + SWIFT_IMPORT_UNSAFE + BridgedRegexLiteralPatternFeature *_Nullable getData() const { + return Data; + } + SwiftInt getCount() const { + return Count; + } +}; + SWIFT_NAME("BridgedRegexLiteralExpr.createParsed(_:loc:regexText:)") BridgedRegexLiteralExpr BridgedRegexLiteralExpr_createParsed(BridgedASTContext cContext, diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 35153dbd8a634..a982a4649d9a2 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -16,10 +16,12 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ArgumentList.h" #include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" #include "swift/AST/IfConfigClauseRangeInfo.h" #include "swift/AST/Stmt.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ProtocolConformanceRef.h" +#include "swift/Basic/Assertions.h" SWIFT_BEGIN_NULLABILITY_ANNOTATIONS @@ -379,6 +381,40 @@ swift::IfConfigClauseRangeInfo BridgedIfConfigClauseRangeInfo::unbridged() const clauseKind); } +//===----------------------------------------------------------------------===// +// MARK: BridgedRegexLiteralPatternFeature +//===----------------------------------------------------------------------===// + +BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind( + SwiftInt rawValue) + : RawValue(rawValue) { + ASSERT(rawValue >= 0); + ASSERT(rawValue == RawValue); +} + +BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind( + UnbridgedTy kind) + : RawValue(kind.getRawValue()) {} + +BridgedRegexLiteralPatternFeatureKind::UnbridgedTy +BridgedRegexLiteralPatternFeatureKind::unbridged() const { + return UnbridgedTy(RawValue); +} + +BridgedRegexLiteralPatternFeature::BridgedRegexLiteralPatternFeature( + UnbridgedTy feature) + : Range(feature.getRange()), Kind(feature.getKind()) {} + +BridgedRegexLiteralPatternFeature::UnbridgedTy +BridgedRegexLiteralPatternFeature::unbridged() const { + return UnbridgedTy(Kind.unbridged(), Range.unbridged()); +} + +BridgedRegexLiteralPatternFeatures::UnbridgedTy +BridgedRegexLiteralPatternFeatures::unbridged() const { + return UnbridgedTy(Data, Count); +} + //===----------------------------------------------------------------------===// // MARK: BridgedStmtConditionElement //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index d092dc497090d..2c70e337b8e50 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -755,6 +755,9 @@ namespace swift { /// Add a character-based range to the currently-active diagnostic. InFlightDiagnostic &highlightChars(SourceLoc Start, SourceLoc End); + /// Add a character-based range to the currently-active diagnostic. + InFlightDiagnostic &highlightChars(CharSourceRange Range); + static const char *fixItStringFor(const FixItID id); /// Get the best location where an 'import' fixit might be offered. diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3bdf543dfafbe..29061595d68a3 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -5962,6 +5962,10 @@ ERROR(regex_capture_types_failed_to_decode,none, "failed to decode capture types for regular expression literal; this may " "be a compiler bug", ()) +ERROR(regex_feature_unavailable, none, + "%0 is only available in %1 %2 or newer", + (StringRef, StringRef, llvm::VersionTuple)) + ERROR(must_import_regex_builder_module,none, "regex builder requires the 'RegexBuilder' module be imported'", ()) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 88fbbc1ae3b0c..b2c657de055b1 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -992,6 +992,50 @@ class InterpolatedStringLiteralExpr : public LiteralExpr { } }; +/// The opaque kind of a RegexLiteralExpr feature, which should only be +/// interpreted by the compiler's regex parsing library. +class RegexLiteralPatternFeatureKind final { + unsigned RawValue; + +public: + RegexLiteralPatternFeatureKind(unsigned rawValue) : RawValue(rawValue) {} + + unsigned getRawValue() const { return RawValue; } + + AvailabilityRange getAvailability(ASTContext &ctx) const; + StringRef getDescription(ASTContext &ctx) const; + + friend llvm::hash_code + hash_value(const RegexLiteralPatternFeatureKind &kind) { + return llvm::hash_value(kind.getRawValue()); + } + + friend bool operator==(const RegexLiteralPatternFeatureKind &lhs, + const RegexLiteralPatternFeatureKind &rhs) { + return lhs.getRawValue() == rhs.getRawValue(); + } + + friend bool operator!=(const RegexLiteralPatternFeatureKind &lhs, + const RegexLiteralPatternFeatureKind &rhs) { + return !(lhs == rhs); + } +}; + +/// A specific feature used in a RegexLiteralExpr, needed for availability +/// diagnostics. +class RegexLiteralPatternFeature final { + RegexLiteralPatternFeatureKind Kind; + CharSourceRange Range; + +public: + RegexLiteralPatternFeature(RegexLiteralPatternFeatureKind kind, + CharSourceRange range) + : Kind(kind), Range(range) {} + + RegexLiteralPatternFeatureKind getKind() const { return Kind; } + CharSourceRange getRange() const { return Range; } +}; + /// A regular expression literal e.g '(a|c)*'. class RegexLiteralExpr : public LiteralExpr { ASTContext *Ctx; @@ -1021,6 +1065,9 @@ class RegexLiteralExpr : public LiteralExpr { /// Retrieve the version of the regex string. unsigned getVersion() const; + /// Retrieve any features used in the regex pattern. + ArrayRef getPatternFeatures() const; + SourceRange getSourceRange() const { return Loc; } static bool classof(const Expr *E) { diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index b876c842368f1..22c51b2997350 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -5110,6 +5110,7 @@ struct RegexLiteralPatternInfo { StringRef RegexToEmit; Type RegexType; size_t Version; + ArrayRef Features; }; /// Parses the regex pattern for a given regex literal using the @@ -5131,6 +5132,47 @@ class RegexLiteralPatternInfoRequest bool isCached() const { return true; } }; +/// The description for a given regex pattern feature. This is cached since +/// the resulting string is allocated in the ASTContext for ease of bridging. +class RegexLiteralFeatureDescriptionRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + StringRef evaluate(Evaluator &evaluator, RegexLiteralPatternFeatureKind kind, + ASTContext *ctx) const; + +public: + bool isCached() const { return true; } +}; + +/// The availability range for a given regex pattern feature. +class RegexLiteralFeatureAvailabilityRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + AvailabilityRange evaluate(Evaluator &evaluator, + RegexLiteralPatternFeatureKind kind, + ASTContext *ctx) const; +}; + +void simple_display(llvm::raw_ostream &out, + RegexLiteralPatternFeatureKind kind); +SourceLoc extractNearestSourceLoc(RegexLiteralPatternFeatureKind kind); + class IsUnsafeRequest : public SimpleRequest= 0 && minor >= 0); + ASSERT(major == Major && minor == Minor); +} + SWIFT_END_NULLABILITY_ANNOTATIONS #endif // SWIFT_BASIC_BASICBRIDGINGIMPL_H diff --git a/include/swift/Bridging/ASTGen.h b/include/swift/Bridging/ASTGen.h index 33b0d142c4ec4..20ace660c2e22 100644 --- a/include/swift/Bridging/ASTGen.h +++ b/include/swift/Bridging/ASTGen.h @@ -103,12 +103,22 @@ bool swift_ASTGen_lexRegexLiteral(const char *_Nonnull *_Nonnull curPtrPtr, bool mustBeRegex, BridgedNullableDiagnosticEngine diagEngine); -bool swift_ASTGen_parseRegexLiteral(BridgedStringRef inputPtr, - size_t *_Nonnull versionOut, - void *_Nonnull UnsafeMutableRawPointer, - size_t captureStructureSize, - BridgedSourceLoc diagLoc, - BridgedDiagnosticEngine diagEngine); +bool swift_ASTGen_parseRegexLiteral( + BridgedStringRef inputPtr, size_t *_Nonnull versionOut, + void *_Nonnull UnsafeMutableRawPointer, size_t captureStructureSize, + BridgedRegexLiteralPatternFeatures *_Nonnull featuresOut, + BridgedSourceLoc diagLoc, BridgedDiagnosticEngine diagEngine); + +void swift_ASTGen_freeBridgedRegexLiteralPatternFeatures( + BridgedRegexLiteralPatternFeatures features); + +void swift_ASTGen_getSwiftVersionForRegexPatternFeature( + BridgedRegexLiteralPatternFeatureKind kind, + BridgedSwiftVersion *_Nonnull versionOut); + +void swift_ASTGen_getDescriptionForRegexPatternFeature( + BridgedRegexLiteralPatternFeatureKind kind, BridgedASTContext astContext, + BridgedStringRef *_Nonnull descriptionOut); intptr_t swift_ASTGen_configuredRegions( BridgedASTContext astContext, diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index dbdb850ab9217..b2a5ef7f5793a 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -225,6 +225,13 @@ InFlightDiagnostic &InFlightDiagnostic::highlightChars(SourceLoc Start, return *this; } +InFlightDiagnostic &InFlightDiagnostic::highlightChars(CharSourceRange Range) { + assert(IsActive && "Cannot modify an inactive diagnostic"); + if (Engine && Range.getStart().isValid()) + Engine->getActiveDiagnostic().addRange(Range); + return *this; +} + /// Add an insertion fix-it to the currently-active diagnostic. The /// text is inserted immediately *after* the token specified. /// diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1231cfecb20d8..62cdf97fbb8d5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2772,6 +2772,28 @@ unsigned RegexLiteralExpr::getVersion() const { .Version; } +ArrayRef +RegexLiteralExpr::getPatternFeatures() const { + auto &eval = getASTContext().evaluator; + return evaluateOrDefault(eval, RegexLiteralPatternInfoRequest{this}, {}) + .Features; +} + +StringRef +RegexLiteralPatternFeatureKind::getDescription(ASTContext &ctx) const { + auto &eval = ctx.evaluator; + return evaluateOrDefault( + eval, RegexLiteralFeatureDescriptionRequest{*this, &ctx}, {}); +} + +AvailabilityRange +RegexLiteralPatternFeatureKind::getAvailability(ASTContext &ctx) const { + auto &eval = ctx.evaluator; + return evaluateOrDefault(eval, + RegexLiteralFeatureAvailabilityRequest{*this, &ctx}, + AvailabilityRange::alwaysAvailable()); +} + TypeJoinExpr::TypeJoinExpr(llvm::PointerUnion result, ArrayRef elements, SingleValueStmtExpr *SVE) : Expr(ExprKind::TypeJoin, /*implicit=*/true, Type()), Var(nullptr), diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index d3e2981f6cb48..93d92a103d489 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -99,6 +99,15 @@ void swift::simple_display(llvm::raw_ostream &out, const TypeLoc source) { out << ")"; } +void swift::simple_display(llvm::raw_ostream &out, + RegexLiteralPatternFeatureKind kind) { + out << "regex pattern feature " << kind.getRawValue(); +} + +SourceLoc swift::extractNearestSourceLoc(RegexLiteralPatternFeatureKind kind) { + return SourceLoc(); +} + //----------------------------------------------------------------------------// // Inherited type computation. //----------------------------------------------------------------------------// diff --git a/lib/ASTGen/Sources/ASTGen/Regex.swift b/lib/ASTGen/Sources/ASTGen/Regex.swift index 860961887ecde..d814197f02052 100644 --- a/lib/ASTGen/Sources/ASTGen/Regex.swift +++ b/lib/ASTGen/Sources/ASTGen/Regex.swift @@ -98,6 +98,7 @@ public func _RegexLiteralParsingFn( _ versionOut: UnsafeMutablePointer, _ captureStructureOut: UnsafeMutableRawPointer, _ captureStructureSize: UInt, + _ patternFeaturesOut: UnsafeMutablePointer, _ bridgedDiagnosticBaseLoc: BridgedSourceLoc, _ bridgedDiagnosticEngine: BridgedDiagnosticEngine ) -> Bool { @@ -113,6 +114,8 @@ public func _RegexLiteralParsingFn( str, captureBufferOut: captureBuffer ) + // TODO: -> [Feature(opaque kind, (String.Index, length))] + patternFeaturesOut.pointee = .init(baseAddress: nil, count: 0) versionOut.pointee = UInt(version) return false } catch let error as CompilerParseError { @@ -136,6 +139,36 @@ public func _RegexLiteralParsingFn( } } +@_cdecl("swift_ASTGen_freeBridgedRegexLiteralPatternFeatures") +func freeBridgedRegexLiteralPatternFeatures( + _ features: BridgedRegexLiteralPatternFeatures +) { + let buffer = UnsafeMutableBufferPointer( + start: features.getData(), count: features.getCount() + ) + buffer.deinitialize() + buffer.deallocate() +} + +@_cdecl("swift_ASTGen_getSwiftVersionForRegexPatternFeature") +func getSwiftVersionForRegexPatternFeature( + _ featureKind: BridgedRegexLiteralPatternFeatureKind, + _ versionOut: UnsafeMutablePointer +) { + // TODO: FeatureKind(opaque kind) -> Version(major, minor) + fatalError("Unimplemented") +} + +@_cdecl("swift_ASTGen_getDescriptionForRegexPatternFeature") +func getDescriptionForRegexPatternFeature( + _ featureKind: BridgedRegexLiteralPatternFeatureKind, + _ context: BridgedASTContext, + _ descriptionOut: UnsafeMutablePointer +) { + // TODO: FeatureKind(opaque kind) -> String + fatalError("Unimplemented") +} + #else // canImport(_CompilerRegexParser) #warning("Regex parsing is disabled") diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index df40644c85787..83568b3025196 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -3634,6 +3634,24 @@ class ExprAvailabilityWalker : public ASTWalker { diagnoseDeclRefAvailability(LE->getInitializer(), LE->getSourceRange()); } + // Diagnose availability for any features used in a regex literal. + if (auto *RE = dyn_cast(E)) { + for (auto &feature : RE->getPatternFeatures()) { + auto featureKind = feature.getKind(); + TypeChecker::checkAvailability( + RE->getSourceRange(), featureKind.getAvailability(Context), + Where.getDeclContext(), + [&](StringRef platformName, llvm::VersionTuple version) { + auto range = feature.getRange(); + auto diag = Context.Diags.diagnose( + range.getStart(), diag::regex_feature_unavailable, + featureKind.getDescription(Context), platformName, version); + diag.highlightChars(range); + return diag; + }); + } + } + if (auto *CE = dyn_cast(E)) { // Diagnose availability of implicit collection literal initializers. diagnoseDeclRefAvailability(CE->getInitializer(), CE->getSourceRange()); diff --git a/lib/Sema/TypeCheckRegex.cpp b/lib/Sema/TypeCheckRegex.cpp index 41ac56c76e7a8..d8731b2546276 100644 --- a/lib/Sema/TypeCheckRegex.cpp +++ b/lib/Sema/TypeCheckRegex.cpp @@ -18,6 +18,7 @@ #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" +#include "swift/Basic/Defer.h" #include "swift/Bridging/ASTGen.h" using namespace swift; @@ -174,21 +175,59 @@ RegexLiteralPatternInfoRequest::evaluate(Evaluator &eval, auto capturesSize = getCaptureStructureSerializationAllocationSize(regexText.size()); std::vector capturesBuf(capturesSize); + + BridgedRegexLiteralPatternFeatures bridgedFeatures; + SWIFT_DEFER { + swift_ASTGen_freeBridgedRegexLiteralPatternFeatures(bridgedFeatures); + }; + bool hadError = swift_ASTGen_parseRegexLiteral( regexText, /*versionOut=*/&version, /*captureStructureOut=*/capturesBuf.data(), /*captureStructureSize=*/capturesBuf.size(), + /*patternFeaturesOut=*/&bridgedFeatures, /*diagBaseLoc=*/regex->getLoc(), &ctx.Diags); if (hadError) - return {regexText, Type(), /*version*/ 0}; + return {regexText, Type(), /*version*/ 0, /*features*/ {}}; + + SmallVector features; + for (auto &bridgedFeature : bridgedFeatures.unbridged()) + features.push_back(bridgedFeature.unbridged()); assert(version >= 1); auto regexTy = computeRegexLiteralType(regex, capturesBuf); // FIXME: We need to plumb through the 'regexToEmit' result to the caller. // For now, it is the same as the input. - return {/*regexToEmit*/ regexText, regexTy, version}; + return {/*regexToEmit*/ regexText, regexTy, version, + ctx.AllocateCopy(features)}; +#else + llvm_unreachable("Shouldn't have parsed a RegexLiteralExpr"); +#endif +} + +StringRef RegexLiteralFeatureDescriptionRequest::evaluate( + Evaluator &evaluator, RegexLiteralPatternFeatureKind kind, + ASTContext *ctx) const { +#if SWIFT_BUILD_REGEX_PARSER_IN_COMPILER + // The resulting string is allocated in the ASTContext, we can return the + // StringRef directly. + BridgedStringRef str; + swift_ASTGen_getDescriptionForRegexPatternFeature(kind, *ctx, &str); + return str.unbridged(); +#else + llvm_unreachable("Shouldn't have parsed a RegexLiteralExpr"); +#endif +} + +AvailabilityRange RegexLiteralFeatureAvailabilityRequest::evaluate( + Evaluator &evaluator, RegexLiteralPatternFeatureKind kind, + ASTContext *ctx) const { +#if SWIFT_BUILD_REGEX_PARSER_IN_COMPILER + BridgedSwiftVersion version; + swift_ASTGen_getSwiftVersionForRegexPatternFeature(kind, &version); + return ctx->getSwiftAvailability(version.getMajor(), version.getMinor()); #else llvm_unreachable("Shouldn't have parsed a RegexLiteralExpr"); #endif