Skip to content

Commit dfe6fd9

Browse files
authored
Merge pull request #62629 from DougGregor/new-parser-diagnostics
Experimentally emit diagnostics from the new Swift parser
2 parents 90dcfbc + 4ef35c5 commit dfe6fd9

File tree

11 files changed

+126
-83
lines changed

11 files changed

+126
-83
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,12 +1964,6 @@ ERROR(attr_requires_concurrency, none,
19641964
ERROR(associatedtype_cannot_be_variadic,none,
19651965
"associated types cannot be variadic", ())
19661966

1967-
//------------------------------------------------------------------------------
1968-
// MARK: Consistency diagnostics
1969-
//------------------------------------------------------------------------------
1970-
ERROR(new_parser_failure, none,
1971-
"new parser has failed consistency checking; please see errors above", ())
1972-
19731967
//------------------------------------------------------------------------------
19741968
// MARK: syntax parsing diagnostics
19751969
//------------------------------------------------------------------------------
@@ -2021,6 +2015,9 @@ ERROR(macro_expansion_decl_expected_macro_identifier,none,
20212015

20222016
ERROR(parser_round_trip_error,none,
20232017
"source file did not round-trip through the Swift Swift parser", ())
2018+
ERROR(parser_new_parser_errors,none,
2019+
"Swift Swift parser generated errors for code that C++ parser accepted",
2020+
())
20242021

20252022
#define UNDEFINE_DIAGNOSTIC_MACROS
20262023
#include "DefineDiagnosticMacros.h"

include/swift/Basic/Features.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@ EXPERIMENTAL_FEATURE(ParserRoundTrip, false)
138138
/// Swift parser.
139139
EXPERIMENTAL_FEATURE(ParserValidation, false)
140140

141-
/// Whether to fold sequence expressions in the syntax tree produced by the
142-
/// Swift Swift parser.
143-
EXPERIMENTAL_FEATURE(ParserSequenceFolding, false)
141+
/// Whether to emit diagnostics from the new parser first, and only emit
142+
/// diagnostics from the existing parser when there are none from the new
143+
/// parser.
144+
EXPERIMENTAL_FEATURE(ParserDiagnostics, false)
144145

145146
/// Enables implicit some while also enabling existential `any`
146147
EXPERIMENTAL_FEATURE(ImplicitSome, false)

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2974,7 +2974,7 @@ static bool usesFeatureParserValidation(Decl *decl) {
29742974
return false;
29752975
}
29762976

2977-
static bool usesFeatureParserSequenceFolding(Decl *decl) {
2977+
static bool usesFeatureParserDiagnostics(Decl *decl) {
29782978
return false;
29792979
}
29802980

lib/ASTGen/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ if (SWIFT_SWIFT_PARSER)
7676
SwiftOperators
7777
SwiftSyntaxBuilder
7878
_SwiftSyntaxMacros
79-
SwiftCompilerSupport
8079
)
8180

8281
# Compute the list of SwiftSyntax targets

lib/ASTGen/Sources/ASTGen/Diagnostics.swift

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,32 +91,34 @@ func emitDiagnostic(
9191
diagnostic: Diagnostic,
9292
messageSuffix: String? = nil
9393
) {
94-
// Collect all of the Fix-It changes based on their Fix-It ID.
95-
var fixItChangesByID: [MessageID : [FixIt.Change]] = [:]
96-
for fixIt in diagnostic.fixIts {
97-
fixItChangesByID[fixIt.message.fixItID, default: []]
98-
.append(contentsOf: fixIt.changes.changes)
99-
}
100-
10194
// Emit the main diagnostic
10295
emitDiagnosticParts(
10396
diagEnginePtr: diagEnginePtr,
10497
sourceFileBuffer: sourceFileBuffer,
10598
message: diagnostic.diagMessage.message + (messageSuffix ?? ""),
10699
severity: diagnostic.diagMessage.severity,
107100
position: diagnostic.position,
108-
highlights: diagnostic.highlights,
109-
fixItChanges: fixItChangesByID[diagnostic.diagnosticID] ?? []
101+
highlights: diagnostic.highlights
110102
)
111103

104+
// Emit Fix-Its.
105+
for fixIt in diagnostic.fixIts {
106+
emitDiagnosticParts(
107+
diagEnginePtr: diagEnginePtr,
108+
sourceFileBuffer: sourceFileBuffer,
109+
message: fixIt.message.message,
110+
severity: .note, position: diagnostic.position,
111+
fixItChanges: fixIt.changes.changes
112+
)
113+
}
114+
112115
// Emit any notes as follow-ons.
113116
for note in diagnostic.notes {
114117
emitDiagnosticParts(
115118
diagEnginePtr: diagEnginePtr,
116119
sourceFileBuffer: sourceFileBuffer,
117120
message: note.message,
118-
severity: .note, position: note.position,
119-
fixItChanges: fixItChangesByID[note.noteMessage.fixItID] ?? []
121+
severity: .note, position: note.position
120122
)
121123
}
122124
}

lib/ASTGen/Sources/ASTGen/SourceFile.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import SwiftParser
22
import SwiftSyntax
3+
import SwiftParserDiagnostics
34

45
/// Describes a source file that has been "exported" to the C++ part of the
56
/// compiler, with enough information to interface with the C++ layer.
@@ -59,3 +60,49 @@ public func roundTripCheck(
5960
return sf.syntax.syntaxTextBytes.elementsEqual(sf.buffer) ? 0 : 1
6061
}
6162
}
63+
64+
extension Syntax {
65+
/// Whether this syntax node is or is enclosed within a #if.
66+
fileprivate var isInIfConfig: Bool {
67+
if self.is(IfConfigDeclSyntax.self) {
68+
return true
69+
}
70+
71+
return parent?.isInIfConfig ?? false
72+
}
73+
}
74+
75+
/// Emit diagnostics within the given source file.
76+
@_cdecl("swift_ASTGen_emitParserDiagnostics")
77+
public func emitParserDiagnostics(
78+
diagEnginePtr: UnsafeMutablePointer<UInt8>,
79+
sourceFilePtr: UnsafeMutablePointer<UInt8>
80+
) -> CInt {
81+
return sourceFilePtr.withMemoryRebound(
82+
to: ExportedSourceFile.self, capacity: 1
83+
) { sourceFile in
84+
var anyDiags = false
85+
86+
let diags = ParseDiagnosticsGenerator.diagnostics(
87+
for: sourceFile.pointee.syntax
88+
)
89+
for diag in diags {
90+
// Skip over diagnostics within #if, because we don't know whether
91+
// we are in an active region or not.
92+
// FIXME: This heuristic could be improved.
93+
if diag.node.isInIfConfig {
94+
continue
95+
}
96+
97+
emitDiagnostic(
98+
diagEnginePtr: diagEnginePtr,
99+
sourceFileBuffer: UnsafeMutableBufferPointer(
100+
mutating: sourceFile.pointee.buffer),
101+
diagnostic: diag
102+
)
103+
anyDiags = true
104+
}
105+
106+
return anyDiags ? 1 : 0
107+
}
108+
}

lib/Parse/CMakeLists.txt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ if (SWIFT_SWIFT_PARSER)
3333
#
3434
# target_link_libraries(swiftParse
3535
# PRIVATE
36-
# SwiftSyntax::SwiftCompilerSupport
36+
# SwiftSyntax::SwiftParser
3737
# ...
3838
# )
3939
target_link_libraries(swiftParse
@@ -46,7 +46,6 @@ if (SWIFT_SWIFT_PARSER)
4646
SwiftSyntax::SwiftOperators
4747
SwiftSyntax::SwiftSyntaxBuilder
4848
SwiftSyntax::_SwiftSyntaxMacros
49-
SwiftSyntax::SwiftCompilerSupport
5049
$<TARGET_OBJECTS:swiftASTGen>
5150
)
5251

@@ -59,15 +58,9 @@ if (SWIFT_SWIFT_PARSER)
5958
SwiftSyntax::SwiftOperators
6059
SwiftSyntax::SwiftSyntaxBuilder
6160
SwiftSyntax::_SwiftSyntaxMacros
62-
SwiftSyntax::SwiftCompilerSupport
6361
swiftASTGen
6462
)
6563

