Add a binder mechanism to the Factory API for handling labels.

Some work needs to be done on both sides to hook up to the API:

- On the front end side, the individual labels need to be plumbed
  through the body builder to the judgment objects (currently the body
  builder discards individual label information).  Follow-up work for
  this will be tracked in
  https://github.com/dart-lang/sdk/issues/33591.

- On the analyzer side, the label information needs to be stored by
  ResolutionStorer and retrieved by ResolutionApplier (currently the
  ResolutionApplier has its own scope resolution mechanism; we don't
  want to keep this because it duplicates resolution logic in the
  front end).  Follw-up work for this will be tracked in
  https://github.com/dart-lang/sdk/issues/33592.

Change-Id: I75afc2be16a277581b0e2ea49b6998e72054a40d
Reviewed-on: https://dart-review.googlesource.com/62000
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/fasta/resolution_storer.dart b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
index 08a565e..af780b2 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_storer.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
@@ -137,8 +137,13 @@
           Token literal, bool value, DartType inferredType) =>
       genericExpression("boolLiteral", location, inferredType);
 
-  void breakStatement(StatementJudgment judgment, Location location,
-      Token breakKeyword, void label, Token semicolon) {}
+  void breakStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token breakKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder) {}
 
   void cascadeExpression(
       ExpressionJudgment judgment, Location location, DartType inferredType) {
@@ -198,11 +203,21 @@
     _store(location, inferredType: inferredType, reference: expressionTarget);
   }
 
-  void continueStatement(StatementJudgment judgment, Location location,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder) {}
 
-  void continueSwitchStatement(StatementJudgment judgment, Location location,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueSwitchStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder) {}
 
   void deferredCheck(ExpressionJudgment judgment, Location location,
           DartType inferredType) =>
@@ -326,8 +341,12 @@
 
   void invalidInitializer(InitializerJudgment judgment, Location location) {}
 
-  void labeledStatement(StatementJudgment judgment, Location location,
-      Token label, Token colon, void statement) {}
+  void labeledStatement(List<Object> labels, void statement) {}
+
+  void statementLabel(covariant void binder, Token label, Token colon) {}
+
+  void binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name) {}
 
   void listLiteral(
           ExpressionJudgment judgment,
@@ -552,6 +571,14 @@
       Token constructorName,
       covariant Object argumentList) {}
 
+  void switchCase(SwitchCaseJudgment judgment, List<Object> labels,
+      Token keyword, void expression, Token colon, List<void> statements) {}
+
+  void switchLabel(covariant void binder, Token label, Token colon) {}
+
+  void binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name) {}
+
   void switchStatement(
       StatementJudgment judgment,
       Location location,
diff --git a/pkg/front_end/lib/src/fasta/kernel/factory.dart b/pkg/front_end/lib/src/fasta/kernel/factory.dart
index 887b329..be008b7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/factory.dart
@@ -9,7 +9,11 @@
 import '../../scanner/token.dart' show Token;
 
 import 'kernel_shadow_ast.dart'
-    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
+    show
+        ExpressionJudgment,
+        InitializerJudgment,
+        StatementJudgment,
+        SwitchCaseJudgment;
 
 /// Abstract base class for factories that can construct trees of expressions,
 /// statements, initializers, and literal types based on tokens, inferred types,
@@ -53,8 +57,13 @@
   Expression boolLiteral(ExpressionJudgment judgment, int fileOffset,
       Token literal, bool value, DartType inferredType);
 
-  Statement breakStatement(StatementJudgment judgment, int fileOffset,
-      Token breakKeyword, Expression label, Token semicolon);
+  Statement breakStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token breakKeyword,
+      Expression label,
+      Token semicolon,
+      covariant Object labelBinder);
 
   Expression cascadeExpression(
       ExpressionJudgment judgment, int fileOffset, DartType inferredType);
@@ -90,11 +99,21 @@
   Expression constructorInvocation(ExpressionJudgment judgment, int fileOffset,
       Node expressionTarget, DartType inferredType);
 
-  Statement continueStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, Expression label, Token semicolon);
+  Statement continueStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      Expression label,
+      Token semicolon,
+      covariant Object labelBinder);
 
-  Statement continueSwitchStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, Expression label, Token semicolon);
+  Statement continueSwitchStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      Expression label,
+      Token semicolon,
+      covariant Object labelBinder);
 
   Expression deferredCheck(
       ExpressionJudgment judgment, int fileOffset, DartType inferredType);
