Rework storing type parameters and function types.

R=brianwilkerson@google.com, paulberry@google.com

Change-Id: Ia2c71237cf0f7d9c31c7036522bb24a1aaead92f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99094
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index f3c39fc..85e699d 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1060,31 +1060,6 @@
     return _type;
   }
 
-  @override
-  List<TypeParameterElement> get typeParameters {
-    if (_typeParameterElements != null) return _typeParameterElements;
-
-    if (linkedNode != null) {
-      var context = enclosingUnit.linkedContext;
-      var containerRef = reference.getChild('@typeParameter');
-      var typeParameters = context.getTypeParameters2(linkedNode);
-      if (typeParameters == null) {
-        return _typeParameterElements = const [];
-      }
-      return _typeParameterElements = typeParameters.typeParameters.map((node) {
-        var name = node.name.name;
-        var reference = containerRef.getChild(name);
-        if (reference.element == null) {
-          reference.node2 = node;
-          TypeParameterElementImpl.forLinkedNode(this, reference, node);
-        }
-        return reference.element as TypeParameterElementImpl;
-      }).toList();
-    }
-
-    return super.typeParameters;
-  }
-
   /// Set the type parameters defined for this class to the given
   /// [typeParameters].
   void set typeParameters(List<TypeParameterElement> typeParameters) {
@@ -9243,7 +9218,8 @@
   @override
   String get name {
     if (linkedNode != null) {
-      return reference.name;
+      TypeParameter node = this.linkedNode;
+      return node.name.name;
     }
     if (_unlinkedTypeParam != null) {
       return _unlinkedTypeParam.name;
@@ -9317,20 +9293,14 @@
     if (_typeParameterElements != null) return _typeParameterElements;
 
     if (linkedNode != null) {
-      var context = enclosingUnit.linkedContext;
-      var containerRef = reference.getChild('@typeParameter');
-      var typeParameters = context.getTypeParameters2(linkedNode);
+      var typeParameters = linkedContext.getTypeParameters2(linkedNode);
       if (typeParameters == null) {
         return _typeParameterElements = const [];
       }
       return _typeParameterElements = typeParameters.typeParameters.map((node) {
-        var name = node.name.name;
-        var reference = containerRef.getChild(name);
-        if (reference.element == null) {
-          reference.node2 = node;
-          TypeParameterElementImpl.forLinkedNode(this, reference, node);
-        }
-        return reference.element as TypeParameterElementImpl;
+        TypeParameterElementImpl element = node.declaredElement;
+        element.enclosingElement = this;
+        return element;
       }).toList();
     }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index b3fd95f..dbf57f9 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -8,6 +8,37 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_visitor.dart';
 
+/// Generates a fresh copy of the given type parameters, with their bounds
+/// substituted to reference the new parameters.
+///
+/// The returned object contains the fresh type parameter list as well as a
+/// mapping to be used for replacing other types to use the new type parameters.
+FreshTypeParameters getFreshTypeParameters(
+    List<TypeParameterElement> typeParameters) {
+  var freshParameters = new List<TypeParameterElementImpl>.generate(
+    typeParameters.length,
+    (i) => new TypeParameterElementImpl(typeParameters[i].name, -1),
+    growable: true,
+  );
+
+  var map = <TypeParameterElement, DartType>{};
+  for (int i = 0; i < typeParameters.length; ++i) {
+    map[typeParameters[i]] = new TypeParameterTypeImpl(freshParameters[i]);
+  }
+
+  var substitution = Substitution.fromMap(map);
+
+  for (int i = 0; i < typeParameters.length; ++i) {
+    var bound = typeParameters[i].bound;
+    if (bound != null) {
+      var newBound = substitution.substituteType(bound);
+      freshParameters[i].bound = newBound;
+    }
+  }
+
+  return new FreshTypeParameters(freshParameters, substitution);
+}
+
 /// Returns a type where all occurrences of the given type parameters have been
 /// replaced with the corresponding types.
 ///
@@ -27,6 +58,30 @@
   return Substitution.fromMap(substitution).substituteType(type);
 }
 
+class FreshTypeParameters {
+  final List<TypeParameterElement> freshTypeParameters;
+  final Substitution substitution;
+
+  FreshTypeParameters(this.freshTypeParameters, this.substitution);
+
+  FunctionType applyToFunctionType(FunctionType type) {
+    return new FunctionTypeImpl.synthetic(
+      substitute(type.returnType),
+      freshTypeParameters,
+      type.parameters.map((parameter) {
+        return ParameterElementImpl.synthetic(
+          parameter.name,
+          substitute(parameter.type),
+          // ignore: deprecated_member_use_from_same_package
+          parameter.parameterKind,
+        );
+      }).toList(),
+    );
+  }
+
+  DartType substitute(DartType type) => substitution.substituteType(type);
+}
+
 abstract class Substitution {
   static const Substitution empty = _NullSubstitution.instance;
 
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index fd78d94..e3d8d32 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -8175,6 +8175,12 @@
   }
 
   @override
+  int get typeParameter_id {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    return _variantField_16 ??= 0;
+  }
+
+  @override
   int get typeParameterList_rightBracket {
     assert(kind == idl.LinkedNodeKind.typeParameterList);
     return _variantField_16 ??= 0;
@@ -8508,6 +8514,12 @@
     _variantField_16 = value;
   }
 
+  set typeParameter_id(int value) {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    assert(value == null || value >= 0);
+    _variantField_16 = value;
+  }
+
   set typeParameterList_rightBracket(int value) {
     assert(kind == idl.LinkedNodeKind.typeParameterList);
     assert(value == null || value >= 0);
@@ -10649,6 +10661,7 @@
     LinkedNodeBuilder typeParameter_bound,
     int typeParameter_extendsKeyword,
     LinkedNodeBuilder typeParameter_name,
+    int typeParameter_id,
     int codeLength,
     int codeOffset,
   })  : _kind = idl.LinkedNodeKind.typeParameter,
@@ -10657,6 +10670,7 @@
         _variantField_6 = typeParameter_bound,
         _variantField_15 = typeParameter_extendsKeyword,
         _variantField_7 = typeParameter_name,
+        _variantField_16 = typeParameter_id,
         _variantField_34 = codeLength,
         _variantField_33 = codeOffset;
 
@@ -14400,6 +14414,14 @@
   }
 
   @override
+  int get typeParameter_id {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    _variantField_16 ??=
+        const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 16, 0);
+    return _variantField_16;
+  }
+
+  @override
   int get typeParameterList_rightBracket {
     assert(kind == idl.LinkedNodeKind.typeParameterList);
     _variantField_16 ??=
@@ -16265,6 +16287,7 @@
         _result["typeParameter_extendsKeyword"] = typeParameter_extendsKeyword;
       if (typeParameter_name != null)
         _result["typeParameter_name"] = typeParameter_name.toJson();
+      if (typeParameter_id != 0) _result["typeParameter_id"] = typeParameter_id;
       if (codeLength != 0) _result["codeLength"] = codeLength;
       if (codeOffset != 0) _result["codeOffset"] = codeOffset;
     }
@@ -17689,6 +17712,7 @@
         "typeParameter_bound": typeParameter_bound,
         "typeParameter_extendsKeyword": typeParameter_extendsKeyword,
         "typeParameter_name": typeParameter_name,
+        "typeParameter_id": typeParameter_id,
         "codeLength": codeLength,
         "codeOffset": codeOffset,
         "isSynthetic": isSynthetic,
