[cfe] Desugar BinaryPattern

Part of https://github.com/dart-lang/sdk/issues/49749

Change-Id: I98dd7d63c560eb4c48350c32826e51df1491d9d9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271708
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index edc8f99..a3764b3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2616,19 +2616,32 @@
     reportIfNotEnabled(
         libraryFeatures.patterns, token.charOffset, token.charCount);
     // ignore: unused_local_variable
-    Pattern left = toPattern(pop());
-    // ignore: unused_local_variable
     Pattern right = toPattern(pop());
+    // ignore: unused_local_variable
+    Pattern left = toPattern(pop());
     // TODO(johnniwinther): Create a binary pattern.
 
     String operator = token.lexeme;
-    BinaryPatternKind kind;
     switch (operator) {
       case '&':
-        kind = BinaryPatternKind.and;
+        push(new AndPattern(left, right, token.charOffset));
         break;
       case '|':
-        kind = BinaryPatternKind.or;
+        Map<String, VariableDeclaration> leftVariablesByName = {
+          for (VariableDeclaration leftVariable in left.declaredVariables)
+            leftVariable.name!: leftVariable
+        };
+        if (!leftVariablesByName.keys.toSet().containsAll(
+                right.declaredVariables.map((variable) => variable.name!)) &&
+            leftVariablesByName.length == right.declaredVariables.length) {
+          // TODO(cstefantsova): Report a compile-time error.
+        }
+        push(new OrPattern(left, right, token.charOffset,
+            orPatternJointVariables: [
+              for (VariableDeclaration leftVariable in left.declaredVariables)
+                forest.createVariableDeclaration(
+                    leftVariable.fileOffset, leftVariable.name)
+            ]));
         break;
       default:
         internalProblem(
@@ -2637,7 +2650,6 @@
             token.charOffset,
             uri);
     }
-    push(new BinaryPattern(left, kind, right, token.charOffset));
   }
 
   void doBinaryExpression(Token token) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index b83a9f9..cf5d623 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -413,8 +413,11 @@
   /// [fileOffset]. The [condition] is the expression preceding the question
   /// mark. The [thenExpression] is the expression following the question mark.
   /// The [elseExpression] is the expression following the colon.
-  Expression createConditionalExpression(int fileOffset, Expression condition,
-      Expression thenExpression, Expression elseExpression) {
+  ConditionalExpression createConditionalExpression(
+      int fileOffset,
+      Expression condition,
+      Expression thenExpression,
+      Expression elseExpression) {
     return new ConditionalExpression(
         condition, thenExpression, elseExpression, const UnknownType())
       ..fileOffset = fileOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index de8361f5..3c9e153 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -5117,7 +5117,9 @@
       InferenceVisitorBase inferenceVisitor) {
     return new PatternTransformationResult([
       new PatternTransformationElement(
-          condition: null, variableInitializers: <Statement>[])
+          kind: PatternTransformationElementKind.regular,
+          condition: null,
+          variableInitializers: <Statement>[])
     ]);
   }
 
@@ -5166,7 +5168,9 @@
         target.member as Procedure);
     return new PatternTransformationResult([
       new PatternTransformationElement(
-          condition: result, variableInitializers: [])
+          kind: PatternTransformationElementKind.regular,
+          condition: result,
+          variableInitializers: [])
     ]);
   }
 
@@ -5181,23 +5185,16 @@
   }
 }
 