@@ -214,8 +233,12 @@
       DartType testedType,
       DartType inferredType);
 
-  Statement labeledStatement(StatementJudgment judgment, int fileOffset,
-      Token label, Token colon, Statement statement);
+  Statement labeledStatement(List<Object> labels, Statement statement);
+
+  Object statementLabel(covariant Object binder, Token label, Token colon);
+
+  Object binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name);
 
   Expression listLiteral(
       ExpressionJudgment judgment,
@@ -342,6 +365,19 @@
       Token constructorName,
       covariant Object argumentList);
 
+  Object switchCase(
+      SwitchCaseJudgment judgment,
+      List<Object> labels,
+      Token keyword,
+      Expression expression,
+      Token colon,
+      List<Statement> statements);
+
+  Object switchLabel(covariant Object binder, Token label, Token colon);
+
+  Object binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name);
+
   Statement switchStatement(
       StatementJudgment judgment,
       int fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
index 3377baf..32b2387 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_factory.dart
@@ -11,8 +11,10 @@
         Expression,
         FunctionType,
         Initializer,
+        LabeledStatement,
         Node,
         Statement,
+        SwitchCase,
         VariableDeclaration;
 
 import 'package:kernel/type_algebra.dart' show Substitution;
@@ -20,7 +22,11 @@
 import 'factory.dart' show Factory;
 
 import 'kernel_shadow_ast.dart'
-    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
+    show
+        ExpressionJudgment,
+        InitializerJudgment,
+        StatementJudgment,
+        SwitchCaseJudgment;
 
 /// Implementation of [Factory] that builds source code into a kernel
 /// representation.
@@ -83,8 +89,13 @@
   }
 
   @override
-  Statement breakStatement(StatementJudgment judgment, int fileOffset,
-      Token breakKeyword, Expression label, Token semicolon) {
+  Statement breakStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token breakKeyword,
+      Expression label,
+      Token semicolon,
+      covariant LabeledStatement labelBinder) {
     return judgment;
   }
 
@@ -135,14 +146,24 @@
   }
 
   @override
-  Statement continueStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, Expression label, Token semicolon) {
+  Statement continueStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      Expression label,
+      Token semicolon,
+      covariant LabeledStatement labelBinder) {
     return judgment;
   }
 
   @override
-  Statement continueSwitchStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, Expression label, Token semicolon) {
+  Statement continueSwitchStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      Expression label,
+      Token semicolon,
+      covariant LabeledStatement labelBinder) {
     return judgment;
   }
 
@@ -316,8 +337,18 @@
   }
 
   @override
-  Statement labeledStatement(StatementJudgment judgment, int fileOffset,
-      Token label, Token colon, Statement statement) {
+  Statement labeledStatement(List<Object> labels, Statement statement) {
+    return labels[0];
+  }
+
+  Object statementLabel(
+      covariant StatementJudgment binder, Token label, Token colon) {
+    return binder;
+  }
+
+  @override
+  Object binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name) {
     return judgment;
   }
 
@@ -518,6 +549,26 @@
     return judgment;
   }
 
+  SwitchCase switchCase(
+      SwitchCaseJudgment judgment,
+      List<Object> labels,
+      Token keyword,
+      Expression expression,
+      Token colon,
+      List<Statement> statements) {
+    return judgment;
+  }
+
+  SwitchCase switchLabel(
+      covariant SwitchCase binder, Token label, Token colon) {
+    return binder;
+  }
+
+  SwitchCase binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name) {
+    return judgment;
+  }
+
   @override
   Statement switchStatement(
       StatementJudgment judgment,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 383fd8e..2f41efc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -326,12 +326,15 @@
 class ContinueJudgment extends BreakStatement implements StatementJudgment {
   ContinueJudgment(LabeledStatement target) : super(target);
 
+  LabeledStatementJudgment get targetJudgment => target;
+
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
     // No inference needs to be done.
-    inferrer.listener.breakStatement(this, fileOffset, null, null, null);
+    inferrer.listener.breakStatement(this, fileOffset, null, null, null,
+        targetJudgment?.createBinder(inferrer));
   }
 }
 
@@ -841,13 +844,15 @@
     implements StatementJudgment {
   ContinueSwitchJudgment(SwitchCase target) : super(target);
 
+  SwitchCaseJudgment get targetJudgment => target;
+
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
     // No inference needs to be done.
-    inferrer.listener
-        .continueSwitchStatement(this, fileOffset, null, null, null);
+    inferrer.listener.continueSwitchStatement(this, fileOffset, null, null,
+        null, targetJudgment?.createBinder(inferrer));
   }
 }
 
