Skip to content

Commit a41a2ff

Browse files
Merge pull request #30693 from nate-chandler/main-attribute
@main: Attribute to add an entry point to a type.
2 parents 78e07c1 + 81dc64f commit a41a2ff

File tree

68 files changed

+925
-67
lines changed

Some content is hidden

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

68 files changed

+925
-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 | OnExtension |
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;
@@ -3814,12 +3828,6 @@ class StructDecl final : public NominalTypeDecl {
38143828
}
38153829
};
38163830

3817-
/// The kind of artificial main to generate for a class.
3818-
enum class ArtificialMainKind : uint8_t {
3819-
NSApplicationMain,
3820-
UIApplicationMain,
3821-
};
3822-
38233831
/// This is the base type for AncestryOptions. Each flag describes possible
38243832
/// interesting kinds of superclasses that a class may have.
38253833
enum class AncestryFlags : uint8_t {
@@ -4087,13 +4095,6 @@ class ClassDecl final : public NominalTypeDecl {
40874095
/// the Objective-C runtime.
40884096
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
40894097

4090-
/// Returns the appropriate kind of entry point to generate for this class,
4091-
/// based on its attributes.
4092-
///
4093-
/// It is an error to call this on a class that does not have a
4094-
/// *ApplicationMain attribute.
4095-
ArtificialMainKind getArtificialMainKind() const;
4096-
40974098
using NominalTypeDecl::lookupDirect;
40984099

40994100
/// Look in this class and its extensions (but not any of its protocols or
@@ -6297,6 +6298,8 @@ class FuncDecl : public AbstractFunctionDecl {
62976298
}
62986299
bool isCallAsFunctionMethod() const;
62996300

6301+
bool isMainTypeMainMethod() const;
6302+
63006303
SelfAccessKind getSelfAccessKind() const;
63016304

63026305
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 () -> Void or () throws -> Void.",
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: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,12 @@ class SourceFile final : public FileUnit {
140140
/// If non-null, used to track name lookups that happen within this file.
141141
Optional<ReferencedNameTracker> RequestReferencedNames;
142142

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

146-
/// The source location of the main class.
147-
SourceLoc MainClassDiagLoc;
147+
/// The source location of the main type.
148+
SourceLoc MainDeclDiagLoc;
148149

149150
/// A hash of all interface-contributing tokens that have been lexed for
150151
/// this source file so far.
@@ -538,26 +539,28 @@ class SourceFile final : public FileUnit {
538539
llvm_unreachable("bad SourceFileKind");
539540
}
540541

541-
ClassDecl *getMainClass() const override {
542-
return MainClass;
542+
Decl *getMainDecl() const override { return MainDecl; }
543+
SourceLoc getMainDeclDiagLoc() const {
544+
assert(hasMainDecl());
545+
return MainDeclDiagLoc;
543546
}
544547
SourceLoc getMainClassDiagLoc() const {
545548
assert(hasMainClass());
546-
return MainClassDiagLoc;
549+
return getMainDeclDiagLoc();
547550
}
548551

549552
/// Register a "main" class for the module, complaining if there is more than
550553
/// one.
551554
///
552555
/// Should only be called during type-checking.
553-
bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc);
556+
bool registerMainDecl(Decl *mainDecl, SourceLoc diagLoc);
554557

555558
/// True if this source file has an application entry point.
556559
///
557560
/// This is true if the source file either is in script mode or contains
558561
/// a designated main class.
559562
bool hasEntryPoint() const override {
560-
return isScriptMode() || hasMainClass();
563+
return isScriptMode() || hasMainDecl();
561564
}
562565

563566
/// 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;
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
@@ -1562,16 +1562,17 @@ bool ModuleDecl::isBuiltinModule() const {
15621562
return this == getASTContext().TheBuiltinModule;
15631563
}
15641564

1565-
bool SourceFile::registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc) {
1566-
if (mainClass == MainClass)
1565+
bool SourceFile::registerMainDecl(Decl *mainDecl, SourceLoc diagLoc) {
1566+
if (mainDecl == MainDecl)
15671567
return false;
15681568

1569-
ArtificialMainKind kind = mainClass->getArtificialMainKind();
1569+
ArtificialMainKind kind = mainDecl->getArtificialMainKind();
15701570
if (getParentModule()->registerEntryPointFile(this, diagLoc, kind))
15711571
return true;
15721572

1573-
MainClass = mainClass;
1574-
MainClassDiagLoc = diagLoc;
1573+
MainDecl = mainDecl;
1574+
MainDeclDiagLoc = diagLoc;
1575+
15751576
return false;
15761577
}
15771578

@@ -1591,53 +1592,59 @@ bool ModuleDecl::registerEntryPointFile(FileUnit *file, SourceLoc diagLoc,
15911592
enum : unsigned {
15921593
UIApplicationMainClass = 0,
15931594
NSApplicationMainClass = 1,
1594-
} mainClassDiagKind;
1595+
MainType = 2,
1596+
} mainTypeDiagKind;
15951597

15961598
switch (kind.getValue()) {
15971599
case ArtificialMainKind::UIApplicationMain:
1598-
mainClassDiagKind = UIApplicationMainClass;
1600+
mainTypeDiagKind = UIApplicationMainClass;
15991601
break;
16001602
case ArtificialMainKind::NSApplicationMain:
1601-
mainClassDiagKind = NSApplicationMainClass;
1603+
mainTypeDiagKind = NSApplicationMainClass;
1604+
break;
1605+
case ArtificialMainKind::TypeMain:
1606+
mainTypeDiagKind = MainType;
16021607
break;
16031608
}
16041609

16051610
FileUnit *existingFile = EntryPointInfo.getEntryPointFile();
1606-
const ClassDecl *existingClass = existingFile->getMainClass();
1611+
const Decl *existingDecl = existingFile->getMainDecl();
16071612
SourceLoc existingDiagLoc;
16081613

16091614
if (auto *sourceFile = dyn_cast<SourceFile>(existingFile)) {
1610-
if (existingClass) {
1611-
existingDiagLoc = sourceFile->getMainClassDiagLoc();
1615+
if (existingDecl) {
1616+
existingDiagLoc = sourceFile->getMainDeclDiagLoc();
16121617
} else {
16131618
if (auto bufID = sourceFile->getBufferID())
16141619
existingDiagLoc = getASTContext().SourceMgr.getLocForBufferStart(*bufID);
16151620
}
16161621
}
16171622

1618-
if (existingClass) {
1623+
if (existingDecl) {
16191624
if (EntryPointInfo.markDiagnosedMultipleMainClasses()) {
1620-
// If we already have a main class, and we haven't diagnosed it,
1625+
// If we already have a main type, and we haven't diagnosed it,
16211626
// do so now.
16221627
if (existingDiagLoc.isValid()) {
1623-
getASTContext().Diags.diagnose(existingDiagLoc, diag::attr_ApplicationMain_multiple,
1624-
mainClassDiagKind);
1628+
getASTContext().Diags.diagnose(existingDiagLoc,
1629+
diag::attr_ApplicationMain_multiple,
1630+
mainTypeDiagKind);
16251631
} else {
1626-
getASTContext().Diags.diagnose(existingClass, diag::attr_ApplicationMain_multiple,
1627-
mainClassDiagKind);
1632+
getASTContext().Diags.diagnose(existingDecl,
1633+
diag::attr_ApplicationMain_multiple,
1634+
mainTypeDiagKind);
16281635
}
16291636
}
16301637

16311638
// Always diagnose the new class.
16321639
getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_multiple,
1633-
mainClassDiagKind);
1640+
mainTypeDiagKind);
16341641

16351642
} else {
16361643
// We don't have an existing class, but we /do/ have a file in script mode.
16371644
// Diagnose that.
16381645
if (EntryPointInfo.markDiagnosedMainClassWithScript()) {
1639-
getASTContext().Diags.diagnose(diagLoc, diag::attr_ApplicationMain_with_script,
1640-
mainClassDiagKind);
1646+
getASTContext().Diags.diagnose(
1647+
diagLoc, diag::attr_ApplicationMain_with_script, mainTypeDiagKind);
16411648

16421649
if (existingDiagLoc.isValid()) {
16431650
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)