-enum BinaryPatternKind {
-  and,
-  or,
-}
-
-/// A [Pattern] for `pattern | pattern` and `pattern & pattern`.
-class BinaryPattern extends Pattern {
+/// A [Pattern] for `pattern & pattern`.
+class AndPattern extends Pattern {
   Pattern left;
-  BinaryPatternKind kind;
   Pattern right;
 
   @override
   List<VariableDeclaration> get declaredVariables =>
       [...left.declaredVariables, ...right.declaredVariables];
 
-  BinaryPattern(this.left, this.kind, this.right, int fileOffset)
-      : super(fileOffset) {
+  AndPattern(this.left, this.right, int fileOffset) : super(fileOffset) {
     left.parent = this;
     right.parent = this;
   }
@@ -5208,7 +5205,7 @@
     required DartType matchedType,
     required SharedMatchContext context,
   }) {
-    return visitor.visitBinaryPattern(this,
+    return visitor.visitAndPattern(this,
         matchedType: matchedType, context: context);
   }
 
@@ -5218,25 +5215,277 @@
       DartType matchedType,
       Expression variableInitializingContext,
       InferenceVisitorBase inferenceVisitor) {
-    return new PatternTransformationResult([
-      new PatternTransformationElement(
-          condition:
-              new InvalidExpression("Unimplemented BinaryPattern.transform"),
-          variableInitializers: [])
-    ]);
+    // intermediateVariable: `matchedType` VAR = `matchedExpression`
+    VariableDeclaration intermediateVariable = inferenceVisitor.engine.forest
+        .createVariableDeclarationForValue(matchedExpression,
+            type: matchedType);
+
+    PatternTransformationResult transformationResult = left.transform(
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        matchedType,
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        inferenceVisitor);
+
+    transformationResult = transformationResult.combine(
+        right.transform(
+            inferenceVisitor.engine.forest
+                .createVariableGet(fileOffset, intermediateVariable),
+            matchedType,
+            inferenceVisitor.engine.forest
+                .createVariableGet(fileOffset, intermediateVariable),
+            inferenceVisitor),
+        inferenceVisitor);
+
+    transformationResult = transformationResult.prependElement(
+        new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [intermediateVariable]),
+        inferenceVisitor);
+
+    return transformationResult;
   }
 
   @override
   void toTextInternal(AstPrinter printer) {
     left.toTextInternal(printer);
-    switch (kind) {
-      case BinaryPatternKind.and:
-        printer.write(' & ');
-        break;
-      case BinaryPatternKind.or:
-        printer.write(' | ');
-        break;
+    printer.write(' & ');
+    right.toTextInternal(printer);
+  }
+
+  @override
+  String toString() {
+    return "BinaryPattern(${toStringInternal()})";
+  }
+}
+
+/// A [Pattern] for `pattern | pattern`.
+class OrPattern extends Pattern {
+  Pattern left;
+  Pattern right;
+  List<VariableDeclaration> _orPatternJointVariables;
+
+  @override
+  List<VariableDeclaration> get declaredVariables => _orPatternJointVariables;
+
+  OrPattern(this.left, this.right, int fileOffset,
+      {required List<VariableDeclaration> orPatternJointVariables})
+      : _orPatternJointVariables = orPatternJointVariables,
+        super(fileOffset) {
+    left.parent = this;
+    right.parent = this;
+  }
+
+  @override
+  PatternInferenceResult acceptInference(
+    InferenceVisitorImpl visitor, {
+    required DartType matchedType,
+    required SharedMatchContext context,
+  }) {
+    return visitor.visitOrPattern(this,
+        matchedType: matchedType, context: context);
+  }
+
+  @override
+  PatternTransformationResult transform(
+      Expression matchedExpression,
+      DartType matchedType,
+      Expression variableInitializingContext,
+      InferenceVisitorBase inferenceVisitor) {
+    // intermediateVariable: `matchedType` VAR = `matchedExpression`
+    VariableDeclaration intermediateVariable = inferenceVisitor.engine.forest
+        .createVariableDeclarationForValue(matchedExpression,
+            type: matchedType);
+
+    // leftConditionIsTrue: bool LVAR = false;
+    VariableDeclaration leftConditionIsTrue = inferenceVisitor.engine.forest
+        .createVariableDeclarationForValue(
+            inferenceVisitor.engine.forest.createBoolLiteral(fileOffset, false),
+            type: inferenceVisitor.coreTypes.boolNonNullableRawType);
+
+    Map<String, VariableDeclaration> leftVariablesByName = {
+      for (VariableDeclaration variable in left.declaredVariables)
+        variable.name!: variable
+    };
+    Map<String, VariableDeclaration> rightVariablesByName = {
+      for (VariableDeclaration variable in right.declaredVariables)
+        variable.name!: variable
+    };
+    List<VariableDeclaration> declaredVariables = this.declaredVariables;
+    for (VariableDeclaration variable in declaredVariables) {
+      VariableDeclaration leftVariable = leftVariablesByName[variable.name!]!;
+      VariableDeclaration rightVariable = rightVariablesByName[variable.name!]!;
+      variable.initializer = inferenceVisitor.engine.forest
+          .createConditionalExpression(
+              fileOffset,
+              inferenceVisitor.engine.forest.createVariableGet(
+                  fileOffset, leftConditionIsTrue),
+              inferenceVisitor.engine.forest
+                  .createVariableGet(fileOffset, leftVariable)
+                ..promotedType = leftVariable.type,
+              inferenceVisitor.engine.forest
+                  .createVariableGet(fileOffset, rightVariable)
+                ..promotedType = rightVariable.type)
+        ..staticType = inferenceVisitor.typeSchemaEnvironment
+            .getStandardUpperBound(leftVariable.type, rightVariable.type,
+                inferenceVisitor.libraryBuilder.library)
+        ..parent = variable;
     }
+
+    // setLeftConditionIsTrue: `leftConditionIsTrue` = true;
+    //   ==> VAR = true;
+    Statement setLeftConditionIsTrue = inferenceVisitor.engine.forest
+        .createExpressionStatement(
+            fileOffset,
+            inferenceVisitor.engine.forest.createVariableSet(
+                fileOffset,
+                leftConditionIsTrue,
+                inferenceVisitor.engine.forest
+                    .createBoolLiteral(fileOffset, true)));
+
+    PatternTransformationResult leftTransformationResult = left.transform(
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        matchedType,
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        inferenceVisitor);
+    leftTransformationResult = leftTransformationResult.prependElement(
+        new PatternTransformationElement(
+            kind: PatternTransformationElementKind.logicalOrPatternLeftBegin,
+            condition: null,
+            variableInitializers: []),
+        inferenceVisitor);
+    // Initialize variables to values captured by [left].
+    leftTransformationResult = leftTransformationResult.combine(
+        new PatternTransformationResult([
+          new PatternTransformationElement(
+              kind: PatternTransformationElementKind.regular,
+              condition: null,
+              variableInitializers: [
+                setLeftConditionIsTrue,
+                for (VariableDeclaration variable in left.declaredVariables)
+                  inferenceVisitor.engine.forest.createExpressionStatement(
+                      fileOffset,
+                      inferenceVisitor.engine.forest.createVariableSet(
+                          fileOffset, variable, variable.initializer!))
+              ])
+        ]),
+        inferenceVisitor);
+    for (VariableDeclaration variable in left.declaredVariables) {
+      variable.name = null;
+      variable.initializer = null;
+      variable.type = const DynamicType();
+    }
+
+    // rightConditionIsTrue: bool RVAR = false;
+    VariableDeclaration rightConditionIsTrue = inferenceVisitor.engine.forest
+        .createVariableDeclarationForValue(
+            inferenceVisitor.engine.forest.createBoolLiteral(fileOffset, false),
+            type: inferenceVisitor.coreTypes.boolNonNullableRawType);
+
+    // setRightConditionIsTrue: `rightConditionIsTrue` = true;
+    //   ==> VAR = true;
+    Statement setRightConditionIsTrue = inferenceVisitor.engine.forest
+        .createExpressionStatement(
+            fileOffset,
+            inferenceVisitor.engine.forest.createVariableSet(
+                fileOffset,
+                rightConditionIsTrue,
+                inferenceVisitor.engine.forest
+                    .createBoolLiteral(fileOffset, true)));
+
+    PatternTransformationResult rightTransformationResult = right.transform(
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        matchedType,
+        inferenceVisitor.engine.forest
+            .createVariableGet(fileOffset, intermediateVariable),
+        inferenceVisitor);
+    rightTransformationResult = rightTransformationResult.prependElement(
+        new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
+            // condition: !`leftConditionIsTrue`
+            condition: inferenceVisitor.engine.forest.createNot(
+                fileOffset,
+                inferenceVisitor.engine.forest
+                    .createVariableGet(fileOffset, leftConditionIsTrue)),
+            variableInitializers: []),
+        inferenceVisitor);
+    rightTransformationResult = rightTransformationResult.prependElement(
+        new PatternTransformationElement(
+            kind: PatternTransformationElementKind.logicalOrPatternRightBegin,
+            condition: null,
+            variableInitializers: []),
+        inferenceVisitor);
+    // Initialize variables to values captured by [right].
+    rightTransformationResult = rightTransformationResult.combine(
+        new PatternTransformationResult([
+          new PatternTransformationElement(
+              kind: PatternTransformationElementKind.regular,
+              condition: null,
+              variableInitializers: [
+                setRightConditionIsTrue,
+                for (VariableDeclaration variable in right.declaredVariables)
+                  inferenceVisitor.engine.forest.createExpressionStatement(
+                      fileOffset,
+                      inferenceVisitor.engine.forest.createVariableSet(
+                          fileOffset, variable, variable.initializer!))
+              ])
+        ]),
+        inferenceVisitor);
+    for (VariableDeclaration variable in right.declaredVariables) {
+      variable.name = null;
+      variable.initializer = null;
+      variable.type = const DynamicType();
+    }
+
+    PatternTransformationResult transformationResult = leftTransformationResult
+        .combine(rightTransformationResult, inferenceVisitor)
+        .combine(
+            new PatternTransformationResult([
+              new PatternTransformationElement(
+                  kind: PatternTransformationElementKind.logicalOrPatternEnd,
+                  condition: null,
+                  variableInitializers: []),
+              new PatternTransformationElement(
+                  kind: PatternTransformationElementKind.regular,
+                  // condition:
+                  //     `leftConditionIsTrue` || `rightConditionIsTrue`
+                  condition: inferenceVisitor.engine.forest
+                      .createLogicalExpression(
+                          fileOffset,
+                          inferenceVisitor.engine.forest.createVariableGet(
+                              fileOffset, leftConditionIsTrue),
+                          doubleBarName.text,
+                          inferenceVisitor.engine.forest.createVariableGet(
+                              fileOffset, rightConditionIsTrue)),
+                  variableInitializers: [])
+            ]),
+            inferenceVisitor);
+
+    transformationResult = transformationResult.prependElement(
+        new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [
+              intermediateVariable,
+              leftConditionIsTrue,
+              rightConditionIsTrue,
+              ...left.declaredVariables,
+              ...right.declaredVariables
+            ]),
+        inferenceVisitor);
+
+    return transformationResult;
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    left.toTextInternal(printer);
+    printer.write(' | ');
     right.toTextInternal(printer);
   }
 
