@@ -414,107 +414,68 @@ 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 << " " ;
417+ os << ' \n ' ;
418+ os << " enum class cases {" ;
419+ llvm::interleave (elementTagMapping, os, [&](const auto &pair){
420+ os << " \n " ;
425421 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-
422+ }, " ," );
423+ // TODO: allow custom name for this special case
424+ auto resilientUnknownDefaultCaseName = " unknownDefault" ;
455425 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 " ;
426+ os << " ,\n " << resilientUnknownDefaultCaseName;
468427 }
469-
470- // Printing case-related functions
428+ os << " \n };\n\n " ; // enum class cases' closing bracket
429+
430+ // Printing struct, is, and get functions for each case
471431 DeclAndTypeClangFunctionPrinter clangFuncPrinter (
472432 os, owningPrinter.prologueOS , owningPrinter.typeMapping ,
473433 owningPrinter.interopContext );
474-
475- for ( const auto &pair : elementTagMapping ) {
434+
435+ auto printIsFunction = [&](StringRef caseName, EnumDecl *ED ) {
476436 os << " inline bool is" ;
477- auto name = pair.first ->getNameStr ().str ();
437+ std::string name;
438+ llvm::raw_string_ostream nameStream (name);
439+ ClangSyntaxPrinter (nameStream).printIdentifier (caseName);
478440 name[0 ] = std::toupper (name[0 ]);
479441 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- }
492-
493- auto associatedValueList = pair.first ->getParameterList ();
442+ os << " return *this == " ;
443+ syntaxPrinter.printBaseName (ED);
444+ os << " ::" ;
445+ syntaxPrinter.printIdentifier (caseName);
446+ os << " ;\n " ;
447+ os << " }\n " ;
448+ };
449+
450+ auto printGetFunction = [&](EnumElementDecl *elementDecl) {
451+ auto associatedValueList = elementDecl->getParameterList ();
494452 // TODO: add tuple type support
495453 if (associatedValueList->size () > 1 ) {
496- continue ;
454+ return ;
497455 }
498456 auto firstType = associatedValueList->front ()->getType ();
499457 auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal ();
500458 OptionalTypeKind optKind;
501459 std::tie (firstType, optKind) =
502460 getObjectTypeAndOptionality (firstTypeDecl, firstType);
503-
504- // FIXME: (tongjie) may have to forward declare return type
461+
462+ auto name = elementDecl->getNameStr ().str ();
463+ name[0 ] = std::toupper (name[0 ]);
464+
465+ // FIXME: may have to forward declare return type
505466 os << " inline " ;
506467 clangFuncPrinter.printClangFunctionReturnType (
507468 firstType, optKind, firstTypeDecl->getModuleContext (),
508469 owningPrinter.outputLang );
509470 os << " get" << name << " () const {\n " ;
510471 os << " if (!is" << name << " ()) abort();\n " ;
511472 os << " alignas(" ;
512- syntaxPrinter.printBaseName (ED );
473+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
513474 os << " ) unsigned char buffer[sizeof(" ;
514- syntaxPrinter.printBaseName (ED );
475+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
515476 os << " )];\n " ;
516477 os << " auto *thisCopy = new(buffer) " ;
517- syntaxPrinter.printBaseName (ED );
478+ syntaxPrinter.printBaseName (elementDecl-> getParentEnum () );
518479 os << " (*this);\n " ;
519480 os << " char * _Nonnull payloadFromDestruction = "
520481 " thisCopy->_destructiveProjectEnumData();\n " ;
@@ -531,7 +492,7 @@ class DeclAndTypePrinter::Implementation
531492 } else {
532493 os << " return " ;
533494 syntaxPrinter.printModuleNamespaceQualifiersIfNeeded (
534- firstTypeDecl->getModuleContext (), ED ->getModuleContext ());
495+ firstTypeDecl->getModuleContext (), elementDecl-> getParentEnum () ->getModuleContext ());
535496 os << cxx_synthesis::getCxxImplNamespaceName ();
536497 os << " ::" ;
537498 ClangValueTypePrinter::printCxxImplClassName (os, firstTypeDecl);
@@ -542,8 +503,77 @@ class DeclAndTypePrinter::Implementation
542503 os << " ::initializeWithTake(result, payloadFromDestruction);\n " ;
543504 os << " });\n " ;
544505 }
545- os << " }\n " ;
506+ os << " }\n " ; // closing bracket of get function
507+ };
508+
509+ auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl) {
510+ os << " static struct { // impl struct for case " << caseName << ' \n ' ;
511+ os << " inline constexpr operator cases() const {\n " ;
512+ os << " return cases::" ;
513+ syntaxPrinter.printIdentifier (caseName);
514+ os << " ;\n " ;
515+ os << " }\n " ;
516+ if (elementDecl != nullptr ) {
517+ os << " inline " ;
518+ syntaxPrinter.printBaseName (elementDecl->getParentEnum ());
519+ os << " operator()(" ;
520+ // TODO: implement parameter for associated value
521+ os << " ) const {\n " ;
522+ // TODO: print _make for now; need to implement actual code making an enum
523+ os << " return " ;
524+ syntaxPrinter.printBaseName (elementDecl->getParentEnum ());
525+ os << " ::_make();\n " ;
526+ os << " }\n " ;
527+ }
528+ os << " } " ;
529+ syntaxPrinter.printIdentifier (caseName);
530+ os << " ;\n " ;
531+ };
532+
533+ for (const auto &pair : elementTagMapping) {
534+ // Printing struct
535+ printStruct (pair.first ->getNameStr (), pair.first );
536+ // Printing `is` function
537+ printIsFunction (pair.first ->getNameStr (), ED);
538+ if (pair.first ->hasAssociatedValues ()) {
539+ // Printing `get` function
540+ printGetFunction (pair.first );
541+ }
542+ os << ' \n ' ;
543+ }
544+
545+ if (ED->isResilient ()) {
546+ // Printing struct for unknownDefault
547+ printStruct (resilientUnknownDefaultCaseName, /* elementDecl */ nullptr );
548+ // Printing isUnknownDefault
549+ printIsFunction (resilientUnknownDefaultCaseName, ED);
550+ os << ' \n ' ;
551+ }
552+ os << ' \n ' ;
553+
554+ // Printing operator cases()
555+ os << " inline operator cases() const {\n " ;
556+ if (ED->isResilient ()) {
557+ os << " auto tag = _getEnumTag();\n " ;
558+ for (const auto &pair : elementTagMapping) {
559+ os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName ();
560+ os << " ::" << pair.second .globalVariableName << " ) return cases::" ;
561+ syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
562+ os << " ;\n " ;
563+ }
564+ os << " return cases::" << resilientUnknownDefaultCaseName << " ;\n " ;
565+ } else { // non-resilient enum
566+ os << " switch (_getEnumTag()) {\n " ;
567+ for (const auto &pair : elementTagMapping) {
568+ os << " case " << pair.second .tag << " : return cases::" ;
569+ syntaxPrinter.printIdentifier (pair.first ->getNameStr ());
570+ os << " ;\n " ;
571+ }
572+ // TODO: change to Swift's fatalError when it's available in C++
573+ os << " default: abort();\n " ;
574+ os << " }\n " ; // switch's closing bracket
546575 }
576+ os << " }\n " ; // operator cases()'s closing bracket
547577 os << " \n " ;
548578 });
549579 os << outOfLineDefinitions;
0 commit comments