Skip to content

Commit 9d4a786

Browse files
committed
[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.
1 parent e07fda5 commit 9d4a786

16 files changed

+383
-8
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
3030

31+
namespace llvm {
32+
template<typename T> class ArrayRef;
33+
}
34+
3135
namespace swift {
3236
class Argument;
3337
class ASTContext;
@@ -42,6 +46,8 @@ class Identifier;
4246
class IfConfigClauseRangeInfo;
4347
struct LabeledStmtInfo;
4448
class ProtocolConformanceRef;
49+
class RegexLiteralPatternFeature;
50+
class RegexLiteralPatternFeatureKind;
4551
class Type;
4652
class CanType;
4753
class TypeBase;
@@ -1351,6 +1357,68 @@ BridgedPrefixUnaryExpr
13511357
BridgedPrefixUnaryExpr_createParsed(BridgedASTContext cContext,
13521358
BridgedExpr oper, BridgedExpr operand);
13531359

1360+
class BridgedRegexLiteralPatternFeatureKind final {
1361+
unsigned RawValue;
1362+
1363+
public:
1364+
BRIDGED_INLINE
1365+
SWIFT_NAME("init(rawValue:)")
1366+
BridgedRegexLiteralPatternFeatureKind(SwiftInt rawValue);
1367+
1368+
using UnbridgedTy = swift::RegexLiteralPatternFeatureKind;
1369+
1370+
BRIDGED_INLINE
1371+
BridgedRegexLiteralPatternFeatureKind(UnbridgedTy kind);
1372+
1373+
BRIDGED_INLINE
1374+
UnbridgedTy unbridged() const;
1375+
};
1376+
1377+
class BridgedRegexLiteralPatternFeature final {
1378+
BridgedCharSourceRange Range;
1379+
BridgedRegexLiteralPatternFeatureKind Kind;
1380+
1381+
public:
1382+
SWIFT_NAME("init(kind:at:)")
1383+
BridgedRegexLiteralPatternFeature(BridgedRegexLiteralPatternFeatureKind kind,
1384+
BridgedCharSourceRange range)
1385+
: Range(range), Kind(kind) {}
1386+
1387+
using UnbridgedTy = swift::RegexLiteralPatternFeature;
1388+
1389+
BRIDGED_INLINE
1390+
BridgedRegexLiteralPatternFeature(UnbridgedTy feature);
1391+
1392+
BRIDGED_INLINE
1393+
UnbridgedTy unbridged() const;
1394+
};
1395+
1396+
class BridgedRegexLiteralPatternFeatures final {
1397+
BridgedRegexLiteralPatternFeature *_Nullable Data;
1398+
SwiftInt Count;
1399+
1400+
public:
1401+
BridgedRegexLiteralPatternFeatures() : Data(nullptr), Count(0) {}
1402+
1403+
SWIFT_NAME("init(baseAddress:count:)")
1404+
BridgedRegexLiteralPatternFeatures(
1405+
BridgedRegexLiteralPatternFeature *_Nullable data, SwiftInt count)
1406+
: Data(data), Count(count) {}
1407+
1408+
using UnbridgedTy = llvm::ArrayRef<BridgedRegexLiteralPatternFeature>;
1409+
1410+
BRIDGED_INLINE
1411+
UnbridgedTy unbridged() const;
1412+
1413+
SWIFT_IMPORT_UNSAFE
1414+
BridgedRegexLiteralPatternFeature *_Nullable getData() const {
1415+
return Data;
1416+
}
1417+
SwiftInt getCount() const {
1418+
return Count;
1419+
}
1420+
};
1421+
13541422
SWIFT_NAME("BridgedRegexLiteralExpr.createParsed(_:loc:regexText:)")
13551423
BridgedRegexLiteralExpr
13561424
BridgedRegexLiteralExpr_createParsed(BridgedASTContext cContext,

include/swift/AST/ASTBridgingImpl.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
#include "swift/AST/ASTContext.h"
1717
#include "swift/AST/ArgumentList.h"
1818
#include "swift/AST/Decl.h"
19+
#include "swift/AST/Expr.h"
1920
#include "swift/AST/IfConfigClauseRangeInfo.h"
2021
#include "swift/AST/Stmt.h"
2122
#include "swift/AST/ProtocolConformance.h"
2223
#include "swift/AST/ProtocolConformanceRef.h"
24+
#include "swift/Basic/Assertions.h"
2325

2426
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
2527

@@ -379,6 +381,40 @@ swift::IfConfigClauseRangeInfo BridgedIfConfigClauseRangeInfo::unbridged() const
379381
clauseKind);
380382
}
381383

384+
//===----------------------------------------------------------------------===//
385+
// MARK: BridgedRegexLiteralPatternFeature
386+
//===----------------------------------------------------------------------===//
387+
388+
BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind(
389+
SwiftInt rawValue)
390+
: RawValue(rawValue) {
391+
ASSERT(rawValue >= 0);
392+
ASSERT(rawValue == RawValue);
393+
}
394+
395+
BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind(
396+
UnbridgedTy kind)
397+
: RawValue(kind.getRawValue()) {}
398+
399+
BridgedRegexLiteralPatternFeatureKind::UnbridgedTy
400+
BridgedRegexLiteralPatternFeatureKind::unbridged() const {
401+
return UnbridgedTy(RawValue);
402+
}
403+
404+
BridgedRegexLiteralPatternFeature::BridgedRegexLiteralPatternFeature(
405+
UnbridgedTy feature)
406+
: Range(feature.getRange()), Kind(feature.getKind()) {}
407+
408+
BridgedRegexLiteralPatternFeature::UnbridgedTy
409+
BridgedRegexLiteralPatternFeature::unbridged() const {
410+
return UnbridgedTy(Kind.unbridged(), Range.unbridged());
411+
}
412+
413+
BridgedRegexLiteralPatternFeatures::UnbridgedTy
414+
BridgedRegexLiteralPatternFeatures::unbridged() const {
415+
return UnbridgedTy(Data, Count);
416+
}
417+
382418
//===----------------------------------------------------------------------===//
383419
// MARK: BridgedStmtConditionElement
384420
//===----------------------------------------------------------------------===//

include/swift/AST/DiagnosticEngine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,9 @@ namespace swift {
755755
/// Add a character-based range to the currently-active diagnostic.
756756
InFlightDiagnostic &highlightChars(SourceLoc Start, SourceLoc End);
757757

758+
/// Add a character-based range to the currently-active diagnostic.
759+
InFlightDiagnostic &highlightChars(CharSourceRange Range);
760+
758761
static const char *fixItStringFor(const FixItID id);
759762

760763
/// Get the best location where an 'import' fixit might be offered.

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5962,6 +5962,10 @@ ERROR(regex_capture_types_failed_to_decode,none,
59625962
"failed to decode capture types for regular expression literal; this may "
59635963
"be a compiler bug", ())
59645964

5965+
ERROR(regex_feature_unavailable, none,
5966+
"%0 is only available in %1 %2 or newer",
5967+
(StringRef, StringRef, llvm::VersionTuple))
5968+
59655969
ERROR(must_import_regex_builder_module,none,
59665970
"regex builder requires the 'RegexBuilder' module be imported'", ())
59675971

include/swift/AST/Expr.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,50 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
992992
}
993993
};
994994

