Version 2.13.0-219.0.dev

Merge commit '3131d5a6c585882656b486a8641b6720690aeb44' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 530baf1..f05045e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -1354,6 +1354,28 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String nameOKEmpty)>
+    templateConstEvalGetterNotFound =
+    const Template<Message Function(String nameOKEmpty)>(
+        messageTemplate: r"""Variable get not found: '#nameOKEmpty'""",
+        withArguments: _withArgumentsConstEvalGetterNotFound);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String nameOKEmpty)> codeConstEvalGetterNotFound =
+    const Code<Message Function(String nameOKEmpty)>(
+  "ConstEvalGetterNotFound",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsConstEvalGetterNotFound(String nameOKEmpty) {
+  // ignore: unnecessary_null_comparison
+  if (nameOKEmpty == null || nameOKEmpty.isEmpty) nameOKEmpty = '(unnamed)';
+  return new Message(codeConstEvalGetterNotFound,
+      message: """Variable get not found: '${nameOKEmpty}'""",
+      arguments: {'nameOKEmpty': nameOKEmpty});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String nameOKEmpty)>
     templateConstEvalInvalidStaticInvocation =
     const Template<Message Function(String nameOKEmpty)>(
         messageTemplate:
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 42230fe..b5a1027 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -180,15 +180,13 @@
       return assists;
     }
 
-    var context = CorrectionProducerContext(
+    var context = CorrectionProducerContext.create(
       selectionOffset: selectionOffset,
       selectionLength: selectionLength,
       resolvedResult: resolvedResult,
       workspace: workspace,
     );
-
-    var setupSuccess = context.setupCompute();
-    if (!setupSuccess) {
+    if (context == null) {
       return assists;
     }
 
@@ -233,16 +231,14 @@
   }
 
   Future<void> _addFromProducers() async {
-    var context = CorrectionProducerContext(
+    var context = CorrectionProducerContext.create(
       selectionOffset: selectionOffset,
       selectionLength: selectionLength,
       resolvedResult: resolvedResult,
       workspace: workspace,
     );
-
-    var setupSuccess = context.setupCompute();
-    if (!setupSuccess) {
-      return;
+    if (context == null) {
+      return assists;
     }
 
     Future<void> compute(CorrectionProducer producer) async {
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
index 0750898..25b6c84 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/utilities/flutter.dart';
 import 'package:analyzer/dart/analysis/results.dart';
@@ -31,18 +29,18 @@
   final ResolvedUnitResult resolvedResult;
   final ChangeWorkspace workspace;
 
-  AstNode node;
+  AstNode? node;
 
   BaseProcessor({
     this.selectionOffset = -1,
     this.selectionLength = 0,
-    @required this.resolvedResult,
-    @required this.workspace,
-  })  : file = resolvedResult.path,
+    required this.resolvedResult,
+    required this.workspace,
+  })   : file = resolvedResult.path!,
         session = resolvedResult.session,
         sessionHelper = AnalysisSessionHelper(resolvedResult.session),
         typeProvider = resolvedResult.typeProvider,
-        selectionEnd = (selectionOffset ?? 0) + (selectionLength ?? 0),
+        selectionEnd = selectionOffset + selectionLength,
         utils = CorrectionUtils(resolvedResult);
 
   Flutter get flutter => Flutter.instance;
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 093355b..9b3dba2 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -263,7 +263,7 @@
         (name) => [],
       );
 
-      var context = CorrectionProducerContext(
+      var context = CorrectionProducerContext.create(
         applyingBulkFixes: true,
         dartFixContext: fixContext,
         diagnostic: diagnostic,
@@ -272,6 +272,9 @@
         selectionLength: diagnostic.length,
         workspace: workspace,
       );
+      if (context == null) {
+        return;
+      }
 
       for (final multiGenerator in multiGenerators) {
         final multiProducer = multiGenerator();
@@ -314,7 +317,7 @@
       ResolvedUnitResult result,
       AnalysisError diagnostic,
       TransformOverrideSet overrideSet) async {
-    var context = CorrectionProducerContext(
+    var context = CorrectionProducerContext.create(
       applyingBulkFixes: true,
       dartFixContext: fixContext,
       diagnostic: diagnostic,
@@ -324,9 +327,7 @@
       selectionLength: diagnostic.length,
       workspace: workspace,
     );
-
-    var setupSuccess = context.setupCompute();
-    if (!setupSuccess) {
+    if (context == null) {
       return;
     }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 6bef12b..425dc82 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'dart:math' as math;
 
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
@@ -31,7 +29,6 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
-import 'package:meta/meta.dart';
 
 /// An object that can compute a correction (fix or assist) in a Dart file.
 abstract class CorrectionProducer extends SingleCorrectionProducer {
@@ -56,28 +53,30 @@
   Future<void> compute(ChangeBuilder builder);
 
   /// Return the class, enum or mixin declaration for the given [element].
-  Future<ClassOrMixinDeclaration> getClassOrMixinDeclaration(
+  Future<ClassOrMixinDeclaration?> getClassOrMixinDeclaration(
       ClassElement element) async {
     var result = await sessionHelper.getElementDeclaration(element);
-    if (result.node is ClassOrMixinDeclaration) {
-      return result.node;
+    var node = result?.node;
+    if (node is ClassOrMixinDeclaration) {
+      return node;
     }
     return null;
   }
 
   /// Return the extension declaration for the given [element].
-  Future<ExtensionDeclaration> getExtensionDeclaration(
+  Future<ExtensionDeclaration?> getExtensionDeclaration(
       ExtensionElement element) async {
     var result = await sessionHelper.getElementDeclaration(element);
-    if (result.node is ExtensionDeclaration) {
-      return result.node;
+    var node = result?.node;
+    if (node is ExtensionDeclaration) {
+      return node;
     }
     return null;
   }
 
   /// Return the class element associated with the [target], or `null` if there
   /// is no such class element.
-  ClassElement getTargetClassElement(Expression target) {
+  ClassElement? getTargetClassElement(Expression target) {
     var type = target.staticType;
     if (type is InterfaceType) {
       return type.element;
@@ -92,7 +91,7 @@
 
   /// Returns an expected [DartType] of [expression], may be `null` if cannot be
   /// inferred.
-  DartType inferUndefinedExpressionType(Expression expression) {
+  DartType? inferUndefinedExpressionType(Expression expression) {
     var parent = expression.parent;
     // myFunction();
     if (parent is ExpressionStatement) {
@@ -120,9 +119,7 @@
       var assignment = parent;
       if (assignment.leftHandSide == expression) {
         var rhs = assignment.rightHandSide;
-        if (rhs != null) {
-          return rhs.staticType;
-        }
+        return rhs.staticType;
       }
     }
     // v = myFunction();
@@ -227,47 +224,72 @@
   final AnalysisSessionHelper sessionHelper;
   final ResolvedUnitResult resolvedResult;
   final ChangeWorkspace workspace;
-  final DartFixContext dartFixContext;
+
+  /// TODO(migration) Make it non-nullable, specialize "fix" context?
+  final DartFixContext? dartFixContext;
 
   /// A flag indicating whether the correction producers will be run in the
   /// context of applying bulk fixes.
   final bool applyingBulkFixes;
 
-  final Diagnostic diagnostic;
+  final Diagnostic? diagnostic;
 
-  final TransformOverrideSet overrideSet;
+  final TransformOverrideSet? overrideSet;
 
-  AstNode _node;
+  final AstNode node;
 
-  CorrectionProducerContext({
-    @required this.resolvedResult,
-    @required this.workspace,
+  CorrectionProducerContext._({
+    required this.resolvedResult,
+    required this.workspace,
     this.applyingBulkFixes = false,
     this.dartFixContext,
     this.diagnostic,
+    required this.node,
     this.overrideSet,
     this.selectionOffset = -1,
     this.selectionLength = 0,
-  })  : file = resolvedResult.path,
+  })  : file = resolvedResult.path!,
         session = resolvedResult.session,
         sessionHelper = AnalysisSessionHelper(resolvedResult.session),
         typeProvider = resolvedResult.typeProvider,
-        selectionEnd = (selectionOffset ?? 0) + (selectionLength ?? 0),
-        unit = resolvedResult.unit,
+        selectionEnd = selectionOffset + selectionLength,
+        unit = resolvedResult.unit!,
         utils = CorrectionUtils(resolvedResult);
 
-  AstNode get node => _node;
-
   /// Return `true` if the lint with the given [name] is enabled.
   bool isLintEnabled(String name) {
     var analysisOptions = session.analysisContext.analysisOptions;
     return analysisOptions.isLintEnabled(name);
   }
 
-  bool setupCompute() {
-    final locator = NodeLocator(selectionOffset, selectionEnd);
-    _node = locator.searchWithin(resolvedResult.unit);
-    return _node != null;
+  static CorrectionProducerContext? create({
+    required ResolvedUnitResult resolvedResult,
+    required ChangeWorkspace workspace,
+    bool applyingBulkFixes = false,
+    DartFixContext? dartFixContext,
+    Diagnostic? diagnostic,
+    TransformOverrideSet? overrideSet,
+    int selectionOffset = -1,
+    int selectionLength = 0,
+  }) {
+    var selectionEnd = selectionOffset + selectionLength;
+    var locator = NodeLocator(selectionOffset, selectionEnd);
+    var node = locator.searchWithin(resolvedResult.unit);
+    if (node == null) {
+      return null;
+    }
+
+    return CorrectionProducerContext._(
+      resolvedResult: resolvedResult,
+      workspace: workspace,
+      node: node,
+      applyingBulkFixes: applyingBulkFixes,
+      dartFixContext: dartFixContext,
+      diagnostic: diagnostic,
+      overrideSet: overrideSet,
+      selectionOffset: selectionOffset,
+      selectionLength: selectionLength,
+    );
   }
 }
 
@@ -283,53 +305,54 @@
   /// Return the arguments that should be used when composing the message for an
   /// assist, or `null` if the assist message has no parameters or if this
   /// producer doesn't support assists.
-  List<Object> get assistArguments => null;
+  List<Object>? get assistArguments => null;
 
   /// Return the assist kind that should be used to build an assist, or `null`
   /// if this producer doesn't support assists.
-  AssistKind get assistKind => null;
+  AssistKind? get assistKind => null;
 
   /// Return the length of the error message being fixed, or `null` if there is
   /// no diagnostic.
-  int get errorLength => diagnostic?.problemMessage?.length;
+  int? get errorLength => diagnostic?.problemMessage.length;
 
   /// Return the text of the error message being fixed, or `null` if there is
   /// no diagnostic.
-  String get errorMessage => diagnostic?.problemMessage?.message;
+  String? get errorMessage => diagnostic?.problemMessage.message;
 
   /// Return the offset of the error message being fixed, or `null` if there is
   /// no diagnostic.
-  int get errorOffset => diagnostic?.problemMessage?.offset;
+  int? get errorOffset => diagnostic?.problemMessage.offset;
 
   /// Return the arguments that should be used when composing the message for a
   /// fix, or `null` if the fix message has no parameters or if this producer
   /// doesn't support fixes.
-  List<Object> get fixArguments => null;
+  List<Object>? get fixArguments => null;
 
   /// Return the fix kind that should be used to build a fix, or `null` if this
   /// producer doesn't support fixes.
-  FixKind get fixKind => null;
+  FixKind? get fixKind => null;
 
   /// Return the arguments that should be used when composing the message for a
   /// multi-fix, or `null` if the fix message has no parameters or if this
   /// producer doesn't support multi-fixes.
-  List<Object> get multiFixArguments => null;
+  List<Object>? get multiFixArguments => null;
 
   /// Return the fix kind that should be used to build a multi-fix, or `null` if
   /// this producer doesn't support multi-fixes.
-  FixKind get multiFixKind => null;
+  FixKind? get multiFixKind => null;
 }
 
 /// The behavior shared by [CorrectionProducer] and [MultiCorrectionProducer].
 abstract class _AbstractCorrectionProducer {
   /// The context used to produce corrections.
-  CorrectionProducerContext _context;
+  /// TODO(migration) Make it not `late`, require in constructor.
+  late CorrectionProducerContext _context;
 
   /// The most deeply nested node that completely covers the highlight region of
   /// the diagnostic, or `null` if there is no diagnostic, such a node does not
   /// exist, or if it hasn't been computed yet. Use [coveredNode] to access this
   /// field.
-  AstNode _coveredNode;
+  AstNode? _coveredNode;
 
   /// Initialize a newly created producer.
   _AbstractCorrectionProducer();
@@ -340,7 +363,7 @@
   /// The most deeply nested node that completely covers the highlight region of
   /// the diagnostic, or `null` if there is no diagnostic or if such a node does
   /// not exist.
-  AstNode get coveredNode {
+  AstNode? get coveredNode {
     // TODO(brianwilkerson) Consider renaming this to `coveringNode`.
     if (_coveredNode == null) {
       var diagnostic = this.diagnostic;
@@ -358,7 +381,7 @@
 
   /// Return the diagnostic being fixed, or `null` if this producer is being
   /// used to produce an assist.
-  Diagnostic get diagnostic => _context.diagnostic;
+  Diagnostic? get diagnostic => _context.diagnostic;
 
   /// Returns the EOL to use for this [CompilationUnit].
   String get eol => utils.endOfLine;
@@ -375,7 +398,7 @@
 
   /// Return the set of overrides to be applied to the transform set when
   /// running tests, or `null` if there are no overrides to apply.
-  TransformOverrideSet get overrideSet => _context.overrideSet;
+  TransformOverrideSet? get overrideSet => _context.overrideSet;
 
   ResolvedUnitResult get resolvedResult => _context.resolvedResult;
 
@@ -413,7 +436,7 @@
 
   /// Return the function body of the most deeply nested method or function that
   /// encloses the [node], or `null` if the node is not in a method or function.
-  FunctionBody getEnclosingFunctionBody() {
+  FunctionBody? getEnclosingFunctionBody() {
     var closure = node.thisOrAncestorOfType<FunctionExpression>();
     if (closure != null) {
       return closure.body;
@@ -441,7 +464,7 @@
   /// Return the top-level declarations with the [name] in libraries that are
   /// available to this context.
   List<TopLevelDeclaration> getTopLevelDeclarations(String name) =>
-      _context.dartFixContext.getTopLevelDeclarations(name);
+      _context.dartFixContext!.getTopLevelDeclarations(name);
 
   /// Return `true` the lint with the given [name] is enabled.
   bool isLintEnabled(String name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
index 79c8f63..289a537 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_async.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -27,21 +25,22 @@
   Future<void> compute(ChangeBuilder builder) async {
     if (isForMissingReturn) {
       var parent = node.parent;
-      DartType returnType;
-      FunctionBody body;
+      FunctionBody? body;
+      DartType? returnType;
       if (parent is FunctionDeclaration) {
-        returnType = parent.declaredElement.returnType;
         body = parent.functionExpression.body;
+        returnType = parent.declaredElement!.returnType;
       } else if (parent is MethodDeclaration) {
-        returnType = parent.declaredElement.returnType;
         body = parent.body;
+        returnType = parent.declaredElement!.returnType;
       }
-      if (body == null) {
+      if (body == null || returnType == null) {
         return;
       }
       if (_isFutureVoid(returnType) && _hasNoReturns(body)) {
+        var final_body = body;
         await builder.addDartFileEdit(file, (builder) {
-          builder.addSimpleInsertion(body.offset, 'async ');
+          builder.addSimpleInsertion(final_body.offset, 'async ');
         });
       }
     } else {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_future.dart b/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_future.dart
index 794bb72..c1892ff 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_future.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_future.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -20,21 +18,26 @@
     //
     // Extract the information needed to build the edit.
     //
-    Expression expression;
+    Expression? expression;
+    var node = this.node;
     if (node is ReturnStatement) {
-      expression = (node as ReturnStatement).expression;
+      expression = node.expression;
     } else if (node is Expression) {
       expression = node;
-    } else {
+    }
+    if (expression == null) {
       return;
     }
     var value = utils.getNodeText(expression);
     //
     // Build the edit.
     //
+    var final_expression = expression;
     await builder.addDartFileEdit(file, (builder) {
       builder.addSimpleReplacement(
-          range.node(expression), 'Future.value($value)');
+        range.node(final_expression),
+        'Future.value($value)',
+      );
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index dfc9b79..e8795a1f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -210,16 +210,19 @@
     var workspace = context.workspace;
     var resolveResult = context.resolveResult;
 
-    var generators = _getGenerators(
-        error.errorCode,
-        CorrectionProducerContext(
-          dartFixContext: context,
-          diagnostic: error,
-          resolvedResult: resolveResult,
-          selectionOffset: context.error.offset,
-          selectionLength: context.error.length,
-          workspace: workspace,
-        ));
+    var correctionContext = CorrectionProducerContext.create(
+      dartFixContext: context,
+      diagnostic: error,
+      resolvedResult: resolveResult,
+      selectionOffset: context.error.offset,
+      selectionLength: context.error.length,
+      workspace: workspace,
+    );
+    if (correctionContext == null) {
+      return const <Fix>[];
+    }
+
+    var generators = _getGenerators(error.errorCode, correctionContext);
 
     var fixes = <Fix>[];
     for (var generator in generators) {
@@ -248,7 +251,7 @@
 
   Future<void> _fixError(DartFixContext fixContext, FixState fixState,
       CorrectionProducer producer, AnalysisError diagnostic) async {
-    var context = CorrectionProducerContext(
+    var context = CorrectionProducerContext.create(
       applyingBulkFixes: true,
       dartFixContext: fixContext,
       diagnostic: diagnostic,
@@ -257,9 +260,7 @@
       selectionLength: diagnostic.length,
       workspace: fixContext.workspace,
     );
-
-    var setupSuccess = context.setupCompute();
-    if (!setupSuccess) {
+    if (context == null) {
       return;
     }
 
@@ -1745,7 +1746,7 @@
 
   Future<void> _addFromProducers() async {
     var error = fixContext.error;
-    var context = CorrectionProducerContext(
+    var context = CorrectionProducerContext.create(
       dartFixContext: fixContext,
       diagnostic: error,
       resolvedResult: resolvedResult,
@@ -1753,9 +1754,7 @@
       selectionLength: fixContext.error.length,
       workspace: workspace,
     );
-
-    var setupSuccess = context.setupCompute();
-    if (!setupSuccess) {
+    if (context == null) {
       return;
     }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 97f21f3..1a2a02f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -59,6 +59,7 @@
         templateConstEvalElementImplementsEqual,
         templateConstEvalFailedAssertionWithMessage,
         templateConstEvalFreeTypeParameter,
+        templateConstEvalGetterNotFound,
         templateConstEvalInvalidType,
         templateConstEvalInvalidBinaryOperandType,
         templateConstEvalInvalidEqualsOperandType,
@@ -559,7 +560,7 @@
         node.function = transform(node.function)..parent = node;
       }
       constantEvaluator.env.addVariableValue(
-          node.variable, new IntermediateValue(node.function));
+          node.variable, new FunctionValue(node.function, null));
     } else {
       return super.visitFunctionDeclaration(node, removalSentinel);
     }
@@ -1394,6 +1395,9 @@
 
   @override
   Constant visitFunctionExpression(FunctionExpression node) {
+    if (enableConstFunctions) {
+      return new FunctionValue(node.function, env);
+    }
     return createInvalidExpressionConstant(node, "Function literal");
   }
 
@@ -2165,6 +2169,9 @@
           node, "method invocation with named arguments");
     }
 
+    final Constant receiver = _evaluateSubexpression(node.receiver);
+    if (receiver is AbortConstant) return receiver;
+
     final List<Constant> arguments =
         _evaluatePositionalArguments(node.arguments);
 
@@ -2176,12 +2183,7 @@
     assert(_gotError == null);
     assert(arguments != null);
 
-    final Constant receiver = _evaluateSubexpression(node.receiver);
-    if (receiver is AbortConstant) {
-      return receiver;
-    } else if (enableConstFunctions &&
-        receiver is IntermediateValue &&
-        receiver.value is FunctionNode) {
+    if (enableConstFunctions && receiver is FunctionValue) {
       // Evaluate type arguments of the method invoked.
       List<DartType> types = _evaluateTypeArguments(node, node.arguments);
       if (types == null && _gotError != null) {
@@ -2203,7 +2205,9 @@
       assert(_gotError == null);
       assert(named != null);
 
-      return _handleFunctionInvocation(receiver.value, types, arguments, named);
+      return _handleFunctionInvocation(
+          receiver.function, types, arguments, named,
+          functionEnvironment: receiver.environment);
     }
 
     if (shouldBeUnevaluated) {
@@ -2465,8 +2469,8 @@
     final VariableDeclaration variable = node.variable;
     if (enableConstFunctions) {
       return env.lookupVariable(variable) ??
-          createInvalidExpressionConstant(
-              node, 'Variable get of an unknown value.');
+          createErrorConstant(node,
+              templateConstEvalGetterNotFound.withArguments(variable.name));
     } else {
       if (variable.parent is Let || _isFormalParameter(variable)) {
         return env.lookupVariable(node.variable) ??
@@ -2815,8 +2819,9 @@
       FunctionNode function,
       List<DartType> typeArguments,
       List<Constant> positionalArguments,
-      Map<String, Constant> namedArguments) {
-    return withNewEnvironment(() {
+      Map<String, Constant> namedArguments,
+      {EvaluationEnvironment functionEnvironment}) {
+    Constant executeFunction() {
       // Map arguments from caller to callee.
       for (int i = 0; i < function.typeParameters.length; i++) {
         env.addTypeParameterValue(function.typeParameters[i], typeArguments[i]);
@@ -2838,7 +2843,12 @@
         env.addVariableValue(parameter, value);
       }
       return execute(function.body);
-    });
+    }
+
+    if (functionEnvironment != null) {
+      return withEnvironment(functionEnvironment, executeFunction);
+    }
+    return withNewEnvironment(executeFunction);
   }
 
   @override
@@ -3264,6 +3274,14 @@
     return result;
   }
 
+  T withEnvironment<T>(EvaluationEnvironment newEnv, T fn()) {
+    final EvaluationEnvironment oldEnv = env;
+    env = newEnv;
+    T result = fn();
+    env = oldEnv;
+    return result;
+  }
+
   /// Binary operation between two operands, at least one of which is a double.
   Constant evaluateBinaryNumericOperation(
       String op, num a, num b, TreeNode node) {
@@ -3424,6 +3442,17 @@
   }
 
   @override
+  ExecutionStatus visitFunctionDeclaration(FunctionDeclaration node) {
+    final EvaluationEnvironment newEnv =
+        new EvaluationEnvironment.withParent(exprEvaluator.env);
+    newEnv.addVariableValue(
+        node.variable, new FunctionValue(node.function, null));
+    final FunctionValue function = new FunctionValue(node.function, newEnv);
+    exprEvaluator.env.addVariableValue(node.variable, function);
+    return const ProceedStatus();
+  }
+
+  @override
   ExecutionStatus visitIfStatement(IfStatement node) {
     Constant condition = evaluate(node.condition);
     if (condition is AbortConstant) return new AbortStatus(condition);
@@ -3740,11 +3769,13 @@
   BreakStatus(this.target);
 }
 
-/// An intermediate result that is used within the [ConstantEvaluator].
-class IntermediateValue implements Constant {
-  dynamic value;
+/// An intermediate result that is used for invoking function nodes with their
+/// respective environment within the [ConstantEvaluator].
+class FunctionValue implements Constant {
+  final FunctionNode function;
+  final EvaluationEnvironment environment;
 
-  IntermediateValue(this.value);
+  FunctionValue(this.function, this.environment);
 
   @override
   R accept<R>(ConstantVisitor<R> v) {
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index a8965ac..35e9097 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -106,6 +106,8 @@
 ConstEvalFailedAssertionWithMessage/example: Fail
 ConstEvalFreeTypeParameter/analyzerCode: Fail
 ConstEvalFreeTypeParameter/example: Fail
+ConstEvalGetterNotFound/analyzerCode: Fail
+ConstEvalGetterNotFound/example: Fail
 ConstEvalInvalidBinaryOperandType/analyzerCode: Fail # CONST_EVAL_TYPE_NUM / CONST_EVAL_TYPE_BOOL
 ConstEvalInvalidBinaryOperandType/example: Fail
 ConstEvalInvalidEqualsOperandType/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 0226a47..540ad5d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -150,6 +150,9 @@
 ConstEvalNonNull:
   template: "Constant expression must be non-null."
 
+ConstEvalGetterNotFound:
+  template: "Variable get not found: '#nameOKEmpty'"
+
 ConstEvalInvalidMethodInvocation:
   template: "The method '#stringOKEmpty' can't be invoked on '#constant' in a constant expression."
   analyzerCode: UNDEFINED_OPERATOR
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart
index de66c5b..6be9676 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart
@@ -13,6 +13,17 @@
   return x;
 }
 
+const var2 = fn2();
+int fn2() {
+  int x = 0;
+  assert(() {
+    var y = x + 1;
+    return y == 1;
+  }());
+  return x;
+}
+
 void main() {
   Expect.equals(var1, 0);
+  Expect.equals(var2, 0);
 }
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.expect
index 8fa0afb..6f5f7b1 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.expect
@@ -6,13 +6,23 @@
 import "package:expect/expect.dart";
 
 static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
 static method fn() → core::int {
   core::int x = 0;
   assert(x.{core::num::==}(0), "fail");
   return x;
 }
+static method fn2() → core::int {
+  core::int x = 0;
+  assert((() → core::bool {
+    core::int y = x.{core::num::+}(1);
+    return y.{core::num::==}(1);
+  }).call());
+  return x;
+}
 static method main() → void {
   exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.transformed.expect
index 8fa0afb..6f5f7b1 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.strong.transformed.expect
@@ -6,13 +6,23 @@
 import "package:expect/expect.dart";
 
 static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
 static method fn() → core::int {
   core::int x = 0;
   assert(x.{core::num::==}(0), "fail");
   return x;
 }
+static method fn2() → core::int {
+  core::int x = 0;
+  assert((() → core::bool {
+    core::int y = x.{core::num::+}(1);
+    return y.{core::num::==}(1);
+  }).call());
+  return x;
+}
 static method main() → void {
   exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline.expect
index 574b595..62e4cad 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline.expect
@@ -2,4 +2,6 @@
 
 const var1 = fn();
 int fn() {}
+const var2 = fn2();
+int fn2() {}
 void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline_modelled.expect
index 574b595..6f46f7e 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.textual_outline_modelled.expect
@@ -1,5 +1,7 @@
 import "package:expect/expect.dart";
 
 const var1 = fn();
+const var2 = fn2();
 int fn() {}
+int fn2() {}
 void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.expect
index 8fa0afb..6f5f7b1 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.expect
@@ -6,13 +6,23 @@
 import "package:expect/expect.dart";
 
 static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
 static method fn() → core::int {
   core::int x = 0;
   assert(x.{core::num::==}(0), "fail");
   return x;
 }
+static method fn2() → core::int {
+  core::int x = 0;
+  assert((() → core::bool {
+    core::int y = x.{core::num::+}(1);
+    return y.{core::num::==}(1);
+  }).call());
+  return x;
+}
 static method main() → void {
   exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.outline.expect
index 786a90f..92461e9 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.outline.expect
@@ -5,7 +5,10 @@
 import "package:expect/expect.dart";
 
 static const field core::int var1 = self::fn();
+static const field core::int var2 = self::fn2();
 static method fn() → core::int
   ;
+static method fn2() → core::int
+  ;
 static method main() → void
   ;
diff --git a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.transformed.expect
index 8fa0afb..6f5f7b1 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_assert_statements.dart.weak.transformed.expect
@@ -6,13 +6,23 @@
 import "package:expect/expect.dart";
 
 static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
 static method fn() → core::int {
   core::int x = 0;
   assert(x.{core::num::==}(0), "fail");
   return x;
 }
+static method fn2() → core::int {
+  core::int x = 0;
+  assert((() → core::bool {
+    core::int y = x.{core::num::+}(1);
+    return y.{core::num::==}(1);
+  }).call());
+  return x;
+}
 static method main() → void {
   exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
 }
 
 constants  {
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart b/pkg/front_end/testcases/const_functions/const_functions_closures.dart
new file mode 100644
index 0000000..70ffa7c
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+// Tests closures with const functions.
+
+import "package:expect/expect.dart";
+
+const var1 = foo();
+int foo() {
+  var f = () {
+    int count = 0;
+    int baz() {
+      ++count;
+      return count;
+    }
+
+    return baz;
+  };
+  var c1 = f();
+  var c2 = f();
+
+  var c1_val1 = c1();
+  assert(c1_val1 == 1);
+  var c1_val2 = c1();
+  assert(c1_val2 == 2);
+  var c1_val3 = c1();
+  assert(c1_val3 == 3);
+
+  var c2_val1 = c2();
+  assert(c1_val1 == 1);
+  var c2_val2 = c2();
+  assert(c1_val2 == 2);
+  var c2_val3 = c2();
+  assert(c1_val3 == 3);
+
+  return 0;
+}
+
+const var2 = fn();
+int fn() {
+  return (() => 0)();
+}
+
+const y = 1;
+const var3 = fn3();
+int fn3() {
+  int y = 2;
+  return y;
+}
+
+const var4 = fn4();
+int fn4() {
+  var x = 0;
+  int innerFn() {
+    return x;
+  }
+
+  return innerFn();
+}
+
+const var5 = fn5(3);
+int fn5(int a) {
+  int recurse(int b) {
+    if (b == 1) return 1;
+    int result = recurse(b - 1);
+    return b * result;
+  }
+
+  return recurse(a);
+}
+
+const var6 = fn6(4);
+int fn6(int a) {
+  int recurse() {
+    a--;
+    if (a == 1) return 1;
+    return a * recurse();
+  }
+
+  return recurse();
+}
+
+void main() {
+  Expect.equals(var1, 0);
+  Expect.equals(var2, 0);
+  Expect.equals(var3, 2);
+  Expect.equals(var4, 0);
+  Expect.equals(var5, 6);
+  Expect.equals(var6, 6);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.expect
new file mode 100644
index 0000000..64a08b6
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
+static const field core::int y = #C2;
+static const field core::int var3 = #C3;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C4;
+static const field core::int var6 = #C4;
+static method foo() → core::int {
+  () → () → core::int f = () → () → core::int {
+    core::int count = 0;
+    function baz() → core::int {
+      count = count.{core::num::+}(1);
+      return count;
+    }
+    return baz;
+  };
+  () → core::int c1 = f.call();
+  () → core::int c2 = f.call();
+  core::int c1_val1 = c1.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c1_val2 = c1.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c1_val3 = c1.call();
+  assert(c1_val3.{core::num::==}(3));
+  core::int c2_val1 = c2.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c2_val2 = c2.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c2_val3 = c2.call();
+  assert(c1_val3.{core::num::==}(3));
+  return 0;
+}
+static method fn() → core::int {
+  return (() → core::int => 0).call();
+}
+static method fn3() → core::int {
+  core::int y = 2;
+  return y;
+}
+static method fn4() → core::int {
+  core::int x = 0;
+  function innerFn() → core::int {
+    return x;
+  }
+  return innerFn.call();
+}
+static method fn5(core::int a) → core::int {
+  function recurse(core::int b) → core::int {
+    if(b.{core::num::==}(1))
+      return 1;
+    core::int result = recurse.call(b.{core::num::-}(1));
+    return b.{core::num::*}(result);
+  }
+  return recurse.call(a);
+}
+static method fn6(core::int a) → core::int {
+  function recurse() → core::int {
+    a = a.{core::num::-}(1);
+    if(a.{core::num::==}(1))
+      return 1;
+    return a.{core::num::*}(recurse.call());
+  }
+  return recurse.call();
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C3, 2);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C4, 6);
+  exp::Expect::equals(#C4, 6);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = 1
+  #C3 = 2
+  #C4 = 6
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.transformed.expect
new file mode 100644
index 0000000..64a08b6
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.strong.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
+static const field core::int y = #C2;
+static const field core::int var3 = #C3;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C4;
+static const field core::int var6 = #C4;
+static method foo() → core::int {
+  () → () → core::int f = () → () → core::int {
+    core::int count = 0;
+    function baz() → core::int {
+      count = count.{core::num::+}(1);
+      return count;
+    }
+    return baz;
+  };
+  () → core::int c1 = f.call();
+  () → core::int c2 = f.call();
+  core::int c1_val1 = c1.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c1_val2 = c1.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c1_val3 = c1.call();
+  assert(c1_val3.{core::num::==}(3));
+  core::int c2_val1 = c2.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c2_val2 = c2.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c2_val3 = c2.call();
+  assert(c1_val3.{core::num::==}(3));
+  return 0;
+}
+static method fn() → core::int {
+  return (() → core::int => 0).call();
+}
+static method fn3() → core::int {
+  core::int y = 2;
+  return y;
+}
+static method fn4() → core::int {
+  core::int x = 0;
+  function innerFn() → core::int {
+    return x;
+  }
+  return innerFn.call();
+}
+static method fn5(core::int a) → core::int {
+  function recurse(core::int b) → core::int {
+    if(b.{core::num::==}(1))
+      return 1;
+    core::int result = recurse.call(b.{core::num::-}(1));
+    return b.{core::num::*}(result);
+  }
+  return recurse.call(a);
+}
+static method fn6(core::int a) → core::int {
+  function recurse() → core::int {
+    a = a.{core::num::-}(1);
+    if(a.{core::num::==}(1))
+      return 1;
+    return a.{core::num::*}(recurse.call());
+  }
+  return recurse.call();
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C3, 2);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C4, 6);
+  exp::Expect::equals(#C4, 6);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = 1
+  #C3 = 2
+  #C4 = 6
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline.expect
new file mode 100644
index 0000000..03a1b47
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline.expect
@@ -0,0 +1,16 @@
+import "package:expect/expect.dart";
+
+const var1 = foo();
+int foo() {}
+const var2 = fn();
+int fn() {}
+const y = 1;
+const var3 = fn3();
+int fn3() {}
+const var4 = fn4();
+int fn4() {}
+const var5 = fn5(3);
+int fn5(int a) {}
+const var6 = fn6(4);
+int fn6(int a) {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..1833158
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.textual_outline_modelled.expect
@@ -0,0 +1,16 @@
+import "package:expect/expect.dart";
+
+const var1 = foo();
+const var2 = fn();
+const var3 = fn3();
+const var4 = fn4();
+const var5 = fn5(3);
+const var6 = fn6(4);
+const y = 1;
+int fn() {}
+int fn3() {}
+int fn4() {}
+int fn5(int a) {}
+int fn6(int a) {}
+int foo() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.expect
new file mode 100644
index 0000000..64a08b6
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
+static const field core::int y = #C2;
+static const field core::int var3 = #C3;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C4;
+static const field core::int var6 = #C4;
+static method foo() → core::int {
+  () → () → core::int f = () → () → core::int {
+    core::int count = 0;
+    function baz() → core::int {
+      count = count.{core::num::+}(1);
+      return count;
+    }
+    return baz;
+  };
+  () → core::int c1 = f.call();
+  () → core::int c2 = f.call();
+  core::int c1_val1 = c1.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c1_val2 = c1.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c1_val3 = c1.call();
+  assert(c1_val3.{core::num::==}(3));
+  core::int c2_val1 = c2.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c2_val2 = c2.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c2_val3 = c2.call();
+  assert(c1_val3.{core::num::==}(3));
+  return 0;
+}
+static method fn() → core::int {
+  return (() → core::int => 0).call();
+}
+static method fn3() → core::int {
+  core::int y = 2;
+  return y;
+}
+static method fn4() → core::int {
+  core::int x = 0;
+  function innerFn() → core::int {
+    return x;
+  }
+  return innerFn.call();
+}
+static method fn5(core::int a) → core::int {
+  function recurse(core::int b) → core::int {
+    if(b.{core::num::==}(1))
+      return 1;
+    core::int result = recurse.call(b.{core::num::-}(1));
+    return b.{core::num::*}(result);
+  }
+  return recurse.call(a);
+}
+static method fn6(core::int a) → core::int {
+  function recurse() → core::int {
+    a = a.{core::num::-}(1);
+    if(a.{core::num::==}(1))
+      return 1;
+    return a.{core::num::*}(recurse.call());
+  }
+  return recurse.call();
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C3, 2);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C4, 6);
+  exp::Expect::equals(#C4, 6);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = 1
+  #C3 = 2
+  #C4 = 6
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.outline.expect
new file mode 100644
index 0000000..6be7921
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.outline.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = self::foo();
+static const field core::int var2 = self::fn();
+static const field core::int y = 1;
+static const field core::int var3 = self::fn3();
+static const field core::int var4 = self::fn4();
+static const field core::int var5 = self::fn5(3);
+static const field core::int var6 = self::fn6(4);
+static method foo() → core::int
+  ;
+static method fn() → core::int
+  ;
+static method fn3() → core::int
+  ;
+static method fn4() → core::int
+  ;
+static method fn5(core::int a) → core::int
+  ;
+static method fn6(core::int a) → core::int
+  ;
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.transformed.expect
new file mode 100644
index 0000000..64a08b6
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_closures.dart.weak.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = #C1;
+static const field core::int var2 = #C1;
+static const field core::int y = #C2;
+static const field core::int var3 = #C3;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C4;
+static const field core::int var6 = #C4;
+static method foo() → core::int {
+  () → () → core::int f = () → () → core::int {
+    core::int count = 0;
+    function baz() → core::int {
+      count = count.{core::num::+}(1);
+      return count;
+    }
+    return baz;
+  };
+  () → core::int c1 = f.call();
+  () → core::int c2 = f.call();
+  core::int c1_val1 = c1.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c1_val2 = c1.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c1_val3 = c1.call();
+  assert(c1_val3.{core::num::==}(3));
+  core::int c2_val1 = c2.call();
+  assert(c1_val1.{core::num::==}(1));
+  core::int c2_val2 = c2.call();
+  assert(c1_val2.{core::num::==}(2));
+  core::int c2_val3 = c2.call();
+  assert(c1_val3.{core::num::==}(3));
+  return 0;
+}
+static method fn() → core::int {
+  return (() → core::int => 0).call();
+}
+static method fn3() → core::int {
+  core::int y = 2;
+  return y;
+}
+static method fn4() → core::int {
+  core::int x = 0;
+  function innerFn() → core::int {
+    return x;
+  }
+  return innerFn.call();
+}
+static method fn5(core::int a) → core::int {
+  function recurse(core::int b) → core::int {
+    if(b.{core::num::==}(1))
+      return 1;
+    core::int result = recurse.call(b.{core::num::-}(1));
+    return b.{core::num::*}(result);
+  }
+  return recurse.call(a);
+}
+static method fn6(core::int a) → core::int {
+  function recurse() → core::int {
+    a = a.{core::num::-}(1);
+    if(a.{core::num::==}(1))
+      return 1;
+    return a.{core::num::*}(recurse.call());
+  }
+  return recurse.call();
+}
+static method main() → void {
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C3, 2);
+  exp::Expect::equals(#C1, 0);
+  exp::Expect::equals(#C4, 6);
+  exp::Expect::equals(#C4, 6);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = 1
+  #C3 = 2
+  #C4 = 6
+}
diff --git a/tests/language/const_functions/const_functions_assert_statements_test.dart b/tests/language/const_functions/const_functions_assert_statements_test.dart
index 1fe02bb..86c0fe7 100644
--- a/tests/language/const_functions/const_functions_assert_statements_test.dart
+++ b/tests/language/const_functions/const_functions_assert_statements_test.dart
@@ -17,6 +17,19 @@
   return x;
 }
 
+const var2 = fn2();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn2() {
+  int x = 0;
+  assert(() {
+    var y = x + 1;
+    return y == 1;
+  }());
+  return x;
+}
+
 void main() {
   Expect.equals(var1, 0);
+  Expect.equals(var2, 0);
 }
diff --git a/tests/language/const_functions/const_functions_closures_error_test.dart b/tests/language/const_functions/const_functions_closures_error_test.dart
new file mode 100644
index 0000000..1383983
--- /dev/null
+++ b/tests/language/const_functions/const_functions_closures_error_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+// Tests erroneous closure situations with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+var varVariable = 1;
+const var1 = fn();
+//           ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn() {
+  return varVariable;
+}
+
+final finalVariable = 1;
+const var2 = fn2();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn2() {
+  return finalVariable;
+}
+
+const var3 = fn3();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn3() {
+  int innerFn() {
+    return x;
+    //     ^
+    // [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
+  }
+
+  const x = 0;
+  //    ^
+  // [cfe] Can't declare 'x' because it was already used in this scope.
+  return innerFn();
+}
+
+const var4 = fn4();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn4() {
+  var a = () {
+    return x;
+    //     ^
+    // [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
+  };
+  var x = 1;
+  //  ^
+  // [cfe] Can't declare 'x' because it was already used in this scope.
+  return a();
+}
+
+const var5 = fn5(1);
+//           ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+fn5(a) {
+  var a = () => a;
+  //  ^
+  // [cfe] Can't declare 'a' because it was already used in this scope.
+  //            ^
+  // [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
+  return a();
+}
+
+const x = 0;
+void fn6() {
+  var x = 1;
+  int a() => x;
+  const z = a();
+  //        ^^^
+  // [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+  //         ^
+  // [cfe] Constant evaluation error:
+}
diff --git a/tests/language/const_functions/const_functions_closures_test.dart b/tests/language/const_functions/const_functions_closures_test.dart
new file mode 100644
index 0000000..9cb6dcc
--- /dev/null
+++ b/tests/language/const_functions/const_functions_closures_test.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+// Tests closures with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = foo();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int foo() {
+  var f = () {
+    int count = 0;
+    int baz() {
+      ++count;
+      return count;
+    }
+
+    return baz;
+  };
+  var c1 = f();
+  var c2 = f();
+
+  var c1_val1 = c1();
+  assert(c1_val1 == 1);
+  var c1_val2 = c1();
+  assert(c1_val2 == 2);
+  var c1_val3 = c1();
+  assert(c1_val3 == 3);
+
+  var c2_val1 = c2();
+  assert(c1_val1 == 1);
+  var c2_val2 = c2();
+  assert(c1_val2 == 2);
+  var c2_val3 = c2();
+  assert(c1_val3 == 3);
+
+  return 0;
+}
+
+const var2 = fn();
+//           ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() {
+  return (() => 0)();
+}
+
+const y = 1;
+const var3 = fn3();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn3() {
+  int y = 2;
+  return y;
+}
+
+const var4 = fn4();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn4() {
+  var x = 0;
+  int innerFn() {
+    return x;
+  }
+
+  return innerFn();
+}
+
+const var5 = fn5(3);
+//           ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn5(int a) {
+  int recurse(int b) {
+    if (b == 1) return 1;
+    int result = recurse(b - 1);
+    return b * result;
+  }
+
+  return recurse(a);
+}
+
+const var6 = fn6(4);
+//           ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn6(int a) {
+  int recurse() {
+    a--;
+    if (a == 1) return 1;
+    return a * recurse();
+  }
+
+  return recurse();
+}
+
+void main() {
+  Expect.equals(var1, 0);
+  Expect.equals(var2, 0);
+  Expect.equals(var3, 2);
+  Expect.equals(var4, 0);
+  Expect.equals(var5, 6);
+  Expect.equals(var6, 6);
+}
diff --git a/tools/VERSION b/tools/VERSION
index ceb1a23..6a92dc7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 218
+PRERELEASE 219
 PRERELEASE_PATCH 0
\ No newline at end of file