Skip to content

Commit 1f7e637

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: store decorated type parameter bounds separately from other element decorated types.
We will need some special treatment for decorated type parameter bounds, because sometimes we will need to create type parameters (e.g. when comparing decorated types). So we store the bounds of non-ephemeral type parameters (the ones whose enclosing element is non-null) in the Variables data structure, and we store the bounds of ephemeral type parameters (the ones whose enclosing element is null) in an expando. Change-Id: I918c9baffedab9a8871ecea37c8101b5ef44a5d9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112743 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent c0d1ded commit 1f7e637

File tree

6 files changed

+98
-15
lines changed

6 files changed

+98
-15
lines changed

pkg/nnbd_migration/lib/src/decorated_type.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ import 'package:nnbd_migration/src/potential_modification.dart';
1313
/// tracking the (unmigrated) [DartType], we track the [ConstraintVariable]s
1414
/// indicating whether the type, and the types that compose it, are nullable.
1515
class DecoratedType {
16+
/// Mapping from type parameter elements to the decorated types of those type
17+
/// parameters' bounds.
18+
///
19+
/// This expando only applies to type parameters whose enclosing element is
20+
/// `null`. Type parameters whose enclosing element is not `null` should be
21+
/// stored in [Variables._decoratedTypeParameterBounds].
22+
static final _decoratedTypeParameterBounds = Expando<DecoratedType>();
23+
1624
final DartType type;
1725

1826
final NullabilityNode node;
@@ -302,6 +310,28 @@ class DecoratedType {
302310
returnType._substitute(substitution, undecoratedResult.returnType),
303311
positionalParameters: newPositionalParameters);
304312
}
313+
314+
/// Retrieves the decorated bound of the given [typeParameter].
315+
///
316+
/// [typeParameter] must have an enclosing element of `null`. Type parameters
317+
/// whose enclosing element is not `null` are tracked by the [Variables]
318+
/// class.
319+
static DecoratedType decoratedTypeParameterBound(
320+
TypeParameterElement typeParameter) {
321+
assert(typeParameter.enclosingElement == null);
322+
return _decoratedTypeParameterBounds[typeParameter];
323+
}
324+
325+
/// Stores he decorated bound of the given [typeParameter].
326+
///
327+
/// [typeParameter] must have an enclosing element of `null`. Type parameters
328+
/// whose enclosing element is not `null` are tracked by the [Variables]
329+
/// class.
330+
static void recordTypeParameterBound(
331+
TypeParameterElement typeParameter, DecoratedType bound) {
332+
assert(typeParameter.enclosingElement == null);
333+
_decoratedTypeParameterBounds[typeParameter] = bound;
334+
}
305335
}
306336

307337
/// A [DecoratedType] based on a type annotation appearing explicitly in the

pkg/nnbd_migration/lib/src/edge_builder.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,13 +1005,15 @@ $stackTrace''');
10051005
for (int i = 0; i < instantiatedType.typeArguments.length; i++) {
10061006
_unionDecoratedTypes(
10071007
instantiatedType.typeArguments[i],
1008-
_variables.decoratedElementType(element.typeParameters[i]),
1008+
_variables.decoratedTypeParameterBound(element.typeParameters[i]),
10091009
origin);
10101010
}
10111011
} else {
10121012
for (int i = 0; i < typeArguments.length; i++) {
10131013
DecoratedType bound;
1014-
bound = _variables.decoratedElementType(element.typeParameters[i]);
1014+
bound =
1015+
_variables.decoratedTypeParameterBound(element.typeParameters[i]);
1016+
assert(bound != null);
10151017
var argumentType =
10161018
_variables.decoratedTypeAnnotation(_source, typeArguments[i]);
10171019
if (argumentType == null) {
@@ -1188,7 +1190,7 @@ $stackTrace''');
11881190
// TODO(paulberry): once we've wired up flow analysis, return promoted
11891191
// bounds if applicable.
11901192
return _variables
1191-
.decoratedElementType((type.type as TypeParameterType).element);
1193+
.decoratedTypeParameterBound((type.type as TypeParameterType).element);
11921194
}
11931195