995+
/// The opaque kind of a RegexLiteralExpr feature, which should only be
996+
/// interpreted by the compiler's regex parsing library.
997+
class RegexLiteralPatternFeatureKind final {
998+
unsigned RawValue;
999+
1000+
public:
1001+
RegexLiteralPatternFeatureKind(unsigned rawValue) : RawValue(rawValue) {}
1002+
1003+
unsigned getRawValue() const { return RawValue; }
1004+
1005+
AvailabilityRange getAvailability(ASTContext &ctx) const;
1006+
StringRef getDescription(ASTContext &ctx) const;
1007+
1008+
friend llvm::hash_code
1009+
hash_value(const RegexLiteralPatternFeatureKind &kind) {
1010+
return llvm::hash_value(kind.getRawValue());
1011+
}
1012+
1013+
friend bool operator==(const RegexLiteralPatternFeatureKind &lhs,
1014+
const RegexLiteralPatternFeatureKind &rhs) {
1015+
return lhs.getRawValue() == rhs.getRawValue();
1016+
}
1017+
1018+
friend bool operator!=(const RegexLiteralPatternFeatureKind &lhs,
1019+
const RegexLiteralPatternFeatureKind &rhs) {
1020+
return !(lhs == rhs);
1021+
}
1022+
};
1023+
1024+
/// A specific feature used in a RegexLiteralExpr, needed for availability
1025+
/// diagnostics.
1026+
class RegexLiteralPatternFeature final {
1027+
RegexLiteralPatternFeatureKind Kind;
1028+
CharSourceRange Range;
1029+
1030+
public:
1031+
RegexLiteralPatternFeature(RegexLiteralPatternFeatureKind kind,
1032+
CharSourceRange range)
1033+
: Kind(kind), Range(range) {}
1034+
1035+
RegexLiteralPatternFeatureKind getKind() const { return Kind; }
1036+
CharSourceRange getRange() const { return Range; }
1037+
};
1038+
9951039
/// A regular expression literal e.g '(a|c)*'.
9961040
class RegexLiteralExpr : public LiteralExpr {
9971041
ASTContext *Ctx;
@@ -1021,6 +1065,9 @@ class RegexLiteralExpr : public LiteralExpr {
10211065
/// Retrieve the version of the regex string.
10221066
unsigned getVersion() const;
10231067

1068+
/// Retrieve any features used in the regex pattern.
1069+
ArrayRef<RegexLiteralPatternFeature> getPatternFeatures() const;
1070+
10241071
SourceRange getSourceRange() const { return Loc; }
10251072

10261073
static bool classof(const Expr *E) {

include/swift/AST/TypeCheckRequests.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5110,6 +5110,7 @@ struct RegexLiteralPatternInfo {
51105110
StringRef RegexToEmit;
51115111
Type RegexType;
51125112
size_t Version;
5113+
ArrayRef<RegexLiteralPatternFeature> Features;
51135114
};
51145115

51155116
/// Parses the regex pattern for a given regex literal using the
@@ -5131,6 +5132,47 @@ class RegexLiteralPatternInfoRequest
51315132
bool isCached() const { return true; }
51325133
};
51335134

5135+
/// The description for a given regex pattern feature. This is cached since
5136+
/// the resulting string is allocated in the ASTContext for ease of bridging.
5137+
class RegexLiteralFeatureDescriptionRequest
5138+
: public SimpleRequest<RegexLiteralFeatureDescriptionRequest,
5139+
StringRef(RegexLiteralPatternFeatureKind,
5140+
ASTContext *),
5141+
RequestFlags::Cached> {
5142+
public:
5143+
using SimpleRequest::SimpleRequest;
5144+
5145+
private:
5146+
friend SimpleRequest;
5147+
5148+
StringRef evaluate(Evaluator &evaluator, RegexLiteralPatternFeatureKind kind,
5149+
ASTContext *ctx) const;
5150+
5151+
public:
5152+
bool isCached() const { return true; }
5153+
};
5154+
5155+
/// The availability range for a given regex pattern feature.
5156+
class RegexLiteralFeatureAvailabilityRequest
5157+
: public SimpleRequest<RegexLiteralFeatureAvailabilityRequest,
5158+
AvailabilityRange(RegexLiteralPatternFeatureKind,
5159+
ASTContext *),
5160+
RequestFlags::Uncached> {
5161+
public:
5162+
using SimpleRequest::SimpleRequest;
5163+
5164+
private:
5165+
friend SimpleRequest;
5166+
5167+
AvailabilityRange evaluate(Evaluator &evaluator,
5168+
RegexLiteralPatternFeatureKind kind,
5169+
ASTContext *ctx) const;
5170+
};
5171+
5172+
void simple_display(llvm::raw_ostream &out,
5173+
RegexLiteralPatternFeatureKind kind);
5174+
SourceLoc extractNearestSourceLoc(RegexLiteralPatternFeatureKind kind);
5175+
51345176
class IsUnsafeRequest
51355177
: public SimpleRequest<IsUnsafeRequest,
51365178
bool(Decl *decl),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,12 @@ SWIFT_REQUEST(TypeChecker, SuppressesConformanceRequest,
595595
SWIFT_REQUEST(TypeChecker, RegexLiteralPatternInfoRequest,
596596
RegexLiteralPatternInfo(const RegexLiteralExpr *),
597597
Cached, NoLocationInfo)
598+
SWIFT_REQUEST(TypeChecker, RegexLiteralFeatureDescriptionRequest,
599+
StringRef(RegexLiteralPatternFeatureKind, ASTContext *),
600+
Cached, NoLocationInfo)
601+
SWIFT_REQUEST(TypeChecker, RegexLiteralFeatureAvailabilityRequest,
602+
AvailabilityRange(RegexLiteralPatternFeatureKind, ASTContext *),
603+
Uncached, NoLocationInfo)
598604

599605
SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
600606
CaptureInfo(AbstractFunctionDecl *),

include/swift/Basic/BasicBridging.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,25 @@ class BridgedCharSourceRangeVector {
413413
#endif
414414
};
415415

416+
//===----------------------------------------------------------------------===//
417+
// MARK: BridgedSwiftVersion
418+
//===----------------------------------------------------------------------===//
419+
420+
class BridgedSwiftVersion {
421+
unsigned Major;
422+
unsigned Minor;
423+
424+
public:
425+
BridgedSwiftVersion() : Major(0), Minor(0) {}
426+
427+
BRIDGED_INLINE
428+
SWIFT_NAME("init(major:minor:)")
429+
BridgedSwiftVersion(SwiftInt major, SwiftInt minor);
430+
431+
unsigned getMajor() const { return Major; }
432+
unsigned getMinor() const { return Minor; }
433+
};
434+
416435
SWIFT_END_NULLABILITY_ANNOTATIONS
417436

418437
#ifndef PURE_BRIDGING_MODE

include/swift/Basic/BasicBridgingImpl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#ifndef SWIFT_BASIC_BASICBRIDGINGIMPL_H
1414
#define SWIFT_BASIC_BASICBRIDGINGIMPL_H
1515

16+
#include "swift/Basic/Assertions.h"
17+
1618
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
1719

1820
//===----------------------------------------------------------------------===//
@@ -123,6 +125,16 @@ swift::CharSourceRange BridgedCharSourceRange::unbridged() const {
123125
return swift::CharSourceRange(Start.unbridged(), ByteLength);
124126
}
125127

128+
//===----------------------------------------------------------------------===//
129+
// MARK: BridgedSwiftVersion
130+
//===----------------------------------------------------------------------===//
131+
132+
BridgedSwiftVersion::BridgedSwiftVersion(SwiftInt major, SwiftInt minor)
133+
: Major(major), Minor(minor) {
134+
ASSERT(major >= 0 && minor >= 0);
135+
ASSERT(major == Major && minor == Minor);
136+
}
137+
126138
SWIFT_END_NULLABILITY_ANNOTATIONS
127139

128140
#endif // SWIFT_BASIC_BASICBRIDGINGIMPL_H

include/swift/Bridging/ASTGen.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,22 @@ bool swift_ASTGen_lexRegexLiteral(const char *_Nonnull *_Nonnull curPtrPtr,
103103
bool mustBeRegex,
104104
BridgedNullableDiagnosticEngine diagEngine);
105105

106-
bool swift_ASTGen_parseRegexLiteral(BridgedStringRef inputPtr,
107-
size_t *_Nonnull versionOut,
108-
void *_Nonnull UnsafeMutableRawPointer,
109-
size_t captureStructureSize,
110-
BridgedSourceLoc diagLoc,
111-
BridgedDiagnosticEngine diagEngine);
106+
bool swift_ASTGen_parseRegexLiteral(
107+
BridgedStringRef inputPtr, size_t *_Nonnull versionOut,
108+
void *_Nonnull UnsafeMutableRawPointer, size_t captureStructureSize,
109+
BridgedRegexLiteralPatternFeatures *_Nonnull featuresOut,
110+
BridgedSourceLoc diagLoc, BridgedDiagnosticEngine diagEngine);
111+
112+
void swift_ASTGen_freeBridgedRegexLiteralPatternFeatures(
113+
BridgedRegexLiteralPatternFeatures features);
114+
115+
void swift_ASTGen_getSwiftVersionForRegexPatternFeature(
116+
BridgedRegexLiteralPatternFeatureKind kind,
117+
BridgedSwiftVersion *_Nonnull versionOut);
118+
119+
void swift_ASTGen_getDescriptionForRegexPatternFeature(
120+
BridgedRegexLiteralPatternFeatureKind kind, BridgedASTContext astContext,
121+
BridgedStringRef *_Nonnull descriptionOut);
112122

113123
intptr_t swift_ASTGen_configuredRegions(
114124
BridgedASTContext astContext,

lib/AST/DiagnosticEngine.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ InFlightDiagnostic &InFlightDiagnostic::highlightChars(SourceLoc Start,
225225
return *this;
226226
}
227227

228+
InFlightDiagnostic &InFlightDiagnostic::highlightChars(CharSourceRange Range) {
229+
assert(IsActive && "Cannot modify an inactive diagnostic");
230+
if (Engine && Range.getStart().isValid())
231+
Engine->getActiveDiagnostic().addRange(Range);
232+
return *this;
233+
}
234+
228235
/// Add an insertion fix-it to the currently-active diagnostic. The
229236
/// text is inserted immediately *after* the token specified.
230237
///

0 commit comments

Comments
 (0)