Skip to content

Commit

Permalink
[mini_types] Add an assertion to verify the runtime type of `PrimaryT…
Browse files Browse the repository at this point in the history
…ype`-derived objects.

The class hierarchy for `PrimaryType` has several subtypes to
represent special types in Dart:

- DynamicType (for `dynamic`)
- FutureOrType (for `FutureOr<...>`)
- InvalidType (for the invalid type)
- NeverType (for `Never`)
- NullType (for `Null`)
- VoidType (for `Void`)

When constructing a `PrimaryType` for one of these special types, we
need to make sure that the type that's being ultimately constructed is
the proper subtype, otherwise algorithms that do `is` tests on the
`Type` hierarchy will behave incorrectly.

This change adds an assertion to the `PrimaryType` constructor to
verify that the appropriate subtype of `Type` is being constructed.

Change-Id: I347cc4893da265b35e97636479700a92a8e61541
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395560
Reviewed-by: Kallen Tu <kallentu@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
  • Loading branch information
stereotype441 authored and Commit Queue committed Nov 16, 2024
1 parent 052c985 commit 5c904c1
Showing 1 changed file with 39 additions and 11 deletions.
50 changes: 39 additions & 11 deletions pkg/_fe_analyzer_shared/test/mini_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// but light weight enough to be suitable for unit testing of code in the
// `_fe_analyzer_shared` package.

import 'dart:core' as core show Type;
import 'dart:core' hide Type;

import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';

Expand Down Expand Up @@ -163,7 +166,7 @@ class FutureOrType extends PrimaryType {

/// A type name that represents an ordinary interface type.
class InterfaceTypeName extends TypeNameInfo {
InterfaceTypeName._(super.name);
InterfaceTypeName._(super.name) : super(expectedRuntimeType: PrimaryType);
}

/// Representation of an invalid type suitable for unit testing of code in the
Expand Down Expand Up @@ -261,7 +264,12 @@ class PrimaryType extends Type {

PrimaryType._(this.nameInfo,
{this.args = const [], super.nullabilitySuffix = NullabilitySuffix.none})
: super._();
: super._() {
assert(
runtimeType == nameInfo._expectedRuntimeType,
'${nameInfo.name} should use ${nameInfo._expectedRuntimeType}, but '
'constructed $runtimeType instead');
}

PrimaryType._special(SpecialTypeName nameInfo,
{List<Type> args = const [],
Expand Down Expand Up @@ -427,7 +435,7 @@ class RecordType extends Type implements SharedRecordTypeStructure<Type> {
/// - `Null`
/// - `void`
class SpecialTypeName extends TypeNameInfo {
SpecialTypeName._(super.name);
SpecialTypeName._(super.name, {required super.expectedRuntimeType});
}

/// Representation of a type suitable for unit testing of code in the
Expand Down Expand Up @@ -512,7 +520,21 @@ abstract class Type implements SharedTypeStructure<Type> {
sealed class TypeNameInfo {
final String name;

TypeNameInfo(this.name);
/// The runtime type that should be used for [Type] objects that refer to
/// `this`.
///
/// An assertion in the [PrimaryType] constructor verifies this.
///
/// This ensures that the methods [Type.closureWithRespectToUnknown],
/// [Type.recursivelyDemote], and [Type.withNullability] (which create new
/// instances of [Type] based on old ones) create the appropriate subtype of
/// [Type]. It also ensures that when [Type] objects are directly constructed
/// (as they are in this file and in `mini_ast.dart`), the appropriate subtype
/// of [Type] is used.
final core.Type _expectedRuntimeType;

TypeNameInfo(this.name, {required core.Type expectedRuntimeType})
: _expectedRuntimeType = expectedRuntimeType;
}

/// A type name that represents a type variable.
Expand All @@ -522,7 +544,9 @@ class TypeParameter extends TypeNameInfo
@override
Type bound;

TypeParameter._(super.name) : bound = Type('Object?');
TypeParameter._(super.name)
: bound = Type('Object?'),
super(expectedRuntimeType: TypeParameterType);

@override
String get displayName => name;
Expand Down Expand Up @@ -607,16 +631,19 @@ abstract final class TypeRegistry {
static Map<String, TypeNameInfo>? _typeNameInfoMap;

/// The [TypeNameInfo] object representing the special type `dynamic`.
static final dynamic_ = SpecialTypeName._('dynamic');
static final dynamic_ =
SpecialTypeName._('dynamic', expectedRuntimeType: DynamicType);

/// The [TypeNameInfo] object representing the special type `error`.
static final error_ = SpecialTypeName._('error');
static final error_ =
SpecialTypeName._('error', expectedRuntimeType: InvalidType);

/// The [TypeNameInfo] object representing the interface type `Future`.
static final future = InterfaceTypeName._('Future');

/// The [TypeNameInfo] object representing the special type `FutureOr`.
static final futureOr = SpecialTypeName._('FutureOr');
static final futureOr =
SpecialTypeName._('FutureOr', expectedRuntimeType: FutureOrType);

/// The [TypeNameInfo] object representing the interface type `Iterable`.
static final iterable = InterfaceTypeName._('Iterable');
Expand All @@ -628,16 +655,17 @@ abstract final class TypeRegistry {
static final map = InterfaceTypeName._('Map');

/// The [TypeNameInfo] object representing the special type `Never`.
static final never = SpecialTypeName._('Never');
static final never =
SpecialTypeName._('Never', expectedRuntimeType: NeverType);

/// The [TypeNameInfo] object representing the special type `Null`.
static final null_ = SpecialTypeName._('Null');
static final null_ = SpecialTypeName._('Null', expectedRuntimeType: NullType);

/// The [TypeNameInfo] object representing the interface type `Stream`.
static final stream = InterfaceTypeName._('Stream');

/// The [TypeNameInfo] object representing the special type `void`.
static final void_ = SpecialTypeName._('void');
static final void_ = SpecialTypeName._('void', expectedRuntimeType: VoidType);

/// Gets [_typeNameInfoMap], throwing an exception if it has not been
/// initialized.
Expand Down

0 comments on commit 5c904c1

Please sign in to comment.