@@ -5294,7 +5543,9 @@
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [intermediateVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [intermediateVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -5363,7 +5614,9 @@
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [intermediateVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [intermediateVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -5437,11 +5690,15 @@
     // condition in the last transformation element.
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: nullCheckCondition, variableInitializers: []),
+            kind: PatternTransformationElementKind.regular,
+            condition: nullCheckCondition,
+            variableInitializers: []),
         inferenceVisitor);
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [intermediateVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [intermediateVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -5618,13 +5875,16 @@
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
             condition: typeAndLengthCheck,
             variableInitializers: elementAccessVariables),
         inferenceVisitor);
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [listVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [listVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -5759,7 +6019,9 @@
     }
     return new PatternTransformationResult([
       new PatternTransformationElement(
-          condition: condition, variableInitializers: [])
+          kind: PatternTransformationElementKind.regular,
+          condition: condition,
+          variableInitializers: [])
     ]);
   }
 
@@ -5828,7 +6090,9 @@
     }
     return new PatternTransformationResult([
       new PatternTransformationElement(
-          condition: condition, variableInitializers: [])
+          kind: PatternTransformationElementKind.regular,
+          condition: condition,
+          variableInitializers: [])
     ]);
   }
 
@@ -6188,13 +6452,16 @@
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
             condition: typeAndKeysCheck,
             variableInitializers: valueAccessVariables),
         inferenceVisitor);
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [mapVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [mapVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -6242,6 +6509,7 @@
       InferenceVisitorBase inferenceVisitor) {
     return new PatternTransformationResult([
       new PatternTransformationElement(
+          kind: PatternTransformationElementKind.regular,
           condition:
               new InvalidExpression("Unimplemented NamedPattern.transform"),
           variableInitializers: [])
@@ -6384,6 +6652,7 @@
     //   ==> [RVAR is `type`]?
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
             condition: !typeCheckNeeded
                 ? null
                 : inferenceVisitor.engine.forest.createIsExpression(
@@ -6398,7 +6667,9 @@
 
     transformationResult = transformationResult.prependElement(
         new PatternTransformationElement(
-            condition: null, variableInitializers: [recordVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [recordVariable]),
         inferenceVisitor);
 
     return transformationResult;
@@ -6447,9 +6718,13 @@
           forNonNullableByDefault: false);
       transformationResult = new PatternTransformationResult([
         new PatternTransformationElement(
-            condition: null, variableInitializers: [matchedExpressionVariable]),
+            kind: PatternTransformationElementKind.regular,
+            condition: null,
+            variableInitializers: [matchedExpressionVariable]),
         new PatternTransformationElement(
-            condition: condition, variableInitializers: [])
+            kind: PatternTransformationElementKind.regular,
+            condition: condition,
+            variableInitializers: [])
       ]);
       variable.initializer = inferenceVisitor.engine.forest
           .createVariableGet(fileOffset, matchedExpressionVariable)
@@ -6513,6 +6788,13 @@
   }
 }
 
+enum PatternTransformationElementKind {
+  regular,
+  logicalOrPatternLeftBegin,
+  logicalOrPatternRightBegin,
+  logicalOrPatternEnd
+}
+
 class PatternTransformationElement {
   /// Part of a matching condition of a pattern
   ///
@@ -6528,8 +6810,15 @@
   /// variables.
   final List<Statement> variableInitializers;
 
+  final PatternTransformationResult? otherwise;
+
+  final PatternTransformationElementKind kind;
+
   PatternTransformationElement(
-      {required this.condition, required this.variableInitializers});
+      {required this.condition,
+      required this.variableInitializers,
+      required this.kind,
+      this.otherwise});
 
   bool get isEmpty => condition == null && variableInitializers.isEmpty;
 }