@@ -18891,13 +18915,13 @@
     implements idl.LinkedNodeType {
   List<LinkedNodeTypeFormalParameterBuilder> _functionFormalParameters;
   LinkedNodeTypeBuilder _functionReturnType;
-  List<int> _functionTypeParameters;
+  List<LinkedNodeTypeTypeParameterBuilder> _functionTypeParameters;
   int _genericTypeAliasReference;
   List<LinkedNodeTypeBuilder> _genericTypeAliasTypeArguments;
   int _interfaceClass;
   List<LinkedNodeTypeBuilder> _interfaceTypeArguments;
   idl.LinkedNodeTypeKind _kind;
-  int _typeParameterParameter;
+  int _typeParameterId;
 
   @override
   List<LinkedNodeTypeFormalParameterBuilder> get functionFormalParameters =>
@@ -18916,11 +18940,10 @@
   }
 
   @override
-  List<int> get functionTypeParameters => _functionTypeParameters ??= <int>[];
+  List<LinkedNodeTypeTypeParameterBuilder> get functionTypeParameters =>
+      _functionTypeParameters ??= <LinkedNodeTypeTypeParameterBuilder>[];
 
-  /// References to [LinkedNodeReferences].
-  set functionTypeParameters(List<int> value) {
-    assert(value == null || value.every((e) => e >= 0));
+  set functionTypeParameters(List<LinkedNodeTypeTypeParameterBuilder> value) {
     this._functionTypeParameters = value;
   }
 
@@ -18965,24 +18988,23 @@
   }
 
   @override
-  int get typeParameterParameter => _typeParameterParameter ??= 0;
+  int get typeParameterId => _typeParameterId ??= 0;
 
-  /// Reference to a [LinkedNodeReferences].
-  set typeParameterParameter(int value) {
+  set typeParameterId(int value) {
     assert(value == null || value >= 0);
-    this._typeParameterParameter = value;
+    this._typeParameterId = value;
   }
 
   LinkedNodeTypeBuilder(
       {List<LinkedNodeTypeFormalParameterBuilder> functionFormalParameters,
       LinkedNodeTypeBuilder functionReturnType,
-      List<int> functionTypeParameters,
+      List<LinkedNodeTypeTypeParameterBuilder> functionTypeParameters,
       int genericTypeAliasReference,
       List<LinkedNodeTypeBuilder> genericTypeAliasTypeArguments,
       int interfaceClass,
       List<LinkedNodeTypeBuilder> interfaceTypeArguments,
       idl.LinkedNodeTypeKind kind,
-      int typeParameterParameter})
+      int typeParameterId})
       : _functionFormalParameters = functionFormalParameters,
         _functionReturnType = functionReturnType,
         _functionTypeParameters = functionTypeParameters,
@@ -18991,12 +19013,13 @@
         _interfaceClass = interfaceClass,
         _interfaceTypeArguments = interfaceTypeArguments,
         _kind = kind,
-        _typeParameterParameter = typeParameterParameter;
+        _typeParameterId = typeParameterId;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
     _functionFormalParameters?.forEach((b) => b.flushInformative());
     _functionReturnType?.flushInformative();
+    _functionTypeParameters?.forEach((b) => b.flushInformative());
     _genericTypeAliasTypeArguments?.forEach((b) => b.flushInformative());
     _interfaceTypeArguments?.forEach((b) => b.flushInformative());
   }
@@ -19018,7 +19041,7 @@
     } else {
       signature.addInt(this._functionTypeParameters.length);
       for (var x in this._functionTypeParameters) {
-        signature.addInt(x);
+        x?.collectApiSignature(signature);
       }
     }
     signature.addInt(this._interfaceClass ?? 0);
@@ -19031,7 +19054,7 @@
       }
     }
     signature.addInt(this._kind == null ? 0 : this._kind.index);
-    signature.addInt(this._typeParameterParameter ?? 0);
+    signature.addInt(this._typeParameterId ?? 0);
     signature.addInt(this._genericTypeAliasReference ?? 0);
     if (this._genericTypeAliasTypeArguments == null) {
       signature.addInt(0);
@@ -19058,8 +19081,8 @@
       offset_functionReturnType = _functionReturnType.finish(fbBuilder);
     }
     if (!(_functionTypeParameters == null || _functionTypeParameters.isEmpty)) {
-      offset_functionTypeParameters =
-          fbBuilder.writeListUint32(_functionTypeParameters);
+      offset_functionTypeParameters = fbBuilder.writeList(
+          _functionTypeParameters.map((b) => b.finish(fbBuilder)).toList());
     }
     if (!(_genericTypeAliasTypeArguments == null ||
         _genericTypeAliasTypeArguments.isEmpty)) {
@@ -19097,8 +19120,8 @@
     if (_kind != null && _kind != idl.LinkedNodeTypeKind.bottom) {
       fbBuilder.addUint8(5, _kind.index);
     }
-    if (_typeParameterParameter != null && _typeParameterParameter != 0) {
-      fbBuilder.addUint32(6, _typeParameterParameter);
+    if (_typeParameterId != null && _typeParameterId != 0) {
+      fbBuilder.addUint32(6, _typeParameterId);
     }
     return fbBuilder.endTable();
   }
@@ -19122,13 +19145,13 @@
 
   List<idl.LinkedNodeTypeFormalParameter> _functionFormalParameters;
   idl.LinkedNodeType _functionReturnType;
-  List<int> _functionTypeParameters;
+  List<idl.LinkedNodeTypeTypeParameter> _functionTypeParameters;
   int _genericTypeAliasReference;
   List<idl.LinkedNodeType> _genericTypeAliasTypeArguments;
   int _interfaceClass;
   List<idl.LinkedNodeType> _interfaceTypeArguments;
   idl.LinkedNodeTypeKind _kind;
-  int _typeParameterParameter;
+  int _typeParameterId;
 
   @override
   List<idl.LinkedNodeTypeFormalParameter> get functionFormalParameters {
@@ -19148,9 +19171,12 @@
   }
 
   @override
-  List<int> get functionTypeParameters {
+  List<idl.LinkedNodeTypeTypeParameter> get functionTypeParameters {
     _functionTypeParameters ??=
-        const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 2, const <int>[]);
+        const fb.ListReader<idl.LinkedNodeTypeTypeParameter>(
+                const _LinkedNodeTypeTypeParameterReader())
+            .vTableGet(
+                _bc, _bcOffset, 2, const <idl.LinkedNodeTypeTypeParameter>[]);
     return _functionTypeParameters;
   }
 
@@ -19191,10 +19217,10 @@
   }
 
   @override
-  int get typeParameterParameter {
-    _typeParameterParameter ??=
+  int get typeParameterId {
+    _typeParameterId ??=
         const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 6, 0);
-    return _typeParameterParameter;
+    return _typeParameterId;
   }
 }
 
@@ -19208,7 +19234,8 @@
     if (functionReturnType != null)
       _result["functionReturnType"] = functionReturnType.toJson();
     if (functionTypeParameters.isNotEmpty)
-      _result["functionTypeParameters"] = functionTypeParameters;
+      _result["functionTypeParameters"] =
+          functionTypeParameters.map((_value) => _value.toJson()).toList();
     if (genericTypeAliasReference != 0)
       _result["genericTypeAliasReference"] = genericTypeAliasReference;
     if (genericTypeAliasTypeArguments.isNotEmpty)
@@ -19221,8 +19248,7 @@
           interfaceTypeArguments.map((_value) => _value.toJson()).toList();
     if (kind != idl.LinkedNodeTypeKind.bottom)
       _result["kind"] = kind.toString().split('.')[1];
-    if (typeParameterParameter != 0)
-      _result["typeParameterParameter"] = typeParameterParameter;
+    if (typeParameterId != 0) _result["typeParameterId"] = typeParameterId;
     return _result;
   }
 
@@ -19236,7 +19262,7 @@
         "interfaceClass": interfaceClass,
         "interfaceTypeArguments": interfaceTypeArguments,
         "kind": kind,
-        "typeParameterParameter": typeParameterParameter,
+        "typeParameterId": typeParameterId,
       };
 
   @override
@@ -19381,6 +19407,116 @@
   String toString() => convert.json.encode(toJson());
 }
 