66-
target_include_directories(swiftParse
67-
PRIVATE
68-
${CMAKE_CURRENT_SOURCE_DIR}/../../../swift-syntax/Sources/SwiftCompilerSupport
69-
)
70-
7164
target_compile_definitions(swiftParse
7265
PRIVATE
7366
SWIFT_SWIFT_PARSER

lib/Parse/ParseDecl.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ extern "C" void swift_ASTGen_destroySourceFile(void *sourceFile);
182182
/// round-trip succeeded, non-zero otherwise.
183183
extern "C" int swift_ASTGen_roundTripCheck(void *sourceFile);
184184

185+
/// Emit parser diagnostics for given source file.. Returns non-zero if any
186+
/// diagnostics were emitted.
187+
extern "C" int swift_ASTGen_emitParserDiagnostics(
188+
void *diagEngine, void *sourceFile
189+
);
185190

186191
// Build AST nodes for the top-level entities in the syntax.
187192
extern "C" void swift_ASTGen_buildTopLevelASTNodes(void *sourceFile,
@@ -200,9 +205,12 @@ extern "C" void swift_ASTGen_buildTopLevelASTNodes(void *sourceFile,
200205
/// \endverbatim
201206
void Parser::parseTopLevelItems(SmallVectorImpl<ASTNode> &items) {
202207
#if SWIFT_SWIFT_PARSER
208+
Optional<DiagnosticTransaction> existingParsingTransaction;
203209
if ((Context.LangOpts.hasFeature(Feature::Macros) ||
204210
Context.LangOpts.hasFeature(Feature::BuiltinMacros) ||
205211
Context.LangOpts.hasFeature(Feature::ParserRoundTrip) ||
212+
Context.LangOpts.hasFeature(Feature::ParserDiagnostics) ||
213+
Context.LangOpts.hasFeature(Feature::ParserValidation) ||
206214
Context.LangOpts.hasFeature(Feature::ParserASTGen)) &&
207215
!SourceMgr.hasIDEInspectionTargetBuffer() &&
208216
SF.Kind != SourceFileKind::SIL) {
@@ -219,6 +227,18 @@ void Parser::parseTopLevelItems(SmallVectorImpl<ASTNode> &items) {
219227
swift_ASTGen_destroySourceFile(exportedSourceFile);
220228
});
221229

230+
// If we're supposed to emit diagnostics from the parser, do so now.
231+
if ((Context.LangOpts.hasFeature(Feature::ParserDiagnostics) ||
232+
Context.LangOpts.hasFeature(Feature::ParserASTGen)) &&
233+
swift_ASTGen_emitParserDiagnostics(
234+
&Context.Diags, SF.exportedSourceFile) &&
235+
Context.Diags.hadAnyError() &&
236+
!Context.LangOpts.hasFeature(Feature::ParserASTGen)) {
237+
// Errors were emitted, and we're still using the C++ parser, so
238+
// disable diagnostics from the C++ parser.
239+
existingParsingTransaction.emplace(Context.Diags);
240+
}
241+
222242
// If we want to do ASTGen, do so now.
223243
if (Context.LangOpts.hasFeature(Feature::ParserASTGen)) {
224244
swift_ASTGen_buildTopLevelASTNodes(
@@ -281,16 +301,31 @@ void Parser::parseTopLevelItems(SmallVectorImpl<ASTNode> &items) {
281301
}
282302

283303
#if SWIFT_SWIFT_PARSER
284-
// Perform round-trip checking.
285-
if (Context.LangOpts.hasFeature(Feature::ParserRoundTrip) &&
304+
if (existingParsingTransaction)
305+
existingParsingTransaction->abort();
306+
307+
// Perform round-trip and/or validation checking.
308+
if ((Context.LangOpts.hasFeature(Feature::ParserRoundTrip) ||
309+
Context.LangOpts.hasFeature(Feature::ParserValidation)) &&
286310
SF.exportedSourceFile &&
287-
!L->lexingCutOffOffset() &&
288-
swift_ASTGen_roundTripCheck(SF.exportedSourceFile)) {
289-
SourceLoc loc;
290-
if (auto bufferID = SF.getBufferID()) {
291-
loc = Context.SourceMgr.getLocForBufferStart(*bufferID);
311+
!L->lexingCutOffOffset()) {
312+
if (Context.LangOpts.hasFeature(Feature::ParserRoundTrip) &&
313+
swift_ASTGen_roundTripCheck(SF.exportedSourceFile)) {
314+
SourceLoc loc;
315+
if (auto bufferID = SF.getBufferID()) {
316+
loc = Context.SourceMgr.getLocForBufferStart(*bufferID);
317+
}
318+
diagnose(loc, diag::parser_round_trip_error);
319+
} else if (Context.LangOpts.hasFeature(Feature::ParserValidation) &&
320+
!Context.Diags.hadAnyError() &&
321+
swift_ASTGen_emitParserDiagnostics(
322+
&Context.Diags, SF.exportedSourceFile)) {
323+
SourceLoc loc;
324+
if (auto bufferID = SF.getBufferID()) {
325+
loc = Context.SourceMgr.getLocForBufferStart(*bufferID);
326+
}
327+
diagnose(loc, diag::parser_new_parser_errors);
292328
}
293-
diagnose(loc, diag::parser_round_trip_error);
294329
}
295330
#endif
296331
}

lib/Parse/ParseRequests.cpp

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
#include "swift/Parse/Parser.h"
2424
#include "swift/Subsystems.h"
2525

26-
#if SWIFT_SWIFT_PARSER
27-
#include "SwiftCompilerSupport.h"
28-
#endif
29-
3026
using namespace swift;
3127

3228
namespace swift {
@@ -175,44 +171,6 @@ SourceFileParsingResult ParseSourceFileRequest::evaluate(Evaluator &evaluator,
175171
if (auto tokens = parser.takeTokenReceiver()->finalize())
176172
tokensRef = ctx.AllocateCopy(*tokens);
177173

178-
#if SWIFT_SWIFT_PARSER
179-
if (ctx.LangOpts.hasFeature(Feature::ParserValidation) &&
180-
ctx.SourceMgr.getIDEInspectionTargetBufferID() != bufferID &&
181-
SF->Kind != SourceFileKind::SIL) {
182-
auto bufferRange = ctx.SourceMgr.getRangeForBuffer(*bufferID);
183-
unsigned int flags = 0;
184-
185-
if (!ctx.Diags.hadAnyError() &&
186-
ctx.LangOpts.hasFeature(Feature::ParserValidation))
187-
flags |= SCC_ParseDiagnostics;
188-
189-
if (ctx.LangOpts.hasFeature(Feature::ParserSequenceFolding) &&
190-
!parser.L->lexingCutOffOffset())
191-
flags |= SCC_FoldSequences;
192-
193-
if (flags) {
194-
SourceLoc startLoc =
195-
parser.SourceMgr.getLocForBufferStart(parser.L->getBufferID());
196-
struct ParserContext {
197-
SourceLoc startLoc;
198-
DiagnosticEngine *engine;
199-
} context{startLoc, &parser.Diags};
200-
int roundTripResult = swift_parser_consistencyCheck(
201-
bufferRange.str().data(), bufferRange.getByteLength(),
202-
SF->getFilename().str().c_str(), flags, static_cast<void *>(&context),
203-
[](ptrdiff_t off, const char *text, void *ctx) {
204-
auto *context = static_cast<ParserContext *>(ctx);
205-
SourceLoc loc = context->startLoc.getAdvancedLoc(off);
206-
context->engine->diagnose(loc, diag::foreign_diagnostic,
207-
StringRef(text));
208-
});
209-
210-
if (roundTripResult)
211-
ctx.Diags.diagnose(SourceLoc(), diag::new_parser_failure);
212-
}
213-
}
214-
#endif
215-
216174
return SourceFileParsingResult{ctx.AllocateCopy(items), tokensRef,
217175
parser.CurrentTokenHash};
218176
}

test/Macros/macro_expand.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ struct OnlyAdds {
5757
func testAddBlocker(a: Int, b: Int, c: Int, oa: OnlyAdds) {
5858
_ = #addBlocker(a * b * c)
5959
#if TEST_DIAGNOSTICS
60-
_ = #addBlocker(a + b * c) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}}{{21-22=-}}
61-
_ = #addBlocker(oa + oa) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}}{{22-23=-}}
62-
// expected-note@-1{{in expansion of macro 'addBlocker' here}}
60+
_ = #addBlocker(a + b * c) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}}
61+
// expected-note@-1{{use '-'}}{{21-22=-}}
62+
_ = #addBlocker(oa + oa) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}}
63+
// expected-note@-1{{in expansion of macro 'addBlocker' here}}
64+
// expected-note@-2{{use '-'}}{{22-23=-}}
6365
#endif
6466
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature ParserDiagnostics
2+
3+
// FIXME: Swift parser is not enabled on Linux CI yet.
4+
// REQUIRES: OS=macosx
5+
// REQUIRES: asserts
6+
7+
_ = [(Int) -> async throws Int]()
8+
// expected-error@-1{{'async throws' may only occur before '->'}}
9+
// expected-note@-2{{move 'async throws' in front of '->'}}{{15-21=}} {{21-28=}} {{20-21= }} {{12-12=async }} {{12-12=throws }}

0 commit comments

Comments
 (0)