mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 15:39:54 +00:00
[ddc] Implement new record types
Update the format of the shape keys to better match the format used in the dart:_rti library. This change applies to the current runtime type system as well. Change-Id: I87d2af2aaf2b9dbe012fae60a64718d264a3a18c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295721 Reviewed-by: Mayank Patke <fishythefish@google.com> Reviewed-by: Mark Zhou <markzipan@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
42c79709a4
commit
f2aa312e17
|
@ -785,7 +785,7 @@ runTests() async {
|
|||
patternClass = elementEnvironment.lookupClass(coreLibrary, 'Pattern');
|
||||
|
||||
final trustedGetRuntimeTypeInterface = elementEnvironment.lookupClass(
|
||||
commonElements.rtiLibrary, 'TrustedGetRuntimeType')!;
|
||||
commonElements.jsHelperLibrary!, 'TrustedGetRuntimeType')!;
|
||||
|
||||
nonPrimitive1 =
|
||||
TypeMask.nonNullSubtype(closedWorld.commonElements.mapClass, closedWorld);
|
||||
|
|
|
@ -3523,10 +3523,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
// RecordType names are already sorted alphabetically in kernel.
|
||||
var positionals = positionalTypeReps.length;
|
||||
var names = type.named.map((e) => e.name);
|
||||
var shape = '$positionals ${names.join(" ")}';
|
||||
var shapeKey = _recordShapeKey(positionals, names);
|
||||
|
||||
return runtimeCall('recordTypeLiteral(#, #, #, [#])', [
|
||||
js.string(shape),
|
||||
js.string(shapeKey),
|
||||
js.number(positionals),
|
||||
names.isEmpty ? js.call('void 0') : js.stringArray(names),
|
||||
[
|
||||
|
@ -6912,17 +6912,27 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
[_emitType(keyType), _emitType(valueType), entries]));
|
||||
}
|
||||
|
||||
/// Returns the key used for shape lookup at runtime.
|
||||
///
|
||||
/// See `shapes` in dart:_runtime (records.dart) for a description.
|
||||
String _recordShapeKey(
|
||||
int positionalElementCount, Iterable<String> namedElementNames) {
|
||||
var elementCount = positionalElementCount + namedElementNames.length;
|
||||
return '$elementCount;${namedElementNames.join(',')}';
|
||||
}
|
||||
|
||||
@override
|
||||
js_ast.Expression visitRecordLiteral(RecordLiteral node) {
|
||||
var names = node.named.map((element) => element.name);
|
||||
var recipe = '${node.positional.length} ${names.join(" ")}';
|
||||
var positionalElementCount = node.positional.length;
|
||||
var shapeKey = _recordShapeKey(positionalElementCount, names);
|
||||
var shapeExpr = runtimeCall('recordLiteral(#, #, #, [#])', [
|
||||
js.string(recipe),
|
||||
js.number(node.positional.length),
|
||||
js.string(shapeKey),
|
||||
js.number(positionalElementCount),
|
||||
names.isEmpty ? js.call('void 0') : js.stringArray(names),
|
||||
[
|
||||
...node.positional.map(_visitExpression),
|
||||
...node.named.map((e) => _visitExpression(e.value))
|
||||
for (var positional in node.positional) _visitExpression(positional),
|
||||
for (var named in node.named) _visitExpression(named.value),
|
||||
]
|
||||
]);
|
||||
return shapeExpr;
|
||||
|
@ -7276,10 +7286,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
js_ast.Expression visitRecordConstant(RecordConstant node) {
|
||||
// RecordConstant names are already sorted alphabetically in kernel.
|
||||
var names = node.named.keys;
|
||||
var shape = '${node.positional.length} ${names.join(" ")}';
|
||||
var positionalElementCount = node.positional.length;
|
||||
var shapeKey = _recordShapeKey(positionalElementCount, names);
|
||||
return runtimeCall('recordLiteral(#, #, #, [#])', [
|
||||
js.string(shape),
|
||||
js.number(node.positional.length),
|
||||
js.string(shapeKey),
|
||||
js.number(positionalElementCount),
|
||||
names.isEmpty ? js.call('void 0') : js.stringArray(names),
|
||||
[
|
||||
...node.positional.map(visitConstant),
|
||||
|
|
|
@ -157,9 +157,8 @@ class _TypeRecipeVisitor extends DartTypeVisitor<String> {
|
|||
Set.unmodifiable(_visitedInterfaceTypes);
|
||||
|
||||
@override
|
||||
String defaultDartType(DartType node) {
|
||||
throw UnimplementedError('Unknown DartType: $node');
|
||||
}
|
||||
String defaultDartType(DartType node) =>
|
||||
throw UnimplementedError('Unknown DartType: $node');
|
||||
|
||||
@override
|
||||
String visitDynamicType(DynamicType node) => Recipe.pushDynamicString;
|
||||
|
@ -263,11 +262,24 @@ class _TypeRecipeVisitor extends DartTypeVisitor<String> {
|
|||
}
|
||||
|
||||
@override
|
||||
// Just emit the recipe for dynamic as a temporary workaround to unblock
|
||||
// the use of record types landing in the sdk.
|
||||
// See: https://github.com/dart-lang/sdk/issues/51904
|
||||
// TODO(nshahan): Implement valid record type recipes.
|
||||
String visitRecordType(RecordType node) => Recipe.pushDynamicString;
|
||||
String visitRecordType(RecordType node) {
|
||||
var recipeBuffer = StringBuffer(Recipe.startRecordString);
|
||||
// Add the names of the named elements.
|
||||
recipeBuffer.writeAll(
|
||||
node.named.map((element) => element.name), Recipe.separatorString);
|
||||
// Add all element types.
|
||||
recipeBuffer.write(Recipe.startFunctionArgumentsString);
|
||||
var elementTypes = [
|
||||
...node.positional,
|
||||
...node.named.map((element) => element.type)
|
||||
];
|
||||
recipeBuffer.writeAll(elementTypes.map((element) => element.accept(this)),
|
||||
Recipe.separatorString);
|
||||
recipeBuffer.write(Recipe.endFunctionArgumentsString);
|
||||
// Add the records nullability.
|
||||
recipeBuffer.write(_nullabilityRecipe(node));
|
||||
return recipeBuffer.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
String visitTypeParameterType(TypeParameterType node) {
|
||||
|
|
|
@ -13,6 +13,12 @@ argumentError(value) {
|
|||
throw ArgumentError.value(value);
|
||||
}
|
||||
|
||||
/// Only used during the development of the new runtime type system in branches
|
||||
/// that should never be executed.
|
||||
// TODO(48585): Remove after switching to the new runtime type system.
|
||||
Never throwUnimplementedInOldRti() => throw UnimplementedError(
|
||||
'This code path is not support with the old runtime type system.');
|
||||
|
||||
throwUnimplementedError(String message) {
|
||||
throw UnimplementedError(message);
|
||||
}
|
||||
|
|
|
@ -96,9 +96,18 @@ final class RecordImpl implements Record {
|
|||
|
||||
/// Cache used to canonicalize all Record shapes in the program.
|
||||
///
|
||||
/// These are keyed by a distinct shape recipe String, which consists of an
|
||||
/// integer followed by space-separated named labels.
|
||||
final _shapes = JS('!', 'new Map()');
|
||||
/// [Shape]s are keyed by a distinct shape key [String], that consists of the
|
||||
/// total number of elements followed by semicolon and then a comma-separated
|
||||
/// list of the named element names in sorted order.
|
||||
///
|
||||
/// Shape key examples:
|
||||
///
|
||||
/// | Record | Shape Key |
|
||||
/// -------------------------------------------------------
|
||||
/// | (false, "hello") | "2;" |
|
||||
/// | (name: "Fosse", legs: 4) | "2;legs,name" |
|
||||
/// | ("hello", name: "Cello", legs: 4) | "3;legs,name" |
|
||||
final shapes = JS('!', 'new Map()');
|
||||
|
||||
/// Cache used to canonicalize all Record representation classes in the program.
|
||||
///
|
||||
|
@ -107,27 +116,30 @@ final _shapes = JS('!', 'new Map()');
|
|||
final _records = JS('!', 'new Map()');
|
||||
|
||||
/// Returns a canonicalized shape for the provided number of [positionals] and
|
||||
/// [named] elements as described by the [shapeRecipe].
|
||||
Shape registerShape(@notNull String shapeRecipe, @notNull int positionals,
|
||||
List<String>? named) {
|
||||
var cached = JS<Shape?>('', '#.get(#)', _shapes, shapeRecipe);
|
||||
/// [named] elements.
|
||||
///
|
||||
/// The [shapeKey] must agree with the number of [positionals] and the [named]
|
||||
/// elements list. See [shapes] for a description of the shape key format.
|
||||
Shape registerShape(
|
||||
@notNull String shapeKey, @notNull int positionals, List<String>? named) {
|
||||
var cached = JS<Shape?>('', '#.get(#)', shapes, shapeKey);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
var shape = Shape(positionals, named);
|
||||
JS('', '#.set(#, #)', _shapes, shapeRecipe, shape);
|
||||
JS('', '#.set(#, #)', shapes, shapeKey, shape);
|
||||
return shape;
|
||||
}
|
||||
|
||||
/// Returns a canonicalized Record class with the provided number of
|
||||
/// [positionals] and [named] elements.
|
||||
///
|
||||
/// The class can be used to construct record values of the shape described by
|
||||
/// the [shapeRecipe].
|
||||
Object registerRecord(@notNull String shapeRecipe, @notNull int positionals,
|
||||
List<String>? named) {
|
||||
var cached = JS('', '#.get(#)', _records, shapeRecipe);
|
||||
/// The [shapeKey] must agree with the number of [positionals] and the [named]
|
||||
/// elements list. See [shapes] for a description of the shape key format.
|
||||
Object registerRecord(
|
||||
@notNull String shapeKey, @notNull int positionals, List<String>? named) {
|
||||
var cached = JS('', '#.get(#)', _records, shapeKey);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
@ -168,19 +180,19 @@ Object registerRecord(@notNull String shapeRecipe, @notNull int positionals,
|
|||
}
|
||||
}
|
||||
|
||||
JS('', '#.set(#, #)', _records, shapeRecipe, newRecord);
|
||||
JS('', '#.set(#, #)', _records, shapeKey, newRecord);
|
||||
return newRecord;
|
||||
}
|
||||
|
||||
/// Creates a shape and binds it to [values].
|
||||
/// Creates a record consisting of [values] with the shape described by the
|
||||
/// number of [positionals] and [named] elements.
|
||||
///
|
||||
/// [shapeRecipe] consists of a space-separated list of elements, where the
|
||||
/// first element is the number of positional elements, followed by every
|
||||
/// named element in sorted order.
|
||||
Object recordLiteral(@notNull String shapeRecipe, @notNull int positionals,
|
||||
/// The [shapeKey] must agree with the number of [positionals] and the [named]
|
||||
/// elements list. See [shapes] for a description of the shape key format.
|
||||
Object recordLiteral(@notNull String shapeKey, @notNull int positionals,
|
||||
List<String>? named, @notNull List values) {
|
||||
var shape = registerShape(shapeRecipe, positionals, named);
|
||||
var record = registerRecord(shapeRecipe, positionals, named);
|
||||
var shape = registerShape(shapeKey, positionals, named);
|
||||
var record = registerRecord(shapeKey, positionals, named);
|
||||
return JS('!', 'new #(#, #)', record, shape, values);
|
||||
}
|
||||
|
||||
|
|
|
@ -2283,12 +2283,11 @@ RecordType recordType(@notNull Shape shape, @notNull List types) =>
|
|||
|
||||
/// Creates a shape and binds it to [types].
|
||||
///
|
||||
/// [shapeRecipe] consists of a space-separated list of elements, where the
|
||||
/// first element is the number of positional elements, followed by every
|
||||
/// named element in sorted order.
|
||||
RecordType recordTypeLiteral(@notNull String shapeRecipe,
|
||||
@notNull int positionals, List<String>? named, @notNull List types) {
|
||||
var shape = registerShape(shapeRecipe, positionals, named);
|
||||
/// The [shapeKey] must agree with the number of [positionals] and the [named]
|
||||
/// elements list. See [shapes] for a description of the shape key format.
|
||||
RecordType recordTypeLiteral(@notNull String shapeKey, @notNull int positionals,
|
||||
List<String>? named, @notNull List types) {
|
||||
var shape = registerShape(shapeKey, positionals, named);
|
||||
return recordType(shape, types);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ abstract class Interceptor {
|
|||
* The interceptor class for [bool].
|
||||
*/
|
||||
@JsPeerInterface(name: 'Boolean')
|
||||
final class JSBool extends Interceptor implements bool {
|
||||
final class JSBool extends Interceptor implements bool, TrustedGetRuntimeType {
|
||||
const JSBool();
|
||||
|
||||
// Note: if you change this, also change the function [S].
|
||||
|
|
|
@ -11,7 +11,8 @@ part of dart._interceptors;
|
|||
* argument added to each member.
|
||||
*/
|
||||
@JsPeerInterface(name: 'Array')
|
||||
class JSArray<E> extends JavaScriptObject implements List<E>, JSIndexable<E> {
|
||||
class JSArray<E> extends JavaScriptObject
|
||||
implements List<E>, JSIndexable<E>, TrustedGetRuntimeType {
|
||||
const JSArray();
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@ library dart._js_helper;
|
|||
import 'dart:async' show Zone;
|
||||
import 'dart:collection';
|
||||
|
||||
import 'dart:_foreign_helper' show JS, JSExportName;
|
||||
import 'dart:_foreign_helper' show JS, JS_CLASS_REF, JS_GET_FLAG, JSExportName;
|
||||
|
||||
import 'dart:_interceptors';
|
||||
import 'dart:_internal'
|
||||
|
@ -19,6 +19,7 @@ import 'dart:_internal'
|
|||
patch;
|
||||
|
||||
import 'dart:_native_typed_data';
|
||||
import 'dart:_rti' as rti show pairwiseIsTest, evaluateRtiForRecord, Rti;
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
part 'annotations.dart';
|
||||
|
@ -863,15 +864,84 @@ void Function(T)? wrapZoneUnaryCallback<T>(void Function(T)? callback) {
|
|||
return Zone.current.bindUnaryCallbackGuarded(callback);
|
||||
}
|
||||
|
||||
/// [createRecordTypePredicate] is currently unused by DDC.
|
||||
Object? createRecordTypePredicate(Object? partialShapeTag, Object? fieldRtis) {
|
||||
throw UnimplementedError('createRecordTypePredicate');
|
||||
/// Returns a JavaScript predicate that tests if the argument is a record with
|
||||
/// the given shape and fields types.
|
||||
///
|
||||
/// Only called from the `dart:_rti` library but requires specific knowledge of
|
||||
/// the record representation in DDC. There is a duplicate version of this
|
||||
/// method in the dart2js version of this library.
|
||||
///
|
||||
/// The shape is determined by the number of fields and the [partialShapeTag].
|
||||
/// [fieldRtis] contains the Rti type objects for each field in order of
|
||||
/// positionals followed by the sorted named elements.
|
||||
Object? createRecordTypePredicate(String partialShapeTag, JSArray fieldRtis) {
|
||||
if (JS_GET_FLAG('NEW_RUNTIME_TYPES')) {
|
||||
var shapeKey =
|
||||
JS<String>('!', '#.length + ";" + #', fieldRtis, partialShapeTag);
|
||||
return (obj) {
|
||||
return JS<bool>(
|
||||
'!', '# instanceof #', obj, JS_CLASS_REF(dart.RecordImpl)) &&
|
||||
JS<dart.RecordImpl>('!', '#', obj).shape ==
|
||||
JS<dart.Shape?>('', '#.get(#)', dart.shapes, shapeKey) &&
|
||||
rti.pairwiseIsTest(fieldRtis, JS<JSArray>('!', '#.values', obj));
|
||||
};
|
||||
} else {
|
||||
dart.throwUnimplementedInOldRti();
|
||||
}
|
||||
}
|
||||
|
||||
/// Entrypoint for rti library. Calls rti.evaluateRtiForRecord with components
|
||||
/// of the record.
|
||||
/// Returns the Rti for the provided [record].
|
||||
///
|
||||
/// [getRtiForRecord] is currently unused by DDC.
|
||||
Never getRtiForRecord(Object? record) {
|
||||
throw UnimplementedError('getRtiForRecord');
|
||||
/// Only called from the `dart:_rti` library but requires specific knowledge of
|
||||
/// the record representation in DDC. There is a duplicate version of this
|
||||
/// method in the dart2js version of this library.
|
||||
///
|
||||
/// Calls [rti.evaluateRtiForRecord] with components of the [record].
|
||||
rti.Rti getRtiForRecord(Object? record) {
|
||||
if (JS_GET_FLAG('NEW_RUNTIME_TYPES')) {
|
||||
var recordObj = JS<dart.RecordImpl>('!', '#', record);
|
||||
var recipeBuffer = StringBuffer('+');
|
||||
var named = recordObj.shape.named;
|
||||
if (named != null) recipeBuffer.writeAll(named, ',');
|
||||
recipeBuffer.write('(');
|
||||
var elementCount = recordObj.values.length;
|
||||
recipeBuffer.writeAll([for (var i = 1; i <= elementCount; i++) i], ',');
|
||||
recipeBuffer.write(')');
|
||||
|
||||
return rti.evaluateRtiForRecord(recipeBuffer.toString(), recordObj.values);
|
||||
} else {
|
||||
dart.throwUnimplementedInOldRti();
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker interface for classes with 'trustworthy' implementations of `get
|
||||
/// runtimeType`.
|
||||
///
|
||||
/// Generally, overrides of `get runtimeType` are not used in displaying the
|
||||
/// types of irritants in TypeErrors or computing the structural `runtimeType`
|
||||
/// of records. Instead the Rti (aka 'true') type is used.
|
||||
///
|
||||
/// The 'true' type is sometimes confusing because it shows implementation
|
||||
/// details, e.g. the true type of `42` is `JSInt` and `2.1` is `JSNumNotInt`.
|
||||
///
|
||||
/// For a limited number of implementation classes we tell a 'white lie' that
|
||||
/// the value is of another type, e.g. that `42` is an `int` and `2.1` is
|
||||
/// `double`. This is achieved by overriding `get runtimeType` to return the
|
||||
/// desired type, and marking the implementation class type with `implements
|
||||
/// [TrustedGetRuntimeType]`.
|
||||
///
|
||||
/// [TrustedGetRuntimeType] is not exposed outside the `dart:` libraries so
|
||||
/// users cannot tell lies.
|
||||
///
|
||||
/// The `Type` returned by a trusted `get runtimeType` must be an instance of
|
||||
/// the system `Type`, which is guaranteed by using a type literal. Type
|
||||
/// literals can be generic and dependent on type variables, e.g. `List<E>`.
|
||||
///
|
||||
/// Care needs to taken to ensure that the runtime does not get caught telling
|
||||
/// lies. Generally, a class's `runtimeType` lies by returning an abstract
|
||||
/// supertype of the class. Since both the the marker interface and `get
|
||||
/// runtimeType` are inherited, there should be no way in which a user can
|
||||
/// extend the class or implement interface of the class.
|
||||
// TODO(48585): Move this class back to the dart:_rti library when old DDC
|
||||
// runtime type system has been removed.
|
||||
abstract class TrustedGetRuntimeType {}
|
||||
|
|
|
@ -16,7 +16,8 @@ final class JSNumNotInt extends JSNumber implements double {}
|
|||
///
|
||||
/// These are made available as extension methods on `Number` in JS.
|
||||
@JsPeerInterface(name: 'Number')
|
||||
final class JSNumber extends Interceptor implements double {
|
||||
final class JSNumber extends Interceptor
|
||||
implements double, TrustedGetRuntimeType {
|
||||
const JSNumber();
|
||||
|
||||
@notNull
|
||||
|
|
|
@ -12,7 +12,7 @@ part of dart._interceptors;
|
|||
*/
|
||||
@JsPeerInterface(name: 'String')
|
||||
final class JSString extends Interceptor
|
||||
implements String, JSIndexable<String> {
|
||||
implements String, JSIndexable<String>, TrustedGetRuntimeType {
|
||||
const JSString();
|
||||
|
||||
@notNull
|
||||
|
@ -207,8 +207,10 @@ final class JSString extends Interceptor
|
|||
case 0x0D:
|
||||
case 0x20:
|
||||
case 0x85:
|
||||
case 0xA0: return true;
|
||||
default: return false;
|
||||
case 0xA0:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch (codeUnit) {
|
||||
|
@ -229,8 +231,10 @@ final class JSString extends Interceptor
|
|||
case 0x202F:
|
||||
case 0x205F:
|
||||
case 0x3000:
|
||||
case 0xFEFF: return true;
|
||||
default: return false;
|
||||
case 0xFEFF:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ import 'dart:_js_helper'
|
|||
throwConcurrentModificationError,
|
||||
lookupAndCacheInterceptor,
|
||||
StringMatch,
|
||||
firstMatchAfter;
|
||||
firstMatchAfter,
|
||||
TrustedGetRuntimeType;
|
||||
|
||||
import 'dart:_foreign_helper'
|
||||
show
|
||||
|
@ -56,8 +57,7 @@ import 'dart:_rti'
|
|||
show
|
||||
createRuntimeType,
|
||||
getRuntimeTypeOfArray,
|
||||
getRuntimeTypeOfInterceptorNotArray,
|
||||
TrustedGetRuntimeType;
|
||||
getRuntimeTypeOfInterceptorNotArray;
|
||||
|
||||
import 'dart:math' show Random, ln2;
|
||||
|
||||
|
|
|
@ -3205,3 +3205,35 @@ void Function(T)? wrapZoneUnaryCallback<T>(void Function(T)? callback) {
|
|||
if (callback == null) return null;
|
||||
return Zone.current.bindUnaryCallbackGuarded(callback);
|
||||
}
|
||||
|
||||
/// A marker interface for classes with 'trustworthy' implementations of `get
|
||||
/// runtimeType`.
|
||||
///
|
||||
/// Generally, overrides of `get runtimeType` are not used in displaying the
|
||||
/// types of irritants in TypeErrors or computing the structural `runtimeType`
|
||||
/// of records. Instead the Rti (aka 'true') type is used.
|
||||
///
|
||||
/// The 'true' type is sometimes confusing because it shows implementation
|
||||
/// details, e.g. the true type of `42` is `JSInt` and `2.1` is `JSNumNotInt`.
|
||||
///
|
||||
/// For a limited number of implementation classes we tell a 'white lie' that
|
||||
/// the value is of another type, e.g. that `42` is an `int` and `2.1` is
|
||||
/// `double`. This is achieved by overriding `get runtimeType` to return the
|
||||
/// desired type, and marking the implementation class type with `implements
|
||||
/// [TrustedGetRuntimeType]`.
|
||||
///
|
||||
/// [TrustedGetRuntimeType] is not exposed outside the `dart:` libraries so
|
||||
/// users cannot tell lies.
|
||||
///
|
||||
/// The `Type` returned by a trusted `get runtimeType` must be an instance of
|
||||
/// the system `Type`, which is guaranteed by using a type literal. Type
|
||||
/// literals can be generic and dependent on type variables, e.g. `List<E>`.
|
||||
///
|
||||
/// Care needs to taken to ensure that the runtime does not get caught telling
|
||||
/// lies. Generally, a class's `runtimeType` lies by returning an abstract
|
||||
/// supertype of the class. Since both the the marker interface and `get
|
||||
/// runtimeType` are inherited, there should be no way in which a user can
|
||||
/// extend the class or implement interface of the class.
|
||||
// TODO(48585): Move this class back to the dart:_rti library when old DDC
|
||||
// runtime type system has been removed.
|
||||
abstract class TrustedGetRuntimeType {}
|
||||
|
|
|
@ -19,9 +19,9 @@ import 'dart:_js_helper'
|
|||
Native,
|
||||
Returns,
|
||||
diagnoseIndexError,
|
||||
diagnoseRangeError;
|
||||
diagnoseRangeError,
|
||||
TrustedGetRuntimeType;
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_rti' show TrustedGetRuntimeType;
|
||||
|
||||
import 'dart:math' as Math;
|
||||
|
||||
|
|
|
@ -22,41 +22,12 @@ import 'dart:_interceptors'
|
|||
show JavaScriptFunction, JSArray, JSNull, JSUnmodifiableArray;
|
||||
import 'dart:_js_helper' as records
|
||||
show createRecordTypePredicate, getRtiForRecord;
|
||||
import 'dart:_js_helper' as helper show TrustedGetRuntimeType;
|
||||
import 'dart:_js_names'
|
||||
show getSpecializedTestTag, unmangleGlobalNameIfPreservedAnyways;
|
||||
import 'dart:_js_shared_embedded_names';
|
||||
import 'dart:_recipe_syntax';
|
||||
|
||||
/// A marker interface for classes with 'trustworthy' implementations of `get
|
||||
/// runtimeType`.
|
||||
///
|
||||
/// Generally, overrides of `get runtimeType` are not used in displaying the
|
||||
/// types of irritants in TypeErrors or computing the structural `runtimeType`
|
||||
/// of records. Instead the Rti (aka 'true') type is used.
|
||||
///
|
||||
/// The 'true' type is sometimes confusing because it shows implementation
|
||||
/// details, e.g. the true type of `42` is `JSInt` and `2.1` is `JSNumNotInt`.
|
||||
///
|
||||
/// For a limited number of implementation classes we tell a 'white lie' that
|
||||
/// the value is of another type, e.g. that `42` is an `int` and `2.1` is
|
||||
/// `double`. This is achieved by overriding `get runtimeType` to return the
|
||||
/// desired type, and marking the implementation class type with `implements
|
||||
/// [TrustedGetRuntimeType]`.
|
||||
///
|
||||
/// [TrustedGetRuntimeType] is not exposed outside the `dart:` libraries so
|
||||
/// users cannot tell lies.
|
||||
///
|
||||
/// The `Type` returned by a trusted `get runtimeType` must be an instance of
|
||||
/// the system `Type`, which is guaranteed by using a type literal. Type
|
||||
/// literals can be generic and dependent on type variables, e.g. `List<E>`.
|
||||
///
|
||||
/// Care needs to taken to ensure that the runtime does not get caught telling
|
||||
/// lies. Generally, a class's `runtimeType` lies by returning an abstract
|
||||
/// supertype of the class. Since both the the marker interface and `get
|
||||
/// runtimeType` are inherited, there should be no way in which a user can
|
||||
/// extend the class or implement interface of the class.
|
||||
abstract class TrustedGetRuntimeType {}
|
||||
|
||||
/// The name of a property on the constructor function of Dart Object
|
||||
/// and interceptor types, used for caching Rti types.
|
||||
const constructorRtiCachePropertyName = r'$ccache';
|
||||
|
@ -986,7 +957,7 @@ Rti _structuralTypeOf(Object? object) {
|
|||
if (object is Record) return records.getRtiForRecord(object);
|
||||
final functionRti = _instanceFunctionType(object);
|
||||
if (functionRti != null) return functionRti;
|
||||
if (object is TrustedGetRuntimeType) {
|
||||
if (object is helper.TrustedGetRuntimeType) {
|
||||
final type = object.runtimeType;
|
||||
return _Utils.as_Type(type)._rti;
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ Value:
|
|||
{
|
||||
"style": "background-color: #d9edf7;color: black"
|
||||
},
|
||||
"List<Object> implements List<Object>, JSIndexable<Object>"
|
||||
"List<Object> implements List<Object>, JSIndexable<Object>, TrustedGetRuntimeType"
|
||||
]
|
||||
-----------------------------------
|
||||
Test: List<Object> definition formatting body
|
||||
|
@ -1788,7 +1788,7 @@ Value:
|
|||
{
|
||||
"style": "background-color: #d9edf7;color: black"
|
||||
},
|
||||
"List<int> implements List<int>, JSIndexable<int>"
|
||||
"List<int> implements List<int>, JSIndexable<int>, TrustedGetRuntimeType"
|
||||
]
|
||||
-----------------------------------
|
||||
Test: List<int> large definition formatting body
|
||||
|
|
|
@ -239,7 +239,7 @@ Value:
|
|||
{
|
||||
"style": "background-color: #d9edf7;color: black"
|
||||
},
|
||||
"List<Object> implements List<Object>, JSIndexable<Object>"
|
||||
"List<Object> implements List<Object>, JSIndexable<Object>, TrustedGetRuntimeType"
|
||||
]
|
||||
-----------------------------------
|
||||
Test: List<Object> definition formatting body
|
||||
|
@ -1788,7 +1788,7 @@ Value:
|
|||
{
|
||||
"style": "background-color: #d9edf7;color: black"
|
||||
},
|
||||
"List<int> implements List<int>, JSIndexable<int>"
|
||||
"List<int> implements List<int>, JSIndexable<int>, TrustedGetRuntimeType"
|
||||
]
|
||||
-----------------------------------
|
||||
Test: List<int> large definition formatting body
|
||||
|
|
Loading…
Reference in a new issue