+class LinkedNodeTypeTypeParameterBuilder extends Object
+    with _LinkedNodeTypeTypeParameterMixin
+    implements idl.LinkedNodeTypeTypeParameter {
+  LinkedNodeTypeBuilder _bound;
+  String _name;
+
+  @override
+  LinkedNodeTypeBuilder get bound => _bound;
+
+  set bound(LinkedNodeTypeBuilder value) {
+    this._bound = value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  set name(String value) {
+    this._name = value;
+  }
+
+  LinkedNodeTypeTypeParameterBuilder({LinkedNodeTypeBuilder bound, String name})
+      : _bound = bound,
+        _name = name;
+
+  /// Flush [informative] data recursively.
+  void flushInformative() {
+    _bound?.flushInformative();
+  }
+
+  /// Accumulate non-[informative] data into [signature].
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    signature.addString(this._name ?? '');
+    signature.addBool(this._bound != null);
+    this._bound?.collectApiSignature(signature);
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_bound;
+    fb.Offset offset_name;
+    if (_bound != null) {
+      offset_bound = _bound.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (offset_bound != null) {
+      fbBuilder.addOffset(1, offset_bound);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _LinkedNodeTypeTypeParameterReader
+    extends fb.TableReader<_LinkedNodeTypeTypeParameterImpl> {
+  const _LinkedNodeTypeTypeParameterReader();
+
+  @override
+  _LinkedNodeTypeTypeParameterImpl createObject(
+          fb.BufferContext bc, int offset) =>
+      new _LinkedNodeTypeTypeParameterImpl(bc, offset);
+}
+
+class _LinkedNodeTypeTypeParameterImpl extends Object
+    with _LinkedNodeTypeTypeParameterMixin
+    implements idl.LinkedNodeTypeTypeParameter {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _LinkedNodeTypeTypeParameterImpl(this._bc, this._bcOffset);
+
+  idl.LinkedNodeType _bound;
+  String _name;
+
+  @override
+  idl.LinkedNodeType get bound {
+    _bound ??= const _LinkedNodeTypeReader().vTableGet(_bc, _bcOffset, 1, null);
+    return _bound;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 0, '');
+    return _name;
+  }
+}
+
+abstract class _LinkedNodeTypeTypeParameterMixin
+    implements idl.LinkedNodeTypeTypeParameter {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (bound != null) _result["bound"] = bound.toJson();
+    if (name != '') _result["name"] = name;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+        "bound": bound,
+        "name": name,
+      };
+
+  @override
+  String toString() => convert.json.encode(toJson());
+}
+
 class LinkedNodeUnitBuilder extends Object
     with _LinkedNodeUnitMixin
     implements idl.LinkedNodeUnit {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index bb86ffb..dea7ce6 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -406,8 +406,6 @@
 
   function,
 
-  genericTypeAlias,
-
   interface,
 
   typeParameter,
@@ -1945,8 +1943,7 @@
 
   functionReturnType:LinkedNodeType (id: 1);
 
-  /// References to [LinkedNodeReferences].
-  functionTypeParameters:[uint] (id: 2);
+  functionTypeParameters:[LinkedNodeTypeTypeParameter] (id: 2);
 
   genericTypeAliasReference:uint (id: 7);
 
@@ -1959,8 +1956,7 @@
 
   kind:LinkedNodeTypeKind (id: 5);
 
-  /// Reference to a [LinkedNodeReferences].
-  typeParameterParameter:uint (id: 6);
+  typeParameterId:uint (id: 6);
 }
 
 /// Information about a formal parameter in a function type.
@@ -1972,6 +1968,13 @@
   type:LinkedNodeType (id: 2);
 }
 
+/// Information about a type parameter in a function type.
+table LinkedNodeTypeTypeParameter {
+  bound:LinkedNodeType (id: 1);
+
+  name:string (id: 0);
+}
+
 /// Information about a single library in a [LinkedNodeLibrary].
 table LinkedNodeUnit {
   node:LinkedNode (id: 2);
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 4b897bc..033e6ff 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -2222,6 +2222,9 @@
   @VariantId(15, variant: LinkedNodeKind.typeParameter)
   int get typeParameter_extendsKeyword;
 
+  @VariantId(16, variant: LinkedNodeKind.typeParameter)
+  int get typeParameter_id;
+
   @VariantId(7, variant: LinkedNodeKind.typeParameter)
   LinkedNode get typeParameter_name;
 
@@ -2501,9 +2504,8 @@
   @Id(1)
   LinkedNodeType get functionReturnType;
 
-  /// References to [LinkedNodeReferences].
   @Id(2)
-  List<int> get functionTypeParameters;
+  List<LinkedNodeTypeTypeParameter> get functionTypeParameters;
 
   @Id(7)
   int get genericTypeAliasReference;
@@ -2521,9 +2523,8 @@
   @Id(5)
   LinkedNodeTypeKind get kind;
 
-  /// Reference to a [LinkedNodeReferences].
   @Id(6)
-  int get typeParameterParameter;
+  int get typeParameterId;
 }
 
 /// Information about a formal parameter in a function type.
@@ -2543,12 +2544,20 @@
   bottom,
   dynamic_,
   function,
-  genericTypeAlias,
   interface,
   typeParameter,
   void_
 }
 
+/// Information about a type parameter in a function type.
+abstract class LinkedNodeTypeTypeParameter extends base.SummaryClass {
+  @Id(1)
+  LinkedNodeType get bound;
+
+  @Id(0)
+  String get name;
+}
+
 /// Information about a single library in a [LinkedNodeLibrary].
 abstract class LinkedNodeUnit extends base.SummaryClass {
   @Id(2)
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index e08c4f6..b9cc2d1 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
@@ -240,7 +239,7 @@
       _getToken(data.classDeclaration_abstractKeyword),
       _getToken(data.classDeclaration_classKeyword),
       _readNode(data.namedCompilationUnitMember_name),
-      _readNodeLazy(data.classOrMixinDeclaration_typeParameters),
+      _readNode(data.classOrMixinDeclaration_typeParameters),
       _readNodeLazy(data.classDeclaration_extendsClause),
       _readNodeLazy(data.classDeclaration_withClause),
       _readNodeLazy(data.classOrMixinDeclaration_implementsClause),
@@ -259,7 +258,7 @@
       _readNodeListLazy(data.annotatedNode_metadata),
       _getToken(data.typeAlias_typedefKeyword),
       _readNode(data.namedCompilationUnitMember_name),
-      _readNodeLazy(data.classTypeAlias_typeParameters),
+      _readNode(data.classTypeAlias_typeParameters),
       _getToken(data.classTypeAlias_equals),
       _getToken(data.classTypeAlias_abstractKeyword),
       _readNodeLazy(data.classTypeAlias_superclass),
@@ -618,7 +617,7 @@
     _localParameters = thisLocalParameters;
 
     var node = astFactory.functionExpression(
-      _readNodeLazy(data.functionExpression_typeParameters),
+      _readNode(data.functionExpression_typeParameters),
       _readNodeLazy(data.functionExpression_formalParameters),
       _readNodeLazy(data.functionExpression_body),
     );
@@ -664,7 +663,7 @@
       _getToken(data.typeAlias_typedefKeyword),
       _readNodeLazy(data.functionTypeAlias_returnType),
       _readNode(data.namedCompilationUnitMember_name),
-      _readNodeLazy(data.functionTypeAlias_typeParameters),
+      _readNode(data.functionTypeAlias_typeParameters),
       _readNodeLazy(data.functionTypeAlias_formalParameters),
       _getToken(data.typeAlias_semicolon),
     );
