@@ -209,14 +209,60 @@ class ClosureConstraintGenerator
209
209
cs.setSolutionApplicationTarget (poundAssertStmt, target);
210
210
}
211
211
212
+ void visitSwitchStmt (SwitchStmt *switchStmt) {
213
+ // FIXME: Very similar to BuilderTransform's visitSwitchStmt. Unify them.
214
+
215
+ // Generate constraints for the subject expression, and capture its
216
+ // type for use in matching the various patterns.
217
+ Expr *subjectExpr = switchStmt->getSubjectExpr ();
218
+ ASTContext &ctx = cs.getASTContext ();
219
+
220
+ // Form a one-way constraint to prevent backward propagation.
221
+ subjectExpr = new (ctx) OneWayExpr (subjectExpr);
222
+
223
+ // FIXME: Add contextual type purpose for switch subjects?
224
+ SolutionApplicationTarget target (
225
+ subjectExpr, closure, CTP_Unused, Type (), /* isDiscarded=*/ false );
226
+ if (cs.generateConstraints (target, FreeTypeVariableBinding::Disallow)) {
227
+ hadError = true ;
228
+ return ;
229
+ }
230
+
231
+ cs.setSolutionApplicationTarget (switchStmt, target);
232
+ subjectExpr = target.getAsExpr ();
233
+ assert (subjectExpr && " Must have a subject expression here" );
234
+
235
+ // Visit the raw cases.
236
+ for (auto rawCase : switchStmt->getRawCases ()) {
237
+ if (auto decl = rawCase.dyn_cast <Decl *>())
238
+ visitDecl (decl);
239
+ else
240
+ visitCaseStmt (cast<CaseStmt>(rawCase.get <Stmt *>()), subjectExpr);
241
+ }
242
+ }
243
+
244
+ void visitCaseStmt (CaseStmt *caseStmt, Expr *subjectExpr) {
245
+ auto locator = cs.getConstraintLocator (
246
+ subjectExpr, LocatorPathElt::ContextualType ());
247
+ Type subjectType = cs.getType (subjectExpr);
248
+
249
+ if (cs.generateConstraints (caseStmt, closure, subjectType, locator)) {
250
+ hadError = true ;
251
+ return ;
252
+ }
253
+
254
+ // Visit the body.
255
+ visit (caseStmt->getBody ());
256
+ }
257
+
258
+ void visitFallthroughStmt (FallthroughStmt *fallthroughStmt) { }
259
+
212
260
#define UNSUPPORTED_STMT (STMT ) void visit##STMT##Stmt(STMT##Stmt *) { \
213
261
llvm_unreachable (" Unsupported statement kind " #STMT); \
214
262
}
215
263
UNSUPPORTED_STMT (Yield)
216
264
UNSUPPORTED_STMT (DoCatch)
217
- UNSUPPORTED_STMT (Switch)
218
265
UNSUPPORTED_STMT (Case)
219
- UNSUPPORTED_STMT (Fallthrough)
220
266
UNSUPPORTED_STMT (Fail)
221
267
#undef UNSUPPORTED_STMT
222
268
};
@@ -503,14 +549,68 @@ class ClosureConstraintApplication
503
549
return poundAssertStmt;
504
550
}
505
551
552
+ ASTNode visitSwitchStmt (SwitchStmt *switchStmt) {
553
+ ConstraintSystem &cs = solution.getConstraintSystem ();
554
+
555
+ // Rewrite the switch subject.
556
+ auto subjectTarget =
557
+ rewriteTarget (*cs.getSolutionApplicationTarget (switchStmt));
558
+ if (subjectTarget) {
559
+ switchStmt->setSubjectExpr (subjectTarget->getAsExpr ());
560
+ } else {
561
+ hadError = true ;
562
+ }
563
+
564
+ // Visit the raw cases.
565
+ bool limitExhaustivityChecks = false ;
566
+ for (auto rawCase : switchStmt->getRawCases ()) {
567
+ if (auto decl = rawCase.dyn_cast <Decl *>()) {
568
+ visitDecl (decl);
569
+ continue ;
570
+ }
571
+
572
+ auto caseStmt = cast<CaseStmt>(rawCase.get <Stmt *>());
573
+ visitCaseStmt (caseStmt);
574
+
575
+ // Check restrictions on '@unknown'.
576
+ if (caseStmt->hasUnknownAttr ()) {
577
+ checkUnknownAttrRestrictions (
578
+ cs.getASTContext (), caseStmt, limitExhaustivityChecks);
579
+ }
580
+ }
581
+
582
+ TypeChecker::checkSwitchExhaustiveness (
583
+ switchStmt, closure, limitExhaustivityChecks);
584
+
585
+ return switchStmt;
586
+ }
587
+
588
+ ASTNode visitCaseStmt (CaseStmt *caseStmt) {
589
+ // Translate the patterns and guard expressions for each case label item.
590
+ for (auto &caseLabelItem : caseStmt->getMutableCaseLabelItems ()) {
591
+ SolutionApplicationTarget caseLabelTarget (&caseLabelItem, closure);
592
+ if (!rewriteTarget (caseLabelTarget)) {
593
+ hadError = true ;
594
+ }
595
+ }
596
+
597
+ // Translate the body.
598
+ auto newBody = visit (caseStmt->getBody ());
599
+ caseStmt->setBody (newBody.get <Stmt *>());
600
+ return caseStmt;
601
+ }
602
+
603
+ ASTNode visitFallthroughStmt (FallthroughStmt *fallthroughStmt) {
604
+ if (checkFallthroughStmt (closure, fallthroughStmt))
605
+ hadError = true ;
606
+ return fallthroughStmt;
607
+ }
608
+
506
609
#define UNSUPPORTED_STMT (STMT ) ASTNode visit##STMT##Stmt(STMT##Stmt *) { \
507
610
llvm_unreachable (" Unsupported statement kind " #STMT); \
508
611
}
509
612
UNSUPPORTED_STMT (Yield)
510
613
UNSUPPORTED_STMT(DoCatch)
511
- UNSUPPORTED_STMT(Switch)
512
- UNSUPPORTED_STMT(Case)
513
- UNSUPPORTED_STMT(Fallthrough)
514
614
UNSUPPORTED_STMT(Fail)
515
615
#undef UNSUPPORTED_STMT
516
616
0 commit comments