Version 2.11.0-198.0.dev

Merge commit 'b4f265290c75fd6c6370cf1403f2b2649c59ad39' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 637e387..de9e6cc 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -351,6 +351,9 @@
   /// Call this method when visiting a boolean literal expression.
   void booleanLiteral(Expression expression, bool value);
 
+  /// Call this method just before visiting a conditional expression ("?:").
+  void conditional_conditionBegin();
+
   /// Call this method upon reaching the ":" part of a conditional expression
   /// ("?:").  [thenExpression] should be the expression preceding the ":".
   void conditional_elseBegin(Expression thenExpression);
@@ -867,6 +870,12 @@
   }
 
   @override
+  void conditional_conditionBegin() {
+    _wrap('conditional_conditionBegin()',
+        () => _wrapped.conditional_conditionBegin());
+  }
+
+  @override
   void conditional_elseBegin(Expression thenExpression) {
     _wrap('conditional_elseBegin($thenExpression',
         () => _wrapped.conditional_elseBegin(thenExpression));
@@ -2732,6 +2741,11 @@
   }
 
   @override
+  void conditional_conditionBegin() {
+    _current = _current.split();
+  }
+
+  @override
   void conditional_elseBegin(Expression thenExpression) {
     _ConditionalContext<Variable, Type> context =
         _stack.last as _ConditionalContext<Variable, Type>;
@@ -2749,9 +2763,9 @@
     _storeExpressionInfo(
         conditionalExpression,
         new ExpressionInfo(
-            _join(thenInfo.after, elseInfo.after),
-            _join(thenInfo.ifTrue, elseInfo.ifTrue),
-            _join(thenInfo.ifFalse, elseInfo.ifFalse)));
+            _merge(thenInfo.after, elseInfo.after),
+            _merge(thenInfo.ifTrue, elseInfo.ifTrue),
+            _merge(thenInfo.ifFalse, elseInfo.ifFalse)));
   }
 
   @override
@@ -2771,9 +2785,9 @@
     AssignedVariablesNodeInfo<Variable> info =
         _assignedVariables._getInfoForNode(doStatement);
     _BranchTargetContext<Variable, Type> context =
-        new _BranchTargetContext<Variable, Type>(_current.reachable.parent);
+        new _BranchTargetContext<Variable, Type>(_current.reachable);
     _stack.add(context);
-    _current = _current.conservativeJoin(info._written, info._captured);
+    _current = _current.conservativeJoin(info._written, info._captured).split();
     _statementToContext[doStatement] = context;
   }
 
@@ -2788,7 +2802,7 @@
   void doStatement_end(Expression condition) {
     _BranchTargetContext<Variable, Type> context =
         _stack.removeLast() as _BranchTargetContext<Variable, Type>;
-    _current = _join(_expressionEnd(condition).ifFalse, context._breakModel);
+    _current = _merge(_expressionEnd(condition).ifFalse, context._breakModel);
   }
 
   @override
@@ -2868,7 +2882,7 @@
   void for_conditionBegin(Node node) {
     AssignedVariablesNodeInfo<Variable> info =
         _assignedVariables._getInfoForNode(node);
-    _current = _current.conservativeJoin(info._written, info._captured);
+    _current = _current.conservativeJoin(info._written, info._captured).split();
   }
 
   @override
@@ -2879,7 +2893,7 @@
     FlowModel<Variable, Type> breakState = context._breakModel;
     FlowModel<Variable, Type> falseCondition = context._conditionInfo.ifFalse;
 
-    _current = _join(falseCondition, breakState)
+    _current = _merge(falseCondition, breakState)
         .inheritTested(typeOperations, _current);
   }
 