@@ -6556,6 +6845,9 @@
     } else if (other.elements.isEmpty) {
       return this;
     } else {
+      // TODO(cstefantsova): Does it make sense to use [prependElement] on each
+      // element from [elements], last to the first, prepending them to the
+      // accumulated result?
       return new PatternTransformationResult([
         ...elements.sublist(0, elements.length - 1),
         ...other.prependElement(elements.last, inferenceVisitor).elements
@@ -6577,11 +6869,16 @@
     if (elements.isEmpty) {
       return new PatternTransformationResult([element]);
     }
+    if (element.kind != PatternTransformationElementKind.regular ||
+        elements.first.kind != PatternTransformationElementKind.regular) {
+      return new PatternTransformationResult([element, ...elements]);
+    }
     PatternTransformationElement outermost = elements.first;
     Expression? elementCondition = element.condition;
     Expression? outermostCondition = outermost.condition;
     if (outermostCondition == null) {
       elements[0] = new PatternTransformationElement(
+          kind: PatternTransformationElementKind.regular,
           condition: elementCondition,
           variableInitializers: [
             ...element.variableInitializers,
@@ -6594,6 +6891,7 @@
         return this;
       } else {
         elements[0] = new PatternTransformationElement(
+            kind: PatternTransformationElementKind.regular,
             condition: inferenceVisitor.engine.forest.createLogicalExpression(
                 elementCondition.fileOffset,
                 elementCondition,
@@ -6607,3 +6905,9 @@
     }
   }
 }
+
+class ContinuationStackElement {
+  List<Statement> statements;
+
+  ContinuationStackElement(this.statements);
+}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
index 4c75b37..5f1ef57 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
@@ -1828,25 +1828,62 @@
         ])
       ];
     }
+
+    List<ContinuationStackElement> continuationStack = [];
     for (int i = transformationResult.elements.length - 1; i >= 0; i--) {
       PatternTransformationElement transformationElement =
           transformationResult.elements[i];
-      replacementStatements = [
-        ...transformationElement.variableInitializers,
-        ...replacementStatements
-      ];
-      Expression? condition = transformationElement.condition;
-      if (condition != null) {
-        replacementStatements = [
-          engine.forest.createIfStatement(
-              node.fileOffset,
-              condition,
-              engine.forest.createBlock(
-                  node.fileOffset, node.fileOffset, replacementStatements),
-              null)
-        ];
+
+      switch (transformationElement.kind) {
+        case PatternTransformationElementKind.regular:
+          replacementStatements = [
+            ...transformationElement.variableInitializers,
+            ...replacementStatements
+          ];
+          Expression? condition = transformationElement.condition;
+          if (condition != null) {
+            replacementStatements = [
+              engine.forest.createIfStatement(
+                  node.fileOffset,
+                  condition,
+                  engine.forest.createBlock(
+                      node.fileOffset, node.fileOffset, replacementStatements),
+                  null)
+            ];
+          }
+          break;
+
+        case PatternTransformationElementKind.logicalOrPatternLeftBegin:
+          ContinuationStackElement leftContinuation =
+              continuationStack.removeLast();
+          ContinuationStackElement rightContinuation =
+              continuationStack.removeLast();
+
+          List<Statement> leftConditionDesugaring = replacementStatements;
+          replacementStatements = [
+            ...leftConditionDesugaring,
+            ...leftContinuation.statements,
+            ...rightContinuation.statements,
+          ];
+
+          break;
+
+        case PatternTransformationElementKind.logicalOrPatternRightBegin:
+          continuationStack
+              .add(new ContinuationStackElement(replacementStatements));
+          replacementStatements = [];
+          break;
+
+        case PatternTransformationElementKind.logicalOrPatternEnd:
+          continuationStack
+              .add(new ContinuationStackElement(replacementStatements));
+          replacementStatements = [];
+          break;
       }
     }
+    assert(continuationStack.isEmpty,
+        "Continuation stack is not empty at the end of desugaring.");
+
     replacementStatements = [
       matchedExpressionVariable,
       if (otherwise != null) isPatternMatchingFailed,
@@ -8802,8 +8839,20 @@
     return const PatternInferenceResult();
   }
 
-  PatternInferenceResult visitBinaryPattern(
-    BinaryPattern pattern, {
+  PatternInferenceResult visitAndPattern(
+    AndPattern pattern, {
+    required DartType matchedType,
+    required SharedMatchContext context,
+  }) {
+    pattern.left
+        .acceptInference(this, matchedType: matchedType, context: context);
+    pattern.right
+        .acceptInference(this, matchedType: matchedType, context: context);
+    return const PatternInferenceResult();
+  }
+
+  PatternInferenceResult visitOrPattern(
+    OrPattern pattern, {
     required DartType matchedType,
     required SharedMatchContext context,
   }) {
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index acd7a90..68058b9 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -1676,6 +1676,7 @@
 joined
 joining
 joins
+joint
 judgment
 judgments
 jump
diff --git a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
index f29e612..a3a1421 100644
--- a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
+++ b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
@@ -1067,20 +1067,15 @@
 
 void _testBinaryMatcher() {
   testMatcher(
-      new BinaryPattern(
-          new ExpressionPattern(new IntLiteral(0)),
-          BinaryPatternKind.and,
-          new ExpressionPattern(new IntLiteral(1)),
-          TreeNode.noOffset),
+      new AndPattern(new ExpressionPattern(new IntLiteral(0)),
+          new ExpressionPattern(new IntLiteral(1)), TreeNode.noOffset),
       '''
 0 & 1''');
 
   testMatcher(
-      new BinaryPattern(
-          new ExpressionPattern(new IntLiteral(0)),
-          BinaryPatternKind.or,
-          new ExpressionPattern(new IntLiteral(1)),
-          TreeNode.noOffset),
+      new OrPattern(new ExpressionPattern(new IntLiteral(0)),
+          new ExpressionPattern(new IntLiteral(1)), TreeNode.noOffset,
+          orPatternJointVariables: []),
       '''
 0 | 1''');
 }
diff --git a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.expect b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.expect
index 4d4b15e..9a8da7a 100644
--- a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.expect
@@ -1,8 +1,10 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
 static method test(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  if(#t2 is core::int? && #t2 is core::double?) {
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.transformed.expect
index 4d4b15e..9a8da7a 100644
--- a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.strong.transformed.expect
@@ -1,8 +1,10 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
 static method test(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  if(#t2 is core::int? && #t2 is core::double?) {
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.expect b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.expect
index 4d4b15e..9a8da7a 100644
--- a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.expect
@@ -1,8 +1,10 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
 static method test(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  if(#t2 is core::int? && #t2 is core::double?) {
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.modular.expect
index 4d4b15e..9a8da7a 100644
--- a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.modular.expect
@@ -1,8 +1,10 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
 static method test(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  if(#t2 is core::int? && #t2 is core::double?) {
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.transformed.expect
index 4d4b15e..9a8da7a 100644
--- a/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/logical_and_inside_if_case.dart.weak.transformed.expect
@@ -1,8 +1,10 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
 static method test(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  if(#t2 is core::int? && #t2 is core::double?) {
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart
index 8e2c853..84cc965 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart
@@ -2,6 +2,22 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-test(dynamic x) {
+test1(dynamic x) {
   if (x case int? _ | double? _) {}
 }
+
+test2(dynamic x) {
+  if (x case [int y, var _] | [var _, String y]) {
+    return y;
+  } else {
+    return null;
+  }
+}
+
+test3(dynamic x) {
+  if (x case == 1 | == 2 | == 3) {
+    return 0;
+  } else {
+    return 1;
+  }
+}
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.expect
index 4d4b15e..b92d69a 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.expect
@@ -1,8 +1,90 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
-static method test(dynamic x) → dynamic {
+static method test1(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  final core::bool #t3 = false;
+  final core::bool #t4 = false;
+  if(#t2 is core::int?) {
+    #t3 = true;
+  }
+  if(!#t3 && #t2 is core::double?) {
+    #t4 = true;
+  }
+  if(#t3 || #t4) {
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  final core::bool #t8 = false;
+  final core::bool #t9 = false;
+  dynamic #t10;
+  dynamic #t11;
+  final dynamic #t12 = #t7;
+  if(#t12 is core::List<dynamic> && #t12{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+    final dynamic #t13 = #t12{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
+    final dynamic #t14 = #t13;
+    if(#t14 is core::int) {
+      #t8 = true;
+      #t10 = #t14{core::int};
+    }
+  }
+  if(!#t8) {
+    final dynamic #t15 = #t7;
+    if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+      final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
+      final dynamic #t17 = #t16;
+      if(#t17 is core::String) {
+        #t9 = true;
+        #t11 = #t17{core::String};
+      }
+    }
+  }
+  if(#t8 || #t9) {
+    #t6 = false;
+    {
+      dynamic y = #t8 ?{core::Object} #t10{core::int} : #t11{core::String};
+      {
+        return y;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method test3(dynamic x) → dynamic {
+  final dynamic #t18 = x;
+  final core::bool #t19 = true;
+  final dynamic #t20 = #t18;
+  final core::bool #t21 = false;
+  final core::bool #t22 = false;
+  final dynamic #t23 = #t20;
+  final core::bool #t24 = false;
+  final core::bool #t25 = false;
+  if(#t23 =={core::Object::==}{(core::Object) → core::bool} 1) {
+    #t24 = true;
+  }
+  if(!#t24 && #t23 =={core::Object::==}{(core::Object) → core::bool} 2) {
+    #t25 = true;
+  }
+  if(#t24 || #t25) {
+    #t21 = true;
+  }
+  if(!#t21 && #t20 =={core::Object::==}{(core::Object) → core::bool} 3) {
+    #t22 = true;
+  }
+  if(#t21 || #t22) {
+    #t19 = false;
+    {
+      return 0;
+    }
+  }
+  if(#t19) {
+    return 1;
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.transformed.expect
index 4d4b15e..b92d69a 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.strong.transformed.expect
@@ -1,8 +1,90 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
-static method test(dynamic x) → dynamic {
+static method test1(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  final core::bool #t3 = false;
+  final core::bool #t4 = false;
+  if(#t2 is core::int?) {
+    #t3 = true;
+  }
+  if(!#t3 && #t2 is core::double?) {
+    #t4 = true;
+  }
+  if(#t3 || #t4) {
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  final core::bool #t8 = false;
+  final core::bool #t9 = false;
+  dynamic #t10;
+  dynamic #t11;
+  final dynamic #t12 = #t7;
+  if(#t12 is core::List<dynamic> && #t12{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+    final dynamic #t13 = #t12{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
+    final dynamic #t14 = #t13;
+    if(#t14 is core::int) {
+      #t8 = true;
+      #t10 = #t14{core::int};
+    }
+  }
+  if(!#t8) {
+    final dynamic #t15 = #t7;
+    if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+      final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
+      final dynamic #t17 = #t16;
+      if(#t17 is core::String) {
+        #t9 = true;
+        #t11 = #t17{core::String};
+      }
+    }
+  }
+  if(#t8 || #t9) {
+    #t6 = false;
+    {
+      dynamic y = #t8 ?{core::Object} #t10{core::int} : #t11{core::String};
+      {
+        return y;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method test3(dynamic x) → dynamic {
+  final dynamic #t18 = x;
+  final core::bool #t19 = true;
+  final dynamic #t20 = #t18;
+  final core::bool #t21 = false;
+  final core::bool #t22 = false;
+  final dynamic #t23 = #t20;
+  final core::bool #t24 = false;
+  final core::bool #t25 = false;
+  if(#t23 =={core::Object::==}{(core::Object) → core::bool} 1) {
+    #t24 = true;
+  }
+  if(!#t24 && #t23 =={core::Object::==}{(core::Object) → core::bool} 2) {
+    #t25 = true;
+  }
+  if(#t24 || #t25) {
+    #t21 = true;
+  }
+  if(!#t21 && #t20 =={core::Object::==}{(core::Object) → core::bool} 3) {
+    #t22 = true;
+  }
+  if(#t21 || #t22) {
+    #t19 = false;
+    {
+      return 0;
+    }
+  }
+  if(#t19) {
+    return 1;
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline.expect
index 8655004..51cd7fc 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline.expect
@@ -1 +1,3 @@
-test(dynamic x) {}
+test1(dynamic x) {}
+test2(dynamic x) {}
+test3(dynamic x) {}
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline_modelled.expect
index 8655004..51cd7fc 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.textual_outline_modelled.expect
@@ -1 +1,3 @@
-test(dynamic x) {}
+test1(dynamic x) {}
+test2(dynamic x) {}
+test3(dynamic x) {}
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.expect
index 4d4b15e..b92d69a 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.expect
@@ -1,8 +1,90 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
-static method test(dynamic x) → dynamic {
+static method test1(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  final core::bool #t3 = false;
+  final core::bool #t4 = false;
+  if(#t2 is core::int?) {
+    #t3 = true;
+  }
+  if(!#t3 && #t2 is core::double?) {
+    #t4 = true;
+  }
+  if(#t3 || #t4) {
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  final core::bool #t8 = false;
+  final core::bool #t9 = false;
+  dynamic #t10;
+  dynamic #t11;
+  final dynamic #t12 = #t7;
+  if(#t12 is core::List<dynamic> && #t12{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+    final dynamic #t13 = #t12{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
+    final dynamic #t14 = #t13;
+    if(#t14 is core::int) {
+      #t8 = true;
+      #t10 = #t14{core::int};
+    }
+  }
+  if(!#t8) {
+    final dynamic #t15 = #t7;
+    if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+      final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
+      final dynamic #t17 = #t16;
+      if(#t17 is core::String) {
+        #t9 = true;
+        #t11 = #t17{core::String};
+      }
+    }
+  }
+  if(#t8 || #t9) {
+    #t6 = false;
+    {
+      dynamic y = #t8 ?{core::Object} #t10{core::int} : #t11{core::String};
+      {
+        return y;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method test3(dynamic x) → dynamic {
+  final dynamic #t18 = x;
+  final core::bool #t19 = true;
+  final dynamic #t20 = #t18;
+  final core::bool #t21 = false;
+  final core::bool #t22 = false;
+  final dynamic #t23 = #t20;
+  final core::bool #t24 = false;
+  final core::bool #t25 = false;
+  if(#t23 =={core::Object::==}{(core::Object) → core::bool} 1) {
+    #t24 = true;
+  }
+  if(!#t24 && #t23 =={core::Object::==}{(core::Object) → core::bool} 2) {
+    #t25 = true;
+  }
+  if(#t24 || #t25) {
+    #t21 = true;
+  }
+  if(!#t21 && #t20 =={core::Object::==}{(core::Object) → core::bool} 3) {
+    #t22 = true;
+  }
+  if(#t21 || #t22) {
+    #t19 = false;
+    {
+      return 0;
+    }
+  }
+  if(#t19) {
+    return 1;
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.modular.expect
index 4d4b15e..b92d69a 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.modular.expect
@@ -1,8 +1,90 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
-static method test(dynamic x) → dynamic {
+static method test1(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  final core::bool #t3 = false;
+  final core::bool #t4 = false;
+  if(#t2 is core::int?) {
+    #t3 = true;
+  }
+  if(!#t3 && #t2 is core::double?) {
+    #t4 = true;
+  }
+  if(#t3 || #t4) {
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  final core::bool #t8 = false;
+  final core::bool #t9 = false;
+  dynamic #t10;
+  dynamic #t11;
+  final dynamic #t12 = #t7;
+  if(#t12 is core::List<dynamic> && #t12{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+    final dynamic #t13 = #t12{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
+    final dynamic #t14 = #t13;
+    if(#t14 is core::int) {
+      #t8 = true;
+      #t10 = #t14{core::int};
+    }
+  }
+  if(!#t8) {
+    final dynamic #t15 = #t7;
+    if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+      final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
+      final dynamic #t17 = #t16;
+      if(#t17 is core::String) {
+        #t9 = true;
+        #t11 = #t17{core::String};
+      }
+    }
+  }
+  if(#t8 || #t9) {
+    #t6 = false;
+    {
+      dynamic y = #t8 ?{core::Object} #t10{core::int} : #t11{core::String};
+      {
+        return y;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method test3(dynamic x) → dynamic {
+  final dynamic #t18 = x;
+  final core::bool #t19 = true;
+  final dynamic #t20 = #t18;
+  final core::bool #t21 = false;
+  final core::bool #t22 = false;
+  final dynamic #t23 = #t20;
+  final core::bool #t24 = false;
+  final core::bool #t25 = false;
+  if(#t23 =={core::Object::==}{(core::Object) → core::bool} 1) {
+    #t24 = true;
+  }
+  if(!#t24 && #t23 =={core::Object::==}{(core::Object) → core::bool} 2) {
+    #t25 = true;
+  }
+  if(#t24 || #t25) {
+    #t21 = true;
+  }
+  if(!#t21 && #t20 =={core::Object::==}{(core::Object) → core::bool} 3) {
+    #t22 = true;
+  }
+  if(#t21 || #t22) {
+    #t19 = false;
+    {
+      return 0;
+    }
+  }
+  if(#t19) {
+    return 1;
   }
 }
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.outline.expect
index 303aa9b..8bb8687 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.outline.expect
@@ -1,5 +1,9 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 
-static method test(dynamic x) → dynamic
+static method test1(dynamic x) → dynamic
+  ;
+static method test2(dynamic x) → dynamic
+  ;
+static method test3(dynamic x) → dynamic
   ;
diff --git a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.transformed.expect
index 4d4b15e..b92d69a 100644
--- a/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart.weak.transformed.expect
@@ -1,8 +1,90 @@
 library /*isNonNullableByDefault*/;
 import self as self;
+import "dart:core" as core;
 
-static method test(dynamic x) → dynamic {
+static method test1(dynamic x) → dynamic {
   final dynamic #t1 = x;
-  if(invalid-expression "Unimplemented BinaryPattern.transform") {
+  final dynamic #t2 = #t1;
+  final core::bool #t3 = false;
+  final core::bool #t4 = false;
+  if(#t2 is core::int?) {
+    #t3 = true;
+  }
+  if(!#t3 && #t2 is core::double?) {
+    #t4 = true;
+  }
+  if(#t3 || #t4) {
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  final core::bool #t8 = false;
+  final core::bool #t9 = false;
+  dynamic #t10;
+  dynamic #t11;
+  final dynamic #t12 = #t7;
+  if(#t12 is core::List<dynamic> && #t12{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+    final dynamic #t13 = #t12{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
+    final dynamic #t14 = #t13;
+    if(#t14 is core::int) {
+      #t8 = true;
+      #t10 = #t14{core::int};
+    }
+  }
+  if(!#t8) {
+    final dynamic #t15 = #t7;
+    if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(2){(core::num) → core::bool}) {
+      final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
+      final dynamic #t17 = #t16;
+      if(#t17 is core::String) {
+        #t9 = true;
+        #t11 = #t17{core::String};
+      }
+    }
+  }
+  if(#t8 || #t9) {
+    #t6 = false;
+    {
+      dynamic y = #t8 ?{core::Object} #t10{core::int} : #t11{core::String};
+      {
+        return y;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method test3(dynamic x) → dynamic {
+  final dynamic #t18 = x;
+  final core::bool #t19 = true;
+  final dynamic #t20 = #t18;
+  final core::bool #t21 = false;
+  final core::bool #t22 = false;
+  final dynamic #t23 = #t20;
+  final core::bool #t24 = false;
+  final core::bool #t25 = false;
+  if(#t23 =={core::Object::==}{(core::Object) → core::bool} 1) {
+    #t24 = true;
+  }
+  if(!#t24 && #t23 =={core::Object::==}{(core::Object) → core::bool} 2) {
+    #t25 = true;
+  }
+  if(#t24 || #t25) {
+    #t21 = true;
+  }
+  if(!#t21 && #t20 =={core::Object::==}{(core::Object) → core::bool} 3) {
+    #t22 = true;
+  }
+  if(#t21 || #t22) {
+    #t19 = false;
+    {
+      return 0;
+    }
+  }
+  if(#t19) {
+    return 1;
   }
 }