From c78afdc6d15f05ade0c42bdddf098d3b676345f5 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 9 Jun 2023 21:51:26 -0700 Subject: [PATCH 1/3] [Macros] Tighten restriction on non-expression macros not having return types There is no reason to special-case `Void` to permit it. Rather, make this a syntactic rule. Thanks to Alex Hoppen for the suggestion. --- lib/Sema/TypeCheckDeclPrimary.cpp | 5 ++--- test/Macros/attached_macros_diags.swift | 6 +++--- test/Macros/macros_diagnostics.swift | 3 +++ test/Macros/parsing.swift | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 91ed49d6f040f..d707b376d61b6 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2072,11 +2072,10 @@ class DeclChecker : public DeclVisitor { } } - // If the macro has a (non-Void) result type, it must have the freestanding + // If the macro has a result type, it must have the freestanding // expression role. Other roles cannot have result types. if (auto resultTypeRepr = MD->getResultTypeRepr()) { - if (!MD->getMacroRoles().contains(MacroRole::Expression) && - !MD->getResultInterfaceType()->isEqual(Ctx.getVoidType())) { + if (!MD->getMacroRoles().contains(MacroRole::Expression)) { auto resultType = MD->getResultInterfaceType(); Ctx.Diags.diagnose( MD->arrowLoc, diag::macro_result_type_cannot_be_used, resultType) diff --git a/test/Macros/attached_macros_diags.swift b/test/Macros/attached_macros_diags.swift index bc592ed27bd86..636d8deb07476 100644 --- a/test/Macros/attached_macros_diags.swift +++ b/test/Macros/attached_macros_diags.swift @@ -6,17 +6,17 @@ // expected-warning@-1{{external macro implementation type 'MyMacros.Macro1' could not be found for macro 'm1()'}} // expected-note@-2{{'m1()' declared here}} -@attached(accessor) macro m2(_: Int) -> Void = #externalMacro(module: "MyMacros", type: "Macro2") +@attached(accessor) macro m2(_: Int) = #externalMacro(module: "MyMacros", type: "Macro2") // expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}} // expected-note@-2{{candidate has partially matching parameter list (Int)}} // expected-note@-3{{candidate expects value of type 'Int' for parameter #1 (got 'String')}} -@attached(accessor) macro m2(_: Double) -> Void = #externalMacro(module: "MyMacros", type: "Macro2") +@attached(accessor) macro m2(_: Double) = #externalMacro(module: "MyMacros", type: "Macro2") // expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}} // expected-note@-2{{candidate has partially matching parameter list (Double)}} // expected-note@-3{{candidate expects value of type 'Double' for parameter #1 (got 'String')}} -@attached(accessor) macro m3(message: String) -> Void = #externalMacro(module: "MyMacros", type: "Macro3") +@attached(accessor) macro m3(message: String) = #externalMacro(module: "MyMacros", type: "Macro3") // expected-warning@-1{{external macro implementation type 'MyMacros.Macro3' could not be found for macro 'm3(message:)'}} @freestanding(expression) macro stringify(_ value: T) -> (T, String) = #externalMacro(module: "MyMacros", type: "StringifyMacro") diff --git a/test/Macros/macros_diagnostics.swift b/test/Macros/macros_diagnostics.swift index 2f9b00a44716e..21acc484a0b44 100644 --- a/test/Macros/macros_diagnostics.swift +++ b/test/Macros/macros_diagnostics.swift @@ -211,6 +211,9 @@ struct SomeType { @freestanding(declaration) macro nonExpressionReturnsVoid(_: T) -> Void = #externalMacro(module: "A", type: "B") // expected-warning@-1{{external macro implementation type}} +// expected-error@-2{{only a freestanding expression macro can produce a result of type 'Void'}} +// expected-note@-3{{make this macro a freestanding expression macro}}{{1-1=@freestanding(expression)\n}} +// expected-note@-4{{remove the result type if the macro does not produce a value}}{{68-76=}} @freestanding(expression) diff --git a/test/Macros/parsing.swift b/test/Macros/parsing.swift index f4380d1ecfd24..ffc039386d8d7 100644 --- a/test/Macros/parsing.swift +++ b/test/Macros/parsing.swift @@ -51,7 +51,7 @@ macro am1() named, // expected-error{{introduced name kind 'named' requires a single argument '(name)'}} arbitrary(a) // expected-error{{introduced name kind 'arbitrary' must not have an argument}} ) -macro am2() -> Void +macro am2() // expected-error@-1{{macro 'am2()' requires a definition}} #m1 + 1 From 7fb1ba9798696ced0c7e245c89d9db88ff2cae42 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 9 Jun 2023 23:16:57 -0700 Subject: [PATCH 2/3] [AST printer] Stop printing `-> ()` types on all macro declarations. --- lib/AST/ASTPrinter.cpp | 8 +++----- test/ModuleInterface/macros.swift | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 15b4c7a67a6e1..bff08aa14dd7c 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4811,16 +4811,14 @@ void PrintAST::visitMacroDecl(MacroDecl *decl) { } ); - { + if (decl->resultType.getTypeRepr() || + !decl->getResultInterfaceType()->isVoid()) { Printer.printStructurePre(PrintStructureKind::DeclResultTypeClause); SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::DeclResultTypeClause); }; - if (decl->parameterList) - Printer << " -> "; - else - Printer << ": "; + Printer << " -> "; TypeLoc resultTypeLoc( decl->resultType.getTypeRepr(), decl->getResultInterfaceType()); diff --git a/test/ModuleInterface/macros.swift b/test/ModuleInterface/macros.swift index 57af7ecbafbfa..63ea8332a7ad3 100644 --- a/test/ModuleInterface/macros.swift +++ b/test/ModuleInterface/macros.swift @@ -30,14 +30,14 @@ @freestanding(expression) public macro publicLine() -> T = #externalMacro(module: "SomeModule", type: "Line") // CHECK: #if compiler(>=5.3) && $Macros -// CHECK: @attached(accessor) public macro myWrapper() -> () = #externalMacro(module: "SomeModule", type: "Wrapper") +// CHECK: @attached(accessor) public macro myWrapper() = #externalMacro(module: "SomeModule", type: "Wrapper") // CHECK-NEXT: #endif @attached(accessor) public macro myWrapper() = #externalMacro(module: "SomeModule", type: "Wrapper") // CHECK: #if compiler(>=5.3) && $Macros && $AttachedMacros -// CHECK: @attached(member, names: named(`init`), prefixed(`$`)) public macro MemberwiseInit() -> () = #externalMacro(module: "SomeModule", type: "MemberwiseInitMacro") +// CHECK: @attached(member, names: named(`init`), prefixed(`$`)) public macro MemberwiseInit() = #externalMacro(module: "SomeModule", type: "MemberwiseInitMacro") // CHECK-NEXT: #endif -@attached(member, names: named(init), prefixed(`$`)) public macro MemberwiseInit() -> () = #externalMacro(module: "SomeModule", type: "MemberwiseInitMacro") +@attached(member, names: named(init), prefixed(`$`)) public macro MemberwiseInit() = #externalMacro(module: "SomeModule", type: "MemberwiseInitMacro") // CHECK-NOT: internalStringify @freestanding(expression) macro internalStringify(_ value: T) -> (T, String) = #externalMacro(module: "SomeModule", type: "StringifyMacro") From f7de3a3590711569ffd93e081eb25f228829416c Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 9 Jun 2023 23:22:09 -0700 Subject: [PATCH 3/3] [Macros] Downgrade "void return for non-expression macro" error in interfaces This allows us to continue to accept Swift interface files created with older versions of the Swift 5.9 compiler that emitted a spurious `-> ()` on non-expression macro declarations. --- lib/Sema/TypeCheckDeclPrimary.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index d707b376d61b6..a0ecff79ba60c 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2076,10 +2076,21 @@ class DeclChecker : public DeclVisitor { // expression role. Other roles cannot have result types. if (auto resultTypeRepr = MD->getResultTypeRepr()) { if (!MD->getMacroRoles().contains(MacroRole::Expression)) { - auto resultType = MD->getResultInterfaceType(); - Ctx.Diags.diagnose( - MD->arrowLoc, diag::macro_result_type_cannot_be_used, resultType) - .highlight(resultTypeRepr->getSourceRange()); + auto resultType = MD->getResultInterfaceType(); { + auto diag = Ctx.Diags.diagnose( + MD->arrowLoc, diag::macro_result_type_cannot_be_used, resultType); + diag.highlight(resultTypeRepr->getSourceRange()); + + // In a .swiftinterface file, downgrade this diagnostic to a warning. + // This allows the compiler to process existing .swiftinterface + // files that contain this issue. + if (resultType->isVoid()) { + if (auto sourceFile = MD->getParentSourceFile()) + if (sourceFile->Kind == SourceFileKind::Interface) + diag.limitBehavior(DiagnosticBehavior::Warning); + } + } + Ctx.Diags.diagnose(MD->arrowLoc, diag::macro_make_freestanding_expression) .fixItInsert(MD->getAttributeInsertionLoc(false), "@freestanding(expression)\n");