Skip to content

Commit ac6d86c

Browse files
stereotype441Commit Queue
authored andcommitted
[analyzer] Represent Null as NullTypeImpl.
This change introduces the class `NullTypeImpl` to represent the special type `Null`, which was previously represented as an ordinary `InterfaceType`. This class mirrors the CFE's `NullType` class. Adding it will facilitate further code sharing between the analyzer and the CFE, because it will allow code that's shared between the analyzer and CFE to use `is` tests to recognize the type `Null`. The new `NullTypeImpl` class always has a nullability suffix of `NullabilitySuffix.none`, so it is impossible for the type `Null?` to occur. This is a benign behavioral change; previously there were some circumstances in which the type `Null?` might occur in the analyzer, but the type `Null?` behaved the same as `Null` so there was no user-visible effect. This behavioral change brings the analyzer's treatment of `Null` into alignment with that of the CFE. This is the first step in a planned patch series. In follow-up CLs, I intend to: - Introduce a public-facing `NullType` for use by clients. - Change `NullTypeImpl` so that it no longer extends `InterfaceTypeImpl`. - Add a base class that is common to the analyzer and CFE `NullType` representations. Change-Id: I9cea84d8149347bffdee006d544af28c66eba429 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396320 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent d79fcdf commit ac6d86c

File tree

10 files changed

+142
-140
lines changed

10 files changed

+142
-140
lines changed

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5900,11 +5900,16 @@ abstract class InterfaceElementImpl extends InstanceElementImpl
59005900
}
59015901
}
59025902

5903-
var result = InterfaceTypeImpl(
5904-
element: this,
5905-
typeArguments: typeArguments,
5906-
nullabilitySuffix: nullabilitySuffix,
5907-
);
5903+
InterfaceTypeImpl result;
5904+
if (name == 'Null' && library.isDartCore) {
5905+
result = NullTypeImpl(element: this);
5906+
} else {
5907+
result = InterfaceTypeImpl(
5908+
element: this,
5909+
typeArguments: typeArguments,
5910+
nullabilitySuffix: nullabilitySuffix,
5911+
);
5912+
}
59085913

59095914
if (typeArguments.isEmpty) {
59105915
switch (nullabilitySuffix) {
@@ -10240,6 +10245,11 @@ class TypeAliasElementImpl extends _ExistingElementImpl
1024010245
typeArguments: typeArguments,
1024110246
),
1024210247
);
10248+
} else if (type is NullTypeImpl) {
10249+
return NullTypeImpl(
10250+
element: type.element,
10251+
alias: InstantiatedTypeAliasElementImpl(
10252+
element: this, typeArguments: typeArguments));
1024310253
} else if (type is InterfaceType) {
1024410254
return InterfaceTypeImpl(
1024510255
element: type.element,

pkg/analyzer/lib/src/dart/element/type.dart

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,9 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
499499
required this.nullabilitySuffix,
500500
super.alias,
501501
}) {
502+
if (element.name == 'Null' && element.library.isDartCore) {
503+
throw ArgumentError('NullTypeImpl should be used for `Null`');
504+
}
502505
if (element.augmentationTarget != null) {
503506
throw ArgumentError(
504507
'InterfaceType(s) can only be created for declarations',
@@ -516,6 +519,13 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
516519
}
517520
}
518521

522+
InterfaceTypeImpl._null({required this.element, super.alias})
523+
: typeArguments = const [],
524+
nullabilitySuffix = NullabilitySuffix.none {
525+
assert(element.name == 'Null' && element.library.isDartCore);
526+
assert(this is NullTypeImpl);
527+
}
528+
519529
@override
520530
List<PropertyAccessorElement> get accessors {
521531
if (_accessors == null) {
@@ -637,11 +647,6 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
637647
return element.name == "Map" && element.library.isDartCore;
638648
}
639649

640-
@override
641-
bool get isDartCoreNull {
642-
return element.name == "Null" && element.library.isDartCore;
643-
}
644-
645650
@override
646651
bool get isDartCoreNum {
647652
return element.name == "num" && element.library.isDartCore;
@@ -1135,6 +1140,18 @@ class NeverTypeImpl extends TypeImpl implements NeverType {
11351140
}
11361141
}
11371142

1143+
/// A concrete implementation of [DartType] representing the type `Null`, with
1144+
/// no type parameters and no nullability suffix.
1145+
class NullTypeImpl extends InterfaceTypeImpl {
1146+
NullTypeImpl({required super.element, super.alias}) : super._null();
1147+
1148+
@override
1149+
bool get isDartCoreNull => true;
1150+
1151+
@override
1152+
NullTypeImpl withNullability(NullabilitySuffix nullabilitySuffix) => this;
1153+
}
1154+
11381155
abstract class RecordTypeFieldImpl implements RecordTypeField {
11391156
@override
11401157
final DartType type;

pkg/analyzer/lib/src/dart/element/type_provider.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -608,10 +608,14 @@ class TypeProviderImpl extends TypeProviderBase {
608608
}).toList(growable: false);
609609
}
610610

611-
return InterfaceTypeImpl(
612-
element: element,
613-
typeArguments: typeArguments,
614-
nullabilitySuffix: NullabilitySuffix.none,
615-
);
611+
if (element.name == 'Null' && element.library.isDartCore) {
612+
return NullTypeImpl(element: element);
613+
} else {
614+
return InterfaceTypeImpl(
615+
element: element,
616+
typeArguments: typeArguments,
617+
nullabilitySuffix: NullabilitySuffix.none,
618+
);
619+
}
616620
}
617621
}

pkg/analyzer/test/generated/elements_types_mixin.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,6 @@ mixin ElementsTypesMixin {
7474
return interfaceTypeNone(element) as InterfaceTypeImpl;
7575
}
7676

77-
InterfaceTypeImpl get nullQuestion {
78-
var element = typeProvider.nullType.element;
79-
return interfaceTypeQuestion(element) as InterfaceTypeImpl;
80-
}
81-
8277
InterfaceType get numNone {
8378
var element = typeProvider.numType.element;
8479
return interfaceTypeNone(element);

pkg/analyzer/test/src/dart/element/always_exhaustive_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class IsAlwaysExhaustiveTest extends AbstractTypeSystemTest {
3636

3737
test_class_Null() {
3838
isAlwaysExhaustive(nullNone);
39-
isAlwaysExhaustive(nullQuestion);
4039
}
4140

4241
test_class_sealed() {

pkg/analyzer/test/src/dart/element/normalize_type_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
319319
// Analyzer: impossible, we have only one suffix
320320

321321
// * if S is Null then Null
322-
check(nullQuestion, nullNone);
322+
// Analyzer: impossible; `Null?` is always represented as `Null`.
323323

324324
// * if S is FutureOr<R> and R is nullable then S
325325
check(futureOrQuestion(intQuestion), futureOrNone(intQuestion));

pkg/analyzer/test/src/dart/element/nullable_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,6 @@ class IsStrictlyNonNullableTest extends AbstractTypeSystemTest {
501501

502502
test_null() {
503503
isNotStrictlyNonNullable(nullNone);
504-
isNotStrictlyNonNullable(nullQuestion);
505504
}
506505

507506
test_typeParameter_boundNone() {

pkg/analyzer/test/src/dart/element/string_types.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mixin StringTypes on AbstractTypeSystemTest {
2828
_defineType('Never', neverNone);
2929
_defineType('Never?', neverQuestion);
3030

31-
_defineType('Null?', nullQuestion);
31+
_defineType('Null', nullNone);
3232

3333
_defineType('Object', objectNone);
3434
_defineType('Object?', objectQuestion);

0 commit comments

Comments
 (0)