Skip to content

Commit f7e2abe

Browse files
committed
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.
1 parent 94078cb commit f7e2abe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+525
-67
lines changed

include/swift/AST/Attr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ SIMPLE_DECL_ATTR(dynamicCallable, DynamicCallable,
147147
OnNominalType |
148148
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
149149
6)
150-
// NOTE: 7 is unused
150+
SIMPLE_DECL_ATTR(main, MainType,
151+
OnClass | OnStruct | OnEnum |
152+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
153+
7)
151154
SIMPLE_DECL_ATTR(_exported, Exported,
152155
OnImport |
153156
UserInaccessible |

include/swift/AST/Decl.h

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ bool conflicting(ASTContext &ctx,
272272
bool *wouldConflictInSwift5 = nullptr,
273273
bool skipProtocolExtensionCheck = false);
274274

275+
/// The kind of artificial main to generate.
276+
enum class ArtificialMainKind : uint8_t {
277+
NSApplicationMain,
278+
UIApplicationMain,
279+
TypeMain,
280+
};
281+
275282
/// Decl - Base class for all declarations in Swift.
276283
class alignas(1 << DeclAlignInBits) Decl {
277284
protected:
@@ -779,6 +786,13 @@ class alignas(1 << DeclAlignInBits) Decl {
779786

780787
SourceLoc TrailingSemiLoc;
781788

789+
/// Returns the appropriate kind of entry point to generate for this class,
790+
/// based on its attributes.
791+
///
792+
/// It is an error to call this on a type that does not have either an
793+
/// *ApplicationMain or an main attribute.
794+
ArtificialMainKind getArtificialMainKind() const;
795+
782796
SWIFT_DEBUG_DUMP;
783797
SWIFT_DEBUG_DUMPER(dump(const char *filename));
784798
void dump(raw_ostream &OS, unsigned Indent = 0) const;
@@ -3810,12 +3824,6 @@ class StructDecl final : public NominalTypeDecl {
38103824
}
38113825
};
38123826

3813-
/// The kind of artificial main to generate for a class.
3814-
enum class ArtificialMainKind : uint8_t {
3815-
NSApplicationMain,
3816-
UIApplicationMain,
3817-
};
3818-
38193827
/// This is the base type for AncestryOptions. Each flag describes possible
38203828
/// interesting kinds of superclasses that a class may have.
38213829
enum class AncestryFlags : uint8_t {
@@ -4083,13 +4091,6 @@ class ClassDecl final : public NominalTypeDecl {
40834091
/// the Objective-C runtime.
40844092
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
40854093

4086-
/// Returns the appropriate kind of entry point to generate for this class,
4087-
/// based on its attributes.
4088-
///
4089-
/// It is an error to call this on a class that does not have a
4090-
/// *ApplicationMain attribute.
4091-
ArtificialMainKind getArtificialMainKind() const;
4092-
40934094
using NominalTypeDecl::lookupDirect;
40944095

40954096
/// Look in this class and its extensions (but not any of its protocols or
@@ -6293,6 +6294,8 @@ class FuncDecl : public AbstractFunctionDecl {
62936294
}
62946295
bool isCallAsFunctionMethod() const;
62956296

6297+
bool isMainTypeMainMethod() const;
6298+
62966299
SelfAccessKind getSelfAccessKind() const;
62976300

62986301
void setSelfAccessKind(SelfAccessKind mod) {

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,17 +2890,19 @@ ERROR(nscopying_doesnt_conform,none,
28902890
" the NSCopying protocol", ())
28912891

28922892
// UIApplicationMain/NSApplicationMain attribute
2893-
#define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'}"
2893+
#define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'|'main'}"
28942894
#define SELECT_APPLICATION_DELEGATE "select{'UIApplicationDelegate'|'NSApplicationDelegate'}"
2895+
#define SELECT_APPLICATION_TYPE "select{class|class|type}"
2896+
#define SELECT_APPLICATION_TYPES "select{classes|classes|types}"
28952897

28962898
ERROR(attr_ApplicationMain_not_ApplicationDelegate,none,
28972899
"%" SELECT_APPLICATION_MAIN "0 class must conform to the %" SELECT_APPLICATION_DELEGATE "0 protocol",
28982900
(unsigned))
28992901
ERROR(attr_generic_ApplicationMain_not_supported,none,
2900-
"generic %" SELECT_APPLICATION_MAIN "0 classes are not supported",
2902+
"generic %" SELECT_APPLICATION_MAIN "0 %" SELECT_APPLICATION_TYPES "0 are not supported",
29012903
(unsigned))
29022904
ERROR(attr_ApplicationMain_multiple,none,
2903-
"%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one class in a module",
2905+
"%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one %" SELECT_APPLICATION_TYPE "0 in a module",
29042906
(unsigned))
29052907
ERROR(attr_ApplicationMain_with_script,none,
29062908
"%" SELECT_APPLICATION_MAIN "0 attribute cannot be used in a module that contains "
@@ -2910,6 +2912,10 @@ NOTE(attr_ApplicationMain_script_here,none,
29102912
"top-level code defined in this source file",
29112913
())
29122914

2915+
ERROR(attr_MainType_without_main,none,
2916+
"%0 is annotated with @main and must provide a main static function of type () -> ().",
2917+
(DeclName))
2918+
29132919
#undef SELECT_APPLICATION_MAIN
29142920
#undef SELECT_APPLICATION_DELEGATE
29152921

include/swift/AST/FileUnit.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,13 @@ class FileUnit : public DeclContext {
260260
bool hasMainClass() const {
261261
return getMainClass();
262262
}
263-
virtual ClassDecl *getMainClass() const {
264-
assert(hasEntryPoint());
265-
return nullptr;
263+
ClassDecl *getMainClass() const {
264+
return dyn_cast_or_null<ClassDecl>(getMainDecl());
265+
}
266+
bool hasMainDecl() const { return getMainDecl(); }
267+
virtual Decl *getMainDecl() const { return nullptr; }
268+
FuncDecl *getMainFunc() const {
269+
return dyn_cast_or_null<FuncDecl>(getMainDecl());
266270
}
267271
virtual bool hasEntryPoint() const {
268272
return false;

include/swift/AST/KnownIdentifiers.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ IDENTIFIER(keyPath)
9292
IDENTIFIER(makeIterator)
9393
IDENTIFIER(Iterator)
9494
IDENTIFIER(load)
95+
IDENTIFIER(main)
96+
IDENTIFIER_WITH_NAME(MainEntryPoint, "$main")
9597
IDENTIFIER(next)
9698
IDENTIFIER_(nsErrorDomain)
9799
IDENTIFIER(objectAtIndexedSubscript)

include/swift/AST/SourceFile.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,15 @@ class SourceFile final : public FileUnit {
148148
Optional<ReferencedNameTracker> ReferencedNames;
149149
Optional<ReferencedNameTracker> RequestReferencedNames;
150150

151-
/// The class in this file marked \@NS/UIApplicationMain.
152-
ClassDecl *MainClass = nullptr;
151+
/// Either the class marked \@NS/UIApplicationMain or the synthesized FuncDecl
152+
/// that calls main on the type marked @main.
153+
Decl *MainDecl = nullptr;
153154

154-
/// The source location of the main class.
155-
SourceLoc MainClassDiagLoc;
155+
/// The source location of the main type.
156+
SourceLoc MainDeclDiagLoc;
157+
158+
/// The main function in the type marked @main.
159+
FuncDecl *MainFunc = nullptr;
156160

157161
/// A hash of all interface-contributing tokens that have been lexed for
158162
/// this source file so far.
@@ -553,26 +557,28 @@ class SourceFile final : public FileUnit {
553557
llvm_unreachable("bad SourceFileKind");
554558
}
555559

556-
ClassDecl *getMainClass() const override {
557-
return MainClass;
560+
Decl *getMainDecl() const override { return MainDecl; }
561+
SourceLoc getMainDeclDiagLoc() const {
562+
assert(hasMainDecl());
563+
return MainDeclDiagLoc;
558564
}
559565
SourceLoc getMainClassDiagLoc() const {
560566
assert(hasMainClass());
561-
return MainClassDiagLoc;
567+
return getMainDeclDiagLoc();
562568
}
563569

564570
/// Register a "main" class for the module, complaining if there is more than
565571
/// one.
566572
///
567573
/// Should only be called during type-checking.
568-
bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc);
574+
bool registerMainDecl(Decl *mainDecl, SourceLoc diagLoc);
569575

570576
/// True if this source file has an application entry point.
571577
///
572578
/// This is true if the source file either is in script mode or contains
573579
/// a designated main class.
574580
bool hasEntryPoint() const override {
575-
return isScriptMode() || hasMainClass();
581+
return isScriptMode() || hasMainDecl();
576582
}
577583

578584
/// Get the root refinement context for the file. The root context may be

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ class SerializedASTFile final : public LoadedFile {
410410

411411
virtual StringRef getModuleDefiningPath() const override;
412412

413-
ClassDecl *getMainClass() const override;
413+
Decl *getMainDecl() const override;
414414

415415
bool hasEntryPoint() const override;
416416

lib/AST/Decl.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4437,12 +4437,14 @@ StringRef ClassDecl::getObjCRuntimeName(
44374437
return mangleObjCRuntimeName(this, buffer);
44384438
}
44394439

4440-
ArtificialMainKind ClassDecl::getArtificialMainKind() const {
4440+
ArtificialMainKind Decl::getArtificialMainKind() const {
44414441
if (getAttrs().hasAttribute<UIApplicationMainAttr>())
44424442
return ArtificialMainKind::UIApplicationMain;
44434443
if (getAttrs().hasAttribute<NSApplicationMainAttr>())
44444444
return ArtificialMainKind::NSApplicationMain;
4445-
llvm_unreachable("class has no @ApplicationMain attr?!");
4445+
if (isa<FuncDecl>(this))
4446+
return ArtificialMainKind::TypeMain;
4447+
llvm_unreachable("type has no @Main attr?!");
44464448
}
44474449

44484450
static bool isOverridingDecl(const ValueDecl *Derived,
@@ -7327,6 +7329,12 @@ bool FuncDecl::isCallAsFunctionMethod() const {
73277329
isInstanceMember();
73287330
}
73297331

7332+
bool FuncDecl::isMainTypeMainMethod() const {
7333+
return (getBaseIdentifier() == getASTContext().Id_main) &&
7334+
!isInstanceMember() && getResultInterfaceType()->isVoid() &&
7335+
getParameters()->size() == 0 && !hasThrows();
7336+
}
7337+
73307338
ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
73317339
bool Failable, SourceLoc FailabilityLoc,
73327340
bool Throws,

lib/AST/Module.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,16 +1554,17 @@ bool ModuleDecl::isBuiltinModule() const {
15541554
return this == getASTContext().TheBuiltinModule;
15551555
}
15561556

1557-
bool SourceFile::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) {
1558-
if (mainClass == MainClass)
1557+
bool SourceFile::registerMainDecl(Decl *mainDecl, SourceLoc diagLoc) {
1558+
if (mainDecl == MainDecl)
15591559
return false;
15601560

1561-
ArtificialMainKind kind = mainClass->getArtificialMainKind();
1561+
ArtificialMainKind kind = mainDecl->getArtificialMainKind();
15621562
if (getParentModule()->registerEntryPointFile(this, diagLoc, kind))
15631563
return true;
15641564

1565-
MainClass = mainClass;
1566-
MainClassDiagLoc = diagLoc;
1565+
MainDecl = mainDecl;
1566+
MainDeclDiagLoc = diagLoc;
1567+
15671568
return false;
15681569
}
15691570

@@ -1583,53 +1584,59 @@ bool ModuleDecl::registerEntryPointFile(FileUnit *file, SourceLoc diagLoc,
15831584
enum : unsigned {
15841585
UIApplicationMainClass = 0,
15851586
NSApplicationMainClass = 1,
1586-
} mainClassDiagKind;
1587+
MainType = 2,
1588+
} mainTypeDiagKind;
15871589

15881590
switch (kind.getValue()) {
15891591
case ArtificialMainKind::UIApplicationMain:
1590-
mainClassDiagKind = UIApplicationMainClass;
1592+
mainTypeDiagKind = UIApplicationMainClass;
15911593
break;
15921594
case ArtificialMainKind::NSApplicationMain:
1593-
mainClassDiagKind = NSApplicationMainClass;
1595+
mainTypeDiagKind = NSApplicationMainClass;
1596+
break;
1597+
case ArtificialMainKind::TypeMain:
1598+
mainTypeDiagKind = MainType;
15941599
break;
15951600
}
15961601

15971602
FileUnit *existingFile = EntryPointInfo.getEntryPointFile();
1598-
const ClassDecl *existingClass = existingFile->getMainClass();
1603+
const Decl *existingDecl = existingFile->getMainDecl();
15991604
SourceLoc existingDiagLoc;
16001605

16011606
if (auto *sourceFile = dyn_cast<SourceFile>(existingFile)) {
1602-
if (existingClass) {
1603-
existingDiagLoc = sourceFile->getMainClassDiagLoc();
1607+
if (existingDecl) {
1608+
existingDiagLoc = sourceFile->getMainDeclDiagLoc();
16041609
} else {
16051610
if (auto bufID = sourceFile->getBufferID())
16061611
existingDiagLoc = getASTContext().SourceMgr.getLocForBufferStart(*bufID);
16071612
}
16081613
}
16091614

1610-
if (existingClass) {
1615+
if (existingDecl) {
16111616
if (EntryPointInfo.markDiagnosedMultipleMainClasses()) {
1612-
// If we already have a main class, and we haven't diagnosed it,
1617+
// If we already have a main type, and we haven't diagnosed it,
16131618
// do so now.
16141619
if (existingDiagLoc.isValid()) {
1615-
getASTContext().Diags.diagnose(existingDiagLoc, diag::attr_ApplicationMain_multiple,
1616-
mainClassDiagKind);
1620+
getASTContext().Diags.diagnose(existingDiagLoc,
1621+
diag::attr_ApplicationMain_multiple,
1622+
mainTypeDiagKind);
16171623
} else {
1618-
getASTContext().Diags.diagnose(existingClass, diag::attr_ApplicationMain_multiple,
1619-
mainClassDiagKind);
1624+
getASTContext().Diags.diagnose(existingDecl,
1625+
diag::attr_ApplicationMain_multiple,
1626+
mainTypeDiagKind);
16201627
}
16211628
}
16221629

16231630
// Always diagnose the new class.
16241631
getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_multiple,
1625-
mainClassDiagKind);
1632+
mainTypeDiagKind);
16261633

16271634
} else {
16281635
// We don't have an existing class, but we /do/ have a file in script mode.
16291636
// Diagnose that.
16301637
if (EntryPointInfo.markDiagnosedMainClassWithScript()) {
1631-
getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_with_script,
1632-
mainClassDiagKind);
1638+
getASTContext().Diags.diagnose(
1639+
diagLoc, diag::attr_ApplicationMain_with_script, mainTypeDiagKind);
16331640

16341641
if (existingDiagLoc.isValid()) {
16351642
getASTContext().Diags.diagnose(existingDiagLoc,

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,7 +1781,7 @@ class SourceFileScope {
17811781

17821782
// If the source file contains an artificial main, emit the implicit
17831783
// toplevel code.
1784-
if (auto mainClass = sf->getMainClass()) {
1784+
if (auto mainDecl = sf->getMainDecl()) {
17851785
assert(!sgm.M.lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION)
17861786
&& "already emitted toplevel before main class?!");
17871787

@@ -1798,7 +1798,7 @@ class SourceFileScope {
17981798
SGF.F.getConventions().getParameterSILTypes().begin();
17991799
entry->createFunctionArgument(*paramTypeIter);
18001800
entry->createFunctionArgument(*std::next(paramTypeIter));
1801-
SGF.emitArtificialTopLevel(mainClass);
1801+
SGF.emitArtificialTopLevel(mainDecl);
18021802
}
18031803
}
18041804
};

0 commit comments

Comments
 (0)