@@ -1725,14 +1730,26 @@
     implements StatementJudgment {
   LabeledStatementJudgment(Statement body) : super(body);
 
+  Object binder;
+
   StatementJudgment get judgment => body;
 
+  Object createBinder(ShadowTypeInferrer inferrer) {
+    // TODO(paulberry): we need one binder for each label
+    return binder ??=
+        inferrer.listener.binderForStatementLabel(this, fileOffset, null);
+  }
+
   @override
   void infer<Expression, Statement, Initializer, Type>(
       ShadowTypeInferrer inferrer,
       Factory<Expression, Statement, Initializer, Type> factory) {
     inferrer.inferStatement(factory, judgment);
-    inferrer.listener.labeledStatement(this, fileOffset, null, null, null);
+    // TODO(paulberry): support multiple labels.
+    List<Object> labels = <Object>[
+      inferrer.listener.statementLabel(createBinder(inferrer), null, null)
+    ];
+    inferrer.listener.labeledStatement(labels, null);
   }
 }
 
@@ -2575,6 +2592,8 @@
 
 /// Concrete shadow object representing a switch case.
 class SwitchCaseJudgment extends SwitchCase {
+  Object binder;
+
   SwitchCaseJudgment(
       List<Expression> expressions, List<int> expressionOffsets, Statement body,
       {bool isDefault: false})
@@ -2587,6 +2606,12 @@
   List<ExpressionJudgment> get expressionJudgments => expressions.cast();
 
   StatementJudgment get bodyJudgment => body;
+
+  Object createBinder(ShadowTypeInferrer inferrer) {
+    // TODO(paulberry): we need one binder for each label
+    return binder ??=
+        inferrer.listener.binderForSwitchLabel(this, fileOffset, null);
+  }
 }
 
 /// Concrete shadow object representing a switch statement in kernel form.
@@ -2613,6 +2638,8 @@
             factory, caseExpression, expressionType, false);
       }
       inferrer.inferStatement(factory, switchCase.bodyJudgment);
+      // TODO(paulberry): support labels.
+      inferrer.listener.switchCase(switchCase, null, null, null, null, null);
     }
     inferrer.listener.switchStatement(
         this, fileOffset, null, null, expression, null, null, cases, null);
diff --git a/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart b/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
index 6f885d1..67cc2bb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/toplevel_inference_factory.dart
@@ -11,7 +11,11 @@
 import 'factory.dart' show Factory;
 
 import 'kernel_shadow_ast.dart'
-    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
+    show
+        ExpressionJudgment,
+        InitializerJudgment,
+        StatementJudgment,
+        SwitchCaseJudgment;
 
 /// Implementation of [Factory] for use during top level type inference, when
 /// no representation of the code semantics needs to be created (only the type
@@ -64,8 +68,13 @@
       bool value, DartType inferredType) {}
 
   @override
-  void breakStatement(StatementJudgment judgment, int fileOffset,
-      Token breakKeyword, void label, Token semicolon) {}
+  void breakStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token breakKeyword,
+      void label,
+      Token semicolon,
+      covariant void labelBinder) {}
 
   @override
   void cascadeExpression(
@@ -108,12 +117,22 @@
       Node expressionTarget, DartType inferredType) {}
 
   @override
-  void continueStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant void labelBinder) {}
 
   @override
-  void continueSwitchStatement(StatementJudgment judgment, int fileOffset,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueSwitchStatement(
+      StatementJudgment judgment,
+      int fileOffset,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant void labelBinder) {}
 
   @override
   void deferredCheck(
@@ -245,8 +264,14 @@
       DartType inferredType) {}
 
   @override
-  void labeledStatement(StatementJudgment judgment, int fileOffset, Token label,
-      Token colon, void statement) {}
+  void labeledStatement(List<Object> labels, void statement) {}
+
+  @override
+  void statementLabel(covariant void binder, Token label, Token colon) {}
+
+  @override
+  void binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name) {}
 
   @override
   void listLiteral(
@@ -402,6 +427,17 @@
       Object argumentList) {}
 
   @override
