[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>
diff --git a/pkg/compiler/test/inference/type_combination_test.dart b/pkg/compiler/test/inference/type_combination_test.dart index 8d772b0..3e90b7a 100644 --- a/pkg/compiler/test/inference/type_combination_test.dart +++ b/pkg/compiler/test/inference/type_combination_test.dart
@@ -785,7 +785,7 @@ patternClass = elementEnvironment.lookupClass(coreLibrary, 'Pattern'); final trustedGetRuntimeTypeInterface = elementEnvironment.lookupClass( - commonElements.rtiLibrary, 'TrustedGetRuntimeType')!; + commonElements.jsHelperLibrary!, 'TrustedGetRuntimeType')!; nonPrimitive1 = TypeMask.nonNullSubtype(closedWorld.commonElements.mapClass, closedWorld);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart index 451816c..98d3e2d 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3523,10 +3523,10 @@ // 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 @@ [_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 @@ 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),
diff --git a/pkg/dev_compiler/lib/src/kernel/type_recipe_generator.dart b/pkg/dev_compiler/lib/src/kernel/type_recipe_generator.dart index d0b7736..0c473ba 100644 --- a/pkg/dev_compiler/lib/src/kernel/type_recipe_generator.dart +++ b/pkg/dev_compiler/lib/src/kernel/type_recipe_generator.dart
@@ -157,9 +157,8 @@ 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 @@ } @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) {
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart index 23611af..e920806 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
@@ -13,6 +13,12 @@ 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); }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/records.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/records.dart index 15b2800..6cc4078 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/records.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/records.dart
@@ -96,9 +96,18 @@ /// 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 _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 @@ } } - 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); }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart index 3933478..11b00c4 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -2283,12 +2283,11 @@ /// 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); }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart index 739c89d..39384f4 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -30,7 +30,7 @@ * 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].
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk/lib/_internal/js_dev_runtime/private/js_array.dart index 041d595..c8cf132 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_array.dart
@@ -11,7 +11,8 @@ * 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(); /**
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart index a4d8848..3c52934 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -7,7 +7,7 @@ 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 @@ 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 @@ 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 {}
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart index 9a28f3a..3de5597 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
@@ -16,7 +16,8 @@ /// /// 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
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_string.dart b/sdk/lib/_internal/js_dev_runtime/private/js_string.dart index a99d26f..2f9e026 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_string.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_string.dart
@@ -12,7 +12,7 @@ */ @JsPeerInterface(name: 'String') final class JSString extends Interceptor - implements String, JSIndexable<String> { + implements String, JSIndexable<String>, TrustedGetRuntimeType { const JSString(); @notNull @@ -207,8 +207,10 @@ 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 @@ case 0x202F: case 0x205F: case 0x3000: - case 0xFEFF: return true; - default: return false; + case 0xFEFF: + return true; + default: + return false; } }
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart index 7f91159..79b283d 100644 --- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart +++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -41,7 +41,8 @@ throwConcurrentModificationError, lookupAndCacheInterceptor, StringMatch, - firstMatchAfter; + firstMatchAfter, + TrustedGetRuntimeType; import 'dart:_foreign_helper' show @@ -56,8 +57,7 @@ show createRuntimeType, getRuntimeTypeOfArray, - getRuntimeTypeOfInterceptorNotArray, - TrustedGetRuntimeType; + getRuntimeTypeOfInterceptorNotArray; import 'dart:math' show Random, ln2;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart index 285644b..9f3b92f 100644 --- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart +++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3205,3 +3205,35 @@ 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 {}
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart index 011e68f..224a45c 100644 --- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart +++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -19,9 +19,9 @@ Native, Returns, diagnoseIndexError, - diagnoseRangeError; + diagnoseRangeError, + TrustedGetRuntimeType; import 'dart:_foreign_helper' show JS; -import 'dart:_rti' show TrustedGetRuntimeType; import 'dart:math' as Math;
diff --git a/sdk/lib/_internal/js_shared/lib/rti.dart b/sdk/lib/_internal/js_shared/lib/rti.dart index 3387b6a..9c3a3d2 100644 --- a/sdk/lib/_internal/js_shared/lib/rti.dart +++ b/sdk/lib/_internal/js_shared/lib/rti.dart
@@ -22,41 +22,12 @@ 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 @@ 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; }
diff --git a/tests/dartdevc/debugger/debugger_test_golden.txt b/tests/dartdevc/debugger/debugger_test_golden.txt index defb03a..3b42e32 100644 --- a/tests/dartdevc/debugger/debugger_test_golden.txt +++ b/tests/dartdevc/debugger/debugger_test_golden.txt
@@ -239,7 +239,7 @@ { "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 @@ { "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
diff --git a/tests/dartdevc_2/debugger/debugger_test_golden.txt b/tests/dartdevc_2/debugger/debugger_test_golden.txt index defb03a..3b42e32 100644 --- a/tests/dartdevc_2/debugger/debugger_test_golden.txt +++ b/tests/dartdevc_2/debugger/debugger_test_golden.txt
@@ -239,7 +239,7 @@ { "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 @@ { "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