Replace nestingLevel with a more direct computation of De Bruijn indices.

Not all of the TypeParameterElementImpl constructors were setting it
anyway, and this was causing problems with one-phase summary
generation.  It would have taken a lot of plumbing to make all the
constructors set it correctly; it's easier to just compute it on the
fly when we need it.

Change-Id: I99d2e79c98a8a1dfbfb4e7f1fe90490db779a955
Reviewed-on: https://dart-review.googlesource.com/74672
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index b1b7397..af11f5a 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -8509,16 +8509,6 @@
   final UnlinkedTypeParam _unlinkedTypeParam;
 
   /**
-   * The number of type parameters whose scope overlaps this one, and which are
-   * declared earlier in the file.
-   *
-   * If the value is negative, then it represents negated De Bruijn index.
-   *
-   * TODO(scheglov) make private?
-   */
-  final int nestingLevel;
-
-  /**
    * The type defined by this type parameter.
    */
   TypeParameterType _type;
@@ -8535,7 +8525,6 @@
    */
   TypeParameterElementImpl(String name, int offset)
       : _unlinkedTypeParam = null,
-        nestingLevel = null,
         super(name, offset);
 
   /**
@@ -8543,21 +8532,20 @@
    */
   TypeParameterElementImpl.forNode(Identifier name)
       : _unlinkedTypeParam = null,
-        nestingLevel = null,
         super.forNode(name);
 
   /**
    * Initialize using the given serialized information.
    */
-  TypeParameterElementImpl.forSerialized(this._unlinkedTypeParam,
-      TypeParameterizedElementMixin enclosingElement, this.nestingLevel)
+  TypeParameterElementImpl.forSerialized(
+      this._unlinkedTypeParam, TypeParameterizedElementMixin enclosingElement)
       : super.forSerialized(enclosingElement);
 
   /**
    * Initialize a newly created synthetic type parameter element to have the
    * given [name], and with [synthetic] set to true.
    */
