@@ -414,107 +414,71 @@ class DeclAndTypePrinter::Implementation
414414 return p1.second .tag < p2.second .tag ;
415415 });
416416
417- if (elementTagMapping.empty ()) {
418- os << " \n " ;
419- return ;
420- }
421-
422- os << " enum class cases {\n " ;
423- for (const auto &pair : elementTagMapping) {
424- os << " " ;
425- syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
426- os << " ,\n " ;
427- }
428- os << " };\n " ; // enum class cases' closing bracket
429-
430- // Printing operator cases()
431- os << " inline operator cases() const {\n " ;
432- if (ED->isResilient ()) {
433- os << " auto tag = _getEnumTag();\n " ;
434- for (const auto &pair : elementTagMapping) {
435- os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName ();
436- os << " ::" << pair.second .globalVariableName << " ) return cases::" ;
437- syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
438- os << " ;\n " ;
439- }
440- // TODO: change to Swift's fatalError when it's available in C++
441- os << " abort();\n " ;
442- } else { // non-resilient enum
443- os << " switch (_getEnumTag()) {\n " ;
444- for (const auto &pair : elementTagMapping) {
445- os << " case " << pair.second .tag << " : return cases::" ;
446- syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
447- os << " ;\n " ;
448- }
449- // TODO: change to Swift's fatalError when it's available in C++
450- os << " default: abort();\n " ;
451- os << " }\n " ; // switch's closing bracket
452- }
453- os << " }\n " ; // operator cases()'s closing bracket
454-
417+ os << ' \n ' ;
418+ os << " enum class cases {" ;
419+ llvm::interleave (
420+ elementTagMapping, os,
421+ [&](const auto &pair) {
422+ os << " \n " ;
423+ syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
424+ },
425+ " ," );
426+ // TODO: allow custom name for this special case
427+ auto resilientUnknownDefaultCaseName = " unknownDefault" ;
455428 if (ED->isResilient ()) {
456- os << " inline bool inResilientUnknownCase() const {\n " ;
457- os << " auto tag = _getEnumTag();\n " ;
458- os << " return" ;
459- llvm::interleave (
460- elementTagMapping, os,
461- [&](const auto &pair) {
462- os << " \n tag != " << cxx_synthesis::getCxxImplNamespaceName ()
463- << " ::" << pair.second .globalVariableName ;
464- },
465- " &&" );
466- os << " ;\n " ;
467- os << " }\n " ;
429+ os << " ,\n " << resilientUnknownDefaultCaseName;
468430 }
431+ os << " \n };\n\n " ; // enum class cases' closing bracket
469432
470- // Printing case-related functions
433+ // Printing struct, is, and get functions for each case
471434 DeclAndTypeClangFunctionPrinter clangFuncPrinter (
472435 os, owningPrinter.prologueOS , owningPrinter.typeMapping ,
473436 owningPrinter.interopContext );
474437
475- for ( const auto &pair : elementTagMapping ) {
438+ auto printIsFunction = [&](StringRef caseName, EnumDecl *ED ) {
476439 os << " inline bool is" ;
477- auto name = pair.first ->getNameStr ().str ();
440+ std::string name;
441+ llvm::raw_string_ostream nameStream (name);
442+ ClangSyntaxPrinter (nameStream).printIdentifier (caseName);
478443 name[0 ] = std::toupper (name[0 ]);
479444 os << name << " () const {\n " ;
480- os << " return _getEnumTag() == " ;
481- if (ED->isResilient ()) {
482- os << cxx_synthesis::getCxxImplNamespaceName ()
483- << " ::" << pair.second .globalVariableName ;
484- } else {
485- os << pair.second .tag ;
486- }
487- os << " ;\n }\n " ;
488-
489- if (!pair.first ->hasAssociatedValues ()) {
490- continue ;
491- }
445+ os << " return *this == " ;
446+ syntaxPrinter.printBaseName (ED);
447+ os << " ::" ;
448+ syntaxPrinter.printIdentifier (caseName);
449+ os << " ;\n " ;
450+ os << " }\n " ;
451+ };
492452
493- auto associatedValueList = pair.first ->getParameterList ();
453+ auto printGetFunction = [&](EnumElementDecl *elementDecl) {
454+ auto associatedValueList = elementDecl->getParameterList ();
494455 // TODO: add tuple type support
495456 if (associatedValueList->size () > 1 ) {
496- continue ;
457+ return ;
497458 }
498459 auto firstType = associatedValueList->front ()->getType ();
499460 auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal ();
500461 OptionalTypeKind optKind;
501462 std::tie (firstType, optKind) =
502463 getObjectTypeAndOptionality (firstTypeDecl, firstType);
503464
504- // FIXME: (tongjie) may have to forward declare return type
465+ auto name = elementDecl->getNameStr ().str ();
466+ name[0 ] = std::toupper (name[0 ]);
467+
468+ // FIXME: may have to forward declare return type
505469 os << " inline " ;
506470 clangFuncPrinter.printClangFunctionReturnType (
507471 firstType, optKind, firstTypeDecl->getModuleContext (),
508472 owningPrinter.outputLang );
509473 os << " get" << name << " () const {\n " ;
510474 os << " if (!is" << name << " ()) abort();\n " ;
511475 os << " alignas(" ;
512- syntaxPrinter.printBaseName (ED );
476+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
513477 os << " ) unsigned char buffer[sizeof(" ;
514- syntaxPrinter.printBaseName (ED );
478+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
515479 os << " )];\n " ;
516480 os << " auto *thisCopy = new(buffer) " ;
517- syntaxPrinter.printBaseName (ED );
481+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
518482 os << " (*this);\n " ;
519483 os << " char * _Nonnull payloadFromDestruction = "
520484 " thisCopy->_destructiveProjectEnumData();\n " ;
@@ -531,7 +495,8 @@ class DeclAndTypePrinter::Implementation
531495 } else {
532496 os << " return " ;
533497 syntaxPrinter.printModuleNamespaceQualifiersIfNeeded (
534- firstTypeDecl->getModuleContext (), ED->getModuleContext ());
498+ firstTypeDecl->getModuleContext (),
499+ elementDecl->getParentEnum ()->getModuleContext ());
535500 os << cxx_synthesis::getCxxImplNamespaceName ();
536501 os << " ::" ;
537502 ClangValueTypePrinter::printCxxImplClassName (os, firstTypeDecl);
@@ -542,8 +507,77 @@ class DeclAndTypePrinter::Implementation
542507 os << " ::initializeWithTake(result, payloadFromDestruction);\n " ;
543508 os << " });\n " ;
544509 }
545- os << " }\n " ;
510+ os << " }\n " ; // closing bracket of get function
511+ };
512+
513+ auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl) {
514+ os << " static struct { // impl struct for case " << caseName << ' \n ' ;
515+ os << " inline constexpr operator cases() const {\n " ;
516+ os << " return cases::" ;
517+ syntaxPrinter.printIdentifier (caseName);
518+ os << " ;\n " ;
519+ os << " }\n " ;
520+ if (elementDecl != nullptr ) {
521+ os << " inline " ;
522+ syntaxPrinter.printBaseName (elementDecl->getParentEnum ());
523+ os << " operator()(" ;
524+ // TODO: implement parameter for associated value
525+ os << " ) const {\n " ;
526+ // TODO: print _make for now; need to print actual code making an enum
527+ os << " return " ;
528+ syntaxPrinter.printBaseName (elementDecl->getParentEnum ());
529+ os << " ::_make();\n " ;
530+ os << " }\n " ;
531+ }
532+ os << " } " ;
533+ syntaxPrinter.printIdentifier (caseName);
534+ os << " ;\n " ;
535+ };
536+
537+ for (const auto &pair : elementTagMapping) {
538+ // Printing struct
539+ printStruct (pair.first ->getNameStr (), pair.first );
540+ // Printing `is` function
541+ printIsFunction (pair.first ->getNameStr (), ED);
542+ if (pair.first ->hasAssociatedValues ()) {
543+ // Printing `get` function
544+ printGetFunction (pair.first );
545+ }
546+ os << ' \n ' ;
547+ }
548+
549+ if (ED->isResilient ()) {
550+ // Printing struct for unknownDefault
551+ printStruct (resilientUnknownDefaultCaseName, /* elementDecl */ nullptr );
552+ // Printing isUnknownDefault
553+ printIsFunction (resilientUnknownDefaultCaseName, ED);
554+ os << ' \n ' ;
555+ }
556+ os << ' \n ' ;
557+
558+ // Printing operator cases()
559+ os << " inline operator cases() const {\n " ;
560+ if (ED->isResilient ()) {
561+ os << " auto tag = _getEnumTag();\n " ;
562+ for (const auto &pair : elementTagMapping) {
563+ os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName ();
564+ os << " ::" << pair.second .globalVariableName << " ) return cases::" ;
565+ syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
566+ os << " ;\n " ;
567+ }
568+ os << " return cases::" << resilientUnknownDefaultCaseName << " ;\n " ;
569+ } else { // non-resilient enum
570+ os << " switch (_getEnumTag()) {\n " ;
571+ for (const auto &pair : elementTagMapping) {
572+ os << " case " << pair.second .tag << " : return cases::" ;
573+ syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
574+ os << " ;\n " ;
575+ }
576+ // TODO: change to Swift's fatalError when it's available in C++
577+ os << " default: abort();\n " ;
578+ os << " }\n " ; // switch's closing bracket
546579 }
580+ os << " }\n " ; // operator cases()'s closing bracket
547581 os << " \n " ;
548582 });
549583 os << outOfLineDefinitions;
0 commit comments