@@ -1247,7 +1247,52 @@ SwiftDeclSynthesizer::makeIndirectFieldAccessors(
12471247
12481248// MARK: Enum RawValue initializers
12491249
1250+ // / Clone a literal expression for use in pattern matching.
1251+ // / Based on cloneRawLiteralExpr from DerivedConformanceRawRepresentable.cpp
1252+ static LiteralExpr *cloneRawLiteralExpr (ASTContext &C, LiteralExpr *expr) {
1253+ LiteralExpr *clone;
1254+ if (auto intLit = dyn_cast<IntegerLiteralExpr>(expr)) {
1255+ clone = new (C) IntegerLiteralExpr (intLit->getDigitsText (), expr->getLoc (),
1256+ /* implicit*/ true );
1257+ if (intLit->isNegative ())
1258+ cast<IntegerLiteralExpr>(clone)->setNegative (expr->getLoc ());
1259+ } else if (isa<NilLiteralExpr>(expr)) {
1260+ clone = new (C) NilLiteralExpr (expr->getLoc ());
1261+ } else if (auto stringLit = dyn_cast<StringLiteralExpr>(expr)) {
1262+ clone = new (C) StringLiteralExpr (stringLit->getValue (), expr->getLoc ());
1263+ } else if (auto floatLit = dyn_cast<FloatLiteralExpr>(expr)) {
1264+ clone = new (C) FloatLiteralExpr (floatLit->getDigitsText (), expr->getLoc (),
1265+ /* implicit*/ true );
1266+ if (floatLit->isNegative ())
1267+ cast<FloatLiteralExpr>(clone)->setNegative (expr->getLoc ());
1268+ } else {
1269+ llvm_unreachable (" invalid raw literal expr" );
1270+ }
1271+ clone->setImplicit ();
1272+ return clone;
1273+ }
1274+
12501275// / Synthesize the body of \c init?(rawValue:RawType) for an imported enum.
1276+ // /
1277+ // / For non-frozen (open) enums, this generates:
1278+ // / init?(rawValue: RawType) {
1279+ // / self = Builtin.reinterpretCast(rawValue)
1280+ // / }
1281+ // / This allows arbitrary raw values for C compatibility.
1282+ // /
1283+ // / For frozen (closed) enums, this generates:
1284+ // / init?(rawValue: RawType) {
1285+ // / switch rawValue {
1286+ // / case <value1>:
1287+ // / self = Builtin.reinterpretCast(rawValue)
1288+ // / case <value2>:
1289+ // / self = Builtin.reinterpretCast(rawValue)
1290+ // / ...
1291+ // / default:
1292+ // / return nil
1293+ // / }
1294+ // / }
1295+ // / This ensures that only declared raw values are accepted.
12511296static std::pair<BraceStmt *, bool >
12521297synthesizeEnumRawValueConstructorBody (AbstractFunctionDecl *afd,
12531298 void *context) {
@@ -1290,11 +1335,92 @@ synthesizeEnumRawValueConstructorBody(AbstractFunctionDecl *afd,
12901335 /* implicit*/ true );
12911336 assign->setType (TupleType::getEmpty (ctx));
12921337
1293- auto *ret = ReturnStmt::createImplicit (ctx, /* expr*/ nullptr );
1338+ // Check if the enum is frozen (closed). If so, we need to validate
1339+ // that the raw value is one of the declared cases.
1340+ bool isFrozen = enumDecl->getAttrs ().hasAttribute <FrozenAttr>();
12941341
1295- auto body = BraceStmt::create (ctx, SourceLoc (), {assign, ret}, SourceLoc (),
1296- /* implicit*/ true );
1297- return {body, /* isTypeChecked=*/ true };
1342+ if (isFrozen) {
1343+ // For frozen enums, generate a switch statement to validate the raw value
1344+ SmallVector<CaseStmt *, 8 > cases;
1345+
1346+ // Build cases for each enum element
1347+ for (auto *elt : enumDecl->getAllElements ()) {
1348+ // Get the raw value literal for this element
1349+ auto rawValueExpr = elt->getStructuralRawValueExpr ();
1350+ if (!rawValueExpr)
1351+ continue ;
1352+
1353+ // Clone the raw value expression for pattern matching
1354+ auto *litExpr = cloneRawLiteralExpr (ctx, cast<LiteralExpr>(rawValueExpr));
1355+ auto *litPat = ExprPattern::createImplicit (ctx, litExpr, ctorDecl);
1356+
1357+ // Create case label
1358+ auto labelItem = CaseLabelItem (litPat);
1359+
1360+ // Create the assignment statement for this case
1361+ auto *caseBodySelfRef = new (ctx) DeclRefExpr (selfDecl, DeclNameLoc (),
1362+ /* implicit*/ true );
1363+ caseBodySelfRef->setType (LValueType::get (selfDecl->getTypeInContext ()));
1364+
1365+ auto *caseParamRef = new (ctx) DeclRefExpr (param, DeclNameLoc (),
1366+ /* implicit*/ true );
1367+ caseParamRef->setType (param->getTypeInContext ());
1368+
1369+ auto *caseArgList = ArgumentList::forImplicitUnlabeled (ctx, {caseParamRef});
1370+ auto *caseReinterpretCastRef =
1371+ new (ctx) DeclRefExpr (concreteDeclRef, DeclNameLoc (), /* implicit*/ true );
1372+ caseReinterpretCastRef->setType (
1373+ FunctionType::get ({FunctionType::Param (rawTy)}, enumTy, info));
1374+
1375+ auto caseReinterpreted =
1376+ CallExpr::createImplicit (ctx, caseReinterpretCastRef, caseArgList);
1377+ caseReinterpreted->setType (enumTy);
1378+ caseReinterpreted->setThrows (nullptr );
1379+
1380+ auto *caseAssign = new (ctx) AssignExpr (caseBodySelfRef, SourceLoc (),
1381+ caseReinterpreted, /* implicit*/ true );
1382+ caseAssign->setType (TupleType::getEmpty (ctx));
1383+
1384+ auto *caseBody = BraceStmt::create (ctx, SourceLoc (), {caseAssign},
1385+ SourceLoc (), /* implicit*/ true );
1386+
1387+ auto *caseStmt = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1388+ {labelItem}, caseBody);
1389+ cases.push_back (caseStmt);
1390+ }
1391+
1392+ // Add default case that returns nil
1393+ auto *defaultPattern = AnyPattern::createImplicit (ctx);
1394+ auto defaultLabelItem = CaseLabelItem (defaultPattern);
1395+
1396+ auto *failStmt = new (ctx) FailStmt (SourceLoc (), SourceLoc (), /* implicit*/ true );
1397+ auto *defaultBody = BraceStmt::create (ctx, SourceLoc (), {failStmt},
1398+ SourceLoc (), /* implicit*/ true );
1399+
1400+ auto *defaultCase = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1401+ {defaultLabelItem}, defaultBody);
1402+ cases.push_back (defaultCase);
1403+
1404+ // Create the switch statement
1405+ auto *switchParamRef = new (ctx) DeclRefExpr (param, DeclNameLoc (),
1406+ /* implicit*/ true );
1407+ switchParamRef->setType (param->getTypeInContext ());
1408+
1409+ auto *switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (),
1410+ switchParamRef, SourceLoc (),
1411+ cases, SourceLoc (), SourceLoc (), ctx);
1412+
1413+ auto body = BraceStmt::create (ctx, SourceLoc (), {switchStmt}, SourceLoc (),
1414+ /* implicit*/ true );
1415+ return {body, /* isTypeChecked=*/ false };
1416+ } else {
1417+ // For non-frozen enums, use the simple reinterpret cast approach
1418+ auto *ret = ReturnStmt::createImplicit (ctx, /* expr*/ nullptr );
1419+
1420+ auto body = BraceStmt::create (ctx, SourceLoc (), {assign, ret}, SourceLoc (),
1421+ /* implicit*/ true );
1422+ return {body, /* isTypeChecked=*/ true };
1423+ }
12981424}
12991425
13001426ConstructorDecl *
0 commit comments