11941196
/// Creates the necessary constraint(s) for an assignment of the given

pkg/nnbd_migration/lib/src/node_builder.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ $stackTrace''');
346346
AlwaysNullableTypeOrigin(_source, node.offset));
347347
decoratedBound = DecoratedType(_typeProvider.objectType, nullabilityNode);
348348
}
349-
_variables.recordDecoratedElementType(element, decoratedBound);
349+
_variables.recordDecoratedTypeParameterBound(element, decoratedBound);
350350
return null;
351351
}
352352

@@ -548,6 +548,10 @@ abstract class VariableRecorder {
548548
Source source, TypeAnnotation node, DecoratedTypeAnnotation type,
549549
{bool potentialModification: true});
550550

551+
/// Stores he decorated bound of the given [typeParameter].
552+
void recordDecoratedTypeParameterBound(
553+
TypeParameterElement typeParameter, DecoratedType bound);
554+
551555
/// Records that [node] is associated with the question of whether the named
552556
/// [parameter] should be optional (should not have a `required`
553557
/// annotation added to it).
@@ -580,6 +584,9 @@ abstract class VariableRepository {
580584
DecoratedType decoratedTypeAnnotation(
581585
Source source, TypeAnnotation typeAnnotation);
582586

587+
/// Retrieves the decorated bound of the given [typeParameter].
588+
DecoratedType decoratedTypeParameterBound(TypeParameterElement typeParameter);
589+
583590
/// Records conditional discard information for the given AST node (which is
584591
/// an `if` statement or a conditional (`?:`) expression).
585592
void recordConditionalDiscard(

pkg/nnbd_migration/lib/src/variables.dart

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class Variables implements VariableRecorder, VariableRepository {
2020

2121
final _decoratedElementTypes = <Element, DecoratedType>{};
2222

23+
final _decoratedTypeParameterBounds = <Element, DecoratedType>{};
24+
2325
final _decoratedDirectSupertypes =
2426
<ClassElement, Map<ClassElement, DecoratedType>>{};
2527

@@ -42,8 +44,12 @@ class Variables implements VariableRecorder, VariableRepository {
4244
}
4345

4446
@override
45-
DecoratedType decoratedElementType(Element element) =>
46-
_decoratedElementTypes[element] ??= _createDecoratedElementType(element);
47+
DecoratedType decoratedElementType(Element element) {
48+
assert(element is! TypeParameterElement,
49+
'Use decoratedTypeParameterBound instead');
50+
return _decoratedElementTypes[element] ??=
51+
_createDecoratedElementType(element);
52+
}
4753

4854
@override
4955
DecoratedType decoratedTypeAnnotation(
@@ -62,6 +68,35 @@ class Variables implements VariableRecorder, VariableRepository {
6268
return decoratedTypeAnnotation;
6369
}
6470

71+
@override
72+
DecoratedType decoratedTypeParameterBound(
73+
TypeParameterElement typeParameter) {
74+
if (typeParameter.enclosingElement == null) {
75+
var decoratedType =
76+
DecoratedType.decoratedTypeParameterBound(typeParameter);
77+
if (decoratedType == null) {
78+
throw StateError(
79+
'A decorated type for the bound of $typeParameter should '
80+
'have been stored by the NodeBuilder via recordTypeParameterBound');
81+
}
82+
return decoratedType;
83+
} else {
84+
var decoratedType = _decoratedTypeParameterBounds[typeParameter];
85+
if (decoratedType == null) {
86+
if (_graph.isBeingMigrated(typeParameter.library.source)) {
87+
throw StateError(
88+
'A decorated type for the bound of $typeParameter should '
89+
'have been stored by the NodeBuilder via '
90+
'recordTypeParameterBound');
91+
}
92+
decoratedType = _alreadyMigratedCodeDecorator
93+
.decorate(typeParameter.bound ?? DynamicTypeImpl.instance);
94+
_decoratedTypeParameterBounds[typeParameter] = decoratedType;
95+
}
96+
return decoratedType;
97+
}
98+
}
99+
65100
Map<Source, List<PotentialModification>> getPotentialModifications() =>
66101
_potentialModifications;
67102

@@ -87,6 +122,8 @@ class Variables implements VariableRecorder, VariableRepository {
87122

88123
void recordDecoratedElementType(Element element, DecoratedType type) {
89124
assert(() {
125+
assert(element is! TypeParameterElement,
126+
'Use recordDecoratedTypeParameterBound instead');
90127
var library = element.library;
91128
if (library == null) {
92129
// No problem; the element is probably a parameter of a function type
@@ -109,6 +146,16 @@ class Variables implements VariableRecorder, VariableRepository {
109146
{})[_uniqueOffsetForTypeAnnotation(node)] = type;
110147
}
111148

149+
@override
150+
void recordDecoratedTypeParameterBound(
151+
TypeParameterElement typeParameter, DecoratedType bound) {
152+
if (typeParameter.enclosingElement == null) {
153+
DecoratedType.recordTypeParameterBound(typeParameter, bound);
154+
} else {
155+
_decoratedTypeParameterBounds[typeParameter] = bound;
156+
}
157+
}
158+
112159
@override
113160
void recordExpressionChecks(
114161
Source source, Expression expression, ExpressionChecks checks) {
@@ -187,11 +234,6 @@ class Variables implements VariableRecorder, VariableRepository {
187234
decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
188235
} else if (element is TopLevelVariableElement) {
189236
decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
190-
} else if (element is TypeParameterElement) {
191-
// By convention, type parameter elements are decorated with the type of
192-
// their bounds.
193-
decoratedType = _alreadyMigratedCodeDecorator
194-
.decorate(element.bound ?? DynamicTypeImpl.instance);
195237
} else {
196238
// TODO(paulberry)
197239
throw UnimplementedError('Decorating ${element.runtimeType}');

pkg/nnbd_migration/test/edge_builder_test.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3626,7 +3626,7 @@ void f(Point<int> x) {}
36263626
var pointClass =
36273627
findNode.typeName('Point').name.staticElement as ClassElement;
36283628
var pointBound =
3629-
variables.decoratedElementType(pointClass.typeParameters[0]);
3629+
variables.decoratedTypeParameterBound(pointClass.typeParameters[0]);
36303630
expect(pointBound.type.toString(), 'num');
36313631
assertEdge(decoratedTypeAnnotation('int>').node, pointBound.node,
36323632
hard: true);
@@ -3637,7 +3637,8 @@ void f(Point<int> x) {}
36373637
void f(List<int> x) {}
36383638
''');
36393639
var listClass = typeProvider.listType.element;
3640-
var listBound = variables.decoratedElementType(listClass.typeParameters[0]);
3640+
var listBound =
3641+
variables.decoratedTypeParameterBound(listClass.typeParameters[0]);
36413642
expect(listBound.type.toString(), 'dynamic');
36423643
assertEdge(decoratedTypeAnnotation('int>').node, listBound.node,
36433644
hard: true);

pkg/nnbd_migration/test/node_builder_test.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ class NodeBuilderTest extends MigrationVisitorTestBase {
2323
variables.decoratedElementType(
2424
findNode.functionDeclaration(search).declaredElement);
2525

26-
DecoratedType decoratedTypeParameterBound(String search) => variables
27-
.decoratedElementType(findNode.typeParameter(search).declaredElement);
26+
DecoratedType decoratedTypeParameterBound(String search) =>
27+
variables.decoratedTypeParameterBound(
28+
findNode.typeParameter(search).declaredElement);
2829

2930
test_class_alias_synthetic_constructors_no_parameters() async {
3031
await analyze('''

0 commit comments

Comments
 (0)