Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
29 changes: 16 additions & 13 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -4083,13 +4091,6 @@ class ClassDecl final : public NominalTypeDecl {
/// the Objective-C runtime.
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &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
Expand Down Expand Up @@ -6293,6 +6294,8 @@ class FuncDecl : public AbstractFunctionDecl {
}
bool isCallAsFunctionMethod() const;

bool isMainTypeMainMethod() const;

SelfAccessKind getSelfAccessKind() const;

void setSelfAccessKind(SelfAccessKind mod) {
Expand Down
12 changes: 9 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand All @@ -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

Expand Down
10 changes: 7 additions & 3 deletions include/swift/AST/FileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClassDecl>(getMainDecl());
}
bool hasMainDecl() const { return getMainDecl(); }
virtual Decl *getMainDecl() const { return nullptr; }
FuncDecl *getMainFunc() const {
return dyn_cast_or_null<FuncDecl>(getMainDecl());
}
virtual bool hasEntryPoint() const {
return false;
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 12 additions & 9 deletions include/swift/AST/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,12 @@ class SourceFile final : public FileUnit {
Optional<ReferencedNameTracker> ReferencedNames;
Optional<ReferencedNameTracker> 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.
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
12 changes: 10 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4437,12 +4437,14 @@ StringRef ClassDecl::getObjCRuntimeName(
return mangleObjCRuntimeName(this, buffer);
}

ArtificialMainKind ClassDecl::getArtificialMainKind() const {
ArtificialMainKind Decl::getArtificialMainKind() const {
if (getAttrs().hasAttribute<UIApplicationMainAttr>())
return ArtificialMainKind::UIApplicationMain;
if (getAttrs().hasAttribute<NSApplicationMainAttr>())
return ArtificialMainKind::NSApplicationMain;
llvm_unreachable("class has no @ApplicationMain attr?!");
if (isa<FuncDecl>(this))
return ArtificialMainKind::TypeMain;
llvm_unreachable("type has no @Main attr?!");
}

static bool isOverridingDecl(const ValueDecl *Derived,
Expand Down Expand Up @@ -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,
Expand Down
47 changes: 27 additions & 20 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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<SourceFile>(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,
Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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?!");

Expand All @@ -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);
}
}
};
Expand Down
Loading