@@ -705,7 +704,7 @@
     GenericFunctionTypeImpl node = astFactory.genericFunctionType(
       _readNodeLazy(data.genericFunctionType_returnType),
       _getToken(data.genericFunctionType_functionKeyword),
-      _readNodeLazy(data.genericFunctionType_typeParameters),
+      _readNode(data.genericFunctionType_typeParameters),
       _readNodeLazy(data.genericFunctionType_formalParameters),
       question: _getToken(data.genericFunctionType_question),
     );
@@ -720,7 +719,7 @@
       _readNodeList(data.annotatedNode_metadata),
       _getToken(data.typeAlias_typedefKeyword),
       _readNode(data.namedCompilationUnitMember_name),
-      _readNodeLazy(data.genericTypeAlias_typeParameters),
+      _readNode(data.genericTypeAlias_typeParameters),
       _getToken(data.genericTypeAlias_equals),
       _readNodeLazy(data.genericTypeAlias_functionType),
       _getToken(data.typeAlias_semicolon),
@@ -896,7 +895,7 @@
       _getToken(data.methodDeclaration_propertyKeyword),
       _getToken(data.methodDeclaration_operatorKeyword),
       _readNode(data.methodDeclaration_name),
-      _readNodeLazy(data.methodDeclaration_typeParameters),
+      _readNode(data.methodDeclaration_typeParameters),
       _readNodeLazy(data.methodDeclaration_formalParameters),
       _readNodeLazy(data.methodDeclaration_body),
     );
@@ -920,7 +919,7 @@
       _readNodeList(data.annotatedNode_metadata),
       _getToken(data.mixinDeclaration_mixinKeyword),
       _readNode(data.namedCompilationUnitMember_name),
-      _readNodeLazy(data.classOrMixinDeclaration_typeParameters),
+      _readNode(data.classOrMixinDeclaration_typeParameters),
       _readNodeLazy(data.mixinDeclaration_onClause),
       _readNodeLazy(data.classOrMixinDeclaration_implementsClause),
       _getToken(data.classOrMixinDeclaration_leftBracket),
@@ -1256,6 +1255,7 @@
       _readNodeLazy(data.typeParameter_bound),
     );
     LazyTypeParameter.setData(node, data);
+    _unitContext.addTypeParameter(data.typeParameter_id, node);
     return node;
   }
 
