Skip to content

Commit 2897beb

Browse files
Dmitry Stefantsovcommit-bot@chromium.org
authored andcommitted
[cfe] Resolve serialization mismatch due to variance computation
Change-Id: Id38c63f5bd659f21423d802fd6180aa04465712c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/123406 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
1 parent decca61 commit 2897beb

29 files changed

+352
-70
lines changed

pkg/front_end/lib/src/fasta/builder/library_builder.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ abstract class LibraryBuilder implements ModifierBuilder {
137137

138138
int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType);
139139

140+
/// Computes variances of type parameters on typedefs.
141+
///
142+
/// The variance property of type parameters on typedefs is computed from the
143+
/// use of the parameters in the right-hand side of the typedef definition.
144+
int computeVariances() => 0;
145+
140146
/// This method instantiates type parameters to their bounds in some cases
141147
/// where they were omitted by the programmer and not provided by the type
142148
/// inference. The method returns the number of distinct type variables
@@ -351,6 +357,9 @@ abstract class LibraryBuilderImpl extends ModifierBuilderImpl
351357
@override
352358
int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) => 0;
353359

360+
@override
361+
int computeVariances() => 0;
362+
354363
@override
355364
int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
356365
ClassBuilder objectClass) {

pkg/front_end/lib/src/fasta/kernel/kernel_target.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ class KernelTarget extends TargetImplementation {
256256
loader.computeLibraryScopes();
257257
setupTopAndBottomTypes();
258258
loader.resolveTypes();
259+
loader.computeVariances();
259260
loader.computeDefaultTypes(dynamicType, bottomType, objectClassBuilder);
260261
List<SourceClassBuilder> myClasses =
261262
loader.checkSemantics(objectClassBuilder);

pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import '../builder/class_builder.dart';
2727
import '../builder/formal_parameter_builder.dart';
2828
import '../builder/function_type_builder.dart';
2929
import '../builder/invalid_type_declaration_builder.dart';
30+
import '../builder/library_builder.dart';
3031
import '../builder/named_type_builder.dart';
3132
import '../builder/nullability_builder.dart';
3233
import '../builder/type_alias_builder.dart';
@@ -44,21 +45,27 @@ import '../fasta_codes.dart'
4445
templateBoundIssueViaCycleNonSimplicity,
4546
templateBoundIssueViaLoopNonSimplicity,
4647
templateBoundIssueViaRawTypeWithNonSimpleBounds,
48+
templateCyclicTypedef,
4749
templateNonSimpleBoundViaReference,
4850
templateNonSimpleBoundViaVariable;
4951

5052
export 'package:kernel/ast.dart' show Variance;
5153

54+
/// Initial value for "variance" that is to be computed by the compiler.
55+
const int pendingVariance = -1;
56+
5257
// Computes the variance of a variable in a type. The function can be run
5358
// before the types are resolved to compute variances of typedefs' type
5459
// variables. For that case if the type has its declaration set to null and its
5560
// name matches that of the variable, it's interpreted as an occurrence of a
5661
// type variable.
57-
int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
62+
int computeVariance(TypeVariableBuilder variable, TypeBuilder type,
63+
LibraryBuilder libraryBuilder) {
5864
if (type is NamedTypeBuilder) {
65+
assert(type.declaration != null);
5966
TypeDeclarationBuilder declaration = type.declaration;
60-
if (declaration == null || declaration is TypeVariableBuilder) {
61-
if (type.name == variable.name) {
67+
if (declaration is TypeVariableBuilder) {
68+
if (declaration == variable) {
6269
return Variance.covariant;
6370
} else {
6471
return Variance.unrelated;
@@ -70,21 +77,46 @@ int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
7077
for (int i = 0; i < type.arguments.length; ++i) {
7178
result = Variance.meet(
7279
result,
73-
Variance.combine(declaration.cls.typeParameters[i].variance,
74-
computeVariance(variable, type.arguments[i])));
80+
Variance.combine(
81+
declaration.cls.typeParameters[i].variance,
82+
computeVariance(
83+
variable, type.arguments[i], libraryBuilder)));
7584
}
7685
}
7786
return result;
7887
} else if (declaration is TypeAliasBuilder) {
7988
int result = Variance.unrelated;
89+
8090
if (type.arguments != null) {
8191
for (int i = 0; i < type.arguments.length; ++i) {
92+
const int visitMarker = -2;
93+
94+
TypeVariableBuilder declarationTypeVariable =
95+
declaration.typeVariables[i];
96+
97+
if (declarationTypeVariable.variance == pendingVariance) {
98+
declarationTypeVariable.variance = visitMarker;
99+
int computedVariance = computeVariance(
100+
declarationTypeVariable, declaration.type, libraryBuilder);
101+
declarationTypeVariable.variance = computedVariance;
102+
} else if (declarationTypeVariable.variance == visitMarker) {
103+
libraryBuilder.addProblem(
104+
templateCyclicTypedef.withArguments(declaration.name),
105+
declaration.charOffset,
106+
declaration.name.length,
107+
declaration.fileUri);
108+
// Use [Variance.unrelated] for recovery. The type with the
109+
// cyclic dependency will be replaced with an [InvalidType]
110+
// elsewhere.
111+
declarationTypeVariable.variance = Variance.unrelated;
112+
}
113+
82114
result = Variance.meet(
83115
result,
84116
Variance.combine(
85-
computeVariance(variable, type.arguments[i]),
86117
computeVariance(
87-
declaration.typeVariables[i], declaration.type)));
118+
variable, type.arguments[i], libraryBuilder),
119+
declarationTypeVariable.variance));
88120
}
89121
}
90122
return result;
@@ -93,8 +125,8 @@ int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
93125
} else if (type is FunctionTypeBuilder) {
94126
int result = Variance.unrelated;
95127
if (type.returnType != null) {
96-
result =
97-
Variance.meet(result, computeVariance(variable, type.returnType));
128+
result = Variance.meet(
129+
result, computeVariance(variable, type.returnType, libraryBuilder));
98130
}
99131
if (type.typeVariables != null) {
100132
for (TypeVariableBuilder typeVariable in type.typeVariables) {
@@ -103,7 +135,7 @@ int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
103135
// of [computeVariance] below is made to simply figure out if [variable]
104136
// occurs in the bound.
105137
if (typeVariable.bound != null &&
106-
computeVariance(variable, typeVariable.bound) !=
138+
computeVariance(variable, typeVariable.bound, libraryBuilder) !=
107139
Variance.unrelated) {
108140
result = Variance.invariant;
109141
}
@@ -114,7 +146,7 @@ int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
114146
result = Variance.meet(
115147
result,
116148
Variance.combine(Variance.contravariant,
117-
computeVariance(variable, formal.type)));
149+
computeVariance(variable, formal.type, libraryBuilder)));
118150
}
119151
}
120152
return result;

pkg/front_end/lib/src/fasta/source/source_class_builder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class SourceClassBuilder extends ClassBuilderImpl
239239
if (typeVariables == null || supertype == null) return supertype;
240240
Message message;
241241
for (int i = 0; i < typeVariables.length; ++i) {
242-
int variance = computeVariance(typeVariables[i], supertype);
242+
int variance = computeVariance(typeVariables[i], supertype, library);
243243
if (!Variance.greaterThanOrEqual(variance, typeVariables[i].variance)) {
244244
if (typeVariables[i].parameter.isLegacyCovariant) {
245245
message = templateInvalidTypeVariableInSupertype.withArguments(

pkg/front_end/lib/src/fasta/source/source_library_builder.dart

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ import '../kernel/type_algorithms.dart'
177177
computeVariance,
178178
findGenericFunctionTypes,
179179
getNonSimplicityIssuesForDeclaration,
180-
getNonSimplicityIssuesForTypeVariables;
180+
getNonSimplicityIssuesForTypeVariables,
181+
pendingVariance;
181182

182183
import '../loader.dart' show Loader;
183184

@@ -1995,9 +1996,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
19951996
FunctionTypeBuilder type,
19961997
int charOffset) {
19971998
if (typeVariables != null) {
1998-
for (int i = 0; i < typeVariables.length; ++i) {
1999-
TypeVariableBuilder variable = typeVariables[i];
2000-
variable.variance = computeVariance(variable, type);
1999+
for (TypeVariableBuilder typeVariable in typeVariables) {
2000+
typeVariable.variance = pendingVariance;
20012001
}
20022002
}
20032003
TypeAliasBuilder typedefBuilder = new TypeAliasBuilder(
@@ -2398,6 +2398,21 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
23982398
return count;
23992399
}
24002400

2401+
int computeVariances() {
2402+
int count = 0;
2403+
for (Builder declaration in libraryDeclaration.members.values) {
2404+
if (declaration is TypeAliasBuilder &&
2405+
declaration.typeVariablesCount > 0) {
2406+
for (TypeVariableBuilder typeParameter in declaration.typeVariables) {
2407+
typeParameter.variance =
2408+
computeVariance(typeParameter, declaration.type, this);
2409+
++count;
2410+
}
2411+
}
2412+
}
2413+
return count;
2414+
}
2415+
24012416
int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
24022417
ClassBuilder objectClass) {
24032418
int count = 0;

pkg/front_end/lib/src/fasta/source/source_loader.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,16 @@ class SourceLoader extends Loader {
513513
ticker.logMs("Resolved $count type-variable bounds");
514514
}
515515

516+
void computeVariances() {
517+
int count = 0;
518+
builders.forEach((Uri uri, LibraryBuilder library) {
519+
if (library.loader == this) {
520+
count += library.computeVariances();
521+
}
522+
});
523+
ticker.logMs("Computed variances of $count type variables");
524+
}
525+
516526
void computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
517527
ClassBuilder objectClass) {
518528
int count = 0;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Test for potentially slow compilation of long typedef dependency chains.
6+
7+
typedef Foo01<X, Y, Z> = void Function(Null);
8+
typedef Foo02<X, Y, Z> = void Function(Foo01<X, Y, Z>);
9+
typedef Foo03<X, Y, Z> = void Function(Foo02<X, Y, Z>);
10+
typedef Foo04<X, Y, Z> = void Function(Foo03<X, Y, Z>);
11+
typedef Foo05<X, Y, Z> = void Function(Foo04<X, Y, Z>);
12+
typedef Foo06<X, Y, Z> = void Function(Foo05<X, Y, Z>);
13+
typedef Foo07<X, Y, Z> = void Function(Foo06<X, Y, Z>);
14+
typedef Foo08<X, Y, Z> = void Function(Foo07<X, Y, Z>);
15+
typedef Foo09<X, Y, Z> = void Function(Foo08<X, Y, Z>);
16+
typedef Foo10<X, Y, Z> = void Function(Foo09<X, Y, Z>);
17+
typedef Foo11<X, Y, Z> = void Function(Foo10<X, Y, Z>);
18+
typedef Foo12<X, Y, Z> = void Function(Foo11<X, Y, Z>);
19+
typedef Foo13<X, Y, Z> = void Function(Foo12<X, Y, Z>);
20+
typedef Foo14<X, Y, Z> = void Function(Foo13<X, Y, Z>);
21+
typedef Foo15<X, Y, Z> = void Function(Foo14<X, Y, Z>);
22+
typedef Foo16<X, Y, Z> = void Function(Foo15<X, Y, Z>);
23+
typedef Foo17<X, Y, Z> = void Function(Foo16<X, Y, Z>);
24+
typedef Foo18<X, Y, Z> = void Function(Foo17<X, Y, Z>);
25+
typedef Foo19<X, Y, Z> = void Function(Foo18<X, Y, Z>);
26+
typedef Foo20<X, Y, Z> = void Function(Foo19<X, Y, Z>);
27+
28+
main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef Foo01<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (core::Null?) →* void;
6+
typedef Foo02<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((core::Null?) →* void) →* void;
7+
typedef Foo03<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((core::Null?) →* void) →* void) →* void;
8+
typedef Foo04<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((core::Null?) →* void) →* void) →* void) →* void;
9+
typedef Foo05<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((core::Null?) →* void) →* void) →* void) →* void) →* void;
10+
typedef Foo06<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void;
11+
typedef Foo07<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
12+
typedef Foo08<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
13+
typedef Foo09<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
14+
typedef Foo10<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
15+
typedef Foo11<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
16+
typedef Foo12<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
17+
typedef Foo13<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
18+
typedef Foo14<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
19+
typedef Foo15<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
20+
typedef Foo16<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
21+
typedef Foo17<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
22+
typedef Foo18<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
23+
typedef Foo19<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = (((((((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
24+
typedef Foo20<unrelated X extends core::Object* = dynamic, unrelated Y extends core::Object* = dynamic, unrelated Z extends core::Object* = dynamic> = ((((((((((((((((((((core::Null?) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void) →* void;
25+
static method main() → dynamic
26+
;

0 commit comments

Comments
 (0)