Skip to content

Commit f2d9287

Browse files
Merge pull request #4611 from swiftwasm/release/5.7
[pull] swiftwasm-release/5.7 from release/5.7
2 parents a8bf124 + 34c2eb2 commit f2d9287

14 files changed

+388
-42
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===--- SyntaxRegexFallbackLexing.h --------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
namespace swift {
14+
/// SwiftSyntax parsing currently doesn't link against
15+
/// SwiftExperimentalStringProcessing and is thus missing the regex lexing
16+
/// functions defined in it. This registers a fallback regex-lexing function
17+
/// implemented in C++ that is sufficient to generate a valid SwiftSyntax tree.
18+
/// The regex parser registered by this function will accept all regex literals
19+
/// and is not suited for normal compilation.
20+
void registerSyntaxFallbackRegexParser();
21+
} // end namespace swift

lib/IDE/CodeCompletionResultType.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,34 @@ TypeRelation USRBasedTypeContext::ContextualType::typeRelation(
308308

309309
// MARK: - CodeCompletionResultType
310310

311+
/// Returns \c true if \p Ty is the 'Any' type or some type that is sufficiently
312+
/// similar to Any, like the 'Any' metatype or an optional type wrapping 'Any'.
313+
static bool isEssentiallyAnyType(Type Ty) {
314+
while (true) {
315+
if (auto MT = Ty->getAs<AnyMetatypeType>()) {
316+
Ty = MT->getInstanceType();
317+
} else if (auto OT = Ty->getOptionalObjectType()) {
318+
Ty = OT;
319+
} else {
320+
break;
321+
}
322+
}
323+
return Ty->isAny();
324+
}
325+
311326
static TypeRelation calculateTypeRelation(Type Ty, Type ExpectedTy,
312327
const DeclContext &DC) {
313328
if (Ty.isNull() || ExpectedTy.isNull() || Ty->is<ErrorType>() ||
314329
ExpectedTy->is<ErrorType>())
315330
return TypeRelation::Unrelated;
316331

332+
/// Computing type relations to 'Any' is not very enlightning because
333+
/// everything would be convertible to it. If the contextual type is 'Any',
334+
/// just report all type relations as 'Unknown'.
335+
if (isEssentiallyAnyType(ExpectedTy)) {
336+
return TypeRelation::Unknown;
337+
}
338+
317339
// Equality/Conversion of GenericTypeParameterType won't account for
318340
// requirements – ignore them
319341
if (!Ty->hasTypeParameter() && !ExpectedTy->hasTypeParameter()) {

lib/Parse/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ add_swift_host_library(swiftParse STATIC
2424
ParseType.cpp
2525
PersistentParserState.cpp
2626
SyntaxParsingCache.cpp
27-
SyntaxParsingContext.cpp)
27+
SyntaxParsingContext.cpp
28+
SyntaxRegexFallbackLexing.cpp)
2829
_swift_gyb_target_sources(swiftParse PRIVATE
2930
ParsedSyntaxBuilders.cpp.gyb
3031
ParsedSyntaxNodes.cpp.gyb
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
//===--- SyntaxRegexFallbackLexing.cpp ------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Parse/SyntaxRegexFallbackLexing.h"
14+
#include "swift/AST/DiagnosticEngine.h"
15+
#include "swift/AST/DiagnosticsParse.h"
16+
#include "swift/Parse/Lexer.h"
17+
#include "swift/Parse/RegexParserBridging.h"
18+
#include <mutex>
19+
20+
using namespace swift;
21+
22+
template <typename... DiagArgTypes, typename... ArgTypes>
23+
static void diagnose(BridgedOptionalDiagnosticEngine bridgedDiag,
24+
const char *ptr, Diag<DiagArgTypes...> DiagID,
25+
ArgTypes &&...Args) {
26+
if (auto *Diag = static_cast<DiagnosticEngine *>(bridgedDiag.object)) {
27+
Diag->diagnose(SourceLoc(llvm::SMLoc::getFromPointer(ptr)), DiagID,
28+
std::forward<ArgTypes>(Args)...);
29+
}
30+
}
31+
32+
bool syntaxparse_lexRegexLiteral(
33+
const char **InputPtr, const char *BufferEnd, bool MustBeRegex,
34+
BridgedOptionalDiagnosticEngine BridgedDiagEngine) {
35+
36+
const char *Ptr = *InputPtr;
37+
38+
// Count leading '#'.
39+
while (*Ptr == '#') {
40+
++Ptr;
41+
}
42+
if (*Ptr != '/') {
43+
// This wasn't a regex literal.
44+
return true;
45+
}
46+
47+
unsigned customDelimiterLen = Ptr - *InputPtr;
48+
49+
++Ptr;
50+
51+
// If the delimiter allows multi-line, try skipping over any whitespace to a
52+
// newline character. If we can do that, we enter multi-line mode.
53+
bool allowsMultiline = customDelimiterLen != 0;
54+
const char *firstNewline = nullptr;
55+
if (allowsMultiline) {
56+
while (Ptr != BufferEnd) {
57+
switch (*Ptr) {
58+
case ' ':
59+
case '\t':
60+
++Ptr;
61+
continue;
62+
case '\r':
63+
case '\n':
64+
firstNewline = Ptr;
65+
break;
66+
default:
67+
break;
68+
}
69+
break;
70+
}
71+
}
72+
73+
bool isMultilineLiteral = (firstNewline != nullptr);
74+
75+
while (true) {
76+
switch (*Ptr++) {
77+
case '\r':
78+
case '\n':
79+
if (!isMultilineLiteral) {
80+
diagnose(BridgedDiagEngine, Ptr, diag::lex_regex_literal_unterminated);
81+
*InputPtr = Ptr - 1;
82+
return false;
83+
}
84+
break;
85+
case '\\':
86+
if (Ptr != BufferEnd) {
87+
if (!isMultilineLiteral && (*Ptr == '\r' || *Ptr == '\n')) {
88+
diagnose(BridgedDiagEngine, Ptr, diag::lex_regex_literal_unterminated);
89+
*InputPtr = Ptr - 1;
90+
return false;
91+
}
92+
if (validateUTF8CharacterAndAdvance(Ptr, BufferEnd) == ~0U)
93+
diagnose(BridgedDiagEngine, Ptr, diag::lex_invalid_utf8);
94+
}
95+
break;
96+
case '/': {
97+
const char *AfterSlashPos = Ptr;
98+
99+
// Eat '#' up to the open delimeter length.
100+
while (*Ptr == '#' && (Ptr - AfterSlashPos) <= customDelimiterLen) {
101+
++Ptr;
102+
}
103+
104+
if ((Ptr - AfterSlashPos) != customDelimiterLen) {
105+
// '#' count didn't match. Reset the cursor after the '/' and move on.
106+
Ptr = AfterSlashPos;
107+
break;
108+
}
109+
110+
// Found the closing delimiter. Finish.
111+
*InputPtr = Ptr;
112+
return false;
113+
}
114+
case '\0': {
115+
if (Ptr - 1 == BufferEnd) {
116+
// Reached to EOF.
117+
diagnose(BridgedDiagEngine, Ptr - 1, diag::lex_regex_literal_unterminated);
118+
// In multi-line mode, we don't want to skip over what is likely
119+
// otherwise valid Swift code, so resume from the first newline.
120+
*InputPtr = firstNewline ? firstNewline : (Ptr - 1);
121+
return false;
122+
}
123+
124+
// TODO: Warn to match the behavior of String literal lexer?
125+
// For now, just ignore them.
126+
break;
127+
}
128+
default: {
129+
--Ptr;
130+
if (validateUTF8CharacterAndAdvance(Ptr, BufferEnd) == ~0U)
131+
diagnose(BridgedDiagEngine, Ptr, diag::lex_invalid_utf8);
132+
break;
133+
}
134+
}
135+
}
136+
}
137+
138+
bool syntaxparse_parseRegexLiteral(const char *InputPtr, unsigned *VersionOut,
139+
void *CaptureStructureOut,
140+
unsigned CaptureStructureSize,
141+
BridgedSourceLoc DiagnosticBaseLoc,
142+
BridgedDiagnosticEngine BridgedDiagEngine) {
143+
*VersionOut = ~0u;
144+
return /*hasError*/ false;
145+
}
146+
147+
void swift::registerSyntaxFallbackRegexParser() {
148+
static std::once_flag flag;
149+
std::call_once(flag, []() {
150+
Parser_registerRegexLiteralLexingFn(syntaxparse_lexRegexLiteral);
151+
Parser_registerRegexLiteralParsingFn(syntaxparse_parseRegexLiteral);
152+
});
153+
}

test/IDE/complete_at_top_level.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ var stringInterp = "\(#^STRING_INTERP_3?check=STRING_INTERP^#)"
328328
_ = "" + "\(#^STRING_INTERP_4?check=STRING_INTERP^#)" + ""
329329
// STRING_INTERP: Begin completions
330330
// STRING_INTERP-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/IsSystem: ['(']{#(value): T#}[')'][#Void#];
331-
// STRING_INTERP-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: FooStruct[#FooStruct#]; name=FooStruct
331+
// STRING_INTERP-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]; name=FooStruct
332332
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Invalid]: fooFunc1()[#Void#];
333333
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule: optStr()[#String?#];
334334
// STRING_INTERP-DAG: Decl[GlobalVar]/Local: fooObject[#FooStruct#];

test/IDE/complete_type_any.swift

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_FUNC_PARAM | %FileCheck %s -check-prefix=ANY_IN_FUNC_PARAM
2-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_VAR_TYPE | %FileCheck %s -check-prefix=ANY_IN_VAR_TYPE
3-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_METATYPE_VARIABLE | %FileCheck %s -check-prefix=ANY_METATYPE_VARIABLE
4-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_METATYPE_MEMBER | %FileCheck %s -check-prefix=ANY_METATYPE_MEMBER
5-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ANY_IN_TYPEALIAS | %FileCheck %s -check-prefix=ANY_IN_TYPEALIAS
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
63

74
func testAnyInParamList(a: #^ANY_IN_FUNC_PARAM^#
85
// ANY_IN_FUNC_PARAM: Begin completions
@@ -31,4 +28,32 @@ typealias A = #^ANY_IN_TYPEALIAS^#
3128
// ANY_IN_TYPEALIAS-DAG: Keyword/None: Any[#Any#]; name=Any
3229
// ANY_IN_TYPEALIAS: End completions
3330

31+
func testRdar64812321() {
32+
func foo<T>(x: T) {}
33+
func foo(x: Any.Type) {}
3434

35+
struct MyStruct {}
36+
let myStruct = MyStruct()
37+
38+
foo(x: #^ANY_RELATIONSHIP^#)
39+
// The MyStruct type should not be preferred over the myStruct instance.
40+
41+
// ANY_RELATIONSHIP: Begin completions
42+
// ANY_RELATIONSHIP-DAG: Decl[LocalVar]/Local: myStruct[#MyStruct#]; name=myStruct
43+
// ANY_RELATIONSHIP-DAG: Decl[Struct]/Local: MyStruct[#MyStruct#]; name=MyStruct
44+
// ANY_RELATIONSHIP: End completions
45+
}
46+
47+
func testRdar84684686() {
48+
func foo(_ x: Any?) {}
49+
50+
struct S {
51+
static func bar(x: Int) -> Int { x }
52+
}
53+
54+
// We should suggest a function call to `bar` here (i.e. `bar(x: <#Int#>)`), not a function reference (i.e. `bar(x:)`)
55+
foo(S.#^ANY_PREFERS_FUNCTION_CALL^#)
56+
// ANY_PREFERS_FUNCTION_CALL: Begin completions
57+
// ANY_PREFERS_FUNCTION_CALL-DAG: Decl[StaticMethod]/CurrNominal: bar({#x: Int#})[#Int#]; name=bar(x:)
58+
// ANY_PREFERS_FUNCTION_CALL: End completions
59+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %swift-syntax-parser-test -dump-diags %s | %FileCheck %s
2+
// CHECK: 7:1 Error: unterminated regex literal
3+
// CHECK: 1 error(s) 0 warnings(s) 0 note(s)
4+
5+
#/
6+
unterminatedLiteral
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %swift-syntax-parser-test -dump-diags %s | %FileCheck %s
2+
// CHECK: 6:21 Error: unterminated regex literal
3+
// CHECK: 1 error(s) 0 warnings(s) 0 note(s)
4+
5+
// IMPORTANT: This file must not contain a trailing newline
6+
/unterminatedLiteral

test/Syntax/round_trip_regex.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %swift-syntax-test -input-source-filename %s -parse-gen -fail-on-parse-error > %t/afterRoundtrip.swift
3+
// RUN: diff -u %s %t/afterRoundtrip.swift
4+
5+
_ = /abc/
6+
_ = #/abc/#
7+
_ = ##/abc/##
8+
9+
func foo<T>(_ x: T...) {}
10+
foo(/abc/, #/abc/#, ##/abc/##)
11+
12+
let arr = [/abc/, #/abc/#, ##/abc/##]
13+
14+
_ = /\w+/.self
15+
_ = #/\w+/#.self
16+
_ = ##/\w+/##.self
17+
18+
_ = /#\/\#\\/
19+
_ = #/#/\/\#\\/#
20+
_ = ##/#|\|\#\\/##
21+
22+
_ = #/
23+
multiline
24+
/#
25+
26+
_ = #/
27+
double
28+
multiline
29+
/#
30+
31+
_ = #/
32+
\
33+
/#
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: not %swift-syntax-test -input-source-filename %s -parse-gen -fail-on-parse-error > %t/afterRoundtrip.swift 2> %t/errors.swift
3+
// RUN: diff -u %s %t/afterRoundtrip.swift
4+
// RUN: cat %t/errors.swift | %FileCheck %s
5+
6+
// Escaping newlines is not supported
7+
_ = /\
8+
/
9+
10+
// CHECK: 7:7: error: unterminated regex literal

0 commit comments

Comments
 (0)