-  TypeParameterElementImpl.synthetic(String name, {this.nestingLevel})
+  TypeParameterElementImpl.synthetic(String name)
       : _unlinkedTypeParam = null,
         super(name, -1) {
     isSynthetic = true;
@@ -8661,12 +8649,6 @@
 abstract class TypeParameterizedElementMixin
     implements TypeParameterizedElement, ElementImpl {
   /**
-   * The cached number of type parameters that are in scope in this context, or
-   * `null` if the number has not yet been computed.
-   */
-  int _nestingLevel;
-
-  /**
    * A cached list containing the type parameters declared by this element
    * directly, or `null` if the elements have not been created yet. This does
    * not include type parameters that are declared by any enclosing elements.
@@ -8723,27 +8705,18 @@
   @override
   TypeParameterizedElementMixin get typeParameterContext => this;
 
-  /**
-   * Find out how many type parameters are in scope in this context.
-   */
-  int get typeParameterNestingLevel =>
-      _nestingLevel ??= (unlinkedTypeParams?.length ?? 0) +
-          (enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0);
-
   @override
   List<TypeParameterElement> get typeParameters {
     if (_typeParameterElements == null) {
       List<UnlinkedTypeParam> unlinkedParams = unlinkedTypeParams;
       if (unlinkedParams != null) {
-        int enclosingNestingLevel =
-            enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
         int numTypeParameters = unlinkedParams.length;
         _typeParameterElements =
             new List<TypeParameterElement>(numTypeParameters);
         for (int i = 0; i < numTypeParameters; i++) {
           _typeParameterElements[i] =
               new TypeParameterElementImpl.forSerialized(
-                  unlinkedParams[i], this, enclosingNestingLevel + i);
+                  unlinkedParams[i], this);
         }
       }
     }
@@ -8786,16 +8759,22 @@
   }
 
   /**
-   * Find out if the given [typeParameter] is in scope in this context.
+   * Return the given [typeParameter]'s de Bruijn index in this context, or
+   * `null` if it's not in scope.
+   *
+   * If an [offset] is provided, then it is added to the computed index.
    */
-  bool isTypeParameterInScope(TypeParameterElement typeParameter) {
+  int computeDeBruijnIndex(TypeParameterElement typeParameter,
+      {int offset = 0}) {
     if (typeParameter.enclosingElement == this) {
-      return true;
+      var index = typeParameters.indexOf(typeParameter);
+      assert(index >= 0);
+      return typeParameters.length - index + offset;
     } else if (enclosingTypeParameterContext != null) {
-      return enclosingTypeParameterContext
-          .isTypeParameterInScope(typeParameter);
+      return enclosingTypeParameterContext.computeDeBruijnIndex(typeParameter,
+          offset: offset + typeParameters.length);
     } else {
-      return false;
+      return null;
     }
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 5463609..7259bf9 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -403,13 +403,8 @@
     for (int i = 0; i < formalCount; i++) {
       var typeParamElement = originalFormals[i];
 
-      // We don't know in which context the fresh function type will be used.
-      // So, we can only compute De Bruijn index for type parameters.
-      int negativeDeBruijnIndex = -(formalCount - i);
-
-      var freshElement = new TypeParameterElementImpl.synthetic(
-          typeParamElement.name,
-          nestingLevel: negativeDeBruijnIndex);
+      var freshElement =
+          new TypeParameterElementImpl.synthetic(typeParamElement.name);
       var freshTypeVar = new TypeParameterTypeImpl(freshElement);
       freshElement.type = freshTypeVar;
 
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 14966b9..4fdd614 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -171,15 +171,9 @@
     return result;
   } else if (type is TypeParameterType) {
     TypeParameterElementImpl element = type.element;
-    if (typeParameterContext != null &&
-        typeParameterContext.isTypeParameterInScope(element)) {
-      var nestingLevel = element.nestingLevel;
-      if (nestingLevel < 0) {
-        result.paramReference = -nestingLevel;
-      } else {
-        result.paramReference =
-            typeParameterContext.typeParameterNestingLevel - nestingLevel;
-      }
+    var deBruijnIndex = typeParameterContext?.computeDeBruijnIndex(element);
+    if (deBruijnIndex != null) {
+      result.paramReference = deBruijnIndex;
     } else {
       throw new StateError('The type parameter $type (in ${element?.location}) '
           'is out of scope on ${typeParameterContext?.location}.');
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index 12b8e8c..9568a0b 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -893,36 +893,36 @@
     expect(x.variable.isStatic, true);
   }
 
-  void test_typeParameter_isTypeParameterInScope_direct() {
+  void test_typeParameter_computeDeBruijnIndex_direct() {
     createLinker('class C<T, U> {}');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     TypeParameterElementImpl t = c.typeParameters[0];
     TypeParameterElementImpl u = c.typeParameters[1];
-    expect(c.isTypeParameterInScope(t), true);
-    expect(c.isTypeParameterInScope(u), true);
+    expect(c.computeDeBruijnIndex(t), 2);
+    expect(c.computeDeBruijnIndex(u), 1);
   }
 
-  void test_typeParameter_isTypeParameterInScope_indirect() {
+  void test_typeParameter_computeDeBruijnIndex_indirect() {
     createLinker('class C<T, U> { f<V, W>() {} }');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     MethodElementForLink f = c.methods[0];
     TypeParameterElementImpl t = c.typeParameters[0];
     TypeParameterElementImpl u = c.typeParameters[1];
-    expect(f.isTypeParameterInScope(t), true);
-    expect(f.isTypeParameterInScope(u), true);
+    expect(f.computeDeBruijnIndex(t), 4);
+    expect(f.computeDeBruijnIndex(u), 3);
   }
 
-  void test_typeParameter_isTypeParameterInScope_reversed() {
+  void test_typeParameter_computeDeBruijnIndex_reversed() {
     createLinker('class C<T, U> { f<V, W>() {} }');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     MethodElementForLink f = c.methods[0];
     TypeParameterElementImpl v = f.typeParameters[0];
     TypeParameterElementImpl w = f.typeParameters[1];
-    expect(c.isTypeParameterInScope(v), false);
-    expect(c.isTypeParameterInScope(w), false);
+    expect(c.computeDeBruijnIndex(v), isNull);
+    expect(c.computeDeBruijnIndex(w), isNull);
   }
 
-  void test_typeParameter_isTypeParameterInScope_unrelated() {
+  void test_typeParameter_computeDeBruijnIndex_unrelated() {
     createLinker('class C<T, U> {} class D<V, W> {}');
     ClassElementForLink_Class c = testLibrary.getContainedName('C');
     ClassElementForLink_Class d = testLibrary.getContainedName('D');
@@ -930,10 +930,10 @@
     TypeParameterElementImpl u = c.typeParameters[1];
     TypeParameterElementImpl v = d.typeParameters[0];
     TypeParameterElementImpl w = d.typeParameters[1];
-    expect(c.isTypeParameterInScope(v), false);
-    expect(c.isTypeParameterInScope(w), false);
-    expect(d.isTypeParameterInScope(t), false);
-    expect(d.isTypeParameterInScope(u), false);
+    expect(c.computeDeBruijnIndex(v), isNull);
+    expect(c.computeDeBruijnIndex(w), isNull);
+    expect(d.computeDeBruijnIndex(t), isNull);
+    expect(d.computeDeBruijnIndex(u), isNull);
   }
 
   void test_variable_initializer_presence() {
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_one_phase_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_one_phase_test.dart
index 87e1d73..ce3cc8d 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_one_phase_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_one_phase_test.dart
@@ -24,12 +24,6 @@
 
   @override
   @failingTest
-  test_constExpr_makeTypedList_functionType_withTypeParameters() {
-    super.test_constExpr_makeTypedList_functionType_withTypeParameters();
-  }
-
-  @override
-  @failingTest
   test_closure_executable_with_bottom_return_type() {
     super.test_closure_executable_with_bottom_return_type();
   }