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();
}