diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 60e0a5bbf1f07..157cbb4adf309 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4264,6 +4264,14 @@ ERROR(attr_MainType_without_main,none, "%0 is annotated with '@main' and must provide a main static function " "of type %" SELECT_APPLICATION_MAIN_TYPES "1", (const ValueDecl *, bool)) +NOTE(note_add_main_sync,none, + "add 'static func main()'", ()) +NOTE(note_add_main_sync_throws,none, + "add 'static func main() throws'", ()) +NOTE(note_add_main_async,none, + "add 'static func main() async'", ()) +NOTE(note_add_main_async_throws,none, + "add 'static func main() async throws'", ()) #undef SELECT_APPLICATION_MAIN_TYPES #undef SELECT_APPLICATION_MAIN diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 123aea0b9ed0e..756a3e780555f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -22,6 +22,7 @@ #include "TypeCheckObjC.h" #include "TypeCheckType.h" #include "TypeChecker.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/AvailabilityInference.h" #include "swift/AST/ClangModuleLoader.h" @@ -3081,6 +3082,37 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) { return std::make_pair(body, /*typechecked=*/false); } +llvm::SmallString<128> generateMainFunctionText(ASTContext &C, Decl *decl, + bool isThrows, bool isAsync) { + // Prepare the indent (same as `printRequirementStub`) + StringRef ExtraIndent; + StringRef CurrentIndent = Lexer::getIndentationForLine( + C.SourceMgr, decl->getStartLoc(), &ExtraIndent); + + llvm::SmallString<128> Text; + llvm::raw_svector_ostream OS(Text); + ExtraIndentStreamPrinter Printer(OS, CurrentIndent); + + Printer.printNewline(); + Printer.printIndent(); + + Printer << ExtraIndent << "static func main() "; + if (isAsync) + Printer << "async "; + if (isThrows) + Printer << "throws "; + + /// Print the "{ <#code#> }" placeholder body + Printer << "{\n"; + Printer.printIndent(); + Printer << ExtraIndent << ExtraIndent << getCodePlaceholder(); + Printer.printNewline(); + Printer.printIndent(); + Printer << ExtraIndent << "}\n"; + + return Text; +} + FuncDecl * SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator, Decl *D) const { @@ -3210,9 +3242,33 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator, const bool hasAsyncSupport = AvailabilityRange::forDeploymentTarget(context).isContainedIn( context.getBackDeployedConcurrencyAvailability()); - context.Diags.diagnose(attr->getLocation(), - diag::attr_MainType_without_main, - nominal, hasAsyncSupport); + + auto location = attr->getLocation(); + auto fixLocation = braces.Start; + + context.Diags.diagnose(location, diag::attr_MainType_without_main, nominal, + hasAsyncSupport); + + context.Diags.diagnose(location, diag::note_add_main_sync) + .fixItInsertAfter( + fixLocation, + generateMainFunctionText(context, nominal, false, false).str()); + context.Diags.diagnose(location, diag::note_add_main_sync_throws) + .fixItInsertAfter( + fixLocation, + generateMainFunctionText(context, nominal, true, false).str()); + + if (hasAsyncSupport) { + context.Diags.diagnose(location, diag::note_add_main_async) + .fixItInsertAfter( + fixLocation, + generateMainFunctionText(context, nominal, false, true).str()); + context.Diags.diagnose(location, diag::note_add_main_async_throws) + .fixItInsertAfter( + fixLocation, + generateMainFunctionText(context, nominal, true, true).str()); + } + attr->setInvalid(); return nullptr; } diff --git a/test/attr/ApplicationMain/attr_main_instance.swift b/test/attr/ApplicationMain/attr_main_instance.swift index 0c672b2a8c4ea..fe7f04d191ca3 100644 --- a/test/attr/ApplicationMain/attr_main_instance.swift +++ b/test/attr/ApplicationMain/attr_main_instance.swift @@ -1,6 +1,10 @@ // RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s @main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}} +// expected-note@-1{{add 'static func main()'}} {{8:15-15=\n static func main() {\n <#code#>\n }\n}} +// expected-note@-2{{add 'static func main() throws'}} {{8:15-15=\n static func main() throws {\n <#code#>\n }\n}} +// expected-note@-3{{add 'static func main() async'}} {{8:15-15=\n static func main() async {\n <#code#>\n }\n}} +// expected-note@-4{{add 'static func main() async throws'}} {{8:15-15=\n static func main() async throws {\n <#code#>\n }\n}} class MyBase { func main() { }