+  void switchCase(SwitchCaseJudgment judgment, List<Object> labels,
+      Token keyword, void expression, Token colon, List<void> statements) {}
+
+  @override
+  void switchLabel(covariant void binder, Token label, Token colon) {}
+
+  @override
+  void binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name) {}
+
+  @override
   void switchStatement(
       StatementJudgment judgment,
       int fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
index 3871939..8f7c7c5 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_listener.dart
@@ -9,7 +9,11 @@
 import '../../scanner/token.dart' show Token;
 
 import '../kernel/kernel_shadow_ast.dart'
-    show ExpressionJudgment, InitializerJudgment, StatementJudgment;
+    show
+        ExpressionJudgment,
+        InitializerJudgment,
+        StatementJudgment,
+        SwitchCaseJudgment;
 
 /// Callback interface used by [TypeInferrer] to report the results of type
 /// inference to a client.
@@ -63,8 +67,13 @@
   void boolLiteral(ExpressionJudgment judgment, Location location,
       Token literal, bool value, DartType inferredType);
 
-  void breakStatement(StatementJudgment judgment, Location location,
-      Token breakKeyword, void label, Token semicolon);
+  void breakStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token breakKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder);
 
   void cascadeExpression(
       ExpressionJudgment judgment, Location location, DartType inferredType);
@@ -100,11 +109,21 @@
   void constructorInvocation(ExpressionJudgment judgment, Location location,
       Reference expressionTarget, DartType inferredType);
 
-  void continueStatement(StatementJudgment judgment, Location location,
-      Token continueKeyword, void label, Token semicolon);
+  void continueStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder);
 
-  void continueSwitchStatement(StatementJudgment judgment, Location location,
-      Token continueKeyword, void label, Token semicolon);
+  void continueSwitchStatement(
+      StatementJudgment judgment,
+      Location location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant Object labelBinder);
 
   void deferredCheck(
       ExpressionJudgment judgment, Location location, DartType inferredType);
@@ -218,8 +237,12 @@
       DartType type,
       DartType inferredType);
 
-  void labeledStatement(StatementJudgment judgment, Location location,
-      Token label, Token colon, void statement);
+  void labeledStatement(List<Object> labels, void statement);
+
+  Object statementLabel(covariant Object binder, Token label, Token colon);
+
+  Object binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name);
 
   void listLiteral(
       ExpressionJudgment judgment,
@@ -346,6 +369,14 @@
       Token constructorName,
       covariant Object argumentList);
 
+  Object switchCase(SwitchCaseJudgment switchCase, List<Object> labels,
+      Token keyword, void expression, Token colon, List<void> statements);
+
+  Object switchLabel(covariant Object binder, Token label, Token colon);
+
+  Object binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name);
+
   void switchStatement(
       StatementJudgment judgment,
       Location location,
@@ -469,7 +500,7 @@
 
   @override
   void breakStatement(StatementJudgment judgment, location, Token breakKeyword,
-      void label, Token semicolon) {}
+      void label, Token semicolon, covariant void labelBinder) {}
 
   @override
   void cascadeExpression(
@@ -510,12 +541,22 @@
       expressionTarget, DartType inferredType) {}
 
   @override
-  void continueStatement(StatementJudgment judgment, location,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueStatement(
+      StatementJudgment judgment,
+      location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant void labelBinder) {}
 
   @override
-  void continueSwitchStatement(StatementJudgment judgment, location,
-      Token continueKeyword, void label, Token semicolon) {}
+  void continueSwitchStatement(
+      StatementJudgment judgment,
+      location,
+      Token continueKeyword,
+      void label,
+      Token semicolon,
+      covariant void labelBinder) {}
 
   @override
   void deferredCheck(
@@ -647,8 +688,14 @@
       DartType inferredType) {}
 
   @override
-  void labeledStatement(StatementJudgment judgment, location, Token label,
-      Token colon, void statement) {}
+  void labeledStatement(List<Object> labels, void statement) {}
+
+  @override
+  void statementLabel(covariant void binder, Token label, Token colon) {}
+
+  @override
+  void binderForStatementLabel(
+      StatementJudgment judgment, int fileOffset, String name) {}
 
   @override
   void listLiteral(
@@ -793,6 +840,17 @@
       covariant Object argumentList) {}
 
   @override
+  void switchCase(SwitchCaseJudgment switchCase, covariant List<Object> labels,
+      Token keyword, void expression, Token colon, List<void> statements) {}
+
+  @override
+  void switchLabel(covariant void binder, Token label, Token colon) {}
+
+  @override
+  void binderForSwitchLabel(
+      SwitchCaseJudgment judgment, int fileOffset, String name) {}
+
+  @override
   void switchStatement(
       StatementJudgment judgment,
       location,