Add support for required named parameters

Change-Id: Iebfd8da18c6f2158ed39043ab116e2670a7329c8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99717
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index aaecbef..85b9e43 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -239,7 +239,7 @@
 // Sort @required named parameters before optional ones.
 int _preferRequiredParams(
     engine.ParameterElement e1, engine.ParameterElement e2) {
-  int rank1 = e1.hasRequired ? 0 : !e1.isNamed ? -1 : 1;
-  int rank2 = e2.hasRequired ? 0 : !e2.isNamed ? -1 : 1;
+  int rank1 = (e1.isRequiredNamed || e1.hasRequired) ? 0 : !e1.isNamed ? -1 : 1;
+  int rank2 = (e2.isRequiredNamed || e2.hasRequired) ? 0 : !e2.isNamed ? -1 : 1;
   return rank1 - rank2;
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 3558966..40af649 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -224,7 +224,7 @@
       return;
     }
     Iterable<ParameterElement> requiredParam =
-        parameters.where((ParameterElement p) => p.isNotOptional);
+        parameters.where((ParameterElement p) => p.isRequiredPositional);
     int requiredCount = requiredParam.length;
     // TODO (jwren) _isAppendingToArgList can be split into two cases (with and
     // without preceded), then _isAppendingToArgList,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index e4d6e0f..0588482 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -514,7 +514,7 @@
     }).toList();
 
     Iterable<ParameterElement> requiredParameters = paramList
-        .where((FormalParameter param) => param.isRequired)
+        .where((FormalParameter param) => param.isRequiredPositional)
         .map((p) => p.declaredElement);
     suggestion.requiredParameterCount = requiredParameters.length;
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index abce4e7..0300ad1 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -63,7 +63,7 @@
     }).toList();
 
     Iterable<ParameterElement> requiredParameters = element.parameters
