diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 0ccc1d770d8a8..8054500c3b772 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 | OnExtension | + 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..69bfdd2e83cd1 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 () -> Void or () throws -> Void.", + (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..c5dad9b5af4ff 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -148,11 +148,12 @@ 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; /// A hash of all interface-contributing tokens that have been lexed for /// this source file so far. @@ -553,26 +554,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..71b9d646f8598 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; +} + 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..04cc658449b71 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,76 @@ 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); + auto moduleLoc = RegularLocation::getModuleLocation(); + auto *entryBlock = B.getInsertionBB(); + + SILDeclRef mainFunctionDeclRef(mainFunc, SILDeclRef::Kind::Func); + SILFunction *mainFunction = + SGM.getFunction(mainFunctionDeclRef, NotForDefinition); + + 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(moduleLoc, mainFunction); + + auto builtinInt32Type = SILType::getBuiltinIntegerType(32, getASTContext()); + + auto *exitBlock = createBasicBlock(); + B.setInsertionPoint(exitBlock); + SILValue exitCode = exitBlock->createPhiArgument(builtinInt32Type, + ValueOwnershipKind::None); + auto returnType = F.getConventions().getSingleSILResultType(); + 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/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..db976e5e56c8d 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,195 @@ void AttributeChecker::visitUIApplicationMainAttr(UIApplicationMainAttr *attr) { C.getIdentifier("UIApplicationMain")); } +void AttributeChecker::visitMainTypeAttr(MainTypeAttr *attr) { + 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()) { + diagnose(attr->getLocation(), + diag::attr_generic_ApplicationMain_not_supported, 2); + attr->setInvalid(); + return; + } + + SourceFile *file = cast(declContext->getModuleScopeContext()); + assert(file); + + // 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 = D->getASTContext(); + auto location = attr->getLocation(); + + auto resolution = resolveValueMember( + *declContext, 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]; + } + + 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*/ SourceLoc(), StaticSpellingKind::KeywordStatic, + /*FuncLoc*/ SourceLoc(), + DeclName(context, DeclBaseName(context.Id_MainEntryPoint), + ParameterList::createEmpty(context)), + /*NameLoc*/ SourceLoc(), /*Throws=*/mainFunctionThrows, + /*ThrowsLoc=*/SourceLoc(), + /*GenericParams=*/nullptr, ParameterList::createEmpty(context), + /*FnRetType=*/TypeLoc::withoutLoc(TupleType::getEmpty(context)), + declContext); + func->setImplicit(true); + func->setSynthesized(true); + + 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(mainFunctionThrows); + + auto *callExpr = CallExpr::createImplicit(context, dotSyntaxCallExpr, {}, {}); + callExpr->setImplicit(true); + 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); + + SmallVector stmts; + stmts.push_back(returnStmt); + auto *body = BraceStmt::create(context, SourceLoc(), stmts, + SourceLoc(), /*Implicit*/true); + func->setBodyParsed(body); + func->setInterfaceType(nominalToVoidToVoidFunctionType); + + iterableDeclContext->addMember(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..758f8a6a9447b --- /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}} +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_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_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..05de870db44da --- /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}} +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..63382fefbf4ed --- /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}} +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_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..33f4ea1ccd297 --- /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}} +extension EntryPoint { +} + + 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..a82b00493bfab --- /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}} +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_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 new file mode 100644 index 0000000000000..0039e8642b696 --- /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}} +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_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_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..f3e8d80c4a266 --- /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 +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 + } +} 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() { + } +} + + + + 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()