Skip to content

Commit 9c59339

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[cfe] Fix bottomType as Never in closures of type schemas
In pre-NNBD Dart the greatest and lowest closures of a type schema were using `Null` as the bottom type and `dynamic` as the top type. In NNBD code, the top type should be `Object?', and the bottom type should be `Never`. Since pre-NNBD code is being deprecated, the code that allows to choose between the two pairs of extreme types should be removed, and `Object?` and `Never` should be used as the only options. For historical reasons, replacing `Object?` with `dynamic` in the algorithms for the greatest and the lowest closures leads to breakages in the existing NNBD code. However, the bottom type is assumed to be `Never` everywhere. This CL removes the ability to parametrise over the bottom type, choosing `Never` as the only option. The discrepancy between `Object?` and `dynamic` will be addressed later. Change-Id: Ia58ccaca37761c5de8e005f11e79b23d02a0e416 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395963 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 5b1e226 commit 9c59339

File tree

8 files changed

+76
-85
lines changed

8 files changed

+76
-85
lines changed

pkg/front_end/lib/src/type_inference/inference_visitor_base.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,11 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
187187
StaticTypeContext get staticTypeContext => _inferrer.staticTypeContext;
188188

189189
DartType computeGreatestClosure(DartType type) {
190-
return greatestClosure(type, const DynamicType(), bottomType);
190+
return greatestClosure(type, topType: const DynamicType());
191191
}
192192

193193
DartType computeGreatestClosure2(DartType type) {
194-
return greatestClosure(type, coreTypes.objectNullableRawType, bottomType);
194+
return greatestClosure(type, topType: coreTypes.objectNullableRawType);
195195
}
196196

197197
DartType computeNullable(DartType type) {

pkg/front_end/lib/src/type_inference/standard_bounds.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:kernel/ast.dart' show DartType, NeverType;
5+
import 'package:kernel/ast.dart' show DartType;
66
import 'package:kernel/src/standard_bounds.dart';
77

88
import 'type_schema.dart' show UnknownType;
@@ -13,16 +13,15 @@ mixin TypeSchemaStandardBounds on StandardBounds {
1313
DartType greatestClosureForLowerBound(DartType typeSchema) {
1414
// - We replace all uses of `T1 <: T2` in the `DOWN` algorithm by `S1 <:
1515
// S2` where `Si` is the greatest closure of `Ti` with respect to `_`.
16-
return greatestClosure(typeSchema, coreTypes.objectNullableRawType,
17-
const NeverType.nonNullable());
16+
return greatestClosure(typeSchema,
17+
topType: coreTypes.objectNullableRawType);
1818
}
1919

2020
@override
2121
DartType leastClosureForUpperBound(DartType typeSchema) {
2222
// - We replace all uses of `T1 <: T2` in the `UP` algorithm by `S1 <: S2`
2323
// where `Si` is the least closure of `Ti` with respect to `_`.
24-
return leastClosure(typeSchema, coreTypes.objectNullableRawType,
25-
const NeverType.nonNullable());
24+
return leastClosure(typeSchema, topType: coreTypes.objectNullableRawType);
2625
}
2726

2827
@override

pkg/front_end/lib/src/type_inference/type_inference_engine.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,7 @@ class OperationsCfe
540540
SharedTypeSchemaView<DartType> schema) {
541541
return new SharedTypeView(type_schema_elimination.greatestClosure(
542542
schema.unwrapTypeSchemaView(),
543-
const DynamicType(),
544-
const NeverType.nonNullable()));
543+
topType: const DynamicType()));
545544
}
546545

547546
@override

