@@ -1295,7 +1295,49 @@ SwiftDeclSynthesizer::makeIndirectFieldAccessors(
12951295
12961296// MARK: Enum RawValue initializers
12971297
1298+ // / Clone a literal expression for use in pattern matching.
1299+ // / Based on cloneRawLiteralExpr from DerivedConformanceRawRepresentable.cpp
1300+ static LiteralExpr *cloneRawLiteralExpr (ASTContext &C, LiteralExpr *expr) {
1301+ LiteralExpr *clone;
1302+ if (auto intLit = dyn_cast<IntegerLiteralExpr>(expr)) {
1303+ clone = new (C) IntegerLiteralExpr (intLit->getDigitsText (), expr->getLoc (),
1304+ /* implicit*/ true );
1305+ if (intLit->isNegative ())
1306+ cast<IntegerLiteralExpr>(clone)->setNegative (expr->getLoc ());
1307+ } else if (isa<NilLiteralExpr>(expr)) {
1308+ clone = new (C) NilLiteralExpr (expr->getLoc ());
1309+ } else if (auto stringLit = dyn_cast<StringLiteralExpr>(expr)) {
1310+ clone = new (C) StringLiteralExpr (stringLit->getValue (), expr->getLoc ());
1311+ } else if (auto floatLit = dyn_cast<FloatLiteralExpr>(expr)) {
1312+ clone = new (C) FloatLiteralExpr (floatLit->getDigitsText (), expr->getLoc (),
1313+ /* implicit*/ true );
1314+ if (floatLit->isNegative ())
1315+ cast<FloatLiteralExpr>(clone)->setNegative (expr->getLoc ());
1316+ } else {
1317+ llvm_unreachable (" invalid raw literal expr" );
1318+ }
1319+ clone->setImplicit ();
1320+ return clone;
1321+ }
1322+
12981323// / Synthesize the body of \c init?(rawValue:RawType) for an imported enum.
1324+ // /
1325+ // / For non-frozen (open) enums, this generates:
1326+ // / init?(rawValue: RawType) {
1327+ // / self = Builtin.reinterpretCast(rawValue)
1328+ // / }
1329+ // / This allows arbitrary raw values for C compatibility.
1330+ // /
1331+ // / For frozen (closed) enums, this generates:
1332+ // / init?(rawValue: RawType) {
1333+ // / switch rawValue {
1334+ // / case <value1>, <value2>, ...:
1335+ // / self = Builtin.reinterpretCast(rawValue)
1336+ // / default:
1337+ // / return nil
1338+ // / }
1339+ // / }
1340+ // / This ensures that only declared raw values are accepted.
12991341static std::pair<BraceStmt *, bool >
13001342synthesizeEnumRawValueConstructorBody (AbstractFunctionDecl *afd,
13011343 void *context) {
@@ -1338,10 +1380,70 @@ synthesizeEnumRawValueConstructorBody(AbstractFunctionDecl *afd,
13381380 /* implicit*/ true );
13391381 assign->setType (TupleType::getEmpty (ctx));
13401382
1383+ // Check if the enum is frozen (closed). If so, we need to validate
1384+ // that the raw value is one of the declared cases.
1385+ bool isFrozen = enumDecl->getAttrs ().hasAttribute <FrozenAttr>();
1386+
1387+ if (isFrozen) {
1388+ // For frozen enums, generate a switch statement to validate the raw value.
1389+
1390+ // Collect all case labels for valid enum values
1391+ SmallVector<CaseLabelItem, 8 > validCaseLabels;
1392+ for (auto *elt : enumDecl->getAllElements ()) {
1393+ // Get the raw value literal for this element
1394+ auto rawValueExpr = elt->getStructuralRawValueExpr ();
1395+ if (!rawValueExpr)
1396+ continue ;
1397+
1398+ // Clone the raw value expression for pattern matching
1399+ auto *litExpr = cloneRawLiteralExpr (ctx, cast<LiteralExpr>(rawValueExpr));
1400+ auto *litPat = ExprPattern::createImplicit (ctx, litExpr, ctorDecl);
1401+
1402+ // Add to the list of valid case labels
1403+ validCaseLabels.push_back (CaseLabelItem (litPat));
1404+ }
1405+
1406+ // Create a single case statement with all valid raw values
1407+ // All valid values perform the same action: reinterpret cast
1408+ auto *caseBody = BraceStmt::create (ctx, SourceLoc (), {assign},
1409+ SourceLoc (), /* implicit*/ true );
1410+ auto *validCase = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1411+ validCaseLabels, caseBody);
1412+
1413+ // Create default case that returns nil
1414+ auto *defaultPattern = AnyPattern::createImplicit (ctx);
1415+ auto defaultLabelItem = CaseLabelItem (defaultPattern);
1416+
1417+ auto *failStmt = new (ctx) FailStmt (SourceLoc (), SourceLoc (), /* implicit*/ true );
1418+ auto *defaultBody = BraceStmt::create (ctx, SourceLoc (), {failStmt},
1419+ SourceLoc (), /* implicit*/ true );
1420+
1421+ auto *defaultCase = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1422+ {defaultLabelItem}, defaultBody);
1423+
1424+ // Create the switch statement
1425+ auto *switchParamRef = new (ctx) DeclRefExpr (param, DeclNameLoc (),
1426+ /* implicit*/ true );
1427+ switchParamRef->setType (param->getTypeInContext ());
1428+
1429+ auto *switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (),
1430+ switchParamRef, SourceLoc (),
1431+ {validCase, defaultCase}, SourceLoc (), SourceLoc (), ctx);
1432+
1433+ auto body = BraceStmt::create (ctx, SourceLoc (), {switchStmt}, SourceLoc (),
1434+ /* implicit*/ true );
1435+ // Return isTypeChecked=false because the switch statement contains patterns
1436+ // and expressions that need type inference and semantic analysis.
1437+ return {body, /* isTypeChecked=*/ false };
1438+ }
1439+
1440+ // For non-frozen enums, use the simple reinterpret cast approach
13411441 auto *ret = ReturnStmt::createImplicit (ctx, /* expr*/ nullptr );
13421442
13431443 auto body = BraceStmt::create (ctx, SourceLoc (), {assign, ret}, SourceLoc (),
13441444 /* implicit*/ true );
1445+ // Return isTypeChecked=true because all types are explicitly set
1446+ // and no type inference is needed.
13451447 return {body, /* isTypeChecked=*/ true };
13461448}
13471449
0 commit comments