@@ -1588,57 +1588,6 @@
   }
 
   DartType _readType(LinkedNodeType data) {
-    if (data == null) return null;
-
-    switch (data.kind) {
-      case LinkedNodeTypeKind.bottom:
-        return BottomTypeImpl.instance;
-      case LinkedNodeTypeKind.dynamic_:
-        return DynamicTypeImpl.instance;
-      case LinkedNodeTypeKind.function:
-        return FunctionTypeImpl.synthetic(
-          _readType(data.functionReturnType),
-          _getElements(data.functionTypeParameters),
-          data.functionFormalParameters
-              .map((p) => ParameterElementImpl.synthetic(
-                  p.name, _readType(p.type), _formalParameterKind(p.kind)))
-              .toList(),
-        );
-      case LinkedNodeTypeKind.interface:
-        var element = _getElement(data.interfaceClass);
-        if (element != null) {
-          return InterfaceTypeImpl.explicit(
-            element,
-            _readTypes(
-              data.interfaceTypeArguments,
-              const <InterfaceType>[],
-            ),
-          );
-        }
-        return DynamicTypeImpl.instance;
-      case LinkedNodeTypeKind.typeParameter:
-        var element = _getElement(data.typeParameterParameter);
-        // TODO(scheglov) Remove when references include all type parameters.
-        element ??= TypeParameterElementImpl('', -1);
-        return TypeParameterTypeImpl(element);
-      case LinkedNodeTypeKind.void_:
-        return VoidTypeImpl.instance;
-      default:
-        throw UnimplementedError('Type kind: ${data.kind}');
-    }
-  }
-
-  List<T> _readTypes<T extends DartType>(
-    List<LinkedNodeType> dataList,
-    List<T> ifEmpty,
-  ) {
-    if (dataList.isEmpty) return ifEmpty;
-
-    var result = List<T>(dataList.length);
-    for (var i = 0; i < dataList.length; ++i) {
-      var data = dataList[i];
-      result[i] = _readType(data);
-    }
-    return result;
+    return _unitContext.readType(data);
   }
 }
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 0766c24..9f70a6b 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -8,8 +8,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
@@ -18,7 +16,7 @@
 
 /// Serializer of fully resolved ASTs into flat buffers.
 class AstBinaryWriter extends ThrowingAstVisitor<LinkedNodeBuilder> {
-  final LinkingBundleContext _linkingBundleContext;
+  final LinkingBundleContext _linkingContext;
   final TokensContext _tokensContext;
 
   /// This field is set temporary while visiting [FieldDeclaration] or
@@ -26,7 +24,7 @@
   /// in these declarations.
   LinkedNodeVariablesDeclarationBuilder _variablesDeclaration;
 
-  AstBinaryWriter(this._linkingBundleContext, this._tokensContext);
+  AstBinaryWriter(this._linkingContext, this._tokensContext);
 
   @override
   LinkedNodeBuilder visitAdjacentStrings(AdjacentStrings node) {
@@ -94,7 +92,7 @@
   @override
   LinkedNodeBuilder visitAssignmentExpression(AssignmentExpression node) {
     return LinkedNodeBuilder.assignmentExpression(
-      assignmentExpression_element: _getReferenceIndex(node.staticElement),
+      assignmentExpression_element: _indexOfElement(node.staticElement),
       assignmentExpression_leftHandSide: node.leftHandSide.accept(this),
       assignmentExpression_operator: _getToken(node.operator),
       assignmentExpression_rightHandSide: node.rightHandSide.accept(this),
@@ -114,7 +112,7 @@
   @override
   LinkedNodeBuilder visitBinaryExpression(BinaryExpression node) {
     return LinkedNodeBuilder.binaryExpression(
-      binaryExpression_element: _getReferenceIndex(node.staticElement),
+      binaryExpression_element: _indexOfElement(node.staticElement),
       binaryExpression_leftOperand: node.leftOperand.accept(this),
       binaryExpression_operator: _getToken(node.operator),
       binaryExpression_rightOperand: node.rightOperand.accept(this),
@@ -303,7 +301,7 @@
   @override
   LinkedNodeBuilder visitConstructorName(ConstructorName node) {
     return LinkedNodeBuilder.constructorName(
-      constructorName_element: _getReferenceIndex(node.staticElement),
+      constructorName_element: _indexOfElement(node.staticElement),
       constructorName_name: node.name?.accept(this),
       constructorName_period: _getToken(node.period),
       constructorName_type: node.type.accept(this),
@@ -695,7 +693,7 @@
   @override
   LinkedNodeBuilder visitIndexExpression(IndexExpression node) {
     return LinkedNodeBuilder.indexExpression(
-      indexExpression_element: _getReferenceIndex(node.staticElement),
+      indexExpression_element: _indexOfElement(node.staticElement),
       indexExpression_index: node.index.accept(this),
       indexExpression_leftBracket: _getToken(node.leftBracket),
       indexExpression_period: _getToken(node.period),
@@ -931,7 +929,7 @@
   LinkedNodeBuilder visitPostfixExpression(PostfixExpression node) {
     return LinkedNodeBuilder.postfixExpression(
       expression_type: _writeType(node.staticType),
-      postfixExpression_element: _getReferenceIndex(node.staticElement),
+      postfixExpression_element: _indexOfElement(node.staticElement),
       postfixExpression_operand: node.operand.accept(this),
       postfixExpression_operator: _getToken(node.operator),
     );
@@ -951,7 +949,7 @@
   LinkedNodeBuilder visitPrefixExpression(PrefixExpression node) {
     return LinkedNodeBuilder.prefixExpression(
       expression_type: _writeType(node.staticType),
-      prefixExpression_element: _getReferenceIndex(node.staticElement),
+      prefixExpression_element: _indexOfElement(node.staticElement),
       prefixExpression_operand: node.operand.accept(this),
       prefixExpression_operator: _getToken(node.operator),
     );
@@ -977,7 +975,7 @@
       redirectingConstructorInvocation_constructorName:
           node.constructorName?.accept(this),
       redirectingConstructorInvocation_element:
-          _getReferenceIndex(node.staticElement),
+          _indexOfElement(node.staticElement),
       redirectingConstructorInvocation_period: _getToken(node.period),
       redirectingConstructorInvocation_thisKeyword: _getToken(node.thisKeyword),
     );
@@ -1053,7 +1051,7 @@
     }
 
     return LinkedNodeBuilder.simpleIdentifier(
-      simpleIdentifier_element: _getReferenceIndex(element),
+      simpleIdentifier_element: _indexOfElement(element),
       simpleIdentifier_token: _getToken(node.token),
       expression_type: _writeType(node.staticType),
     );
@@ -1092,8 +1090,7 @@
       superConstructorInvocation_arguments: node.argumentList.accept(this),
       superConstructorInvocation_constructorName:
           node.constructorName?.accept(this),
-      superConstructorInvocation_element:
-          _getReferenceIndex(node.staticElement),
+      superConstructorInvocation_element: _indexOfElement(node.staticElement),
       superConstructorInvocation_period: _getToken(node.period),
       superConstructorInvocation_superKeyword: _getToken(node.superKeyword),
     );
@@ -1222,6 +1219,9 @@
         typeParameter_name: node.name.accept(this));
     _storeDeclaration(builder, node);
     _storeCodeOffsetLength(builder, node);
+    builder.typeParameter_id = _linkingContext.idOfTypeParameter(
+      node.declaredElement,
+    );
     return builder;
   }
 
@@ -1307,21 +1307,6 @@
     return node.accept(this);
   }
 
-  int _getReferenceIndex(Element element) {
-    if (element == null) return 0;
-
-    if (element is Member) {
-      element = (element as Member).baseElement;
-    }
-
-    var reference = (element as ElementImpl).reference;
-    if (identical(element, DynamicElementImpl.instance)) {
-      reference = _linkingBundleContext.dynamicReference;
-    }
-
-    return _linkingBundleContext.indexOfReference(reference);
-  }
-
   int _getToken(Token token) {
     return _tokensContext.indexOfToken(token);
   }
@@ -1335,6 +1320,10 @@
     return result;
   }
 
+  int _indexOfElement(Element element) {
+    return _linkingContext.indexOfElement(element);
+  }
+
   void _storeAnnotatedNode(LinkedNodeBuilder builder, AnnotatedNode node) {
     builder
       ..annotatedNode_comment = node.documentationComment?.accept(this)
@@ -1517,7 +1506,7 @@
     builder
       ..uriBasedDirective_uri = node.uri.accept(this)
       ..uriBasedDirective_uriContent = node.uriContent
-      ..uriBasedDirective_uriElement = _getReferenceIndex(node.uriElement);
+      ..uriBasedDirective_uriElement = _indexOfElement(node.uriElement);
   }
 
   void _writeActualReturnType(LinkedNodeBuilder builder, AstNode node) {
@@ -1545,6 +1534,6 @@
   }
 
   LinkedNodeTypeBuilder _writeType(DartType type) {
-    return _linkingBundleContext.writeType(type);
+    return _linkingContext.writeType(type);
   }
 }
diff --git a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart b/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
index 7339358..f320371 100644
--- a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
@@ -299,6 +299,7 @@
       var unitRef = reference.getChild('@unit');
       var unitReference = unitRef.getChild(unitContext.uriStr);
       var resolver = ReferenceResolver(
+        linker.linkingBundleContext,
         nodesToBuildType,
         linker.elementFactory,
         element,
diff --git a/pkg/analyzer/lib/src/summary2/lazy_ast.dart b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
index 21076aa..9c7c1cc 100644
--- a/pkg/analyzer/lib/src/summary2/lazy_ast.dart
+++ b/pkg/analyzer/lib/src/summary2/lazy_ast.dart
@@ -45,7 +45,6 @@
   bool _hasImplementsClause = false;
   bool _hasMembers = false;
   bool _hasMetadata = false;
-  bool _hasTypeParameters = false;
   bool _hasWithClause = false;
 
   LazyClassDeclaration(this.data);
@@ -123,19 +122,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    ClassDeclaration node,
-  ) {
-    var lazy = LazyClassDeclaration.get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.classOrMixinDeclaration_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void readWithClause(
     AstBinaryReader reader,
     ClassDeclaration node,
@@ -163,7 +149,6 @@
   bool _hasImplementsClause = false;
   bool _hasMetadata = false;
   bool _hasSuperclass = false;
-  bool _hasTypeParameters = false;
   bool _hasWithClause = false;
 
   LazyClassTypeAlias(this.data);
@@ -228,19 +213,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    ClassTypeAlias node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.classTypeAlias_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void readWithClause(
     AstBinaryReader reader,
     ClassTypeAlias node,
@@ -635,6 +607,7 @@
     AstBinaryReader reader,
     FunctionDeclaration node,
   ) {
+    readFunctionExpression(reader, node);
     if (reader.isLazy) {
       var lazy = get(node);
       if (!lazy._hasReturnType) {
@@ -698,7 +671,6 @@
 
   bool _hasBody = false;
   bool _hasFormalParameters = false;
-  bool _hasTypeParameters = false;
 
   LazyFunctionExpression(this.data);
 
@@ -732,19 +704,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    FunctionExpression node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.functionExpression_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void setData(FunctionExpression node, LinkedNode data) {
     node.setProperty(_key, LazyFunctionExpression(data));
   }
@@ -759,7 +718,6 @@
   bool _hasFormalParameters = false;
   bool _hasMetadata = false;
   bool _hasReturnType = false;
-  bool _hasTypeParameters = false;
 
   LazyFunctionTypeAlias(this.data);
 
@@ -823,19 +781,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    FunctionTypeAlias node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.functionTypeAlias_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void setData(FunctionTypeAlias node, LinkedNode data) {
     node.setProperty(_key, LazyFunctionTypeAlias(data));
   }
@@ -895,7 +840,6 @@
 
   bool _hasDocumentationComment = false;
   bool _hasFunction = false;
-  bool _hasTypeParameters = false;
 
   LazyGenericTypeAlias(this.data);
 
@@ -929,19 +873,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    GenericTypeAlias node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.genericTypeAlias_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void setData(GenericTypeAlias node, LinkedNode data) {
     node.setProperty(_key, LazyGenericTypeAlias(data));
   }
@@ -957,7 +888,6 @@
   bool _hasFormalParameters = false;
   bool _hasMetadata = false;
   bool _hasReturnType = false;
-  bool _hasTypeParameters = false;
 
   LazyMethodDeclaration(this.data);
 
@@ -1034,19 +964,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    MethodDeclaration node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.methodDeclaration_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void setData(MethodDeclaration node, LinkedNode data) {
     node.setProperty(_key, LazyMethodDeclaration(data));
   }
@@ -1061,7 +978,6 @@
   bool _hasOnClause = false;
   bool _hasImplementsClause = false;
   bool _hasMembers = false;
-  bool _hasTypeParameters = false;
 
   LazyMixinDeclaration(this.data);
 
@@ -1123,19 +1039,6 @@
     }
   }
 
-  static void readTypeParameters(
-    AstBinaryReader reader,
-    MixinDeclarationImpl node,
-  ) {
-    var lazy = get(node);
-    if (lazy != null && !lazy._hasTypeParameters) {
-      node.typeParameters = reader.readNode(
-        lazy.data.classOrMixinDeclaration_typeParameters,
-      );
-      lazy._hasTypeParameters = true;
-    }
-  }
-
   static void setData(MixinDeclaration node, LinkedNode data) {
     node.setProperty(_key, LazyMixinDeclaration(data));
   }
diff --git a/pkg/analyzer/lib/src/summary2/linked_bundle_context.dart b/pkg/analyzer/lib/src/summary2/linked_bundle_context.dart
index 88f8655..f81e2c4 100644
--- a/pkg/analyzer/lib/src/summary2/linked_bundle_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_bundle_context.dart
@@ -82,52 +82,6 @@
     return result;
   }
 
-  InterfaceType getInterfaceType(LinkedNodeType linkedType) {
-    var type = getType(linkedType);
-    if (type is InterfaceType && !type.element.isEnum) {
-      return type;
-    }
-    return null;
-  }
-
-  DartType getType(LinkedNodeType linkedType) {
-    var kind = linkedType.kind;
-    if (kind == LinkedNodeTypeKind.dynamic_) {
-      return DynamicTypeImpl.instance;
-    } else if (kind == LinkedNodeTypeKind.genericTypeAlias) {
-      var reference = referenceOfIndex(linkedType.genericTypeAliasReference);
-      return GenericTypeAliasElementImpl.typeAfterSubstitution(
-        elementFactory.elementOfReference(reference),
-        linkedType.genericTypeAliasTypeArguments.map(getType).toList(),
-      );
-    } else if (kind == LinkedNodeTypeKind.function) {
-      var returnType = getType(linkedType.functionReturnType);
-      var formalParameters = linkedType.functionFormalParameters.map((p) {
-        return ParameterElementImpl.synthetic(
-          p.name,
-          getType(p.type),
-          _formalParameterKind(p.kind),
-        );
-      }).toList();
-      return FunctionElementImpl.synthetic(formalParameters, returnType).type;
-    } else if (kind == LinkedNodeTypeKind.interface) {
-      var reference = referenceOfIndex(linkedType.interfaceClass);
-      Element element = elementFactory.elementOfReference(reference);
-      return InterfaceTypeImpl.explicit(
-        element,
-        linkedType.interfaceTypeArguments.map(getType).toList(),
-      );
-    } else if (kind == LinkedNodeTypeKind.typeParameter) {
-      var reference = referenceOfIndex(linkedType.typeParameterParameter);
-      Element element = elementFactory.elementOfReference(reference);
-      return TypeParameterTypeImpl(element);
-    } else if (kind == LinkedNodeTypeKind.void_) {
-      return VoidTypeImpl.instance;
-    } else {
-      throw UnimplementedError('$kind');
-    }
-  }
-
   Reference referenceOfIndex(int index) {
     var reference = _references[index];
     if (reference != null) return reference;
@@ -147,16 +101,6 @@
 
     return reference;
   }
-
-  ParameterKind _formalParameterKind(LinkedNodeFormalParameterKind kind) {
-    if (kind == LinkedNodeFormalParameterKind.optionalNamed) {
-      return ParameterKind.NAMED;
-    }
-    if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
-      return ParameterKind.POSITIONAL;
-    }
-    return ParameterKind.REQUIRED;
-  }
 }
 
 class LinkedLibraryContext {
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index e16238f..88344cb 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -152,11 +152,6 @@
       return _typeAlias(unit, reference);
     }
 
-    if (parentName == '@typeParameter') {
-      var enclosing = elementOfReference(parent2) as TypeParameterizedElement;
-      return _typeParameter(enclosing, reference);
-    }
-
     if (parentName == '@unit') {
       elementOfReference(parent2);
       // Creating a library fills all its units.
@@ -296,14 +291,6 @@
     return reference.element;
   }
 
-  Element _typeParameter(
-      TypeParameterizedElement enclosing, Reference reference) {
-    enclosing.typeParameters;
-    // Requesting type parameters sets elements for all their references.
-    assert(reference.element != null);
-    return reference.element;
-  }
-
   /// Index nodes for which we choose to create elements individually,
   /// for example [ClassDeclaration], so that its [Reference] has the node,
   /// and we can call the [ClassElementImpl] constructor.
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 4d82d2d..8a906fe 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -27,6 +29,17 @@
   CompilationUnit _unit;
   bool _hasDirectivesRead = false;
 
+  /// Mapping from identifiers to real or synthetic type parameters.
+  ///
+  /// Real type parameters have corresponding [TypeParameter] nodes, and are
+  /// referenced from other AST nodes.
+  ///
+  /// Synthetic type parameters are added when [readType] begins reading a
+  /// [FunctionType], and removed when reading is done.
+  final Map<int, TypeParameterElement> _typeParameters = {};
+
+  int _nextSyntheticTypeParameterId = 0x10000;
+
   LinkedUnitContext(this.bundleContext, this.libraryContext,
       this.indexInLibrary, this.uriStr, this.data,
       {CompilationUnit unit})
@@ -59,6 +72,15 @@
     return _unit;
   }
 
+  /// Every [TypeParameter] node has [TypeParameterElement], which is created
+  /// during reading of this node. All type parameter nodes are read before
+  /// any nodes that reference them (bounds are read lazily later).
+  void addTypeParameter(int id, TypeParameter node) {
+    var element = TypeParameterElementImpl.forLinkedNode(null, null, node);
+    _typeParameters[id] = element;
+    node.name.staticElement = element;
+  }
+
   /// Return the absolute URI referenced in the [directive].
   Uri directiveUri(Uri libraryUri, UriBasedDirective directive) {
     var relativeUriStr = directive.uri.stringValue;
@@ -269,7 +291,11 @@
   }
 
   InterfaceType getInterfaceType(LinkedNodeType linkedType) {
-    return bundleContext.getInterfaceType(linkedType);
+    var type = readType(linkedType);
+    if (type is InterfaceType && !type.element.isEnum) {
+      return type;
+    }
+    return null;
   }
 
   List<Annotation> getLibraryMetadata(CompilationUnit unit) {
@@ -460,10 +486,8 @@
 
   TypeParameterList getTypeParameters2(AstNode node) {
     if (node is ClassDeclaration) {
-      LazyClassDeclaration.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is ClassTypeAlias) {
-      LazyClassTypeAlias.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is ConstructorDeclaration) {
       return null;
@@ -471,21 +495,16 @@
       LazyFunctionDeclaration.readFunctionExpression(_astReader, node);
       return getTypeParameters2(node.functionExpression);
     } else if (node is FunctionExpression) {
-      LazyFunctionExpression.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is FunctionTypeAlias) {
-      LazyFunctionTypeAlias.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is GenericFunctionType) {
       return node.typeParameters;
     } else if (node is GenericTypeAlias) {
-      LazyGenericTypeAlias.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is MethodDeclaration) {
-      LazyMethodDeclaration.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else if (node is MixinDeclaration) {
-      LazyMixinDeclaration.readTypeParameters(_astReader, node);
       return node.typeParameters;
     } else {
       throw UnimplementedError('${node.runtimeType}');
@@ -671,6 +690,58 @@
     return _astReader.readNode(linkedNode);
   }
 
+  DartType readType(LinkedNodeType linkedType) {
+    if (linkedType == null) return null;
+
+    var kind = linkedType.kind;
+    if (kind == LinkedNodeTypeKind.bottom) {
+      return BottomTypeImpl.instance;
+    } else if (kind == LinkedNodeTypeKind.dynamic_) {
+      return DynamicTypeImpl.instance;
+    } else if (kind == LinkedNodeTypeKind.function) {
+      var typeParameterDataList = linkedType.functionTypeParameters;
+
+      var typeParameters = <TypeParameterElement>[];
+      for (var typeParameterData in typeParameterDataList) {
+        var element = TypeParameterElementImpl(typeParameterData.name, -1);
+        typeParameters.add(element);
+        _typeParameters[_nextSyntheticTypeParameterId++] = element;
+      }
+
+      var returnType = readType(linkedType.functionReturnType);
+      var formalParameters = linkedType.functionFormalParameters.map((p) {
+        var type = readType(p.type);
+        var kind = _formalParameterKind(p.kind);
+        return ParameterElementImpl.synthetic(p.name, type, kind);
+      }).toList();
+
+      for (var i = 0; i < typeParameterDataList.length; ++i) {
+        _typeParameters.remove(--_nextSyntheticTypeParameterId);
+      }
+
+      return FunctionTypeImpl.synthetic(
+        returnType,
+        typeParameters,
+        formalParameters,
+      );
+    } else if (kind == LinkedNodeTypeKind.interface) {
+      var element = bundleContext.elementOfIndex(linkedType.interfaceClass);
+      return InterfaceTypeImpl.explicit(
+        element,
+        linkedType.interfaceTypeArguments.map(readType).toList(),
+      );
+    } else if (kind == LinkedNodeTypeKind.typeParameter) {
+      var id = linkedType.typeParameterId;
+      var element = _typeParameters[id];
+      assert(element != null);
+      return TypeParameterTypeImpl(element);
+    } else if (kind == LinkedNodeTypeKind.void_) {
+      return VoidTypeImpl.instance;
+    } else {
+      throw UnimplementedError('$kind');
+    }
+  }
+
   void setReturnType(LinkedNodeBuilder node, DartType type) {
     throw UnimplementedError();
 //    var typeData = bundleContext.linking.writeType(type);
@@ -693,6 +764,16 @@
     }
   }
 
+  ParameterKind _formalParameterKind(LinkedNodeFormalParameterKind kind) {
+    if (kind == LinkedNodeFormalParameterKind.optionalNamed) {
+      return ParameterKind.NAMED;
+    }
+    if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
+      return ParameterKind.POSITIONAL;
+    }
+    return ParameterKind.REQUIRED;
+  }
+
   List<ClassMember> _getClassOrMixinMembers(ClassOrMixinDeclaration node) {
     if (node is ClassDeclaration) {
       LazyClassDeclaration.readMembers(_astReader, node);
diff --git a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
index 6a9fc44..06d86ce 100644
--- a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
@@ -5,7 +5,9 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -28,8 +30,35 @@
     name: [''],
   );
 
+  final Map<TypeParameterElement, int> _typeParameters = Map.identity();
+  int _nextTypeParameterId = 1;
+  int _nextSyntheticTypeParameterId = 0x10000;
+
   LinkingBundleContext(this.dynamicReference);
 
+  void addTypeParameter(TypeParameterElement element) {
+    _typeParameters[element] = _nextTypeParameterId++;
+  }
+
+  int idOfTypeParameter(TypeParameterElement element) {
+    return _typeParameters[element];
+  }
+
+  int indexOfElement(Element element) {
+    if (element == null) return 0;
+
+    if (identical(element, DynamicElementImpl.instance)) {
+      return indexOfReference(dynamicReference);
+    }
+
+    if (element is Member) {
+      element = (element as Member).baseElement;
+    }
+
+    var reference = (element as ElementImpl).reference;
+    return indexOfReference(reference);
+  }
+
   int indexOfReference(Reference reference) {
     if (reference == null) return 0;
     if (reference.parent == null) return 0;
@@ -56,29 +85,18 @@
         kind: LinkedNodeTypeKind.dynamic_,
       );
     } else if (type is FunctionType) {
-      return LinkedNodeTypeBuilder(
-        kind: LinkedNodeTypeKind.function,
-        functionFormalParameters: type.parameters
-            .map((p) => LinkedNodeTypeFormalParameterBuilder(
-                  // ignore: deprecated_member_use_from_same_package
-                  kind: _formalParameterKind(p.parameterKind),
-                  name: p.name,
-                  type: writeType(p.type),
-                ))
-            .toList(),
-        functionReturnType: writeType(type.returnType),
-        functionTypeParameters: _getReferences(type.typeParameters),
-      );
+      return _writeFunctionType(type);
     } else if (type is InterfaceType) {
       return LinkedNodeTypeBuilder(
         kind: LinkedNodeTypeKind.interface,
-        interfaceClass: _getReferenceIndex(type.element),
+        interfaceClass: indexOfElement(type.element),
         interfaceTypeArguments: type.typeArguments.map(writeType).toList(),
       );
     } else if (type is TypeParameterType) {
+      TypeParameterElementImpl element = type.element;
       return LinkedNodeTypeBuilder(
         kind: LinkedNodeTypeKind.typeParameter,
-        typeParameterParameter: _getReferenceIndex(type.element),
+        typeParameterId: _typeParameters[element],
       );
     } else if (type is VoidType) {
       return LinkedNodeTypeBuilder(
@@ -89,7 +107,9 @@
     }
   }
 
-  LinkedNodeFormalParameterKind _formalParameterKind(ParameterKind kind) {
+  LinkedNodeFormalParameterKind _formalParameterKind(ParameterElement p) {
+    // ignore: deprecated_member_use_from_same_package
+    var kind = p.parameterKind;
     if (kind == ParameterKind.NAMED) {
       return LinkedNodeFormalParameterKind.optionalNamed;
     }
@@ -99,19 +119,57 @@
     return LinkedNodeFormalParameterKind.required;
   }
 
-  int _getReferenceIndex(Element element) {
-    if (element == null) return 0;
+  FunctionType _toSyntheticFunctionType(FunctionType type) {
+    var typeParameters = type.typeFormals;
 
-    var reference = (element as ElementImpl).reference;
-    return indexOfReference(reference);
+    if (typeParameters.isEmpty) return type;
+
+    var onlySyntheticTypeParameters = typeParameters.every((e) {
+      return e is TypeParameterElementImpl && e.linkedNode == null;
+    });
+    if (onlySyntheticTypeParameters) return type;
+
+    var parameters = getFreshTypeParameters(typeParameters);
+    return parameters.applyToFunctionType(type);
   }
 
-  List<int> _getReferences(List<Element> elements) {
-    var result = List<int>(elements.length);
-    for (var i = 0; i < elements.length; ++i) {
-      var element = elements[i];
-      result[i] = _getReferenceIndex(element);
+  LinkedNodeTypeBuilder _writeFunctionType(FunctionType type) {
+    type = _toSyntheticFunctionType(type);
+
+    var typeParameterBuilders = <LinkedNodeTypeTypeParameterBuilder>[];
+
+    var typeParameters = type.typeFormals;
+    for (var i = 0; i < typeParameters.length; ++i) {
+      var typeParameter = typeParameters[i];
+      _typeParameters[typeParameter] = _nextSyntheticTypeParameterId++;
+      typeParameterBuilders.add(
+        LinkedNodeTypeTypeParameterBuilder(name: typeParameter.name),
+      );
     }
+
+    for (var i = 0; i < typeParameters.length; ++i) {
+      var typeParameter = typeParameters[i];
+      typeParameterBuilders[i].bound = writeType(typeParameter.bound);
+    }
+
+    var result = LinkedNodeTypeBuilder(
+      kind: LinkedNodeTypeKind.function,
+      functionFormalParameters: type.parameters
+          .map((p) => LinkedNodeTypeFormalParameterBuilder(
+                kind: _formalParameterKind(p),
+                name: p.name,
+                type: writeType(p.type),
+              ))
+          .toList(),
+      functionReturnType: writeType(type.returnType),
+      functionTypeParameters: typeParameterBuilders,
+    );
+
+    for (var typeParameter in typeParameters) {
+      _typeParameters.remove(typeParameter);
+      --_nextSyntheticTypeParameterId;
+    }
+
     return result;
   }
 }
diff --git a/pkg/analyzer/lib/src/summary2/reference.dart b/pkg/analyzer/lib/src/summary2/reference.dart
index 7f8af39..989ab17 100644
--- a/pkg/analyzer/lib/src/summary2/reference.dart
+++ b/pkg/analyzer/lib/src/summary2/reference.dart
@@ -71,8 +71,6 @@
 
   bool get isTypeAlias => parent != null && parent.name == '@typeAlias';
 
-  bool get isTypeParameter => parent != null && parent.name == '@typeParameter';
-
   int get numOfChildren => _children != null ? _children.length : 0;
 
   /// Return the child with the given name, or `null` if does not exist.
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 28bb335..ddf9870 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/linked_element_factory.dart';
+import 'package:analyzer/src/summary2/linking_bundle_context.dart';
 import 'package:analyzer/src/summary2/linking_node_scope.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/summary2/type_builder.dart';
@@ -510,6 +511,7 @@
 /// the type is set, otherwise we keep it empty, so we will attempt to infer
 /// it later).
 class ReferenceResolver extends ThrowingAstVisitor<void> {
+  final LinkingBundleContext linkingContext;
   final NodesToBuildType nodesToBuildType;
   final LinkedElementFactory elementFactory;
   final LibraryElement _libraryElement;
@@ -518,6 +520,7 @@
   Scope scope;
 
   ReferenceResolver(
+    this.linkingContext,
     this.nodesToBuildType,
     this.elementFactory,
     this._libraryElement,
@@ -536,6 +539,7 @@
     var name = node.name.name;
     reference = reference.getChild('@class').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = ClassElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -564,6 +568,7 @@
     var name = node.name.name;
     reference = reference.getChild('@class').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = ClassElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -654,6 +659,7 @@
     var name = node.name.name;
     reference = reference.getChild('@function').getChild(name);
 
+    _createTypeParameterElements(node.functionExpression.typeParameters);
     var element = FunctionElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -685,6 +691,7 @@
     var name = node.name.name;
     reference = reference.getChild('@typeAlias').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = GenericTypeAliasElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -719,6 +726,7 @@
     var name = '${outerReference.numOfChildren}';
     reference = reference.getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = GenericFunctionTypeElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -744,6 +752,7 @@
     var name = node.name.name;
     reference = reference.getChild('@typeAlias').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = GenericTypeAliasElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -772,6 +781,7 @@
     var name = node.name.name;
     reference = reference.getChild('@method').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = MethodElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -798,6 +808,7 @@
     var name = node.name.name;
     reference = reference.getChild('@class').getChild(name);
 
+    _createTypeParameterElements(node.typeParameters);
     var element = ClassElementImpl.forLinkedNode(
       outerReference.element,
       reference,
@@ -879,4 +890,18 @@
   void visitWithClause(WithClause node) {
     node.mixinTypes.accept(this);
   }
+
+  void _createTypeParameterElement(TypeParameter node) {
+    var element = TypeParameterElementImpl.forLinkedNode(null, null, node);
+    node.name.staticElement = element;
+    linkingContext.addTypeParameter(element);
+  }
+
+  void _createTypeParameterElements(TypeParameterList typeParameterList) {
+    if (typeParameterList == null) return;
+
+    for (var typeParameter in typeParameterList.typeParameters) {
+      _createTypeParameterElement(typeParameter);
+    }
+  }
 }
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index 13a6dc4..b92d04b 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -231,9 +231,9 @@
       var element = TypeBuilder.typeNameElementIndex(type.typeName_name);
       var reference = _walker.bundleContext.referenceOfIndex(element);
 
-      if (reference.isTypeParameter) {
-        return allowTypeParameters;
-      }
+//      if (reference.isTypeParameter) {
+//        return allowTypeParameters;
+//      }
 
       var arguments = type.typeName_typeArguments;
       if (arguments == null) {
diff --git a/pkg/analyzer/lib/src/summary2/type_builder.dart b/pkg/analyzer/lib/src/summary2/type_builder.dart
index 3588181..7093935 100644
--- a/pkg/analyzer/lib/src/summary2/type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/type_builder.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
@@ -70,21 +69,28 @@
     }
   }
 
-  DartType _buildFunctionType(
+  FunctionType _buildFunctionType(
+    TypeParameterList typeParameterList,
     TypeAnnotation returnTypeNode,
     FormalParameterList parameterList,
   ) {
     var returnType = returnTypeNode?.type ?? _dynamicType;
 
-    // TODO(scheglov) type parameters
-    var typeParameters = const <TypeParameterElement>[];
+    List<TypeParameterElement> typeParameters;
+    if (typeParameterList != null) {
+      typeParameters = typeParameterList.typeParameters
+          .map<TypeParameterElement>((p) => p.declaredElement)
+          .toList();
+    } else {
+      typeParameters = const <TypeParameterElement>[];
+    }
 
-    var formalParameters = parameterList.parameters.map((p) {
-      // TODO(scheglov) other types and kinds
+    var formalParameters = parameterList.parameters.map((parameter) {
       return ParameterElementImpl.synthetic(
-        (p as SimpleFormalParameter).identifier.name,
-        LazyAst.getType(p),
-        ParameterKind.REQUIRED,
+        parameter.identifier.name,
+        LazyAst.getType(parameter),
+        // ignore: deprecated_member_use_from_same_package
+        parameter.kind,
       );
     }).toList();
 
@@ -96,8 +102,11 @@
   }
 
   void _buildGenericFunctionType(GenericFunctionTypeImpl node) {
-    // TODO(scheglov) Type parameters?
-    node.type = _buildFunctionType(node.returnType, node.parameters);
+    node.type = _buildFunctionType(
+      node.typeParameters,
+      node.returnType,
+      node.parameters,
+    );
   }
 
   void _buildTypeName(TypeName node) {
@@ -214,7 +223,11 @@
   void _fieldFormalParameter(FieldFormalParameter node) {
     var parameterList = node.parameters;
     if (parameterList != null) {
-      var type = _buildFunctionType(node.type, parameterList);
+      var type = _buildFunctionType(
+        node.typeParameters,
+        node.type,
+        parameterList,
+      );
       LazyAst.setType(node, type);
     } else {
       LazyAst.setType(node, node.type?.type ?? _dynamicType);
@@ -222,7 +235,11 @@
   }
 
   void _functionTypedFormalParameter(FunctionTypedFormalParameter node) {
-    var type = _buildFunctionType(node.returnType, node.parameters);
+    var type = _buildFunctionType(
+      node.typeParameters,
+      node.returnType,
+      node.parameters,
+    );
     LazyAst.setType(node, type);
   }
 
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 313fe5d..3be71f3 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -308,12 +308,6 @@
 
   @override
   @failingTest
-  test_const_reference_topLevelFunction_generic() async {
-    await super.test_const_reference_topLevelFunction_generic();
-  }
-
-  @override
-  @failingTest
   test_const_reference_topLevelVariable_imported() async {
     await super.test_const_reference_topLevelVariable_imported();
   }
@@ -514,12 +508,6 @@
 
   @override
   @failingTest
-  test_infer_generic_typedef_simple() async {
-    await super.test_infer_generic_typedef_simple();
-  }
-
-  @override
-  @failingTest
   test_inference_issue_32394() async {
     await super.test_inference_issue_32394();
   }
@@ -850,12 +838,6 @@
 
   @override
   @failingTest
-  test_typedef_generic_asFieldType() async {
-    await super.test_typedef_generic_asFieldType();
-  }
-
-  @override
-  @failingTest
   test_typedef_notSimplyBounded_dependency_via_param_type_new_style_name_included() async {
     await super
         .test_typedef_notSimplyBounded_dependency_via_param_type_new_style_name_included();
@@ -945,12 +927,6 @@
 
   @override
   @failingTest
-  test_unused_type_parameter() async {
-    await super.test_unused_type_parameter();
-  }
-
-  @override
-  @failingTest
   test_variable_propagatedType_final_dep_inLib() async {
     await super.test_variable_propagatedType_final_dep_inLib();
   }