@@ -2894,7 +2908,7 @@
   void forEach_bodyBegin(Node node, Variable loopVariable, Type writtenType) {
     AssignedVariablesNodeInfo<Variable> info =
         _assignedVariables._getInfoForNode(node);
-    _current = _current.conservativeJoin(info._written, info._captured);
+    _current = _current.conservativeJoin(info._written, info._captured).split();
     _SimpleStatementContext<Variable, Type> context =
         new _SimpleStatementContext<Variable, Type>(
             _current.reachable.parent, _current);
@@ -2908,7 +2922,7 @@
   void forEach_end() {
     _SimpleStatementContext<Variable, Type> context =
         _stack.removeLast() as _SimpleStatementContext<Variable, Type>;
-    _current = _join(_current, context._previous);
+    _current = _merge(_current, context._previous);
   }
 
   @override
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 0af6a2f..979be2e 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -76,6 +76,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
+        flow.conditional_conditionBegin();
         flow.conditional_thenBegin(h.notNull(x, _Type('int?'))());
         expect(flow.promotedType(x).type, 'int');
         flow.conditional_elseBegin(_Expression());
@@ -90,6 +91,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
+        flow.conditional_conditionBegin();
         flow.conditional_thenBegin(h.eqNull(x, _Type('int?'))());
         expect(flow.promotedType(x), isNull);
         flow.conditional_elseBegin(_Expression());
@@ -109,6 +111,7 @@
         h.declare(x, initialized: true);
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
+        flow.conditional_conditionBegin();
         flow.conditional_thenBegin(_Expression());
         h.promote(x, 'int');
         h.promote(y, 'int');
@@ -4176,6 +4179,7 @@
       LazyExpression cond, LazyExpression ifTrue, LazyExpression ifFalse) {
     return () {
       var expr = _Expression();
+      _flow.conditional_conditionBegin();
       _flow.conditional_thenBegin(cond());
       _flow.conditional_elseBegin(ifTrue());
       _flow.conditional_end(expr, ifFalse());
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/conditional.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/conditional.dart
index 9b8e497..4f93355 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/conditional.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/conditional.dart
@@ -29,3 +29,19 @@
   x is int? ? /*int?*/ x : /*num*/ x;
   x;
 }
+
+void conditional_join_then(bool b, Object x) {
+  if (b ? x is int : x is int) {
+    /*int*/ x;
+  } else {
+    x;
+  }
+}
+
+void conditional_join_else(bool b, Object x) {
+  if (b ? x is! int : x is! int) {
+    x;
+  } else {
+    /*int*/ x;
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/promotion_in_dead_code.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/promotion_in_dead_code.dart
index 4a3c9a5..e8dfacd 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/promotion_in_dead_code.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/promotion_in_dead_code.dart
@@ -6,6 +6,69 @@
 // promotion continue to function properly even when used inside unreachable
 // code.
 
+conditionalIs(Object o) {
+  return;
+  o is int ? null : throw 'bad';
+  /*int*/ o;
+}
+
+conditionalIsNot(Object o) {
+  return;
+  o is! int ? throw 'bad' : null;
+  /*int*/ o;
+}
+
+conditionalJoinFalse(Object o, bool b) {
+  return;
+  if (b ? o is! int : o is! int) return;
+  /*int*/ o;
+}
+
+conditionalJoinTrue(Object o, bool b) {
+  return;
+  if (!(b ? o is int : o is int)) return;
+  /*int*/ o;
+}
+
+doBreak(Object o) {
+  return;
+  do {
+    if (o is int) break;
+  } while (true);
+  /*int*/ o;
+}
+
+doContinue(Object o) {
+  return;
+  do {
+    if (o is int) continue;
+    return;
+  } while (false);
+  /*int*/ o;
+}
+
+doCondition(Object o) {
+  return;
+  do {} while (o is! int);
+  /*int*/ o;
+}
+
+forBreak(Object o) {
+  return;
+  for (;;) {
+    if (o is int) break;
+  }
+  /*int*/ o;
+}
+
+forContinue(Object o) {
+  return;
+  for (;; /*int*/ o) {
+    if (o is int) continue;
+    return;
+  }
+}
+
 ifIsNot(Object o) {
   return;
   if (o is! int) return;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0d46f4a..46728e7 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1093,6 +1093,7 @@
   void visitConditionalExpression(ConditionalExpression node) {
     Expression condition = node.condition;
     var flow = _flowAnalysis?.flow;
+    flow?.conditional_conditionBegin();
 
     // TODO(scheglov) Do we need these checks for null?
     condition?.accept(this);
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 7288dd8..e380a35 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -378,6 +378,7 @@
   @override
   ExpressionInferenceResult visitConditionalExpression(
       ConditionalExpression node, DartType typeContext) {
+    inferrer.flowAnalysis.conditional_conditionBegin();
     InterfaceType expectedType =
         inferrer.coreTypes.boolRawType(inferrer.library.nonNullable);
     ExpressionInferenceResult conditionResult = inferrer.inferExpression(
@@ -401,7 +402,7 @@
     node.otherwise = otherwiseResult.expression..parent = node;
     inferrer.registerIfUnreachableForTesting(node.otherwise,
         isReachable: isOtherwiseReachable);
-    inferrer.flowAnalysis.conditional_end(node.condition, node.otherwise);
+    inferrer.flowAnalysis.conditional_end(node, node.otherwise);
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(thenResult.inferredType,
             otherwiseResult.inferredType, inferrer.library.library);
diff --git a/pkg/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
index be6237c..28a9847 100644
--- a/pkg/meta/pubspec.yaml
+++ b/pkg/meta/pubspec.yaml
@@ -1,5 +1,5 @@
 name: meta
-version: 1.3.0-nullsafety.3
+version: 1.3.0-nullsafety.4
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/meta
 description: >
  This library contains the declarations of annotations that developers can use
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 7d4a32e..3f22a7d 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -619,6 +619,7 @@
 
   @override
   DecoratedType visitConditionalExpression(ConditionalExpression node) {
+    _flowAnalysis.conditional_conditionBegin();
     _checkExpressionNotNull(node.condition);
     NullabilityNode trueGuard;
     NullabilityNode falseGuard;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2b1195d..25776cd 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -9361,6 +9361,13 @@
   return Symbols::New(thread, printer.buffer());
 }
 
+const char* Function::QualifiedUserVisibleNameCString() const {
+  Thread* thread = Thread::Current();
+  ZoneTextBuffer printer(thread->zone());
+  PrintName(NameFormattingParams(kUserVisibleName), &printer);
+  return printer.buffer();
+}
+
 void Function::PrintName(const NameFormattingParams& params,
                          BaseTextBuffer* printer) const {
   // If |this| is the generated asynchronous body closure, use the
@@ -24410,10 +24417,10 @@
                                     intptr_t frame_index) {
   ASSERT(!function.IsNull());
   const auto& script = Script::Handle(zone, function.script());
-  auto& handle = String::Handle(zone, function.QualifiedUserVisibleName());
-  auto const function_name = handle.ToCString();
-  handle = script.IsNull() ? String::New("Kernel") : script.url();
-  auto url = handle.ToCString();
+  const char* function_name = function.QualifiedUserVisibleNameCString();
+  const char* url = script.IsNull()
+                        ? "Kernel"
+                        : String::Handle(zone, script.url()).ToCString();
 
   // If the URI starts with "data:application/dart;" this is a URI encoded
   // script so we shouldn't print the entire URI because it could be very long.
@@ -24443,6 +24450,7 @@
   auto& code = Code::Handle(zone);
   auto& bytecode = Bytecode::Handle(zone);
 
+  NoSafepointScope no_allocation;
   GrowableArray<const Function*> inlined_functions;
   GrowableArray<TokenPosition> inlined_token_positions;
   ZoneTextBuffer buffer(zone, 1024);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 9a9702f..e9a388b 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2482,6 +2482,7 @@
                  BaseTextBuffer* printer) const;
   StringPtr QualifiedScrubbedName() const;
   StringPtr QualifiedUserVisibleName() const;
+  const char* QualifiedUserVisibleNameCString() const;
 
   virtual StringPtr DictionaryName() const { return name(); }
 
diff --git a/tools/VERSION b/tools/VERSION
index 7d7e434..245fc79 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 197
+PRERELEASE 198
 PRERELEASE_PATCH 0
\ No newline at end of file