Repository: apple/swift
File: lib/ClangImporter/SwiftDeclSynthesizer.cpp (C++)

Code before:
                                                     /*implicit*/ true);
      caseBodySelfRef->setType(LValueType::get(selfDecl->getTypeInContext()));

      auto *caseParamRef = new (ctx) DeclRefExpr(param, DeclNameLoc(),
                                                  /*implicit*/ true);
      caseParamRef->setType(param->getTypeInContext());

      auto *caseArgList = ArgumentList::forImplicitUnlabeled(ctx, {caseParamRef});
      auto *caseReinterpretCastRef =
          new (ctx) DeclRefExpr(concreteDeclRef, DeclNameLoc(), /*implicit*/ true);
      caseReinterpretCastRef->setType(
          FunctionType::get({FunctionType::Param(rawTy)}, enumTy, info));

      auto caseReinterpreted =
          CallExpr::createImplicit(ctx, caseReinterpretCastRef, caseArgList);
      caseReinterpreted->setType(enumTy);
      caseReinterpreted->setThrows(nullptr);

      auto *caseAssign = new (ctx) AssignExpr(caseBodySelfRef, SourceLoc(),
                                               caseReinterpreted, /*implicit*/ true);
      caseAssign->setType(TupleType::getEmpty(ctx));

      auto *caseBody = BraceStmt::create(ctx, SourceLoc(), {caseAssign},
                                         SourceLoc(), /*implicit*/ true);

      auto *caseStmt = CaseStmt::createImplicit(ctx, CaseParentKind::Switch,
                                                {labelItem}, caseBody);
      cases.push_back(caseStmt);
    }

    // Add default case that returns nil
    auto *defaultPattern = AnyPattern::createImplicit(ctx);
    auto defaultLabelItem = CaseLabelItem(defaultPattern);

    auto *failStmt = new (ctx) FailStmt(SourceLoc(), SourceLoc(), /*implicit*/ true);
    auto *defaultBody = BraceStmt::create(ctx, SourceLoc(), {failStmt},
                                          SourceLoc(), /*implicit*/ true);

    auto *defaultCase = CaseStmt::createImplicit(ctx, CaseParentKind::Switch,
                                                 {defaultLabelItem}, defaultBody);
    cases.push_back(defaultCase);

    // Create the switch statement
    auto *switchParamRef = new (ctx) DeclRefExpr(param, DeclNameLoc(),
                                                  /*implicit*/ true);
    switchParamRef->setType(param->getTypeInContext());

    auto *switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(),
                                          switchParamRef, SourceLoc(),
                                          cases, SourceLoc(), SourceLoc(), ctx);


Review comment (suggestion):
Great contribution! You could save a few bytes by generating one case statement with each known case as a series of labels, as their bodies are the same (reinterpret cast)

equivalent to the source:
```
switch rawValue {
case .first, .second, third:
  reinterpretCast
default:
  return nil
}
```

function merging may consolidate these blocks on the back end but better not to emit them in the first place

Code after:
    auto *validCase = CaseStmt::createImplicit(ctx, CaseParentKind::Switch,
                                               validCaseLabels, caseBody);

    // Create default case that returns nil
    auto *defaultPattern = AnyPattern::createImplicit(ctx);
    auto defaultLabelItem = CaseLabelItem(defaultPattern);

    auto *failStmt = new (ctx) FailStmt(SourceLoc(), SourceLoc(), /*implicit*/ true);
    auto *defaultBody = BraceStmt::create(ctx, SourceLoc(), {failStmt},
                                          SourceLoc(), /*implicit*/ true);

    auto *defaultCase = CaseStmt::createImplicit(ctx, CaseParentKind::Switch,
                                                 {defaultLabelItem}, defaultBody);

    // Create the switch statement
    auto *switchParamRef = new (ctx) DeclRefExpr(param, DeclNameLoc(),
                                                  /*implicit*/ true);
    switchParamRef->setType(param->getTypeInContext());

    auto *switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(),
                                          switchParamRef, SourceLoc(),
                                          {validCase, defaultCase}, SourceLoc(), SourceLoc(), ctx);

    auto body = BraceStmt::create(ctx, SourceLoc(), {switchStmt}, SourceLoc(),
                                  /*implicit*/ true);
    // Return isTypeChecked=false because the switch statement contains patterns
    // and expressions that need type inference and semantic analysis.
    return {body, /*isTypeChecked=*/false};
  }

  // For non-frozen enums, use the simple reinterpret cast approach
  auto *ret = ReturnStmt::createImplicit(ctx, /*expr*/ nullptr);

  auto body = BraceStmt::create(ctx, SourceLoc(), {assign, ret}, SourceLoc(),
                                /*implicit*/ true);
  // Return isTypeChecked=true because all types are explicitly set
  // and no type inference is needed.
  return {body, /*isTypeChecked=*/true};
}

ConstructorDecl *
SwiftDeclSynthesizer::makeEnumRawValueConstructor(EnumDecl *enumDecl) {
  ASTContext &C = ImporterImpl.SwiftContext;
  auto rawTy = enumDecl->getRawType();

  auto param = new (C) ParamDecl(SourceLoc(), SourceLoc(), C.Id_rawValue,
                                 SourceLoc(), C.Id_rawValue, enumDecl);
  param->setSpecifier(ParamSpecifier::Default);
  param->setInterfaceType(rawTy);

  auto paramPL = ParameterList::createWithoutLoc(param);