From df99de804d195ce77167f47dfbec7d3636cb6d34 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 14 Feb 2020 18:47:06 -0800 Subject: [PATCH 1/4] Added executable entry-point via @main type. When a type (class, enum, or struct) is annotated @main, it is required to provide a function with the following signature: static func main() -> () That function will be called when the executable the type is defined within is launched. --- include/swift/AST/Attr.def | 5 +- include/swift/AST/Decl.h | 29 ++-- include/swift/AST/DiagnosticsSema.def | 12 +- include/swift/AST/FileUnit.h | 10 +- include/swift/AST/KnownIdentifiers.def | 2 + include/swift/AST/SourceFile.h | 24 ++- .../Serialization/SerializedModuleLoader.h | 2 +- lib/AST/Decl.cpp | 12 +- lib/AST/Module.cpp | 47 +++--- lib/SILGen/SILGen.cpp | 4 +- lib/SILGen/SILGenFunction.cpp | 35 +++- lib/SILGen/SILGenFunction.h | 6 +- lib/Sema/CSGen.cpp | 4 +- lib/Sema/TypeCheckAttr.cpp | 156 +++++++++++++++++- lib/Sema/TypeCheckDeclOverride.cpp | 1 + lib/Serialization/ModuleFile.cpp | 4 +- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/Serialization.cpp | 2 +- test/IDE/complete_decl_attribute.swift | 5 + .../ApplicationMain/attr_main_arguments.swift | 8 + .../ApplicationMain/attr_main_class.swift | 7 + .../attr_main_classmethod.swift | 8 + .../attr_main_dynamicCallable.swift | 9 + .../attr_main_dynamicMemberLookup.swift | 10 ++ .../attr/ApplicationMain/attr_main_enum.swift | 7 + .../ApplicationMain/attr_main_generic.swift | 7 + .../ApplicationMain/attr_main_inherited.swift | 10 ++ .../ApplicationMain/attr_main_instance.swift | 8 + .../attr_main_multi_file/main1.swift | 12 ++ .../attr_main_multi_file/main2.swift | 14 ++ .../ApplicationMain/attr_main_multiple.swift | 19 +++ .../ApplicationMain/attr_main_protocol.swift | 6 + .../ApplicationMain/attr_main_return.swift | 8 + .../ApplicationMain/attr_main_struct.swift | 7 + .../attr_main_struct_available_future.swift | 13 ++ .../attr_main_struct_available_past.swift | 11 ++ .../attr_main_struct_from_protocol.swift | 19 +++ ...truct_from_two_protocols_one_missing.swift | 23 +++ .../ApplicationMain/attr_main_throws.swift | 8 + .../attr_main_with_maindotswift/file.swift | 12 ++ .../attr_main_with_maindotswift/main.swift | 4 + 41 files changed, 525 insertions(+), 67 deletions(-) create mode 100644 test/attr/ApplicationMain/attr_main_arguments.swift create mode 100644 test/attr/ApplicationMain/attr_main_class.swift create mode 100644 test/attr/ApplicationMain/attr_main_classmethod.swift create mode 100644 test/attr/ApplicationMain/attr_main_dynamicCallable.swift create mode 100644 test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum.swift create mode 100644 test/attr/ApplicationMain/attr_main_generic.swift create mode 100644 test/attr/ApplicationMain/attr_main_inherited.swift create mode 100644 test/attr/ApplicationMain/attr_main_instance.swift create mode 100644 test/attr/ApplicationMain/attr_main_multi_file/main1.swift create mode 100644 test/attr/ApplicationMain/attr_main_multi_file/main2.swift create mode 100644 test/attr/ApplicationMain/attr_main_multiple.swift create mode 100644 test/attr/ApplicationMain/attr_main_protocol.swift create mode 100644 test/attr/ApplicationMain/attr_main_return.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_available_future.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_available_past.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_from_protocol.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_from_two_protocols_one_missing.swift create mode 100644 test/attr/ApplicationMain/attr_main_throws.swift create mode 100644 test/attr/ApplicationMain/attr_main_with_maindotswift/file.swift create mode 100644 test/attr/ApplicationMain/attr_main_with_maindotswift/main.swift diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 0ccc1d770d8a8..d1947d774b900 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -147,7 +147,10 @@ SIMPLE_DECL_ATTR(dynamicCallable, DynamicCallable, OnNominalType | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, 6) -// NOTE: 7 is unused +SIMPLE_DECL_ATTR(main, MainType, + OnClass | OnStruct | OnEnum | + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, + 7) SIMPLE_DECL_ATTR(_exported, Exported, OnImport | UserInaccessible | diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 37d1980786131..34dedeba14fd4 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -272,6 +272,13 @@ bool conflicting(ASTContext &ctx, bool *wouldConflictInSwift5 = nullptr, bool skipProtocolExtensionCheck = false); +/// The kind of artificial main to generate. +enum class ArtificialMainKind : uint8_t { + NSApplicationMain, + UIApplicationMain, + TypeMain, +}; + /// Decl - Base class for all declarations in Swift. class alignas(1 << DeclAlignInBits) Decl { protected: @@ -779,6 +786,13 @@ class alignas(1 << DeclAlignInBits) Decl { SourceLoc TrailingSemiLoc; + /// Returns the appropriate kind of entry point to generate for this class, + /// based on its attributes. + /// + /// It is an error to call this on a type that does not have either an + /// *ApplicationMain or an main attribute. + ArtificialMainKind getArtificialMainKind() const; + SWIFT_DEBUG_DUMP; SWIFT_DEBUG_DUMPER(dump(const char *filename)); void dump(raw_ostream &OS, unsigned Indent = 0) const; @@ -3810,12 +3824,6 @@ class StructDecl final : public NominalTypeDecl { } }; -/// The kind of artificial main to generate for a class. -enum class ArtificialMainKind : uint8_t { - NSApplicationMain, - UIApplicationMain, -}; - /// This is the base type for AncestryOptions. Each flag describes possible /// interesting kinds of superclasses that a class may have. enum class AncestryFlags : uint8_t { @@ -4083,13 +4091,6 @@ class ClassDecl final : public NominalTypeDecl { /// the Objective-C runtime. StringRef getObjCRuntimeName(llvm::SmallVectorImpl &buffer) const; - /// Returns the appropriate kind of entry point to generate for this class, - /// based on its attributes. - /// - /// It is an error to call this on a class that does not have a - /// *ApplicationMain attribute. - ArtificialMainKind getArtificialMainKind() const; - using NominalTypeDecl::lookupDirect; /// Look in this class and its extensions (but not any of its protocols or @@ -6293,6 +6294,8 @@ class FuncDecl : public AbstractFunctionDecl { } bool isCallAsFunctionMethod() const; + bool isMainTypeMainMethod() const; + SelfAccessKind getSelfAccessKind() const; void setSelfAccessKind(SelfAccessKind mod) { diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index bcd996b4fcae2..eecf6c88b2089 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2890,17 +2890,19 @@ ERROR(nscopying_doesnt_conform,none, " the NSCopying protocol", ()) // UIApplicationMain/NSApplicationMain attribute -#define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'}" +#define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'|'main'}" #define SELECT_APPLICATION_DELEGATE "select{'UIApplicationDelegate'|'NSApplicationDelegate'}" +#define SELECT_APPLICATION_TYPE "select{class|class|type}" +#define SELECT_APPLICATION_TYPES "select{classes|classes|types}" ERROR(attr_ApplicationMain_not_ApplicationDelegate,none, "%" SELECT_APPLICATION_MAIN "0 class must conform to the %" SELECT_APPLICATION_DELEGATE "0 protocol", (unsigned)) ERROR(attr_generic_ApplicationMain_not_supported,none, - "generic %" SELECT_APPLICATION_MAIN "0 classes are not supported", + "generic %" SELECT_APPLICATION_MAIN "0 %" SELECT_APPLICATION_TYPES "0 are not supported", (unsigned)) ERROR(attr_ApplicationMain_multiple,none, - "%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one class in a module", + "%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one %" SELECT_APPLICATION_TYPE "0 in a module", (unsigned)) ERROR(attr_ApplicationMain_with_script,none, "%" SELECT_APPLICATION_MAIN "0 attribute cannot be used in a module that contains " @@ -2910,6 +2912,10 @@ NOTE(attr_ApplicationMain_script_here,none, "top-level code defined in this source file", ()) +ERROR(attr_MainType_without_main,none, + "%0 is annotated with @main and must provide a main static function of type () -> ().", + (DeclName)) + #undef SELECT_APPLICATION_MAIN #undef SELECT_APPLICATION_DELEGATE diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h index 61894edc1fdfb..569978be82f83 100644 --- a/include/swift/AST/FileUnit.h +++ b/include/swift/AST/FileUnit.h @@ -260,9 +260,13 @@ class FileUnit : public DeclContext { bool hasMainClass() const { return getMainClass(); } - virtual ClassDecl *getMainClass() const { - assert(hasEntryPoint()); - return nullptr; + ClassDecl *getMainClass() const { + return dyn_cast_or_null(getMainDecl()); + } + bool hasMainDecl() const { return getMainDecl(); } + virtual Decl *getMainDecl() const { return nullptr; } + FuncDecl *getMainFunc() const { + return dyn_cast_or_null(getMainDecl()); } virtual bool hasEntryPoint() const { return false; diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 33cf89a73156b..8dfd2d1bc24c9 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -92,6 +92,8 @@ IDENTIFIER(keyPath) IDENTIFIER(makeIterator) IDENTIFIER(Iterator) IDENTIFIER(load) +IDENTIFIER(main) +IDENTIFIER_WITH_NAME(MainEntryPoint, "$main") IDENTIFIER(next) IDENTIFIER_(nsErrorDomain) IDENTIFIER(objectAtIndexedSubscript) diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index b3fcb9ac66973..bc9722061df61 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -148,11 +148,15 @@ class SourceFile final : public FileUnit { Optional ReferencedNames; Optional RequestReferencedNames; - /// The class in this file marked \@NS/UIApplicationMain. - ClassDecl *MainClass = nullptr; + /// Either the class marked \@NS/UIApplicationMain or the synthesized FuncDecl + /// that calls main on the type marked @main. + Decl *MainDecl = nullptr; - /// The source location of the main class. - SourceLoc MainClassDiagLoc; + /// The source location of the main type. + SourceLoc MainDeclDiagLoc; + + /// The main function in the type marked @main. + FuncDecl *MainFunc = nullptr; /// A hash of all interface-contributing tokens that have been lexed for /// this source file so far. @@ -553,26 +557,28 @@ class SourceFile final : public FileUnit { llvm_unreachable("bad SourceFileKind"); } - ClassDecl *getMainClass() const override { - return MainClass; + Decl *getMainDecl() const override { return MainDecl; } + SourceLoc getMainDeclDiagLoc() const { + assert(hasMainDecl()); + return MainDeclDiagLoc; } SourceLoc getMainClassDiagLoc() const { assert(hasMainClass()); - return MainClassDiagLoc; + return getMainDeclDiagLoc(); } /// Register a "main" class for the module, complaining if there is more than /// one. /// /// Should only be called during type-checking. - bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); + bool registerMainDecl(Decl *mainDecl, SourceLoc diagLoc); /// True if this source file has an application entry point. /// /// This is true if the source file either is in script mode or contains /// a designated main class. bool hasEntryPoint() const override { - return isScriptMode() || hasMainClass(); + return isScriptMode() || hasMainDecl(); } /// Get the root refinement context for the file. The root context may be diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index c02d80846b7eb..1704c64b15876 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -410,7 +410,7 @@ class SerializedASTFile final : public LoadedFile { virtual StringRef getModuleDefiningPath() const override; - ClassDecl *getMainClass() const override; + Decl *getMainDecl() const override; bool hasEntryPoint() const override; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c47b7dc5f5b06..aae1ffbf351cc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4437,12 +4437,14 @@ StringRef ClassDecl::getObjCRuntimeName( return mangleObjCRuntimeName(this, buffer); } -ArtificialMainKind ClassDecl::getArtificialMainKind() const { +ArtificialMainKind Decl::getArtificialMainKind() const { if (getAttrs().hasAttribute()) return ArtificialMainKind::UIApplicationMain; if (getAttrs().hasAttribute()) return ArtificialMainKind::NSApplicationMain; - llvm_unreachable("class has no @ApplicationMain attr?!"); + if (isa(this)) + return ArtificialMainKind::TypeMain; + llvm_unreachable("type has no @Main attr?!"); } static bool isOverridingDecl(const ValueDecl *Derived, @@ -7327,6 +7329,12 @@ bool FuncDecl::isCallAsFunctionMethod() const { isInstanceMember(); } +bool FuncDecl::isMainTypeMainMethod() const { + return (getBaseIdentifier() == getASTContext().Id_main) && + !isInstanceMember() && getResultInterfaceType()->isVoid() && + getParameters()->size() == 0 && !hasThrows(); +} + ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, bool Throws, diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 85873e2cdca97..e399ee9fe88ab 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1554,16 +1554,17 @@ bool ModuleDecl::isBuiltinModule() const { return this == getASTContext().TheBuiltinModule; } -bool SourceFile::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) { - if (mainClass == MainClass) +bool SourceFile::registerMainDecl(Decl *mainDecl, SourceLoc diagLoc) { + if (mainDecl == MainDecl) return false; - ArtificialMainKind kind = mainClass->getArtificialMainKind(); + ArtificialMainKind kind = mainDecl->getArtificialMainKind(); if (getParentModule()->registerEntryPointFile(this, diagLoc, kind)) return true; - MainClass = mainClass; - MainClassDiagLoc = diagLoc; + MainDecl = mainDecl; + MainDeclDiagLoc = diagLoc; + return false; } @@ -1583,53 +1584,59 @@ bool ModuleDecl::registerEntryPointFile(FileUnit *file, SourceLoc diagLoc, enum : unsigned { UIApplicationMainClass = 0, NSApplicationMainClass = 1, - } mainClassDiagKind; + MainType = 2, + } mainTypeDiagKind; switch (kind.getValue()) { case ArtificialMainKind::UIApplicationMain: - mainClassDiagKind = UIApplicationMainClass; + mainTypeDiagKind = UIApplicationMainClass; break; case ArtificialMainKind::NSApplicationMain: - mainClassDiagKind = NSApplicationMainClass; + mainTypeDiagKind = NSApplicationMainClass; + break; + case ArtificialMainKind::TypeMain: + mainTypeDiagKind = MainType; break; } FileUnit *existingFile = EntryPointInfo.getEntryPointFile(); - const ClassDecl *existingClass = existingFile->getMainClass(); + const Decl *existingDecl = existingFile->getMainDecl(); SourceLoc existingDiagLoc; if (auto *sourceFile = dyn_cast(existingFile)) { - if (existingClass) { - existingDiagLoc = sourceFile->getMainClassDiagLoc(); + if (existingDecl) { + existingDiagLoc = sourceFile->getMainDeclDiagLoc(); } else { if (auto bufID = sourceFile->getBufferID()) existingDiagLoc = getASTContext().SourceMgr.getLocForBufferStart(*bufID); } } - if (existingClass) { + if (existingDecl) { if (EntryPointInfo.markDiagnosedMultipleMainClasses()) { - // If we already have a main class, and we haven't diagnosed it, + // If we already have a main type, and we haven't diagnosed it, // do so now. if (existingDiagLoc.isValid()) { - getASTContext().Diags.diagnose(existingDiagLoc, diag::attr_ApplicationMain_multiple, - mainClassDiagKind); + getASTContext().Diags.diagnose(existingDiagLoc, + diag::attr_ApplicationMain_multiple, + mainTypeDiagKind); } else { - getASTContext().Diags.diagnose(existingClass, diag::attr_ApplicationMain_multiple, - mainClassDiagKind); + getASTContext().Diags.diagnose(existingDecl, + diag::attr_ApplicationMain_multiple, + mainTypeDiagKind); } } // Always diagnose the new class. getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_multiple, - mainClassDiagKind); + mainTypeDiagKind); } else { // We don't have an existing class, but we /do/ have a file in script mode. // Diagnose that. if (EntryPointInfo.markDiagnosedMainClassWithScript()) { - getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_with_script, - mainClassDiagKind); + getASTContext().Diags.diagnose( + diagLoc, diag::attr_ApplicationMain_with_script, mainTypeDiagKind); if (existingDiagLoc.isValid()) { getASTContext().Diags.diagnose(existingDiagLoc, diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index f4410f7937e12..5004872a1192b 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1781,7 +1781,7 @@ class SourceFileScope { // If the source file contains an artificial main, emit the implicit // toplevel code. - if (auto mainClass = sf->getMainClass()) { + if (auto mainDecl = sf->getMainDecl()) { assert(!sgm.M.lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION) && "already emitted toplevel before main class?!"); @@ -1798,7 +1798,7 @@ class SourceFileScope { SGF.F.getConventions().getParameterSILTypes().begin(); entry->createFunctionArgument(*paramTypeIter); entry->createFunctionArgument(*std::next(paramTypeIter)); - SGF.emitArtificialTopLevel(mainClass); + SGF.emitArtificialTopLevel(mainDecl); } } }; diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index ce3d5ee63cb74..eda24bbc12b0c 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -20,14 +20,15 @@ #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/FileUnit.h" +#include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILProfiler.h" #include "swift/SIL/SILUndef.h" -#include "swift/AST/DiagnosticsSIL.h" using namespace swift; using namespace Lowering; @@ -541,16 +542,18 @@ void SILGenFunction::emitClosure(AbstractClosureExpr *ace) { emitEpilog(ace); } -void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { +void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { // Load argc and argv from the entry point arguments. SILValue argc = F.begin()->getArgument(0); SILValue argv = F.begin()->getArgument(1); - switch (mainClass->getArtificialMainKind()) { + switch (mainDecl->getArtificialMainKind()) { case ArtificialMainKind::UIApplicationMain: { // Emit a UIKit main. // return UIApplicationMain(C_ARGC, C_ARGV, nil, ClassName); + auto *mainClass = cast(mainDecl); + CanType NSStringTy = SGM.Types.getNSStringType(); CanType OptNSStringTy = OptionalType::get(NSStringTy)->getCanonicalType(); @@ -676,6 +679,8 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { // Emit an AppKit main. // return NSApplicationMain(C_ARGC, C_ARGV); + auto *mainClass = cast(mainDecl); + SILParameterInfo argTypes[] = { SILParameterInfo(argc->getType().getASTType(), ParameterConvention::Direct_Unowned), @@ -715,6 +720,30 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { B.createReturn(mainClass, r); return; } + + case ArtificialMainKind::TypeMain: { + // Emit a call to the main static function. + // return Module.$main(); + auto *mainFunc = cast(mainDecl); + + SILGenFunctionBuilder builder(SGM); + + SILDeclRef mainFunctionDeclRef(mainFunc, SILDeclRef::Kind::Func); + SILFunction *mainFunction = + SGM.getFunction(mainFunctionDeclRef, NotForDefinition); + + auto mainFunctionRef = B.createFunctionRef(mainFunc, mainFunction); + + B.createApply(mainFunc, mainFunctionRef, SubstitutionMap(), {}); + + SILValue returnValue = B.createIntegerLiteral( + mainFunc, SILType::getBuiltinIntegerType(32, getASTContext()), 0); + auto returnType = F.getConventions().getSingleSILResultType(); + if (returnValue->getType() != returnType) + returnValue = B.createStruct(mainFunc, returnType, returnValue); + B.createReturn(mainFunc, returnValue); + return; + } } } diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 6152ddee9257b..5474bc87dd62b 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -607,9 +607,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction void emitDestroyingDestructor(DestructorDecl *dd); /// Generates code for an artificial top-level function that starts an - /// application based on a main class. - void emitArtificialTopLevel(ClassDecl *mainClass); - + /// application based on a main type and optionally a main type. + void emitArtificialTopLevel(Decl *mainDecl); + /// Generates code for a class deallocating destructor. This /// calls the destroying destructor and then deallocates 'self'. void emitDeallocatingDestructor(DestructorDecl *dd); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index ecc257c90a47e..3f62559357bc1 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -4550,8 +4550,8 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) { // Look up all members of BaseTy with the given Name. MemberLookupResult LookupResult = CS.performMemberLookup( - ConstraintKind::ValueMember, DeclNameRef(Name), BaseTy, - FunctionRefKind::SingleApply, nullptr, false); + ConstraintKind::ValueMember, DeclNameRef(Name), BaseTy, + FunctionRefKind::SingleApply, CS.getConstraintLocator(nullptr), false); // Keep track of all the unviable members. for (auto Can : LookupResult.UnviableCandidates) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 07dfd65154610..6332ae5c21760 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -34,6 +34,7 @@ #include "swift/Parse/Lexer.h" #include "swift/Sema/IDETypeChecking.h" #include "clang/Basic/CharInfo.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" using namespace swift; @@ -217,6 +218,7 @@ class AttributeChecker : public AttributeVisitor { void visitNSApplicationMainAttr(NSApplicationMainAttr *attr); void visitUIApplicationMainAttr(UIApplicationMainAttr *attr); + void visitMainTypeAttr(MainTypeAttr *attr); void visitUnsafeNoObjCTaggedPointerAttr(UnsafeNoObjCTaggedPointerAttr *attr); void visitSwiftNativeObjCRuntimeBaseAttr( @@ -1678,7 +1680,7 @@ void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr, // Register the class as the main class in the module. If there are multiples // they will be diagnosed. - if (SF->registerMainClass(CD, attr->getLocation())) + if (SF->registerMainDecl(CD, attr->getLocation())) attr->setInvalid(); } @@ -1697,6 +1699,158 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) { C.getIdentifier("UIApplicationMain")); } +void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { + auto *nominal = dyn_cast(D); + + if (!nominal) { + assert(false && "Should have already recognized that the MainType decl " + "isn't applicable to decls other than NominalTypeDecls"); + return; + } + + // The type cannot be generic. + if (nominal->isGenericContext()) { + diagnose(attr->getLocation(), + diag::attr_generic_ApplicationMain_not_supported, 2); + attr->setInvalid(); + return; + } + + auto *file = cast(nominal->getModuleScopeContext()); + + // Create a function + // + // func $main() { + // return MainType.main() + // } + // + // to be called as the entry point. The advantage of setting up such a + // function is that we get full type-checking for mainType.main() as part of + // usual type-checking. The alternative would be to directly call + // mainType.main() from the entry point, and that would require fully + // type-checking the call to mainType.main(). + auto &context = nominal->getASTContext(); + auto location = attr->getLocation(); + + auto resolution = resolveValueMember(*nominal, nominal->getInterfaceType(), + context.Id_main); + + FuncDecl *mainFunction = nullptr; + + if (resolution.hasBestOverload()) { + auto best = resolution.getBestOverload(); + if (auto function = dyn_cast(best)) { + if (function->isMainTypeMainMethod()) { + mainFunction = function; + } + } + } + + if (mainFunction == nullptr) { + SmallVector viableCandidates; + + for (auto *candidate : resolution.getMemberDecls(Viable)) { + if (auto func = dyn_cast(candidate)) { + if (func->isMainTypeMainMethod()) { + viableCandidates.push_back(func); + } + } + } + + if (viableCandidates.size() != 1) { + diagnose(attr->getLocation(), diag::attr_MainType_without_main, + nominal->getBaseName()); + attr->setInvalid(); + return; + } + mainFunction = viableCandidates[0]; + } + + auto voidToVoidFunctionType = FunctionType::get({}, context.TheEmptyTupleType); + auto *func = FuncDecl::create( + context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::None, + /*FuncLoc*/ location, + DeclName(context, DeclBaseName(context.Id_MainEntryPoint), + ParameterList::createEmpty(context)), + /*NameLoc*/ SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*GenericParams=*/nullptr, ParameterList::createEmpty(context), + /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), + nominal->getParentSourceFile()); + func->setImplicit(true); + func->setSynthesized(true); + func->setInterfaceType(voidToVoidFunctionType); + + auto *typeExpr = TypeExpr::createImplicit(nominal->getDeclaredType(), context); + + SubstitutionMap substitutionMap; + if (auto *environment = mainFunction->getGenericEnvironment()) { + substitutionMap = SubstitutionMap::get( + environment->getGenericSignature(), + [&](SubstitutableType *type) { return nominal->getDeclaredType(); }, + LookUpConformanceInModule(nominal->getModuleContext())); + } else { + substitutionMap = SubstitutionMap(); + } + + auto funcDeclRef = ConcreteDeclRef(mainFunction, substitutionMap); + auto *funcDeclRefExpr = new (context) DeclRefExpr( + funcDeclRef, DeclNameLoc(location), /*Implicit*/ true); + funcDeclRefExpr->setImplicit(true); + funcDeclRefExpr->setType(mainFunction->getInterfaceType()); + + auto *dotSyntaxCallExpr = new (context) DotSyntaxCallExpr( + funcDeclRefExpr, /*DotLoc*/ SourceLoc(), typeExpr, voidToVoidFunctionType); + dotSyntaxCallExpr->setImplicit(true); + dotSyntaxCallExpr->setThrows(false); + + auto *callExpr = CallExpr::createImplicit(context, dotSyntaxCallExpr, {}, {}); + callExpr->setImplicit(true); + callExpr->setThrows(false); + callExpr->setType(context.TheEmptyTupleType); + auto *returnStmt = + new (context) ReturnStmt(SourceLoc(), callExpr, /*Implicit=*/true); + + SmallVector stmts; + stmts.push_back(returnStmt); + auto *body = BraceStmt::create(context, SourceLoc(), stmts, + SourceLoc(), /*Implicit*/true); + func->setBodyParsed(body); + func->setInterfaceType(voidToVoidFunctionType); + + nominal->getParentSourceFile()->addTopLevelDecl(func); + // This function must be type-checked. Why? Consider the following scenario: + // + // protocol AlmostMainable {} + // protocol ReallyMainable {} + // extension AlmostMainable where Self : ReallyMainable { + // static func main() {} + // } + // @main struct Main : AlmostMainable {} + // + // Note in particular that Main does not conform to ReallyMainable. + // + // In this case, resolveValueMember will find the function main in the + // extension, and so, since there is one candidate, the function $main will + // accordingly be formed as usual: + // + // func $main() { + // return Main.main() + // } + // + // Of course, this function's body does not type-check. + // + // FIXME: Stop using the legacy type checker here. However, it will still be + // necessary to type-check the function at that point. + file->DelayedFunctions.push_back(func); + + // Register the func as the main decl in the module. If there are multiples + // they will be diagnosed. + if (file->registerMainDecl(func, attr->getLocation())) { + attr->setInvalid(); + return; + } +} + /// Determine whether the given context is an extension to an Objective-C class /// where the class is defined in the Objective-C module and the extension is /// defined within its module. diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 07d4287420b93..8f90b3c83e0c7 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1448,6 +1448,7 @@ namespace { UNINTERESTING_ATTR(Specialize) UNINTERESTING_ATTR(DynamicReplacement) UNINTERESTING_ATTR(PrivateImport) + UNINTERESTING_ATTR(MainType) // Differentiation-related attributes. UNINTERESTING_ATTR(Differentiable) diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 0dbe8b3730a72..1aa87d1e84069 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -2974,9 +2974,9 @@ bool SerializedASTFile::getAllGenericSignatures( return true; } -ClassDecl *SerializedASTFile::getMainClass() const { +Decl *SerializedASTFile::getMainDecl() const { assert(hasEntryPoint()); - return cast_or_null(File.getDecl(File.Bits.EntryPointDeclID)); + return File.getDecl(File.Bits.EntryPointDeclID); } const version::Version &SerializedASTFile::getLanguageVersionBuiltWith() const { diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index c1b3982fd9cf8..ca49bee023b5e 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 554; // serialize accesslevel for OpaqueTypeDecl +const uint16_t SWIFTMODULE_VERSION_MINOR = 555; // add @main attribute /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index aeea197186dae..ebb7244898060 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -4986,7 +4986,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { } for (auto nextFile : files) { if (nextFile->hasEntryPoint()) - entryPointClassID = addDeclRef(nextFile->getMainClass()); + entryPointClassID = addDeclRef(nextFile->getMainDecl()); // FIXME: Switch to a visitor interface? SmallVector fileDecls; diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 77e1cb166a598..8fc1fcce7ecc3 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -79,6 +79,7 @@ struct MyStruct {} // KEYWORD3-NEXT: Keyword/None: available[#Class Attribute#]; name=available{{$}} // KEYWORD3-NEXT: Keyword/None: objc[#Class Attribute#]; name=objc{{$}} // KEYWORD3-NEXT: Keyword/None: dynamicCallable[#Class Attribute#]; name=dynamicCallable{{$}} +// KEYWORD3-NEXT: Keyword/None: main[#Class Attribute#]; name=main // KEYWORD3-NEXT: Keyword/None: dynamicMemberLookup[#Class Attribute#]; name=dynamicMemberLookup{{$}} // KEYWORD3-NEXT: Keyword/None: IBDesignable[#Class Attribute#]; name=IBDesignable{{$}} // KEYWORD3-NEXT: Keyword/None: UIApplicationMain[#Class Attribute#]; name=UIApplicationMain{{$}} @@ -98,6 +99,7 @@ struct MyStruct {} // KEYWORD4-NEXT: Keyword/None: available[#Enum Attribute#]; name=available{{$}} // KEYWORD4-NEXT: Keyword/None: objc[#Enum Attribute#]; name=objc{{$}} // KEYWORD4-NEXT: Keyword/None: dynamicCallable[#Enum Attribute#]; name=dynamicCallable +// KEYWORD4-NEXT: Keyword/None: main[#Enum Attribute#]; name=main // KEYWORD4-NEXT: Keyword/None: dynamicMemberLookup[#Enum Attribute#]; name=dynamicMemberLookup // KEYWORD4-NEXT: Keyword/None: usableFromInline[#Enum Attribute#]; name=usableFromInline // KEYWORD4-NEXT: Keyword/None: frozen[#Enum Attribute#]; name=frozen @@ -110,6 +112,7 @@ struct MyStruct {} // KEYWORD5: Begin completions // KEYWORD5-NEXT: Keyword/None: available[#Struct Attribute#]; name=available{{$}} // KEYWORD5-NEXT: Keyword/None: dynamicCallable[#Struct Attribute#]; name=dynamicCallable +// KEYWORD5-NEXT: Keyword/None: main[#Struct Attribute#]; name=main // KEYWORD5-NEXT: Keyword/None: dynamicMemberLookup[#Struct Attribute#]; name=dynamicMemberLookup // KEYWORD5-NEXT: Keyword/None: usableFromInline[#Struct Attribute#]; name=usableFromInline // KEYWORD5-NEXT: Keyword/None: frozen[#Struct Attribute#]; name=frozen @@ -219,6 +222,7 @@ struct _S { // ON_MEMBER_LAST-DAG: Keyword/None: available[#Declaration Attribute#]; name=available // ON_MEMBER_LAST-DAG: Keyword/None: objc[#Declaration Attribute#]; name=objc // ON_MEMBER_LAST-DAG: Keyword/None: dynamicCallable[#Declaration Attribute#]; name=dynamicCallable +// ON_MEMBER_LAST-DAG: Keyword/None: main[#Declaration Attribute#]; name=main // ON_MEMBER_LAST-DAG: Keyword/None: dynamicMemberLookup[#Declaration Attribute#]; name=dynamicMemberLookup // ON_MEMBER_LAST-DAG: Keyword/None: NSCopying[#Declaration Attribute#]; name=NSCopying // ON_MEMBER_LAST-DAG: Keyword/None: IBAction[#Declaration Attribute#]; name=IBAction @@ -265,6 +269,7 @@ func dummy2() {} // KEYWORD_LAST-NEXT: Keyword/None: available[#Declaration Attribute#]; name=available{{$}} // KEYWORD_LAST-NEXT: Keyword/None: objc[#Declaration Attribute#]; name=objc{{$}} // KEYWORD_LAST-NEXT: Keyword/None: dynamicCallable[#Declaration Attribute#]; name=dynamicCallable +// KEYWORD_LAST-NEXT: Keyword/None: main[#Declaration Attribute#]; name=main // KEYWORD_LAST-NEXT: Keyword/None: dynamicMemberLookup[#Declaration Attribute#]; name=dynamicMemberLookup // KEYWORD_LAST-NEXT: Keyword/None: NSCopying[#Declaration Attribute#]; name=NSCopying{{$}} // KEYWORD_LAST-NEXT: Keyword/None: IBAction[#Declaration Attribute#]; name=IBAction{{$}} diff --git a/test/attr/ApplicationMain/attr_main_arguments.swift b/test/attr/ApplicationMain/attr_main_arguments.swift new file mode 100644 index 0000000000000..342d22252401c --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_arguments.swift @@ -0,0 +1,8 @@ +// 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 of type () -> ().}} +struct MyBase { + static func main(_ argc: Int, _ argv: [String]) { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_class.swift b/test/attr/ApplicationMain/attr_main_class.swift new file mode 100644 index 0000000000000..4d016d81b4c5e --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main +class EntryPoint { + static func main() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_classmethod.swift b/test/attr/ApplicationMain/attr_main_classmethod.swift new file mode 100644 index 0000000000000..2d36066ad7357 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_classmethod.swift @@ -0,0 +1,8 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main +class MyBase { + class func main() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_dynamicCallable.swift b/test/attr/ApplicationMain/attr_main_dynamicCallable.swift new file mode 100644 index 0000000000000..11b011eddeb6d --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_dynamicCallable.swift @@ -0,0 +1,9 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main // expected-error{{'Foo' is annotated with @main and must provide a main static function of type () -> ().}} +struct Foo { + @dynamicCallable + struct main { + func dynamicallyCall(withArguments args: [Any]) -> () { return } + } +} diff --git a/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift b/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift new file mode 100644 index 0000000000000..a731febbfdda2 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main @dynamicMemberLookup // expected-error{{'Main' is annotated with @main and must provide a main static function of type () -> ().}} +struct Main { + subscript(dynamicMember member: String) -> () -> Void { + return { + } + } +} + diff --git a/test/attr/ApplicationMain/attr_main_enum.swift b/test/attr/ApplicationMain/attr_main_enum.swift new file mode 100644 index 0000000000000..b28a5163810ed --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main +enum EntryPoint { + static func main() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_generic.swift b/test/attr/ApplicationMain/attr_main_generic.swift new file mode 100644 index 0000000000000..30f521909f6e6 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_generic.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main // expected-error{{generic 'main' types are not supported}} +class MyBase { + static func main() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_inherited.swift b/test/attr/ApplicationMain/attr_main_inherited.swift new file mode 100644 index 0000000000000..b98e25fdd5006 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_inherited.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +class MainBase { + static func main() { + } +} + +@main +class Main : MainBase { } + diff --git a/test/attr/ApplicationMain/attr_main_instance.swift b/test/attr/ApplicationMain/attr_main_instance.swift new file mode 100644 index 0000000000000..31831f9bdc369 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_instance.swift @@ -0,0 +1,8 @@ +// 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 of type () -> ().}} +class MyBase { + func main() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_multi_file/main1.swift b/test/attr/ApplicationMain/attr_main_multi_file/main1.swift new file mode 100644 index 0000000000000..073dddc354eee --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_multi_file/main1.swift @@ -0,0 +1,12 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// NB: No "-verify"--this file should parse successfully on its own. +// RUN: %target-swift-frontend -typecheck -parse-as-library %s + +@main // expected-error{{'main' attribute can only apply to one type in a module}} +class MyMain { + static func main() { + } +} + +func hi() {} diff --git a/test/attr/ApplicationMain/attr_main_multi_file/main2.swift b/test/attr/ApplicationMain/attr_main_multi_file/main2.swift new file mode 100644 index 0000000000000..5717584488722 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_multi_file/main2.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-frontend -typecheck -verify %s %S/main1.swift + +// Serialized partial AST support: +// RUN: %target-swift-frontend -module-name main -emit-module-path %t.swiftmodule -primary-file %s %S/main1.swift +// RUN: %target-swift-frontend -module-name main -parse-as-library -typecheck %t.swiftmodule -primary-file %S/main1.swift -verify -verify-ignore-unknown + +@main // expected-error{{'main' attribute can only apply to one type in a module}} +class EvilMain { + static func main() { + } +} + +// FIXME: Remove -verify-ignore-unknown. +// :0: error: unexpected error produced: 'NSApplicationMain' attribute can only apply to one class in a module diff --git a/test/attr/ApplicationMain/attr_main_multiple.swift b/test/attr/ApplicationMain/attr_main_multiple.swift new file mode 100644 index 0000000000000..c1d772c413f4c --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_multiple.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main // expected-error{{'main' attribute can only apply to one type in a module}} +struct MyMain1 { + static func main() { + } +} + +@main // expected-error{{'main' attribute can only apply to one type in a module}} +enum MyMain2 { + static func main() { + } +} + +@main // expected-error{{'main' attribute can only apply to one type in a module}} +class MyMain3 { + static func main() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_protocol.swift b/test/attr/ApplicationMain/attr_main_protocol.swift new file mode 100644 index 0000000000000..d8f9bdc925b69 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_protocol.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main // expected-error{{'@main' attribute cannot be applied to this declaration}} +protocol EntryPoint { + static func main() +} diff --git a/test/attr/ApplicationMain/attr_main_return.swift b/test/attr/ApplicationMain/attr_main_return.swift new file mode 100644 index 0000000000000..8cc8e3c15d040 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_return.swift @@ -0,0 +1,8 @@ +// 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 of type () -> ().}} +struct MyBase { + static func main() -> Int { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_struct.swift b/test/attr/ApplicationMain/attr_main_struct.swift new file mode 100644 index 0000000000000..096b9d0f62e79 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main +struct EntryPoint { + static func main() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_struct_available_future.swift b/test/attr/ApplicationMain/attr_main_struct_available_future.swift new file mode 100644 index 0000000000000..5d36cda72d3c9 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_available_future.swift @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +// REQUIRES: OS=macosx + +@main // expected-error {{'main()' is only available in macOS 10.99 or newer}} +@available(OSX 10.0, *) +struct EntryPoint { + @available(OSX 10.99, *) + static func main() { + } +} + + diff --git a/test/attr/ApplicationMain/attr_main_struct_available_past.swift b/test/attr/ApplicationMain/attr_main_struct_available_past.swift new file mode 100644 index 0000000000000..5805697989c04 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_available_past.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +// REQUIRES: OS=macosx + +@main +struct EntryPoint { + @available(OSX 10.0, *) + static func main() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_struct_from_protocol.swift b/test/attr/ApplicationMain/attr_main_struct_from_protocol.swift new file mode 100644 index 0000000000000..b59d6453f8b05 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_from_protocol.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +protocol Runnable { + init() + func run() +} + +extension Runnable { + static func main() { + let it = Self.init() + it.run() + } +} + +@main +struct EntryPoint : Runnable { + func run() { + } +} diff --git a/test/attr/ApplicationMain/attr_main_struct_from_two_protocols_one_missing.swift b/test/attr/ApplicationMain/attr_main_struct_from_two_protocols_one_missing.swift new file mode 100644 index 0000000000000..561fac3ace780 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_from_two_protocols_one_missing.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +protocol Runnable { + init() + func run() +} + +protocol OtherThing { +} + +extension Runnable where Self : OtherThing { // expected-note{{where 'Self' = 'EntryPoint'}} + static func main() { + let it = Self.init() + it.run() + } +} + +@main // expected-error{{referencing static method 'main()' on 'Runnable' requires that 'EntryPoint' conform to 'OtherThing'}} +struct EntryPoint : Runnable { + func run() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_throws.swift b/test/attr/ApplicationMain/attr_main_throws.swift new file mode 100644 index 0000000000000..19aef346bea13 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_throws.swift @@ -0,0 +1,8 @@ +// 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 of type () -> ().}} +struct MyBase { + static func main() throws { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_with_maindotswift/file.swift b/test/attr/ApplicationMain/attr_main_with_maindotswift/file.swift new file mode 100644 index 0000000000000..122f23538ee43 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_with_maindotswift/file.swift @@ -0,0 +1,12 @@ +// This file is a part of the multi-file test driven by 'main.swift'. + +// NB: No "-verify"--this file should parse successfully on its own. +// RUN: %target-swift-frontend -typecheck -parse-as-library %s + +@main // expected-error{{'main' attribute cannot be used in a module that contains top-level code}} +class MyMain { + static func main() { + } +} + +func hi() {} diff --git a/test/attr/ApplicationMain/attr_main_with_maindotswift/main.swift b/test/attr/ApplicationMain/attr_main_with_maindotswift/main.swift new file mode 100644 index 0000000000000..7c01c7c3b4464 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_with_maindotswift/main.swift @@ -0,0 +1,4 @@ +// expected-note{{top-level code defined in this source file}} +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s %S/file.swift + +hi() From c545e4d125d05490cbda7cc0e3fa370ff4947431 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 24 Feb 2020 17:08:48 -0800 Subject: [PATCH 2/4] @main: Added $main func to @main type. Previously, the function was being added to the list of top level decls in the source file as that list was being iterated, leading to iterator issues. Here, the function is instead added to the nominal type decl which is decorated with @main. Doing so requires calling the $main function with the metatype for the nominal type. The workaround for the iterator invalidation issue which had been applied previously, namely changing the type of the Decls member of SourceFile from std::vector to SmallVector is reverted. --- lib/SILGen/SILGenFunction.cpp | 5 ++++- lib/Sema/TypeCheckAttr.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index eda24bbc12b0c..11d74b28dfb0a 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -732,9 +732,12 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SILFunction *mainFunction = SGM.getFunction(mainFunctionDeclRef, NotForDefinition); + NominalTypeDecl *mainType = cast(mainFunc->getDeclContext()); + auto metatype = B.createMetatype(mainType, getLoweredType(mainType->getInterfaceType())); + auto mainFunctionRef = B.createFunctionRef(mainFunc, mainFunction); - B.createApply(mainFunc, mainFunctionRef, SubstitutionMap(), {}); + B.createApply(mainFunc, mainFunctionRef, SubstitutionMap(), {metatype}); SILValue returnValue = B.createIntegerLiteral( mainFunc, SILType::getBuiltinIntegerType(32, getASTContext()), 0); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 6332ae5c21760..1f593d202421c 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1767,18 +1767,18 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { } auto voidToVoidFunctionType = FunctionType::get({}, context.TheEmptyTupleType); + auto nominalToVoidToVoidFunctionType = FunctionType::get({AnyFunctionType::Param(nominal->getInterfaceType())}, voidToVoidFunctionType); auto *func = FuncDecl::create( - context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::None, + context, /*StaticLoc*/ nominal->getBraces().End, StaticSpellingKind::KeywordStatic, /*FuncLoc*/ location, DeclName(context, DeclBaseName(context.Id_MainEntryPoint), ParameterList::createEmpty(context)), - /*NameLoc*/ SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*NameLoc*/ nominal->getBraces().End, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParameterList::createEmpty(context), /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), - nominal->getParentSourceFile()); + nominal); func->setImplicit(true); func->setSynthesized(true); - func->setInterfaceType(voidToVoidFunctionType); auto *typeExpr = TypeExpr::createImplicit(nominal->getDeclaredType(), context); @@ -1815,9 +1815,9 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { auto *body = BraceStmt::create(context, SourceLoc(), stmts, SourceLoc(), /*Implicit*/true); func->setBodyParsed(body); - func->setInterfaceType(voidToVoidFunctionType); + func->setInterfaceType(nominalToVoidToVoidFunctionType); - nominal->getParentSourceFile()->addTopLevelDecl(func); + nominal->addMember(func); // This function must be type-checked. Why? Consider the following scenario: // // protocol AlmostMainable {} From 2676c2aed277def91de4bf6397443b05847436c2 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 24 Mar 2020 14:59:06 -0700 Subject: [PATCH 3/4] @main: Allowed attribute on extensions. Previously the @main attribute could only be applied to NominalTypeDecls. Here, that limitation is lifted so that the attribute can be applied to ExtensionDecls. --- include/swift/AST/Attr.def | 2 +- lib/SILGen/SILGenFunction.cpp | 10 ++++- lib/Sema/TypeCheckAttr.cpp | 39 ++++++++++++++----- .../attr_main_class_extension.swift | 12 ++++++ ...r_main_class_extension_external_main.swift | 11 ++++++ .../A.swift | 6 +++ .../main.swift | 12 ++++++ .../A.swift | 9 +++++ .../main.swift | 9 +++++ .../attr_main_enum_extension.swift | 13 +++++++ ...tr_main_enum_extension_external_main.swift | 13 +++++++ .../A.swift | 6 +++ .../main.swift | 12 ++++++ .../A.swift | 9 +++++ .../main.swift | 9 +++++ .../main1.swift | 10 +++++ .../main2.swift | 11 ++++++ .../attr_main_extension_nofunc.swift | 10 +++++ .../attr_main_struct_extension.swift | 11 ++++++ ..._main_struct_extension_external_main.swift | 11 ++++++ .../A.swift | 6 +++ .../main.swift | 12 ++++++ .../A.swift | 9 +++++ .../main.swift | 9 +++++ .../attr_main_tuple_extension.swift | 11 ++++++ 25 files changed, 261 insertions(+), 11 deletions(-) create mode 100644 test/attr/ApplicationMain/attr_main_class_extension.swift create mode 100644 test/attr/ApplicationMain/attr_main_class_extension_external_main.swift create mode 100644 test/attr/ApplicationMain/attr_main_class_extension_multi_module/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_class_extension_multi_module/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension_external_main.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension_multi_module/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension_multi_module/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_extension_multi_file/main1.swift create mode 100644 test/attr/ApplicationMain/attr_main_extension_multi_file/main2.swift create mode 100644 test/attr/ApplicationMain/attr_main_extension_nofunc.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension_external_main.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension_multi_module/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension_multi_module/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/A.swift create mode 100644 test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/main.swift create mode 100644 test/attr/ApplicationMain/attr_main_tuple_extension.swift diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index d1947d774b900..8054500c3b772 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -148,7 +148,7 @@ SIMPLE_DECL_ATTR(dynamicCallable, DynamicCallable, ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, 6) SIMPLE_DECL_ATTR(main, MainType, - OnClass | OnStruct | OnEnum | + OnClass | OnStruct | OnEnum | OnExtension | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, 7) SIMPLE_DECL_ATTR(_exported, Exported, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 11d74b28dfb0a..c189293b87143 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -732,7 +732,15 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { SILFunction *mainFunction = SGM.getFunction(mainFunctionDeclRef, NotForDefinition); - NominalTypeDecl *mainType = cast(mainFunc->getDeclContext()); + ExtensionDecl *mainExtension = + dyn_cast(mainFunc->getDeclContext()); + + NominalTypeDecl *mainType; + if (mainExtension) { + mainType = mainExtension->getExtendedNominal(); + } else { + mainType = cast(mainFunc->getDeclContext()); + } auto metatype = B.createMetatype(mainType, getLoweredType(mainType->getInterfaceType())); auto mainFunctionRef = B.createFunctionRef(mainFunc, mainFunction); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1f593d202421c..4162ccac80f4b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1700,13 +1700,32 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) { } void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { - auto *nominal = dyn_cast(D); + auto *extension = dyn_cast(D); + + IterableDeclContext *iterableDeclContext; + DeclContext *declContext; + NominalTypeDecl *nominal; + SourceRange braces; + + if (extension) { + nominal = extension->getExtendedNominal(); + iterableDeclContext = extension; + declContext = extension; + braces = extension->getBraces(); + } else { + nominal = dyn_cast(D); + iterableDeclContext = nominal; + declContext = nominal; + braces = nominal->getBraces(); + } if (!nominal) { assert(false && "Should have already recognized that the MainType decl " "isn't applicable to decls other than NominalTypeDecls"); return; } + assert(iterableDeclContext); + assert(declContext); // The type cannot be generic. if (nominal->isGenericContext()) { @@ -1716,7 +1735,8 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { return; } - auto *file = cast(nominal->getModuleScopeContext()); + SourceFile *file = cast(declContext->getModuleScopeContext()); + assert(file); // Create a function // @@ -1729,11 +1749,11 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { // usual type-checking. The alternative would be to directly call // mainType.main() from the entry point, and that would require fully // type-checking the call to mainType.main(). - auto &context = nominal->getASTContext(); + auto &context = D->getASTContext(); auto location = attr->getLocation(); - auto resolution = resolveValueMember(*nominal, nominal->getInterfaceType(), - context.Id_main); + auto resolution = resolveValueMember( + *declContext, nominal->getInterfaceType(), context.Id_main); FuncDecl *mainFunction = nullptr; @@ -1769,14 +1789,14 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { auto voidToVoidFunctionType = FunctionType::get({}, context.TheEmptyTupleType); auto nominalToVoidToVoidFunctionType = FunctionType::get({AnyFunctionType::Param(nominal->getInterfaceType())}, voidToVoidFunctionType); auto *func = FuncDecl::create( - context, /*StaticLoc*/ nominal->getBraces().End, StaticSpellingKind::KeywordStatic, + context, /*StaticLoc*/ braces.End, StaticSpellingKind::KeywordStatic, /*FuncLoc*/ location, DeclName(context, DeclBaseName(context.Id_MainEntryPoint), ParameterList::createEmpty(context)), - /*NameLoc*/ nominal->getBraces().End, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*NameLoc*/ braces.End, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParameterList::createEmpty(context), /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), - nominal); + declContext); func->setImplicit(true); func->setSynthesized(true); @@ -1817,7 +1837,8 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { func->setBodyParsed(body); func->setInterfaceType(nominalToVoidToVoidFunctionType); - nominal->addMember(func); + iterableDeclContext->addMember(func); + // This function must be type-checked. Why? Consider the following scenario: // // protocol AlmostMainable {} diff --git a/test/attr/ApplicationMain/attr_main_class_extension.swift b/test/attr/ApplicationMain/attr_main_class_extension.swift new file mode 100644 index 0000000000000..cf35b1e7d068d --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +class EntryPoint { +} + +@main +extension EntryPoint { + static func main() { + } +} + + diff --git a/test/attr/ApplicationMain/attr_main_class_extension_external_main.swift b/test/attr/ApplicationMain/attr_main_class_extension_external_main.swift new file mode 100644 index 0000000000000..9b1de9f38122e --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension_external_main.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +class EntryPoint { +} + +@main +extension EntryPoint { + static func main() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_class_extension_multi_module/A.swift b/test/attr/ApplicationMain/attr_main_class_extension_multi_module/A.swift new file mode 100644 index 0000000000000..e8916035d61b1 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension_multi_module/A.swift @@ -0,0 +1,6 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public class Main { +} diff --git a/test/attr/ApplicationMain/attr_main_class_extension_multi_module/main.swift b/test/attr/ApplicationMain/attr_main_class_extension_multi_module/main.swift new file mode 100644 index 0000000000000..8dfa607443f70 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension_multi_module/main.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { + static func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/A.swift b/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/A.swift new file mode 100644 index 0000000000000..d0170aec59f44 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/A.swift @@ -0,0 +1,9 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public class Main { + public class func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/main.swift b/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/main.swift new file mode 100644 index 0000000000000..35bde630d090c --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_class_extension_multi_module_external_main/main.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { +} diff --git a/test/attr/ApplicationMain/attr_main_enum_extension.swift b/test/attr/ApplicationMain/attr_main_enum_extension.swift new file mode 100644 index 0000000000000..f831528f01ce3 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension.swift @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +enum EntryPoint { +} + +@main +extension EntryPoint { + static func main() { + } +} + + + diff --git a/test/attr/ApplicationMain/attr_main_enum_extension_external_main.swift b/test/attr/ApplicationMain/attr_main_enum_extension_external_main.swift new file mode 100644 index 0000000000000..6284731d92d15 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension_external_main.swift @@ -0,0 +1,13 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +enum EntryPoint { + static func main() { + } +} + +@main +extension EntryPoint { +} + + + diff --git a/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/A.swift b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/A.swift new file mode 100644 index 0000000000000..bc7f50900fea6 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/A.swift @@ -0,0 +1,6 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public enum Main { +} diff --git a/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/main.swift b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/main.swift new file mode 100644 index 0000000000000..8dfa607443f70 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module/main.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { + static func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/A.swift b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/A.swift new file mode 100644 index 0000000000000..fb7c59621799b --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/A.swift @@ -0,0 +1,9 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public enum Main { + public static func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/main.swift b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/main.swift new file mode 100644 index 0000000000000..35bde630d090c --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_enum_extension_multi_module_external_main/main.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { +} diff --git a/test/attr/ApplicationMain/attr_main_extension_multi_file/main1.swift b/test/attr/ApplicationMain/attr_main_extension_multi_file/main1.swift new file mode 100644 index 0000000000000..a01e2cdc0fb8b --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_extension_multi_file/main1.swift @@ -0,0 +1,10 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +@main +extension Main { + static func main() { + print("hello world") + } +} diff --git a/test/attr/ApplicationMain/attr_main_extension_multi_file/main2.swift b/test/attr/ApplicationMain/attr_main_extension_multi_file/main2.swift new file mode 100644 index 0000000000000..6bad5e48d5cfd --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_extension_multi_file/main2.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -verify %s %S/main1.swift + +// Serialized partial AST support: +// RUN: %target-swift-frontend -module-name main -emit-module-path %t.swiftmodule -primary-file %s %S/main1.swift +// RUN: %target-swift-frontend -module-name main -parse-as-library -typecheck %t.swiftmodule -primary-file %S/main1.swift -verify -verify-ignore-unknown + +class Main { +} + +// FIXME: Remove -verify-ignore-unknown. +// :0: error: unexpected error produced: 'main' attribute can only apply to one class in a module diff --git a/test/attr/ApplicationMain/attr_main_extension_nofunc.swift b/test/attr/ApplicationMain/attr_main_extension_nofunc.swift new file mode 100644 index 0000000000000..16cf107f8dbdd --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_extension_nofunc.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +class EntryPoint { +} + +@main // expected-error{{'EntryPoint' is annotated with @main and must provide a main static function of type () -> ()}} +extension EntryPoint { +} + + diff --git a/test/attr/ApplicationMain/attr_main_struct_extension.swift b/test/attr/ApplicationMain/attr_main_struct_extension.swift new file mode 100644 index 0000000000000..fb1f4e1b3faf3 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +struct EntryPoint { +} + +@main +extension EntryPoint { + static func main() { + } +} + diff --git a/test/attr/ApplicationMain/attr_main_struct_extension_external_main.swift b/test/attr/ApplicationMain/attr_main_struct_extension_external_main.swift new file mode 100644 index 0000000000000..10a934fca75d7 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension_external_main.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +struct EntryPoint { + static func main() { + } +} + +@main +extension EntryPoint { +} + diff --git a/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/A.swift b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/A.swift new file mode 100644 index 0000000000000..78d48559c680e --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/A.swift @@ -0,0 +1,6 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public struct Main { +} diff --git a/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/main.swift b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/main.swift new file mode 100644 index 0000000000000..8dfa607443f70 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module/main.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { + static func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/A.swift b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/A.swift new file mode 100644 index 0000000000000..10c6d2339e92f --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/A.swift @@ -0,0 +1,9 @@ +// This file is a part of the multi-file test driven by 'main2.swift'. + +// RUN: %target-swift-frontend -parse %s + +public struct Main { + public static func main() { + print("ok") + } +} diff --git a/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/main.swift b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/main.swift new file mode 100644 index 0000000000000..35bde630d090c --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_struct_extension_multi_module_external_main/main.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -emit-module -emit-library -module-name ModuleA -module-link-name ModuleA %S/A.swift -o %t/%target-library-name(ModuleA) +// RUN: %target-swift-frontend -c -I %t -L %t -lModuleA -parse-as-library %s + +import ModuleA + +@main +extension Main { +} diff --git a/test/attr/ApplicationMain/attr_main_tuple_extension.swift b/test/attr/ApplicationMain/attr_main_tuple_extension.swift new file mode 100644 index 0000000000000..b8a02493be7c9 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_tuple_extension.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s + +@main +extension (Int, String) { // expected-error {{non-nominal type '(Int, String)' cannot be extended}} + static func main() { + } +} + + + + From 81dc64fee3df5b623d123c635aeb7a2d770b78a0 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 16 Apr 2020 13:59:31 -0700 Subject: [PATCH 4/4] @main: Enable main function to throw. SE-0281 was accepted with the modification that the main function should be allowed to be throwing. Here support for enabling that is added. Support is implemented in two steps: (1) The $main wrapper function is modified to be throwing static func $main() throws { return try main() } whenever the main function is throwing (it remains non-throwing when $main is not throwing). (2) The @main entry point is modified to be sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { entry(%argc : $Int32, %argv : $UnsafeMutablePointer>>): %the_main_type = metatype $@thin TheMainType.Type %the_main_func = function_ref @`TheMainType.main()` : $@convention(method) (@thin TheMainType.Type) -> @error Error try_apply %the_main_func(%the_main_type) : $@convention(method) (@thin TheMainType.Type) -> @error Error, normal success, error failure success(%_ : $()): %success_code_builtin_int32 = integer_literal $Builtin.Int32, 0 br bb1(%success_code_builtin_int32 : $Builtin.Int32) failure(%error : @owned $Error): %_ = builtin "errorInMain"(%error : $Error) : $() end_lifetime %error : $Error %error_code_builtin_int32 = integer_literal $Builtin.Int32, 1 br bb1(%error_code_builtin_int32 : $Builtin.Int32) exit(%code_builtin_int32 : $Builtin.Int32): %code = struct $Int32 (%code_builtin_int32 : $Builtin.Int32) return %code : $Int32 } whenever the main function is throwing (and consequently $main also is). In the non-throwing case, (a) the try_apply instruction is replaced with an apply instruction, (b) the body of the success block is appended to the entry block, and (c) the success and failure blocks are removed. --- include/swift/AST/DiagnosticsSema.def | 2 +- include/swift/AST/SourceFile.h | 3 -- lib/AST/Decl.cpp | 2 +- lib/SILGen/SILGenFunction.cpp | 53 +++++++++++++++---- lib/Sema/TypeCheckAttr.cpp | 28 +++++++--- .../ApplicationMain/attr_main_arguments.swift | 2 +- .../attr_main_dynamicCallable.swift | 2 +- .../attr_main_dynamicMemberLookup.swift | 2 +- .../attr_main_extension_nofunc.swift | 2 +- .../ApplicationMain/attr_main_instance.swift | 2 +- ...attr_main_resolves_types_nonthrowing.swift | 22 ++++++++ ...tr_main_resolves_types_nonthrowing_2.swift | 20 +++++++ .../attr_main_resolves_types_throws.swift | 20 +++++++ .../attr_main_resolves_types_throws_2.swift | 21 ++++++++ .../ApplicationMain/attr_main_return.swift | 2 +- .../ApplicationMain/attr_main_throws.swift | 2 +- .../attr_main_throws_prints_error.swift | 16 ++++++ 17 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing.swift create mode 100644 test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing_2.swift create mode 100644 test/attr/ApplicationMain/attr_main_resolves_types_throws.swift create mode 100644 test/attr/ApplicationMain/attr_main_resolves_types_throws_2.swift create mode 100644 test/attr/ApplicationMain/attr_main_throws_prints_error.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index eecf6c88b2089..69bfdd2e83cd1 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2913,7 +2913,7 @@ NOTE(attr_ApplicationMain_script_here,none, ()) ERROR(attr_MainType_without_main,none, - "%0 is annotated with @main and must provide a main static function of type () -> ().", + "%0 is annotated with @main and must provide a main static function of type () -> Void or () throws -> Void.", (DeclName)) #undef SELECT_APPLICATION_MAIN diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index bc9722061df61..c5dad9b5af4ff 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -155,9 +155,6 @@ class SourceFile final : public FileUnit { /// The source location of the main type. SourceLoc MainDeclDiagLoc; - /// The main function in the type marked @main. - FuncDecl *MainFunc = nullptr; - /// A hash of all interface-contributing tokens that have been lexed for /// this source file so far. /// We only collect interface hash for primary input files. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index aae1ffbf351cc..71b9d646f8598 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7332,7 +7332,7 @@ bool FuncDecl::isCallAsFunctionMethod() const { bool FuncDecl::isMainTypeMainMethod() const { return (getBaseIdentifier() == getASTContext().Id_main) && !isInstanceMember() && getResultInterfaceType()->isVoid() && - getParameters()->size() == 0 && !hasThrows(); + getParameters()->size() == 0; } ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index c189293b87143..04cc658449b71 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -725,8 +725,8 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { // Emit a call to the main static function. // return Module.$main(); auto *mainFunc = cast(mainDecl); - - SILGenFunctionBuilder builder(SGM); + auto moduleLoc = RegularLocation::getModuleLocation(); + auto *entryBlock = B.getInsertionBB(); SILDeclRef mainFunctionDeclRef(mainFunc, SILDeclRef::Kind::Func); SILFunction *mainFunction = @@ -743,16 +743,51 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { } auto metatype = B.createMetatype(mainType, getLoweredType(mainType->getInterfaceType())); - auto mainFunctionRef = B.createFunctionRef(mainFunc, mainFunction); + auto mainFunctionRef = B.createFunctionRef(moduleLoc, mainFunction); - B.createApply(mainFunc, mainFunctionRef, SubstitutionMap(), {metatype}); + auto builtinInt32Type = SILType::getBuiltinIntegerType(32, getASTContext()); - SILValue returnValue = B.createIntegerLiteral( - mainFunc, SILType::getBuiltinIntegerType(32, getASTContext()), 0); + auto *exitBlock = createBasicBlock(); + B.setInsertionPoint(exitBlock); + SILValue exitCode = exitBlock->createPhiArgument(builtinInt32Type, + ValueOwnershipKind::None); auto returnType = F.getConventions().getSingleSILResultType(); - if (returnValue->getType() != returnType) - returnValue = B.createStruct(mainFunc, returnType, returnValue); - B.createReturn(mainFunc, returnValue); + if (exitCode->getType() != returnType) + exitCode = B.createStruct(moduleLoc, returnType, exitCode); + B.createReturn(moduleLoc, exitCode); + + if (mainFunc->hasThrows()) { + auto *successBlock = createBasicBlock(); + B.setInsertionPoint(successBlock); + successBlock->createPhiArgument(SGM.Types.getEmptyTupleType(), + ValueOwnershipKind::None); + SILValue zeroReturnValue = + B.createIntegerLiteral(moduleLoc, builtinInt32Type, 0); + B.createBranch(moduleLoc, exitBlock, {zeroReturnValue}); + + auto *failureBlock = createBasicBlock(); + B.setInsertionPoint(failureBlock); + SILValue error = failureBlock->createPhiArgument( + SILType::getExceptionType(getASTContext()), + ValueOwnershipKind::Owned); + // Log the error. + B.createBuiltin(moduleLoc, getASTContext().getIdentifier("errorInMain"), + SGM.Types.getEmptyTupleType(), {}, {error}); + B.createEndLifetime(moduleLoc, error); + SILValue oneReturnValue = + B.createIntegerLiteral(moduleLoc, builtinInt32Type, 1); + B.createBranch(moduleLoc, exitBlock, {oneReturnValue}); + + B.setInsertionPoint(entryBlock); + B.createTryApply(moduleLoc, mainFunctionRef, SubstitutionMap(), + {metatype}, successBlock, failureBlock); + } else { + B.setInsertionPoint(entryBlock); + B.createApply(moduleLoc, mainFunctionRef, SubstitutionMap(), {metatype}); + SILValue returnValue = + B.createIntegerLiteral(moduleLoc, builtinInt32Type, 0); + B.createBranch(moduleLoc, exitBlock, {returnValue}); + } return; } } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 4162ccac80f4b..db976e5e56c8d 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1786,14 +1786,19 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { mainFunction = viableCandidates[0]; } - auto voidToVoidFunctionType = FunctionType::get({}, context.TheEmptyTupleType); + bool mainFunctionThrows = mainFunction->hasThrows(); + + auto voidToVoidFunctionType = + FunctionType::get({}, context.TheEmptyTupleType, + FunctionType::ExtInfo().withThrows(mainFunctionThrows)); auto nominalToVoidToVoidFunctionType = FunctionType::get({AnyFunctionType::Param(nominal->getInterfaceType())}, voidToVoidFunctionType); auto *func = FuncDecl::create( - context, /*StaticLoc*/ braces.End, StaticSpellingKind::KeywordStatic, - /*FuncLoc*/ location, + context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::KeywordStatic, + /*FuncLoc*/ SourceLoc(), DeclName(context, DeclBaseName(context.Id_MainEntryPoint), ParameterList::createEmpty(context)), - /*NameLoc*/ braces.End, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*NameLoc*/ SourceLoc(), /*Throws=*/mainFunctionThrows, + /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParameterList::createEmpty(context), /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), declContext); @@ -1821,12 +1826,23 @@ void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { auto *dotSyntaxCallExpr = new (context) DotSyntaxCallExpr( funcDeclRefExpr, /*DotLoc*/ SourceLoc(), typeExpr, voidToVoidFunctionType); dotSyntaxCallExpr->setImplicit(true); - dotSyntaxCallExpr->setThrows(false); + dotSyntaxCallExpr->setThrows(mainFunctionThrows); auto *callExpr = CallExpr::createImplicit(context, dotSyntaxCallExpr, {}, {}); callExpr->setImplicit(true); - callExpr->setThrows(false); + callExpr->setThrows(mainFunctionThrows); callExpr->setType(context.TheEmptyTupleType); + + Expr *returnedExpr; + + if (mainFunctionThrows) { + auto *tryExpr = new (context) TryExpr( + SourceLoc(), callExpr, context.TheEmptyTupleType, /*implicit=*/true); + returnedExpr = tryExpr; + } else { + returnedExpr = callExpr; + } + auto *returnStmt = new (context) ReturnStmt(SourceLoc(), callExpr, /*Implicit=*/true); diff --git a/test/attr/ApplicationMain/attr_main_arguments.swift b/test/attr/ApplicationMain/attr_main_arguments.swift index 342d22252401c..758f8a6a9447b 100644 --- a/test/attr/ApplicationMain/attr_main_arguments.swift +++ b/test/attr/ApplicationMain/attr_main_arguments.swift @@ -1,6 +1,6 @@ // 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 of type () -> ().}} +@main // expected-error{{'MyBase' is annotated with @main and must provide a main static function}} struct MyBase { static func main(_ argc: Int, _ argv: [String]) { } diff --git a/test/attr/ApplicationMain/attr_main_dynamicCallable.swift b/test/attr/ApplicationMain/attr_main_dynamicCallable.swift index 11b011eddeb6d..05de870db44da 100644 --- a/test/attr/ApplicationMain/attr_main_dynamicCallable.swift +++ b/test/attr/ApplicationMain/attr_main_dynamicCallable.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s -@main // expected-error{{'Foo' is annotated with @main and must provide a main static function of type () -> ().}} +@main // expected-error{{'Foo' is annotated with @main and must provide a main static function}} struct Foo { @dynamicCallable struct main { diff --git a/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift b/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift index a731febbfdda2..63382fefbf4ed 100644 --- a/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift +++ b/test/attr/ApplicationMain/attr_main_dynamicMemberLookup.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s -@main @dynamicMemberLookup // expected-error{{'Main' is annotated with @main and must provide a main static function of type () -> ().}} +@main @dynamicMemberLookup // expected-error{{'Main' is annotated with @main and must provide a main static function}} struct Main { subscript(dynamicMember member: String) -> () -> Void { return { diff --git a/test/attr/ApplicationMain/attr_main_extension_nofunc.swift b/test/attr/ApplicationMain/attr_main_extension_nofunc.swift index 16cf107f8dbdd..33f4ea1ccd297 100644 --- a/test/attr/ApplicationMain/attr_main_extension_nofunc.swift +++ b/test/attr/ApplicationMain/attr_main_extension_nofunc.swift @@ -3,7 +3,7 @@ class EntryPoint { } -@main // expected-error{{'EntryPoint' is annotated with @main and must provide a main static function of type () -> ()}} +@main // expected-error{{'EntryPoint' is annotated with @main and must provide a main static function}} extension EntryPoint { } diff --git a/test/attr/ApplicationMain/attr_main_instance.swift b/test/attr/ApplicationMain/attr_main_instance.swift index 31831f9bdc369..a82b00493bfab 100644 --- a/test/attr/ApplicationMain/attr_main_instance.swift +++ b/test/attr/ApplicationMain/attr_main_instance.swift @@ -1,6 +1,6 @@ // 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 of type () -> ().}} +@main // expected-error{{'MyBase' is annotated with @main and must provide a main static function}} class MyBase { func main() { } diff --git a/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing.swift b/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing.swift new file mode 100644 index 0000000000000..410221f847bc5 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing.swift @@ -0,0 +1,22 @@ +// RUN: %target-run-simple-swift(-parse-as-library) | %FileCheck %s +// REQUIRES: executable_test + +protocol P { +} +extension P { + static func main() throws { + print("P.main") + } +} +struct S { + static func main() { + print("S.main") + } +} + +// CHECK: S.main +@main +extension S : P {} + + + diff --git a/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing_2.swift b/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing_2.swift new file mode 100644 index 0000000000000..15d9f0aaa4ed0 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_resolves_types_nonthrowing_2.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-parse-as-library) | %FileCheck %s +// REQUIRES: executable_test + +protocol P { +} +extension P { + static func main() { + print("P.main") + } +} +struct S { + static func main() { + print("S.main though neither throw") + } +} + +// CHECK: S.main though neither throw +@main +extension S : P {} + diff --git a/test/attr/ApplicationMain/attr_main_resolves_types_throws.swift b/test/attr/ApplicationMain/attr_main_resolves_types_throws.swift new file mode 100644 index 0000000000000..3b970da871747 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_resolves_types_throws.swift @@ -0,0 +1,20 @@ +// RUN: %target-run-simple-swift(-parse-as-library) | %FileCheck %s +// REQUIRES: executable_test + +protocol P { +} +extension P { + static func main() { + print("P.main") + } +} +struct S { + static func main() throws { + print("S.main though throwing") + } +} + +// CHECK: S.main though throwing +@main +extension S : P {} + diff --git a/test/attr/ApplicationMain/attr_main_resolves_types_throws_2.swift b/test/attr/ApplicationMain/attr_main_resolves_types_throws_2.swift new file mode 100644 index 0000000000000..da20c662375b3 --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_resolves_types_throws_2.swift @@ -0,0 +1,21 @@ +// RUN: %target-run-simple-swift(-parse-as-library) | %FileCheck %s +// REQUIRES: executable_test + +protocol P { +} +extension P { + static func main() throws { + print("P.main") + } +} +struct S { + static func main() throws { + print("S.main though both throw") + } +} + +// CHECK: S.main though both throw +@main +extension S : P {} + + diff --git a/test/attr/ApplicationMain/attr_main_return.swift b/test/attr/ApplicationMain/attr_main_return.swift index 8cc8e3c15d040..0039e8642b696 100644 --- a/test/attr/ApplicationMain/attr_main_return.swift +++ b/test/attr/ApplicationMain/attr_main_return.swift @@ -1,6 +1,6 @@ // 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 of type () -> ().}} +@main // expected-error{{'MyBase' is annotated with @main and must provide a main static function}} struct MyBase { static func main() -> Int { } diff --git a/test/attr/ApplicationMain/attr_main_throws.swift b/test/attr/ApplicationMain/attr_main_throws.swift index 19aef346bea13..f3e8d80c4a266 100644 --- a/test/attr/ApplicationMain/attr_main_throws.swift +++ b/test/attr/ApplicationMain/attr_main_throws.swift @@ -1,6 +1,6 @@ // 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 of type () -> ().}} +@main struct MyBase { static func main() throws { } diff --git a/test/attr/ApplicationMain/attr_main_throws_prints_error.swift b/test/attr/ApplicationMain/attr_main_throws_prints_error.swift new file mode 100644 index 0000000000000..6f87bb65eac3a --- /dev/null +++ b/test/attr/ApplicationMain/attr_main_throws_prints_error.swift @@ -0,0 +1,16 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library %s -o %t/main +// RUN: %target-codesign %t/main +// RUN: not --crash %t/main 2>&1 | %FileCheck %s +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +enum Err : Error { case or } + +// CHECK: Fatal error: Error raised at top level: main.Err.or: +@main +struct S { + static func main() throws { + throw Err.or + } +}