@@ -1247,7 +1247,49 @@ 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>, <value2>, ...:
1287+ // / self = Builtin.reinterpretCast(rawValue)
1288+ // / default:
1289+ // / return nil
1290+ // / }
1291+ // / }
1292+ // / This ensures that only declared raw values are accepted.
12511293static std::pair<BraceStmt *, bool >
12521294synthesizeEnumRawValueConstructorBody (AbstractFunctionDecl *afd,
12531295 void *context) {
@@ -1290,10 +1332,70 @@ synthesizeEnumRawValueConstructorBody(AbstractFunctionDecl *afd,
12901332 /* implicit*/ true );
12911333 assign->setType (TupleType::getEmpty (ctx));
12921334
1335+ // Check if the enum is frozen (closed). If so, we need to validate
1336+ // that the raw value is one of the declared cases.
1337+ bool isFrozen = enumDecl->getAttrs ().hasAttribute <FrozenAttr>();
1338+
1339+ if (isFrozen) {
1340+ // For frozen enums, generate a switch statement to validate the raw value.
1341+
1342+ // Collect all case labels for valid enum values
1343+ SmallVector<CaseLabelItem, 8 > validCaseLabels;
1344+ for (auto *elt : enumDecl->getAllElements ()) {
1345+ // Get the raw value literal for this element
1346+ auto rawValueExpr = elt->getStructuralRawValueExpr ();
1347+ if (!rawValueExpr)
1348+ continue ;
1349+
1350+ // Clone the raw value expression for pattern matching
1351+ auto *litExpr = cloneRawLiteralExpr (ctx, cast<LiteralExpr>(rawValueExpr));
1352+ auto *litPat = ExprPattern::createImplicit (ctx, litExpr, ctorDecl);
1353+
1354+ // Add to the list of valid case labels
1355+ validCaseLabels.push_back (CaseLabelItem (litPat));
1356+ }
1357+
1358+ // Create a single case statement with all valid raw values
1359+ // All valid values perform the same action: reinterpret cast
1360+ auto *caseBody = BraceStmt::create (ctx, SourceLoc (), {assign},
1361+ SourceLoc (), /* implicit*/ true );
1362+ auto *validCase = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1363+ validCaseLabels, caseBody);
1364+
1365+ // Create default case that returns nil
1366+ auto *defaultPattern = AnyPattern::createImplicit (ctx);
1367+ auto defaultLabelItem = CaseLabelItem (defaultPattern);
1368+
1369+ auto *failStmt = new (ctx) FailStmt (SourceLoc (), SourceLoc (), /* implicit*/ true );
1370+ auto *defaultBody = BraceStmt::create (ctx, SourceLoc (), {failStmt},
1371+ SourceLoc (), /* implicit*/ true );
1372+
1373+ auto *defaultCase = CaseStmt::createImplicit (ctx, CaseParentKind::Switch,
1374+ {defaultLabelItem}, defaultBody);
1375+
1376+ // Create the switch statement
1377+ auto *switchParamRef = new (ctx) DeclRefExpr (param, DeclNameLoc (),
1378+ /* implicit*/ true );
1379+ switchParamRef->setType (param->getTypeInContext ());
1380+
1381+ auto *switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (),
1382+ switchParamRef, SourceLoc (),
1383+ {validCase, defaultCase}, SourceLoc (), SourceLoc (), ctx);
1384+
1385+ auto body = BraceStmt::create (ctx, SourceLoc (), {switchStmt}, SourceLoc (),
1386+ /* implicit*/ true );
1387+ // Return isTypeChecked=false because the switch statement contains patterns
1388+ // and expressions that need type inference and semantic analysis.
1389+ return {body, /* isTypeChecked=*/ false };
1390+ }
1391+
1392+ // For non-frozen enums, use the simple reinterpret cast approach
12931393 auto *ret = ReturnStmt::createImplicit (ctx, /* expr*/ nullptr );
12941394
12951395 auto body = BraceStmt::create (ctx, SourceLoc (), {assign, ret}, SourceLoc (),
12961396 /* implicit*/ true );
1397+ // Return isTypeChecked=true because all types are explicitly set
1398+ // and no type inference is needed.
12971399 return {body, /* isTypeChecked=*/ true };
12981400}
12991401
0 commit comments