-        .where((ParameterElement param) => param.isNotOptional);
+        .where((ParameterElement param) => param.isRequiredPositional);
     suggestion.requiredParameterCount = requiredParameters.length;
 
     Iterable<ParameterElement> namedParameters =
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 9a58459..8fee019 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -1009,7 +1009,7 @@
         if (expression is FunctionExpression) {
           NodeList<FormalParameter> parameters =
               expression.parameters.parameters;
-          if (parameters.length == 1 && parameters[0].isRequired) {
+          if (parameters.length == 1 && parameters[0].isRequiredPositional) {
             if (extractBody(expression) != null) {
               return expression;
             }
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 e605378..e2b0c41 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1747,7 +1747,7 @@
       // prepare parameters and arguments
       Iterable<ParameterElement> requiredParameters = superConstructor
           .parameters
-          .where((parameter) => parameter.isNotOptional);
+          .where((parameter) => parameter.isRequiredPositional);
       // add proposal
       ClassMemberLocation targetLocation =
           utils.prepareNewConstructorLocation(targetClassNode);
@@ -3908,7 +3908,7 @@
     // Prepare the last required parameter.
     FormalParameter lastRequiredParameter;
     for (FormalParameter parameter in parameters) {
-      if (parameter.isRequired) {
+      if (parameter.isRequiredPositional) {
         lastRequiredParameter = parameter;
       }
     }
@@ -4692,7 +4692,7 @@
 
   _ExecutableParameters._(this.sessionHelper, this.executable) {
     for (var parameter in executable.parameters) {
-      if (parameter.isNotOptional) {
+      if (parameter.isRequiredPositional) {
         required.add(parameter);
       } else if (parameter.isOptionalPositional) {
         optionalPositional.add(parameter);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index c552695..fa26c42 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -74,7 +74,7 @@
       argumentSource = utils.getNodeText(argument);
     } else {
       // report about a missing required parameter
-      if (parameter.isNotOptional) {
+      if (parameter.isRequiredPositional) {
         status.addError('No argument for the parameter "${parameter.name}".',
             newLocation_fromNode(contextNode));
         return;
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart
index 060cf6f..0d1562d 100644
--- a/pkg/analysis_server/lib/src/status/ast_writer.dart
+++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -71,12 +71,16 @@
       properties['static keyword'] = node.staticKeyword;
     } else if (node is FormalParameter) {
       properties['declaredElement'] = node.declaredElement;
-      if (node.isNamed) {
-        properties['kind'] = 'named';
+      if (node.isRequiredPositional) {
+        properties['kind'] = 'required-positional';
+      } else if (node.isRequiredNamed) {
+        properties['kind'] = 'required-named';
       } else if (node.isOptionalPositional) {
-        properties['kind'] = 'positional';
+        properties['kind'] = 'optional-positional';
+      } else if (node.isOptionalNamed) {
+        properties['kind'] = 'optional-named';
       } else {
-        properties['kind'] = 'required';
+        properties['kind'] = 'unknown kind';
       }
     } else if (node is FunctionDeclaration) {
       properties['declaredElement'] = node.declaredElement;
diff --git a/pkg/analysis_server/lib/src/status/element_writer.dart b/pkg/analysis_server/lib/src/status/element_writer.dart
index 4e8d3ec..a4a20c9 100644
--- a/pkg/analysis_server/lib/src/status/element_writer.dart
+++ b/pkg/analysis_server/lib/src/status/element_writer.dart
@@ -129,12 +129,16 @@
     if (element is ParameterElement) {
       properties['defaultValueCode'] = element.defaultValueCode;
       properties['isInitializingFormal'] = element.isInitializingFormal;
-      if (element.isNotOptional) {
-        properties['parameterKind'] = 'required';
+      if (element.isRequiredPositional) {
+        properties['parameterKind'] = 'required-positional';
+      } else if (element.isRequiredNamed) {
+        properties['parameterKind'] = 'required-named';
       } else if (element.isOptionalPositional) {
-        properties['parameterKind'] = 'positional';
-      } else if (element.isNamed) {
-        properties['parameterKind'] = 'named';
+        properties['parameterKind'] = 'optional-positional';
+      } else if (element.isOptionalNamed) {
+        properties['parameterKind'] = 'optional-named';
+      } else {
+        properties['parameterKind'] = 'unknown kind';
       }
     }
     if (element is PropertyAccessorElement) {
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 72e85e0..02f1091 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -2289,15 +2289,17 @@
   /// even though they are implicitly final.
   bool get isFinal;
 
-  /// Return `true` if this parameter is a named parameter. Named parameters are
-  /// always optional, even when they are annotated with the `@required`
-  /// annotation.
+  /// Return `true` if this parameter is a named parameter. Named parameters can
+  /// either be required or optional.
   bool get isNamed;
 
   /// Return `true` if this parameter is an optional parameter. Optional
   /// parameters can either be positional or named.
   bool get isOptional;
 
+  /// Return `true` if this parameter is both an optional and named parameter.
+  bool get isOptionalNamed;
+
   /// Return `true` if this parameter is both an optional and positional
   /// parameter.
   bool get isOptionalPositional;
@@ -2307,12 +2309,22 @@
   bool get isPositional;
 
   /// Return `true` if this parameter is a required parameter. Required
-  /// parameters are always positional.
+  /// parameters can either be positional or named.
   ///
   /// Note: this will return `false` for a named parameter that is annotated
   /// with the `@required` annotation.
   bool get isRequired;
 
+  /// Return `true` if this parameter is both a required and named parameter.
+  ///
+  /// Note: this will return `false` for a named parameter that is annotated
+  /// with the `@required` annotation.
+  bool get isRequiredNamed;
+
+  /// Return `true` if this parameter is both a required and positional
+  /// parameter.
+  bool get isRequiredPositional;
+
   /// Return the kind of this parameter.
   @deprecated
   ParameterKind get kind;
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 4a83f50..d8e8eb6 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1426,6 +1426,9 @@
   /// parameters can either be positional or named.
   bool get isOptional;
 
+  /// Return `true` if this parameter is both an optional and named parameter.
+  bool get isOptionalNamed;
+
   /// Return `true` if this parameter is both an optional and positional
   /// parameter.
   bool get isOptionalPositional;
@@ -1434,6 +1437,13 @@
   /// parameters can either be required or optional.
   bool get isPositional;
 
+  /// Return `true` if this parameter is both a required and named parameter.
+  bool get isRequiredNamed;
+
+  /// Return `true` if this parameter is both a required and positional
+  /// parameter.
+  bool get isRequiredPositional;
+
   /// Return the kind of this parameter.
   @deprecated
   ParameterKind get parameterKind;
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
index 20859c2..9b9a320 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
@@ -678,11 +678,13 @@
     if (parameters == null) return;
 
     for (var parameter in parameters.parameters) {
-      if (parameter.isRequired) {
+      if (parameter.isRequiredPositional) {
         signature.addInt(1);
+      } else if (parameter.isRequiredNamed) {
+        signature.addInt(4);
       } else if (parameter.isOptionalPositional) {
         signature.addInt(2);
-      } else {
+      } else if (parameter.isOptionalNamed) {
         signature.addInt(3);
       }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index e7eff04..4f012a1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -94,7 +94,7 @@
   /**
    * The version of data format, should be incremented on every format change.
    */
-  static const int DATA_VERSION = 79;
+  static const int DATA_VERSION = 80;
 
   /**
    * The number of exception contexts allowed to write. Once this field is
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 8797967..b3de9e4 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -4223,13 +4223,17 @@
   ParameterElement get element => declaredElement;
 
   @override
-  bool get isNamed => kind == ParameterKind.NAMED;
+  bool get isNamed =>
+      kind == ParameterKind.NAMED || kind == ParameterKind.NAMED_REQUIRED;
 
   @override
   bool get isOptional =>
       kind == ParameterKind.NAMED || kind == ParameterKind.POSITIONAL;
 
   @override
+  bool get isOptionalNamed => kind == ParameterKind.NAMED;
+
+  @override
   bool get isOptionalPositional => kind == ParameterKind.POSITIONAL;
 
   @override
@@ -4237,7 +4241,14 @@
       kind == ParameterKind.POSITIONAL || kind == ParameterKind.REQUIRED;
 
   @override
-  bool get isRequired => kind == ParameterKind.REQUIRED;
+  bool get isRequired =>
+      kind == ParameterKind.REQUIRED || kind == ParameterKind.NAMED_REQUIRED;
+
+  @override
+  bool get isRequiredNamed => kind == ParameterKind.NAMED_REQUIRED;
+
+  @override
+  bool get isRequiredPositional => kind == ParameterKind.REQUIRED;
 
   @override
   // Overridden to remove the 'deprecated' annotation.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 945fd82..7e910a3 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4621,10 +4621,10 @@
           if (closing != null) {
             buffer.write(closing);
           }
-          if (parameterKind == ParameterKind.POSITIONAL) {
+          if (parameter.isOptionalPositional) {
             buffer.write("[");
             closing = "]";
-          } else if (parameterKind == ParameterKind.NAMED) {
+          } else if (parameter.isNamed) {
             buffer.write("{");
             closing = "}";
           } else {
@@ -8026,7 +8026,7 @@
       {bool synthetic: false}) {
     ParameterElementImpl element;
     if (unlinkedParameter.isInitializingFormal) {
-      if (unlinkedParameter.kind == UnlinkedParamKind.required) {
+      if (unlinkedParameter.kind == UnlinkedParamKind.requiredPositional) {
         element = new FieldFormalParameterElementImpl.forSerialized(
             unlinkedParameter, enclosingElement);
       } else {
@@ -8034,7 +8034,7 @@
             unlinkedParameter, enclosingElement);
       }
     } else {
-      if (unlinkedParameter.kind == UnlinkedParamKind.required) {
+      if (unlinkedParameter.kind == UnlinkedParamKind.requiredPositional) {
         element = new ParameterElementImpl.forSerialized(
             unlinkedParameter, enclosingElement);
       } else {
@@ -8260,7 +8260,8 @@
       if (unlinkedParam != null) {
         if (isSynthetic ||
             (unlinkedParam.name.isEmpty &&
-                unlinkedParam.kind != UnlinkedParamKind.named &&
+                unlinkedParam.kind != UnlinkedParamKind.requiredNamed &&
+                unlinkedParam.kind != UnlinkedParamKind.optionalNamed &&
                 enclosingElement is GenericFunctionTypeElement)) {
           return -1;
         }
@@ -8281,15 +8282,18 @@
     }
     if (unlinkedParam != null) {
       switch (unlinkedParam.kind) {
-        case UnlinkedParamKind.named:
+        case UnlinkedParamKind.optionalNamed:
           _parameterKind = ParameterKind.NAMED;
           break;
-        case UnlinkedParamKind.positional:
+        case UnlinkedParamKind.optionalPositional:
           _parameterKind = ParameterKind.POSITIONAL;
           break;
-        case UnlinkedParamKind.required:
+        case UnlinkedParamKind.requiredPositional:
           _parameterKind = ParameterKind.REQUIRED;
           break;
+        case UnlinkedParamKind.requiredNamed:
+          _parameterKind = ParameterKind.NAMED_REQUIRED;
+          break;
       }
     }
     return _parameterKind;
@@ -8397,21 +8401,17 @@
 
   @override
   void appendTo(StringBuffer buffer) {
-    String left = "";
-    String right = "";
-    while (true) {
-      if (parameterKind == ParameterKind.NAMED) {
-        left = "{";
-        right = "}";
-      } else if (parameterKind == ParameterKind.POSITIONAL) {
-        left = "[";
-        right = "]";
-      } else if (parameterKind == ParameterKind.REQUIRED) {}
-      break;
+    if (isNamed) {
+      buffer.write("{");
+      appendToWithoutDelimiters(buffer);
+      buffer.write("}");
+    } else if (isOptionalPositional) {
+      buffer.write("[");
+      appendToWithoutDelimiters(buffer);
+      buffer.write("]");
+    } else {
+      appendToWithoutDelimiters(buffer);
     }
-    buffer.write(left);
-    appendToWithoutDelimiters(buffer);
-    buffer.write(right);
   }
 
   @deprecated
@@ -8587,10 +8587,14 @@
 /// [ParameterElement].
 mixin ParameterElementMixin implements ParameterElement {
   @override
-  bool get isNamed => parameterKind == ParameterKind.NAMED;
+  bool get isNamed =>
+      parameterKind == ParameterKind.NAMED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
-  bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
+  bool get isNotOptional =>
+      parameterKind == ParameterKind.REQUIRED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
   bool get isOptional =>
@@ -8598,6 +8602,9 @@
       parameterKind == ParameterKind.POSITIONAL;
 
   @override
+  bool get isOptionalNamed => parameterKind == ParameterKind.NAMED;
+
+  @override
   bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
 
   @override
@@ -8606,6 +8613,12 @@
       parameterKind == ParameterKind.REQUIRED;
 
   @override
+  bool get isRequiredNamed => parameterKind == ParameterKind.NAMED_REQUIRED;
+
+  @override
+  bool get isRequiredPositional => parameterKind == ParameterKind.REQUIRED;
+
+  @override
   // Overridden to remove the 'deprecated' annotation.
   ParameterKind get parameterKind;
 
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index ea1a3aa..3d6f75a 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -651,10 +651,10 @@
         if (closing != null) {
           buffer.write(closing);
         }
-        if (parameterKind == ParameterKind.POSITIONAL) {
+        if (parameter.isOptionalPositional) {
           buffer.write("[");
           closing = "]";
-        } else if (parameterKind == ParameterKind.NAMED) {
+        } else if (parameter.isNamed) {
           buffer.write("{");
           closing = "}";
         } else {
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 3f36fcf..d5d0dac 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -602,10 +602,16 @@
 
   @override
   Map<String, DartType> get namedParameterTypes {
+    // TODO(brianwilkerson) This implementation breaks the contract because the
+    //  parameters will not necessarily be returned in the order in which they
+    //  were declared.
     Map<String, DartType> types = <String, DartType>{};
     _forEachParameterType(ParameterKind.NAMED, (name, type) {
       types[name] = type;
     });
+    _forEachParameterType(ParameterKind.NAMED_REQUIRED, (name, type) {
+      types[name] = type;
+    });
     return types;
   }
 
@@ -1055,7 +1061,7 @@
     var tOptional = <ParameterElement>[];
     var tNamed = <String, ParameterElement>{};
     for (var p in tParams) {
-      if (p.isNotOptional) {
+      if (p.isRequiredPositional) {
         tRequired.add(p);
       } else if (p.isOptionalPositional) {
         tOptional.add(p);
@@ -1069,7 +1075,7 @@
     var sOptional = <ParameterElement>[];
     var sNamed = <String, ParameterElement>{};
     for (var p in sParams) {
-      if (p.isNotOptional) {
+      if (p.isRequiredPositional) {
         sRequired.add(p);
       } else if (p.isOptionalPositional) {
         sOptional.add(p);
@@ -3430,7 +3436,7 @@
   @override
   List<String> get normalParameterNames {
     return baseParameters
-        .where((parameter) => parameter.isNotOptional)
+        .where((parameter) => parameter.isRequiredPositional)
         .map((parameter) => parameter.name)
         .toList();
   }
@@ -3717,8 +3723,10 @@
   List<FunctionTypeAliasElement> get newPrune => const [];
 
   @override
-  List<String> get normalParameterNames =>
-      parameters.where((p) => p.isNotOptional).map((p) => p.name).toList();
+  List<String> get normalParameterNames => parameters
+      .where((p) => p.isRequiredPositional)
+      .map((p) => p.name)
+      .toList();
 
   @override
   List<String> get optionalParameterNames => parameters
diff --git a/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
index 0184c06..b1781ea 100644
--- a/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
@@ -359,6 +359,8 @@
       if (r > numOfRequiredParams) {
         r = numOfRequiredParams;
       }
+      // TODO(brianwilkerson) Handle the fact that named parameters can now be
+      //  required.
       namedParametersList.addAll(_getNamedParameterNames(element));
     }
     return _createSyntheticExecutableElement(
@@ -426,6 +428,8 @@
       parameter.parameterKind = ParameterKind.POSITIONAL;
       parameters[i] = parameter;
     }
+    // TODO(brianwilkerson) Handle the fact that named parameters can now be
+    //  required.
     for (int m = 0; m < namedParameters.length; m++, i++) {
       ParameterElementImpl parameter =
           new ParameterElementImpl(namedParameters[m], 0);
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 345f166..cf78496 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -853,7 +853,8 @@
       }
     }
 
-    ParameterKind analyzerKind = _toAnalyzerParameterKind(kind);
+    ParameterKind analyzerKind =
+        _toAnalyzerParameterKind(kind, requiredKeyword);
     FormalParameter parameter = node;
     if (analyzerKind != ParameterKind.REQUIRED) {
       parameter = ast.defaultFormalParameter(
@@ -3262,10 +3263,14 @@
     return variableDeclaration;
   }
 
-  ParameterKind _toAnalyzerParameterKind(FormalParameterKind type) {
+  ParameterKind _toAnalyzerParameterKind(
+      FormalParameterKind type, Token requiredKeyword) {
     if (type == FormalParameterKind.optionalPositional) {
       return ParameterKind.POSITIONAL;
     } else if (type == FormalParameterKind.optionalNamed) {
+      if (requiredKeyword != null) {
+        return ParameterKind.NAMED_REQUIRED;
+      }
       return ParameterKind.NAMED;
     } else {
       return ParameterKind.REQUIRED;
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e0566d3..1f966ce 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5613,7 +5613,7 @@
     }
 
     NodeList<FormalParameter> parameters = parameterList.parameters;
-    if (parameters.length != 1 || !parameters[0].isRequired) {
+    if (parameters.length != 1 || !parameters[0].isRequiredPositional) {
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER,
           setterName);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1ff7522..a11d056 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -5429,7 +5429,7 @@
     int length = parameters.length;
     for (int i = 0; i < length; i++) {
       ParameterElement parameter = parameters[i];
-      if (parameter.isNotOptional) {
+      if (parameter.isRequiredPositional) {
         unnamedParameters.add(parameter);
         unnamedParameterCount++;
         requiredParameterCount++;
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 285df36..cf33a07 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -123,9 +123,9 @@
       List<ParameterElement> parameters = node.parameterElements;
       {
         Iterator<ParameterElement> positional =
-            parameters.where((p) => !p.isNamed).iterator;
+            parameters.where((p) => p.isPositional).iterator;
         Iterator<ParameterElement> fnPositional =
-            functionType.parameters.where((p) => !p.isNamed).iterator;
+            functionType.parameters.where((p) => p.isPositional).iterator;
         while (positional.moveNext() && fnPositional.moveNext()) {
           inferType(positional.current, fnPositional.current.type);
         }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index b2fa6c8..aa034dc 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -771,6 +771,8 @@
     }
 
     // Union the named parameters together.
+    // TODO(brianwilkerson) Handle the fact that named parameters can now be
+    //  required.
     Map<String, DartType> fNamed = f.namedParameterTypes;
     Map<String, DartType> gNamed = g.namedParameterTypes;
     for (String name in fNamed.keys.toSet()..addAll(gNamed.keys)) {
@@ -2166,6 +2168,8 @@
           ParameterKind.POSITIONAL));
     }
 
+    // TODO(brianwilkerson) Handle the fact that named parameters can now be
+    //  required.
     Map<String, DartType> fNamed = f.namedParameterTypes;
     Map<String, DartType> gNamed = g.namedParameterTypes;
     for (String name in fNamed.keys.toSet()..retainAll(gNamed.keys)) {
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index d1904a0..160c47a 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -50,20 +50,32 @@
 }
 
 /**
- * The kinds of a parameter. There are two basic kinds of parameters: required
- * and optional. Optional parameters are further divided into two kinds:
- * positional optional and named optional.
+ * The kind of a parameter. A parameter can be either positional or named, and
+ * can be either required or optional. 
  */
 class ParameterKind implements Comparable<ParameterKind> {
+  /// A positional required parameter.
   static const ParameterKind REQUIRED =
-      const ParameterKind('REQUIRED', 0, false);
+      const ParameterKind('REQUIRED', 0, false, false);
 
+  /// A positional optional parameter.
   static const ParameterKind POSITIONAL =
-      const ParameterKind('POSITIONAL', 1, true);
+      const ParameterKind('POSITIONAL', 1, false, true);
 
-  static const ParameterKind NAMED = const ParameterKind('NAMED', 2, true);
+  /// A named required parameter.
+  static const ParameterKind NAMED_REQUIRED =
+      const ParameterKind('NAMED_REQUIRED', 2, true, false);
 
-  static const List<ParameterKind> values = const [REQUIRED, POSITIONAL, NAMED];
+  /// A named optional parameter.
+  static const ParameterKind NAMED =
+      const ParameterKind('NAMED', 2, true, true);
+
+  static const List<ParameterKind> values = const [
+    REQUIRED,
+    POSITIONAL,
+    NAMED_REQUIRED,
+    NAMED
+  ];
 
   /**
    * The name of this parameter.
@@ -76,14 +88,19 @@
   final int ordinal;
 
   /**
-   * A flag indicating whether this is an optional parameter.
+   * A flag indicating whether this is a named or positional parameter.
+   */
+  final bool isNamed;
+
+  /**
+   * A flag indicating whether this is an optional or required parameter.
    */
   final bool isOptional;
 
   /**
    * Initialize a newly created kind with the given state.
    */
-  const ParameterKind(this.name, this.ordinal, this.isOptional);
+  const ParameterKind(this.name, this.ordinal, this.isNamed, this.isOptional);
 
   @override
   int get hashCode => ordinal;
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 431ccb0..8a57f1e 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -1488,6 +1488,10 @@
         if (buffer.isNotEmpty) {
           buffer.write(', ');
         }
+        if (parameter.isNamed) {
+          buffer.write(parameter.identifier.name);
+          buffer.write(': ');
+        }
         var valueOffset = buffer.length;
         buffer.write(parameter.identifier.name);
         var valueLength = buffer.length - valueOffset;
@@ -1527,7 +1531,7 @@
     if (parameters == null) return null;
 
     return parameters.parameters
-        .takeWhile((parameter) => parameter.isRequired)
+        .takeWhile((parameter) => parameter.isRequiredPositional)
         .length;
   }
 
diff --git a/pkg/analyzer/lib/src/summary/expr_builder.dart b/pkg/analyzer/lib/src/summary/expr_builder.dart
index 77bcdd9..7f07f7e 100644
--- a/pkg/analyzer/lib/src/summary/expr_builder.dart
+++ b/pkg/analyzer/lib/src/summary/expr_builder.dart
@@ -673,9 +673,10 @@
     simpleParam.identifier.staticElement = param;
     simpleParam.declaredElement = param;
     var unlinkedParam = (param as ParameterElementImpl).unlinkedParam;
-    if (unlinkedParam.kind == UnlinkedParamKind.positional) {
+    if (unlinkedParam.kind == UnlinkedParamKind.optionalPositional) {
       return AstTestFactory.positionalFormalParameter(simpleParam, null);
-    } else if (unlinkedParam.kind == UnlinkedParamKind.named) {
+    } else if (unlinkedParam.kind == UnlinkedParamKind.requiredNamed ||
+        unlinkedParam.kind == UnlinkedParamKind.optionalNamed) {
       return AstTestFactory.namedFormalParameter(simpleParam, null);
     } else {
       return simpleParam;
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 7f60c19..ff08343 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -137,7 +137,7 @@
     int index = const fb.Uint8Reader().read(bc, offset);
     return index < idl.LinkedNodeFormalParameterKind.values.length
         ? idl.LinkedNodeFormalParameterKind.values[index]
-        : idl.LinkedNodeFormalParameterKind.required;
+        : idl.LinkedNodeFormalParameterKind.requiredPositional;
   }
 }
 
@@ -292,7 +292,7 @@
     int index = const fb.Uint8Reader().read(bc, offset);
     return index < idl.UnlinkedParamKind.values.length
         ? idl.UnlinkedParamKind.values[index]
-        : idl.UnlinkedParamKind.required;
+        : idl.UnlinkedParamKind.requiredPositional;
   }
 }
 
@@ -9841,7 +9841,8 @@
     assert(kind == idl.LinkedNodeKind.fieldFormalParameter ||
         kind == idl.LinkedNodeKind.functionTypedFormalParameter ||
         kind == idl.LinkedNodeKind.simpleFormalParameter);
-    return _variantField_26 ??= idl.LinkedNodeFormalParameterKind.required;
+    return _variantField_26 ??=
+        idl.LinkedNodeFormalParameterKind.requiredPositional;
   }
 
   set formalParameter_kind(idl.LinkedNodeFormalParameterKind value) {
@@ -11904,7 +11905,8 @@
       fbBuilder.addOffset(25, offset_variantField_25);
     }
     if (_variantField_26 != null &&
-        _variantField_26 != idl.LinkedNodeFormalParameterKind.required) {
+        _variantField_26 !=
+            idl.LinkedNodeFormalParameterKind.requiredPositional) {
       fbBuilder.addUint8(26, _variantField_26.index);
     }
     if (offset_variantField_30 != null) {
@@ -15501,7 +15503,10 @@
         kind == idl.LinkedNodeKind.functionTypedFormalParameter ||
         kind == idl.LinkedNodeKind.simpleFormalParameter);
     _variantField_26 ??= const _LinkedNodeFormalParameterKindReader().vTableGet(
-        _bc, _bcOffset, 26, idl.LinkedNodeFormalParameterKind.required);
+        _bc,
+        _bcOffset,
+        26,
+        idl.LinkedNodeFormalParameterKind.requiredPositional);
     return _variantField_26;
   }
 
@@ -15810,7 +15815,8 @@
             normalFormalParameter_identifier.toJson();
       if (codeLength != 0) _result["codeLength"] = codeLength;
       if (codeOffset != 0) _result["codeOffset"] = codeOffset;
-      if (formalParameter_kind != idl.LinkedNodeFormalParameterKind.required)
+      if (formalParameter_kind !=
+          idl.LinkedNodeFormalParameterKind.requiredPositional)
         _result["formalParameter_kind"] =
             formalParameter_kind.toString().split('.')[1];
       if (normalFormalParameter_comment != null)
@@ -15844,7 +15850,8 @@
             normalFormalParameter_identifier.toJson();
       if (codeLength != 0) _result["codeLength"] = codeLength;
       if (codeOffset != 0) _result["codeOffset"] = codeOffset;
-      if (formalParameter_kind != idl.LinkedNodeFormalParameterKind.required)
+      if (formalParameter_kind !=
+          idl.LinkedNodeFormalParameterKind.requiredPositional)
         _result["formalParameter_kind"] =
             formalParameter_kind.toString().split('.')[1];
       if (normalFormalParameter_comment != null)
@@ -15875,7 +15882,8 @@
             normalFormalParameter_identifier.toJson();
       if (codeLength != 0) _result["codeLength"] = codeLength;
       if (codeOffset != 0) _result["codeOffset"] = codeOffset;
-      if (formalParameter_kind != idl.LinkedNodeFormalParameterKind.required)
+      if (formalParameter_kind !=
+          idl.LinkedNodeFormalParameterKind.requiredPositional)
         _result["formalParameter_kind"] =
             formalParameter_kind.toString().split('.')[1];
       if (normalFormalParameter_comment != null)
@@ -19647,7 +19655,7 @@
 
   @override
   idl.LinkedNodeFormalParameterKind get kind =>
-      _kind ??= idl.LinkedNodeFormalParameterKind.required;
+      _kind ??= idl.LinkedNodeFormalParameterKind.requiredPositional;
 
   set kind(idl.LinkedNodeFormalParameterKind value) {
     this._kind = value;
@@ -19698,7 +19706,8 @@
       offset_type = _type.finish(fbBuilder);
     }
     fbBuilder.startTable();
-    if (_kind != null && _kind != idl.LinkedNodeFormalParameterKind.required) {
+    if (_kind != null &&
+        _kind != idl.LinkedNodeFormalParameterKind.requiredPositional) {
       fbBuilder.addUint8(0, _kind.index);
     }
     if (offset_name != null) {
@@ -19735,8 +19744,8 @@
 
   @override
   idl.LinkedNodeFormalParameterKind get kind {
-    _kind ??= const _LinkedNodeFormalParameterKindReader().vTableGet(
-        _bc, _bcOffset, 0, idl.LinkedNodeFormalParameterKind.required);
+    _kind ??= const _LinkedNodeFormalParameterKindReader().vTableGet(_bc,
+        _bcOffset, 0, idl.LinkedNodeFormalParameterKind.requiredPositional);
     return _kind;
   }
 
@@ -19758,7 +19767,7 @@
   @override
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
-    if (kind != idl.LinkedNodeFormalParameterKind.required)
+    if (kind != idl.LinkedNodeFormalParameterKind.requiredPositional)
       _result["kind"] = kind.toString().split('.')[1];
     if (name != '') _result["name"] = name;
     if (type != null) _result["type"] = type.toJson();
@@ -26036,7 +26045,8 @@
   }
 
   @override
-  idl.UnlinkedParamKind get kind => _kind ??= idl.UnlinkedParamKind.required;
+  idl.UnlinkedParamKind get kind =>
+      _kind ??= idl.UnlinkedParamKind.requiredPositional;
 
   /// Kind of the parameter.
   set kind(idl.UnlinkedParamKind value) {
@@ -26240,7 +26250,7 @@
     if (_isInitializingFormal == true) {
       fbBuilder.addBool(6, true);
     }
-    if (_kind != null && _kind != idl.UnlinkedParamKind.required) {
+    if (_kind != null && _kind != idl.UnlinkedParamKind.requiredPositional) {
       fbBuilder.addUint8(4, _kind.index);
     }
     if (offset_name != null) {
@@ -26371,7 +26381,7 @@
   @override
   idl.UnlinkedParamKind get kind {
     _kind ??= const _UnlinkedParamKindReader()
-        .vTableGet(_bc, _bcOffset, 4, idl.UnlinkedParamKind.required);
+        .vTableGet(_bc, _bcOffset, 4, idl.UnlinkedParamKind.requiredPositional);
     return _kind;
   }
 
@@ -26433,7 +26443,7 @@
     if (isFunctionTyped != false) _result["isFunctionTyped"] = isFunctionTyped;
     if (isInitializingFormal != false)
       _result["isInitializingFormal"] = isInitializingFormal;
-    if (kind != idl.UnlinkedParamKind.required)
+    if (kind != idl.UnlinkedParamKind.requiredPositional)
       _result["kind"] = kind.toString().split('.')[1];
     if (name != '') _result["name"] = name;
     if (nameOffset != 0) _result["nameOffset"] = nameOffset;
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index a3cb2fc..9577473 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -176,11 +176,13 @@
 
 /// Kinds of formal parameters.
 enum LinkedNodeFormalParameterKind : byte {
-  required,
+  requiredPositional,
 
   optionalPositional,
 
-  optionalNamed
+  optionalNamed,
+
+  requiredNamed
 }
 
 /// Kinds of [LinkedNode].
@@ -1095,14 +1097,17 @@
 
 /// Enum used to indicate the kind of a parameter.
 enum UnlinkedParamKind : byte {
-  /// Parameter is required.
-  required,
+  /// Parameter is required and positional.
+  requiredPositional,
 
-  /// Parameter is positional optional (enclosed in `[]`)
-  positional,
+  /// Parameter is optional and positional (enclosed in `[]`)
+  optionalPositional,
 
-  /// Parameter is named optional (enclosed in `{}`)
-  named
+  /// Parameter is optional and named (enclosed in `{}`)
+  optionalNamed,
+
+  /// Parameter is required and named (enclosed in `{}`).
+  requiredNamed
 }
 
 /// TODO(scheglov) document
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 805f155..1f18604 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -2407,9 +2407,10 @@
 
 /// Kinds of formal parameters.
 enum LinkedNodeFormalParameterKind {
-  required,
+  requiredPositional,
   optionalPositional,
-  optionalNamed
+  optionalNamed,
+  requiredNamed
 }
 
 /// Kinds of [LinkedNode].
@@ -4300,14 +4301,17 @@
 
 /// Enum used to indicate the kind of a parameter.
 enum UnlinkedParamKind {
-  /// Parameter is required.
-  required,
+  /// Parameter is required and positional.
+  requiredPositional,
 
-  /// Parameter is positional optional (enclosed in `[]`)
-  positional,
+  /// Parameter is optional and positional (enclosed in `[]`)
+  optionalPositional,
 
-  /// Parameter is named optional (enclosed in `{}`)
-  named
+  /// Parameter is optional and named (enclosed in `{}`)
+  optionalNamed,
+
+  /// Parameter is required and named (enclosed in `{}`).
+  requiredNamed
 }
 
 /// Unlinked summary information about a part declaration.
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 76eaf73..ac8bd0e 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -317,12 +317,14 @@
     TypeParameterSerializationContext typeParameterContext) {
   UnlinkedParamBuilder b = new UnlinkedParamBuilder();
   b.name = parameter.name;
-  if (parameter.isNotOptional) {
-    b.kind = UnlinkedParamKind.required;
+  if (parameter.isRequiredPositional) {
+    b.kind = UnlinkedParamKind.requiredPositional;
+  } else if (parameter.isRequiredNamed) {
+    b.kind = UnlinkedParamKind.requiredNamed;
   } else if (parameter.isOptionalPositional) {
-    b.kind = UnlinkedParamKind.positional;
-  } else if (parameter.isNamed) {
-    b.kind = UnlinkedParamKind.named;
+    b.kind = UnlinkedParamKind.optionalPositional;
+  } else if (parameter.isOptionalNamed) {
+    b.kind = UnlinkedParamKind.optionalNamed;
   }
   DartType type = parameter.type;
   if (!parameter.hasImplicitType) {
@@ -4290,10 +4292,14 @@
   bool get isInitializingFormal => unlinkedParam.isInitializingFormal;
 
   @override
-  bool get isNamed => parameterKind == ParameterKind.NAMED;
+  bool get isNamed =>
+      parameterKind == ParameterKind.NAMED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
-  bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
+  bool get isNotOptional =>
+      parameterKind == ParameterKind.REQUIRED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
   bool get isOptional =>
@@ -4301,6 +4307,9 @@
       parameterKind == ParameterKind.POSITIONAL;
 
   @override
+  bool get isOptionalNamed => parameterKind == ParameterKind.NAMED;
+
+  @override
   bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
 
   @override
@@ -4309,16 +4318,24 @@
       parameterKind == ParameterKind.REQUIRED;
 
   @override
+  bool get isRequiredNamed => parameterKind == ParameterKind.NAMED_REQUIRED;
+
+  @override
+  bool get isRequiredPositional => parameterKind == ParameterKind.REQUIRED;
+
+  @override
   String get name => unlinkedParam.name;
 
   @override
   ParameterKind get parameterKind {
     switch (unlinkedParam.kind) {
-      case UnlinkedParamKind.required:
+      case UnlinkedParamKind.requiredPositional:
         return ParameterKind.REQUIRED;
-      case UnlinkedParamKind.positional:
+      case UnlinkedParamKind.requiredNamed:
+        return ParameterKind.NAMED_REQUIRED;
+      case UnlinkedParamKind.optionalPositional:
         return ParameterKind.POSITIONAL;
-      case UnlinkedParamKind.named:
+      case UnlinkedParamKind.optionalNamed:
         return ParameterKind.NAMED;
     }
     return null;
@@ -4402,10 +4419,14 @@
   bool get isInitializingFormal => unlinkedParam.isInitializingFormal;
 
   @override
-  bool get isNamed => parameterKind == ParameterKind.NAMED;
+  bool get isNamed =>
+      parameterKind == ParameterKind.NAMED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
-  bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
+  bool get isNotOptional =>
+      parameterKind == ParameterKind.REQUIRED ||
+      parameterKind == ParameterKind.NAMED_REQUIRED;
 
   @override
   bool get isOptional =>
@@ -4413,6 +4434,9 @@
       parameterKind == ParameterKind.POSITIONAL;
 
   @override
+  bool get isOptionalNamed => parameterKind == ParameterKind.NAMED;
+
+  @override
   bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
 
   @override
@@ -4421,6 +4445,12 @@
       parameterKind == ParameterKind.REQUIRED;
 
   @override
+  bool get isRequiredNamed => parameterKind == ParameterKind.NAMED_REQUIRED;
+
+  @override
+  bool get isRequiredPositional => parameterKind == ParameterKind.REQUIRED;
+
+  @override
   bool get isSynthetic => true;
 
   @override
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index a1bf744..34b2ff1 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -44,6 +44,10 @@
         super(forConst);
 
   @override
+  EntityRefNullabilitySuffix computeNullabilitySuffix(Token question) =>
+      visitor.computeNullabilitySuffix(question);
+
+  @override
   bool isParameterName(String name) {
     return variableNames?.contains(name) ?? false;
   }
@@ -167,10 +171,6 @@
       EntityRefNullabilitySuffix nullabilitySuffix) {
     return visitor.serializeTypeName(name, arguments, nullabilitySuffix);
   }
-
-  @override
-  EntityRefNullabilitySuffix computeNullabilitySuffix(Token question) =>
-      visitor.computeNullabilitySuffix(question);
 }
 
 /// A [_Scope] represents a set of name/value pairs defined locally within a
@@ -365,6 +365,12 @@
     return scope;
   }
 
+  EntityRefNullabilitySuffix computeNullabilitySuffix(Token question) {
+    if (!_nnbd) return EntityRefNullabilitySuffix.starOrIrrelevant;
+    if (question != null) return EntityRefNullabilitySuffix.question;
+    return EntityRefNullabilitySuffix.none;
+  }
+
   /// Serialize the given list of [annotations].  If there are no annotations,
   /// the empty list is returned.
   List<UnlinkedExprBuilder> serializeAnnotations(
@@ -837,12 +843,14 @@
     if (_parametersMayInheritCovariance) {
       b.inheritsCovariantSlot = assignSlot();
     }
-    if (node.isRequired) {
-      b.kind = UnlinkedParamKind.required;
+    if (node.isRequiredPositional) {
+      b.kind = UnlinkedParamKind.requiredPositional;
+    } else if (node.isRequiredNamed) {
+      b.kind = UnlinkedParamKind.requiredNamed;
     } else if (node.isOptionalPositional) {
-      b.kind = UnlinkedParamKind.positional;
-    } else if (node.isNamed) {
-      b.kind = UnlinkedParamKind.named;
+      b.kind = UnlinkedParamKind.optionalPositional;
+    } else if (node.isOptionalNamed) {
+      b.kind = UnlinkedParamKind.optionalNamed;
     } else {
       // ignore: deprecated_member_use_from_same_package
       throw new StateError('Unexpected parameter kind: ${node.kind}');
@@ -905,12 +913,6 @@
     return null;
   }
 
-  EntityRefNullabilitySuffix computeNullabilitySuffix(Token question) {
-    if (!_nnbd) return EntityRefNullabilitySuffix.starOrIrrelevant;
-    if (question != null) return EntityRefNullabilitySuffix.question;
-    return EntityRefNullabilitySuffix.none;
-  }
-
   /// Serialize a type name (which might be defined in a nested scope, at top
   /// level within this library, or at top level within an imported library) to
   /// a [EntityRef].  Note that this method does the right thing if the
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index df53896..87db843 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -343,6 +343,8 @@
 
   @override
   LinkedNodeBuilder visitDefaultFormalParameter(DefaultFormalParameter node) {
+    // TODO(brianwilkerson) Record whether the node is required, either by
+    //  adding a new bool field or by recording a parameter kind.
     var builder = LinkedNodeBuilder.defaultFormalParameter(
       defaultFormalParameter_defaultValue: node.defaultValue?.accept(this),
       defaultFormalParameter_isNamed: node.isNamed,
@@ -1437,11 +1439,17 @@
   void _storeForLoopParts(LinkedNodeBuilder builder, ForLoopParts node) {}
 
   void _storeFormalParameter(LinkedNodeBuilder builder, FormalParameter node) {
-    var kind = LinkedNodeFormalParameterKind.required;
-    if (node.isNamed) {
-      kind = LinkedNodeFormalParameterKind.optionalNamed;
+    var kind;
+    if (node.isRequiredPositional) {
+      kind = LinkedNodeFormalParameterKind.requiredPositional;
+    } else if (node.isRequiredNamed) {
+      kind = LinkedNodeFormalParameterKind.requiredNamed;
     } else if (node.isOptionalPositional) {
       kind = LinkedNodeFormalParameterKind.optionalPositional;
+    } else if (node.isOptionalNamed) {
+      kind = LinkedNodeFormalParameterKind.optionalNamed;
+    } else {
+      throw new StateError('Unknown kind of parameter');
     }
     builder.formalParameter_kind = kind;
 
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index ce18580..445d65e 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -877,9 +877,10 @@
   ParameterKind _formalParameterKind(LinkedNodeFormalParameterKind kind) {
     if (kind == LinkedNodeFormalParameterKind.optionalNamed) {
       return ParameterKind.NAMED;
-    }
-    if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
+    } else if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
       return ParameterKind.POSITIONAL;
+    } else if (kind == LinkedNodeFormalParameterKind.requiredNamed) {
+      return ParameterKind.NAMED_REQUIRED;
     }
     return ParameterKind.REQUIRED;
   }
diff --git a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
index 8ab18a5..144df5d 100644
--- a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
@@ -109,11 +109,12 @@
     var kind = p.parameterKind;
     if (kind == ParameterKind.NAMED) {
       return LinkedNodeFormalParameterKind.optionalNamed;
-    }
-    if (kind == ParameterKind.POSITIONAL) {
+    } else if (kind == ParameterKind.POSITIONAL) {
       return LinkedNodeFormalParameterKind.optionalPositional;
+    } else if (kind == ParameterKind.NAMED_REQUIRED) {
+      return LinkedNodeFormalParameterKind.requiredNamed;
     }
-    return LinkedNodeFormalParameterKind.required;
+    return LinkedNodeFormalParameterKind.requiredPositional;
   }
 
   FunctionType _toSyntheticFunctionType(FunctionType type) {
diff --git a/pkg/analyzer/test/dart/element/builder_test.dart b/pkg/analyzer/test/dart/element/builder_test.dart
index 25ba692..da4866a 100644
--- a/pkg/analyzer/test/dart/element/builder_test.dart
+++ b/pkg/analyzer/test/dart/element/builder_test.dart
@@ -466,7 +466,7 @@
     expect(parameter.isConst, isFalse);
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -490,7 +490,7 @@
     expect(parameter.isExplicitlyCovariant, isTrue);
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -514,7 +514,7 @@
     expect(parameter.isConst, isFalse);
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     expect(typeElement.typeParameters, hasLength(1));
     _assertVisibleRange(parameter, 100, 110);
   }
@@ -641,7 +641,7 @@
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
     expect(parameter.name, parameterName);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -667,7 +667,7 @@
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
     expect(parameter.name, parameterName);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -691,7 +691,7 @@
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
     expect(parameter.name, parameterName);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -718,7 +718,7 @@
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
     expect(parameter.name, parameterName);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     _assertVisibleRange(parameter, 100, 110);
   }
 
@@ -1855,7 +1855,7 @@
     expect(parameter.isConst, isFalse);
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     expect(parameter.parameters, hasLength(0));
   }
 
@@ -1879,7 +1879,7 @@
     expect(parameter.isConst, isFalse);
     expect(parameter.isFinal, isFalse);
     expect(parameter.isSynthetic, isFalse);
-    expect(parameter.isNotOptional, isTrue);
+    expect(parameter.isRequiredPositional, isTrue);
     expect(typeElement.parameters, hasLength(1));
   }
 
diff --git a/pkg/analyzer/test/src/dart/element/function_type_test.dart b/pkg/analyzer/test/src/dart/element/function_type_test.dart
index 975952b..a0c2fd3 100644
--- a/pkg/analyzer/test/src/dart/element/function_type_test.dart
+++ b/pkg/analyzer/test/src/dart/element/function_type_test.dart
@@ -497,7 +497,7 @@
         normalParameterNames: ['x'],
         normalParameterTypes: [same(objectType)],
         parameters: hasLength(1));
-    expect(f.parameters[0].isNotOptional, isTrue);
+    expect(f.parameters[0].isRequiredPositional, isTrue);
     expect(f.parameters[0].name, 'x');
     expect(f.parameters[0].type, same(objectType));
   }
@@ -1226,7 +1226,9 @@
   ClassElement get enclosingElement => super.enclosingElement;
 }
 
-class MockParameterElement implements ParameterElementImpl {
+class MockParameterElement
+    with ParameterElementMixin
+    implements ParameterElementImpl {
   @override
   Element enclosingElement;
 
@@ -1245,15 +1247,6 @@
   @override
   get displayName => name;
 
-  @override
-  bool get isNamed => parameterKind == ParameterKind.NAMED;
-
-  @override
-  bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
-
-  @override
-  bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
-
   noSuchMethod(Invocation invocation) {
     return super.noSuchMethod(invocation);
   }
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 3ca6771..f923d30 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -311,6 +311,22 @@
     buffer.writeln(';');
   }
 
+  void writeExportScope(LibraryElement e) {
+    if (!withExportScope) return;
+
+    buffer.writeln();
+    buffer.writeln('-' * 20);
+    buffer.writeln('Exports:');
+
+    var map = e.exportNamespace.definedNames;
+    var names = map.keys.toList()..sort();
+    for (var name in names) {
+      var element = map[name];
+      var elementLocationStr = _getElementLocationString(element);
+      buffer.writeln('  $name: $elementLocationStr');
+    }
+  }
+
   void writeFunctionElement(FunctionElement e) {
     writeDocumentation(e);
     writeMetadata(e, '', '\n');
@@ -705,7 +721,7 @@
     String defaultValueSeparator;
     Expression defaultValue;
     String closeString;
-    if (e.isNotOptional) {
+    if (e.isRequiredPositional) {
       closeString = '';
     } else if (e.isOptionalPositional) {
       buffer.write('[');
@@ -939,22 +955,6 @@
     e.functions.forEach(writeFunctionElement);
   }
 
-  void writeExportScope(LibraryElement e) {
-    if (!withExportScope) return;
-
-    buffer.writeln();
-    buffer.writeln('-' * 20);
-    buffer.writeln('Exports:');
-
-    var map = e.exportNamespace.definedNames;
-    var names = map.keys.toList()..sort();
-    for (var name in names) {
-      var element = map[name];
-      var elementLocationStr = _getElementLocationString(element);
-      buffer.writeln('  $name: $elementLocationStr');
-    }
-  }
-
   void writeUri(Source source) {
     if (source != null) {
       Uri uri = source.uri;
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 18865ae..4f0c3d2 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -4708,7 +4708,7 @@
 ''').executables);
     UnlinkedParam param = executable.parameters[0];
     expect(param.isFunctionTyped, isTrue);
-    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.kind, UnlinkedParamKind.optionalPositional);
     expect(param.defaultValueCode, 'foo');
     assertUnlinkedConst(param.initializer.bodyExpr, 'foo', operators: [
       UnlinkedExprOperation.pushReference
@@ -4741,7 +4741,7 @@
         executables: serializeClassText('class C { C({this.x}); final x; }')
             .executables);
     UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.named);
+    expect(parameter.kind, UnlinkedParamKind.optionalNamed);
     expect(parameter.initializer, isNull);
     expect(parameter.defaultValueCode, isEmpty);
   }
@@ -4751,7 +4751,7 @@
         executables: serializeClassText('class C { C({this.x: 42}); final x; }')
             .executables);
     UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.named);
+    expect(parameter.kind, UnlinkedParamKind.optionalNamed);
     expect(parameter.initializer, isNotNull);
     expect(parameter.defaultValueCode, '42');
     _assertCodeRange(parameter.codeRange, 13, 10);
@@ -4772,7 +4772,7 @@
         executables: serializeClassText('class C { C([this.x]); final x; }')
             .executables);
     UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.positional);
+    expect(parameter.kind, UnlinkedParamKind.optionalPositional);
     expect(parameter.initializer, isNull);
     expect(parameter.defaultValueCode, isEmpty);
   }
@@ -4783,7 +4783,7 @@
             serializeClassText('class C { C([this.x = 42]); final x; }')
                 .executables);
     UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.positional);
+    expect(parameter.kind, UnlinkedParamKind.optionalPositional);
     expect(parameter.initializer, isNotNull);
     expect(parameter.defaultValueCode, '42');
     _assertCodeRange(parameter.codeRange, 13, 11);
@@ -4796,7 +4796,7 @@
         executables:
             serializeClassText('class C { C(this.x); final x; }').executables);
     UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.required);
+    expect(parameter.kind, UnlinkedParamKind.requiredPositional);
   }
 
   test_constructor_initializing_formal_typedef() {
@@ -4817,7 +4817,7 @@
   final int x;
 }''').executables);
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.kind, UnlinkedParamKind.optionalPositional);
     expect(param.defaultValueCode, '42');
     assertUnlinkedConst(param.initializer.bodyExpr, '42',
         operators: [UnlinkedExprOperation.pushInt], ints: [42]);
@@ -6357,7 +6357,7 @@
 int foo(int a, String b) => 0;
 ''');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.kind, UnlinkedParamKind.optionalPositional);
     expect(param.initializer, isNotNull);
     expect(param.defaultValueCode, 'foo');
     assertUnlinkedConst(param.initializer.bodyExpr, 'foo', operators: [
@@ -6381,7 +6381,7 @@
   test_executable_param_kind_named() {
     UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.named);
+    expect(param.kind, UnlinkedParamKind.optionalNamed);
     expect(param.initializer, isNull);
     expect(param.defaultValueCode, isEmpty);
   }
@@ -6389,7 +6389,7 @@
   test_executable_param_kind_named_withDefault() {
     UnlinkedExecutable executable = serializeExecutableText('f({x: 42}) {}');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.named);
+    expect(param.kind, UnlinkedParamKind.optionalNamed);
     expect(param.initializer, isNotNull);
     expect(param.defaultValueCode, '42');
     _assertCodeRange(param.codeRange, 3, 5);
@@ -6400,7 +6400,7 @@
   test_executable_param_kind_positional() {
     UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.kind, UnlinkedParamKind.optionalPositional);
     expect(param.initializer, isNull);
     expect(param.defaultValueCode, isEmpty);
   }
@@ -6408,7 +6408,7 @@
   test_executable_param_kind_positional_withDefault() {
     UnlinkedExecutable executable = serializeExecutableText('f([x = 42]) {}');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.kind, UnlinkedParamKind.optionalPositional);
     expect(param.initializer, isNotNull);
     expect(param.defaultValueCode, '42');
     _assertCodeRange(param.codeRange, 3, 6);
@@ -6419,7 +6419,7 @@
   test_executable_param_kind_required() {
     UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
     UnlinkedParam param = executable.parameters[0];
-    expect(param.kind, UnlinkedParamKind.required);
+    expect(param.kind, UnlinkedParamKind.requiredPositional);
     expect(param.initializer, isNull);
     expect(param.defaultValueCode, isEmpty);
   }
diff --git a/pkg/analyzer/tool/summary/dump_inferred_types.dart b/pkg/analyzer/tool/summary/dump_inferred_types.dart
index 81d2a34..ee6bb64 100644
--- a/pkg/analyzer/tool/summary/dump_inferred_types.dart
+++ b/pkg/analyzer/tool/summary/dump_inferred_types.dart
@@ -176,9 +176,9 @@
     } else {
       result = param.name;
     }
-    if (param.kind == UnlinkedParamKind.named) {
+    if (param.kind == UnlinkedParamKind.optionalNamed) {
       result = '{$result}';
-    } else if (param.kind == UnlinkedParamKind.positional) {
+    } else if (param.kind == UnlinkedParamKind.optionalPositional) {
       result = '[$result]';
     }
     return result;
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
index d5122fc75..228f53d 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/suggestion_builder.dart
@@ -125,7 +125,7 @@
       }).toList();
 
       Iterable<ParameterElement> requiredParameters = element.parameters
-          .where((ParameterElement param) => param.isNotOptional);
+          .where((ParameterElement param) => param.isRequiredPositional);
       suggestion.requiredParameterCount = requiredParameters.length;
 
       Iterable<ParameterElement> namedParameters =