pkg/front_end/lib/src/type_inference/type_schema_elimination.dart

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import 'type_schema.dart' show UnknownType;
2020
///
2121
/// Note that the greatest closure of a type schema is always a supertype of any
2222
/// type which matches the schema.
23-
DartType greatestClosure(
24-
DartType schema, DartType topType, DartType bottomType) {
25-
return _TypeSchemaEliminationVisitor.run(false, schema, topType, bottomType);
23+
DartType greatestClosure(DartType schema, {required DartType topType}) {
24+
return _TypeSchemaEliminationVisitor.run(schema,
25+
computeLeastClosure: false, topType: topType);
2626
}
2727

2828
/// Returns the least closure of the given type [schema] with respect to `?`.
@@ -38,8 +38,9 @@ DartType greatestClosure(
3838
///
3939
/// Note that the least closure of a type schema is always a subtype of any type
4040
/// which matches the schema.
41-
DartType leastClosure(DartType schema, DartType topType, DartType bottomType) {
42-
return _TypeSchemaEliminationVisitor.run(true, schema, topType, bottomType);
41+
DartType leastClosure(DartType schema, {required DartType topType}) {
42+
return _TypeSchemaEliminationVisitor.run(schema,
43+
computeLeastClosure: true, topType: topType);
4344
}
4445

4546
/// Visitor that computes least and greatest closures of a type schema.
@@ -48,16 +49,15 @@ DartType leastClosure(DartType schema, DartType topType, DartType bottomType) {
4849
/// type, otherwise it returns the result of substituting `?` with `Null` or
4950
/// `Object`, as appropriate.
5051
class _TypeSchemaEliminationVisitor extends ReplacementVisitor {
51-
final DartType topType;
52-
final DartType bottomType;
52+
final DartType _topType;
5353

54-
_TypeSchemaEliminationVisitor(this.topType, this.bottomType);
54+
_TypeSchemaEliminationVisitor(this._topType);
5555

5656
@override
5757
DartType? visitAuxiliaryType(AuxiliaryType node, Variance variance) {
58-
bool isLeastClosure = variance == Variance.covariant;
58+
bool computeLeastClosure = variance == Variance.covariant;
5959
if (node is UnknownType) {
60-
return isLeastClosure ? bottomType : topType;
60+
return computeLeastClosure ? const NeverType.nonNullable() : _topType;
6161
}
6262
// Coverage-ignore-block(suite): Not run.
6363
throw new UnsupportedError(
@@ -67,21 +67,18 @@ class _TypeSchemaEliminationVisitor extends ReplacementVisitor {
6767
/// Runs an instance of the visitor on the given [schema] and returns the
6868
/// resulting type. If the schema contains no instances of `?`, the original
6969
/// schema object is returned to avoid unnecessary allocation.
70-
static DartType run(bool isLeastClosure, DartType schema, DartType topType,
71-
DartType bottomType) {
70+
static DartType run(DartType schema,
71+
{required bool computeLeastClosure, required DartType topType}) {
7272
assert(topType == const DynamicType() ||
7373
topType is InterfaceType &&
7474
topType.nullability == Nullability.nullable &&
7575
topType.classNode.enclosingLibrary.importUri.isScheme("dart") &&
7676
topType.classNode.enclosingLibrary.importUri.path == "core" &&
7777
topType.classNode.name == "Object");
78-
assert(bottomType == const NeverType.nonNullable() ||
79-
// Coverage-ignore(suite): Not run.
80-
bottomType is NullType);
8178
_TypeSchemaEliminationVisitor visitor =
82-
new _TypeSchemaEliminationVisitor(topType, bottomType);
83-
DartType? result = schema.accept1(
84-
visitor, isLeastClosure ? Variance.covariant : Variance.contravariant);
79+
new _TypeSchemaEliminationVisitor(topType);
80+
DartType? result = schema.accept1(visitor,
81+
computeLeastClosure ? Variance.covariant : Variance.contravariant);
8582
return result ?? schema;
8683
}
8784
}

pkg/front_end/lib/src/type_inference/type_schema_environment.dart

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,10 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
392392
/// If [isContravariant] is `true`, then we are solving for a contravariant
393393
/// type parameter which means we choose the upper bound rather than the
394394
/// lower bound for normally covariant type parameters.
395-
DartType solveTypeConstraint(
396-
MergedTypeConstraint constraint, DartType topType, DartType bottomType,
397-
{bool grounded = false, bool isContravariant = false}) {
398-
assert(bottomType == const NeverType.nonNullable() ||
399-
// Coverage-ignore(suite): Not run.
400-
bottomType == const NullType());
395+
DartType solveTypeConstraint(MergedTypeConstraint constraint,
396+
{required DartType topType,
397+
bool grounded = false,
398+
bool isContravariant = false}) {
401399
if (!isContravariant) {
402400
// Prefer the known bound, if any.
403401
if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
@@ -411,13 +409,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
411409
// e.g. `Iterable<?>`
412410
if (constraint.lower is! SharedUnknownTypeSchemaView<DartType>) {
413411
return grounded
414-
? leastClosure(
415-
constraint.lower.unwrapTypeSchemaView(), topType, bottomType)
412+
? leastClosure(constraint.lower.unwrapTypeSchemaView(),
413+
topType: topType)
416414
: constraint.lower.unwrapTypeSchemaView();
417415
} else if (constraint.upper is! UnknownType) {
418416
return grounded
419-
? greatestClosure(
420-
constraint.upper.unwrapTypeSchemaView(), topType, bottomType)
417+
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
418+
topType: topType)
421419
: constraint.upper.unwrapTypeSchemaView();
422420
} else {
423421
return const UnknownType();
@@ -437,13 +435,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
437435
if (constraint.upper is! UnknownType) {
438436
// Coverage-ignore-block(suite): Not run.
439437
return grounded
440-
? greatestClosure(
441-
constraint.upper.unwrapTypeSchemaView(), topType, bottomType)
438+
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
439+
topType: topType)
442440
: constraint.upper.unwrapTypeSchemaView();
443441
} else if (constraint.lower is! UnknownType) {
444442
return grounded
445-
? leastClosure(
446-
constraint.lower.unwrapTypeSchemaView(), topType, bottomType)
443+
? leastClosure(constraint.lower.unwrapTypeSchemaView(),
444+
topType: topType)
447445
:
448446
// Coverage-ignore(suite): Not run.
449447
constraint.lower.unwrapTypeSchemaView();
@@ -535,9 +533,10 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
535533
new SharedTypeSchemaView(extendsConstraint), operations);
536534
}
537535

538-
return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
539-
const NeverType.nonNullable(),
540-
grounded: true, isContravariant: isContravariant);
536+
return solveTypeConstraint(constraint,
537+
topType: coreTypes.objectNullableRawType,
538+
grounded: true,
539+
isContravariant: isContravariant);
541540
}
542541

543542
void _mergeInConstraintsFromBound(
@@ -577,7 +576,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
577576
}
578577

579578
DartType t = solveTypeConstraint(constraint,
580-
coreTypes.objectNullableRawType, const NeverType.nonNullable());
579+
topType: coreTypes.objectNullableRawType);
581580
if (!isKnown(t)) {
582581
return t;
583582
}
@@ -604,8 +603,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
604603
constraint = constraint.clone();
605604
constraint.mergeInTypeSchemaUpper(
606605
new SharedTypeSchemaView(extendsConstraint), operations);
607-
return solveTypeConstraint(constraint, coreTypes.objectNullableRawType,
608-
const NeverType.nonNullable());
606+
return solveTypeConstraint(constraint,
607+
topType: coreTypes.objectNullableRawType);
609608
}
610609

611610
return t;

pkg/front_end/test/type_inference/type_schema_elimination_nnbd_test.dart

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ class TypeSchemaEliminationTest {
2424
};
2525

2626
DartType greatestClosure(DartType schema) {
27-
return typeSchemaElimination.greatestClosure(
28-
schema, const DynamicType(), const NeverType.nonNullable());
27+
return typeSchemaElimination.greatestClosure(schema,
28+
topType: env.coreTypes.objectNullableRawType);
2929
}
3030

3131
DartType leastClosure(DartType schema) {
32-
return typeSchemaElimination.leastClosure(
33-
schema, const DynamicType(), const NeverType.nonNullable());
32+
return typeSchemaElimination.leastClosure(schema,
33+
topType: env.coreTypes.objectNullableRawType);
3434
}
3535

3636
void testGreatest(String type, String expectedClosure) {
@@ -45,47 +45,47 @@ class TypeSchemaEliminationTest {
4545
}
4646

4747
void test_greatestClosure_contravariant() {
48-
testGreatest("(UNKNOWN) ->* dynamic", "(Never) ->* dynamic");
49-
testGreatest("({UNKNOWN foo}) ->* dynamic", "({Never foo}) ->* dynamic");
48+
testGreatest("(UNKNOWN) -> dynamic", "(Never) -> dynamic");
49+
testGreatest("({UNKNOWN foo}) -> dynamic", "({Never foo}) -> dynamic");
5050
}
5151

5252
void test_greatestClosure_contravariant_contravariant() {
53-
testGreatest("((UNKNOWN) ->* dynamic) ->* dynamic",
54-
"((dynamic) ->* dynamic) ->* dynamic");
53+
testGreatest("((UNKNOWN) -> dynamic) -> dynamic",
54+
"((Object?) -> dynamic) -> dynamic");
5555
}
5656

5757
void test_greatestClosure_covariant() {
58-
testGreatest("() ->* UNKNOWN", "() ->* dynamic");
59-
testGreatest("List<UNKNOWN>*", "List<dynamic>*");
58+
testGreatest("() -> UNKNOWN", "() -> Object?");
59+
testGreatest("List<UNKNOWN>", "List<Object?>");
6060
}
6161

6262
void test_greatestClosure_function_multipleUnknown() {
63-
testGreatest("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
64-
"(Never, Never, {Never a, Never b}) ->* dynamic");
63+
testGreatest("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) -> UNKNOWN",
64+
"(Never, Never, {Never a, Never b}) -> Object?");
6565
}
6666

6767
void test_greatestClosure_simple() {
68-
testGreatest("UNKNOWN", "dynamic");
68+
testGreatest("UNKNOWN", "Object?");
6969
}
7070

7171
void test_leastClosure_contravariant() {
72-
testLeast("(UNKNOWN) ->* dynamic", "(dynamic) ->* dynamic");
73-
testLeast("({UNKNOWN foo}) ->* dynamic", "({dynamic foo}) ->* dynamic");
72+
testLeast("(UNKNOWN) -> dynamic", "(Object?) -> dynamic");
73+
testLeast("({UNKNOWN foo}) -> dynamic", "({Object? foo}) -> dynamic");
7474
}
7575

7676
void test_leastClosure_contravariant_contravariant() {
77-
testLeast("((UNKNOWN) ->* dynamic) ->* dynamic",
78-
"((Never) ->* dynamic) ->* dynamic");
77+
testLeast(
78+
"((UNKNOWN) -> dynamic) -> dynamic", "((Never) -> dynamic) -> dynamic");
7979
}
8080

8181
void test_leastClosure_covariant() {
82-
testLeast("() ->* UNKNOWN", "() ->* Never");
83-
testLeast("List<UNKNOWN>*", "List<Never>*");
82+
testLeast("() -> UNKNOWN", "() -> Never");
83+
testLeast("List<UNKNOWN>", "List<Never>");
8484
}
8585

8686
void test_leastClosure_function_multipleUnknown() {
87-
testLeast("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
88-
"(dynamic, dynamic, {dynamic a, dynamic b}) ->* Never");
87+
testLeast("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) -> UNKNOWN",
88+
"(Object?, Object?, {Object? a, Object? b}) -> Never");
8989
}
9090

9191
void test_leastClosure_simple() {

pkg/front_end/test/type_inference/type_schema_elimination_test.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ class TypeSchemaEliminationTest {
2424
};
2525

2626
DartType greatestClosure(DartType schema) {
27-
return typeSchemaElimination.greatestClosure(
28-
schema, new DynamicType(), new NullType());
27+
return typeSchemaElimination.greatestClosure(schema,
28+
topType: new DynamicType());
2929
}
3030

3131
DartType leastClosure(DartType schema) {
32-
return typeSchemaElimination.leastClosure(
33-
schema, new DynamicType(), new NullType());
32+
return typeSchemaElimination.leastClosure(schema,
33+
topType: new DynamicType());
3434
}
3535

3636
void testGreatest(String type, String expectedClosure) {
@@ -45,8 +45,8 @@ class TypeSchemaEliminationTest {
4545
}
4646

4747
void test_greatestClosure_contravariant() {
48-
testGreatest("(UNKNOWN) ->* dynamic", "(Null) ->* dynamic");
49-
testGreatest("({UNKNOWN foo}) ->* dynamic", "({Null foo}) ->* dynamic");
48+
testGreatest("(UNKNOWN) ->* dynamic", "(Never) ->* dynamic");
49+
testGreatest("({UNKNOWN foo}) ->* dynamic", "({Never foo}) ->* dynamic");
5050
}
5151

5252
void test_greatestClosure_contravariant_contravariant() {
@@ -61,7 +61,7 @@ class TypeSchemaEliminationTest {
6161

6262
void test_greatestClosure_function_multipleUnknown() {
6363
testGreatest("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
64-
"(Null, Null, {Null a, Null b}) ->* dynamic");
64+
"(Never, Never, {Never a, Never b}) ->* dynamic");
6565
}
6666

6767
void test_greatestClosure_simple() {
@@ -75,20 +75,20 @@ class TypeSchemaEliminationTest {
7575

7676
void test_leastClosure_contravariant_contravariant() {
7777
testLeast("((UNKNOWN) ->* UNKNOWN) ->* dynamic",
78-
"((Null) ->* dynamic) ->* dynamic");
78+
"((Never) ->* dynamic) ->* dynamic");
7979
}
8080

8181
void test_leastClosure_covariant() {
82-
testLeast("() ->* UNKNOWN", "() ->* Null");
83-
testLeast("List<UNKNOWN>*", "List<Null>*");
82+
testLeast("() ->* UNKNOWN", "() ->* Never");
83+
testLeast("List<UNKNOWN>*", "List<Never>*");
8484
}
8585

8686
void test_leastClosure_function_multipleUnknown() {
8787
testLeast("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
88-
"(dynamic, dynamic, {dynamic a, dynamic b}) ->* Null");
88+
"(dynamic, dynamic, {dynamic a, dynamic b}) ->* Never");
8989
}
9090

9191
void test_leastClosure_simple() {
92-
testLeast("UNKNOWN", "Null");
92+
testLeast("UNKNOWN", "Never");
9393
}
9494
}

pkg/front_end/test/type_inference/type_schema_environment_test_base.dart

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,8 @@ abstract class TypeSchemaEnvironmentTestBase {
6767
void checkConstraintSolving(String constraint, String expected,
6868
{required bool grounded}) {
6969
expect(
70-
typeSchemaEnvironment.solveTypeConstraint(
71-
parseConstraint(constraint),
72-
coreTypes.objectNullableRawType,
73-
new NeverType.internal(Nullability.nonNullable),
74-
grounded: grounded),
70+
typeSchemaEnvironment.solveTypeConstraint(parseConstraint(constraint),
71+
topType: coreTypes.objectNullableRawType, grounded: grounded),
7572
parseType(expected));
7673
}
7774

0 commit comments

Comments
 (0)