Skip to content

Commit 0fb7f8f

Browse files
authored
Merge pull request #64745 from DougGregor/macros-unpack-diagnosticserror-5.9
2 parents 396b537 + 71974f1 commit 0fb7f8f

File tree

3 files changed

+97
-53
lines changed

3 files changed

+97
-53
lines changed

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -310,23 +310,35 @@ func expandFreestandingMacroInProcess(
310310
discriminator: discriminator
311311
)
312312

313+
guard let parentExpansion = macroSyntax.asProtocol(
314+
FreestandingMacroExpansionSyntax.self
315+
) else {
316+
print("not on a macro expansion node: \(macroSyntax.recursiveDescription)")
317+
return nil
318+
}
319+
320+
let macroName = parentExpansion.macro.text
321+
322+
// Make sure we emit all of the diagnostics from the context.
323+
defer {
324+
// Emit diagnostics accumulated in the context.
325+
for diag in context.diagnostics {
326+
sourceManager.diagnose(
327+
diagnostic: diag,
328+
messageSuffix: " (from macro '\(macroName)')"
329+
)
330+
}
331+
332+
context.diagnostics = []
333+
}
334+
313335
let macroPtr = macroPtr.bindMemory(to: ExportedMacro.self, capacity: 1)
314336

315-
let macroName: String
316337
let evaluatedSyntax: Syntax
317338
do {
318339
switch macroPtr.pointee.macro {
319340
// Handle expression macro.
320341
case let exprMacro as ExpressionMacro.Type:
321-
guard let parentExpansion = macroSyntax.asProtocol(
322-
FreestandingMacroExpansionSyntax.self
323-
) else {
324-
print("not on a macro expansion node: \(macroSyntax.recursiveDescription)")
325-
return nil
326-
}
327-
328-
macroName = parentExpansion.macro.text
329-
330342
func expandExpressionMacro<Node: FreestandingMacroExpansionSyntax>(
331343
_ node: Node
332344
) throws -> ExprSyntax {
@@ -346,14 +358,6 @@ func expandFreestandingMacroInProcess(
346358
// Handle declaration macro. The resulting decls are wrapped in a
347359
// `CodeBlockItemListSyntax`.
348360
case let declMacro as DeclarationMacro.Type:
349-
guard let parentExpansion = macroSyntax.asProtocol(
350-
FreestandingMacroExpansionSyntax.self
351-
) else {
352-
print("not on a macro expansion decl: \(macroSyntax.recursiveDescription)")
353-
return nil
354-
}
355-
macroName = parentExpansion.macro.text
356-
357361
func expandDeclarationMacro<Node: FreestandingMacroExpansionSyntax>(
358362
_ node: Node
359363
) throws -> [DeclSyntax] {
@@ -374,25 +378,10 @@ func expandFreestandingMacroInProcess(
374378
return nil
375379
}
376380
} catch {
377-
// Record the error
378-
sourceManager.diagnose(
379-
diagnostic: Diagnostic(
380-
node: macroSyntax,
381-
message: ThrownErrorDiagnostic(message: String(describing: error))
382-
),
383-
messageSuffix: " (from macro '\(macroName)')"
384-
)
381+
context.addDiagnostics(from: error, node: macroSyntax)
385382
return nil
386383
}
387384

388-
// Emit diagnostics accumulated in the context.
389-
for diag in context.diagnostics {
390-
sourceManager.diagnose(
391-
diagnostic: diag,
392-
messageSuffix: " (from macro '\(macroName)')"
393-
)
394-
}
395-
396385
return evaluatedSyntax.trimmedDescription
397386
}
398387

@@ -670,6 +659,20 @@ func expandAttachedMacroInProcess(
670659
)
671660

672661
let macroName = customAttrNode.attributeName.trimmedDescription
662+
663+
// Emit all of the accumulated diagnostics before we exit.
664+
defer {
665+
// Emit diagnostics accumulated in the context.
666+
for diag in context.diagnostics {
667+
sourceManager.diagnose(
668+
diagnostic: diag,
669+
messageSuffix: " (from macro '\(macroName)')"
670+
)
671+
}
672+
673+
context.diagnostics = []
674+
}
675+
673676
var expandedSources: [String]
674677
do {
675678
switch (macro, macroRole) {
@@ -806,27 +809,10 @@ func expandAttachedMacroInProcess(
806809
return nil
807810
}
808811
} catch {
809-
// Record the error
810-
// FIXME: Need to decide where to diagnose the error:
811-
sourceManager.diagnose(
812-
diagnostic: Diagnostic(
813-
node: Syntax(declarationNode),
814-
message: ThrownErrorDiagnostic(message: String(describing: error))
815-
),
816-
messageSuffix: " (from macro '\(macroName)')"
817-
)
818-
812+
context.addDiagnostics(from: error, node: declarationNode)
819813
return nil
820814
}
821815

822-
// Emit diagnostics accumulated in the context.
823-
for diag in context.diagnostics {
824-
sourceManager.diagnose(
825-
diagnostic: diag,
826-
messageSuffix: " (from macro '\(macroName)')"
827-
)
828-
}
829-
830816
return expandedSources
831817
}
832818

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,51 @@ public struct WarningMacro: ExpressionMacro {
316316
}
317317
}
318318

319+
public struct ErrorMacro: ExpressionMacro {
320+
public static func expansion(
321+
of macro: some FreestandingMacroExpansionSyntax,
322+
in context: some MacroExpansionContext
323+
) throws -> ExprSyntax {
324+
guard let firstElement = macro.argumentList.first,
325+
let stringLiteral = firstElement.expression.as(StringLiteralExprSyntax.self),
326+
stringLiteral.segments.count == 1,
327+
case let .stringSegment(messageString)? = stringLiteral.segments.first
328+
else {
329+
let errorNode: Syntax
330+
if let firstElement = macro.argumentList.first {
331+
errorNode = Syntax(firstElement)
332+
} else {
333+
errorNode = Syntax(macro)
334+
}
335+
336+
let messageID = MessageID(domain: "silly", id: "error")
337+
let diag = Diagnostic(
338+
node: errorNode,
339+
message: SimpleDiagnosticMessage(
340+
message: "#myError macro requires a string literal",
341+
diagnosticID: messageID,
342+
severity: .error
343+
)
344+
)
345+
346+
throw DiagnosticsError(diagnostics: [diag])
347+
}
348+
349+
context.diagnose(
350+
Diagnostic(
351+
node: Syntax(macro),
352+
message: SimpleDiagnosticMessage(
353+
message: messageString.content.description,
354+
diagnosticID: MessageID(domain: "test", id: "error"),
355+
severity: .error
356+
)
357+
)
358+
)
359+
360+
return "()"
361+
}
362+
}
363+
319364
public struct PropertyWrapperMacro {}
320365

321366
extension PropertyWrapperMacro: AccessorMacro, Macro {

test/Macros/macro_expand_throwing.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-build-swift -swift-version 5 -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath -swift-version 5
33

44
// Make sure the diagnostic comes through...
5-
// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser
5+
// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS
66

77
// Make sure the diagnostic doesn't crash in SILGen
88
// RUN: not %target-swift-frontend -swift-version 5 -emit-sil -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir %s -module-name MacroUser -o - -g
@@ -12,9 +12,22 @@
1212

1313
@freestanding(expression) macro myWarning(_ message: String) = #externalMacro(module: "MacroDefinition", type: "WarningMacro")
1414

15+
@freestanding(expression) macro myError(_ message: String) = #externalMacro(module: "MacroDefinition", type: "ErrorMacro")
16+
1517
func testThrownError() {
1618
let name = "hello"
1719
#myWarning (name) // expected-error{{#myWarning macro requires a string literal (from macro 'myWarning')}}
1820

1921
#myWarning("experimental features ahead") // expected-warning{{experimental features ahead}}
2022
}
23+
24+
#if TEST_DIAGNOSTICS
25+
func testThrownErrors() {
26+
let name = "hello"
27+
#myError(
28+
name
29+
) // expected-error@-1{{macro requires a string literal (from macro 'myError')}}
30+
31+
#myError("experimental features ahead") // expected-error{{experimental features ahead}}
32+
}
33+
#endif

0 commit comments

Comments
 (0)