mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:48:25 +00:00
[ddc] Add support for new native types
Use the "extension type" class as the interceptor object for the dart:_rti library. This applies to the new type system for values that are represented as a native JavaScript type. For example: Number, bool, String, Array, etc. Issue: https://github.com/dart-lang/sdk/issues/48585 Change-Id: Ie6214aa897d3ae8abb4f9619cd2be984eeb9c4ea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/266544 Reviewed-by: Mark Zhou <markzipan@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
1e4a974a5d
commit
c010e4ffbd
|
@ -813,6 +813,11 @@ defaultNoSuchMethod(obj, Invocation i) {
|
|||
throw NoSuchMethodError.withInvocation(obj, i);
|
||||
}
|
||||
|
||||
// TODO(nshahan) Replace with rti.getRuntimeType() when classes representing
|
||||
// native types don't have to "pretend" to be Dart classes. Ex:
|
||||
// JSNumber -> int or double
|
||||
// JSArray<E> -> List<E>
|
||||
// NativeFloat32List -> Float32List
|
||||
runtimeType(obj) {
|
||||
return obj == null ? Null : JS('', '#[dartx.runtimeType]', obj);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,34 @@ RecordType getRecordType(_RecordImpl obj) {
|
|||
return type;
|
||||
}
|
||||
|
||||
/// Returns the interceptor for [obj] as needed by the dart:rti library.
|
||||
@notNull
|
||||
Object getInterceptorForRti(obj) {
|
||||
var classRef;
|
||||
if (obj == null) {
|
||||
classRef = JS_CLASS_REF(Null);
|
||||
} else {
|
||||
switch (JS<String>('!', 'typeof #', obj)) {
|
||||
case 'number':
|
||||
classRef = JS('', 'Math.floor(#) == # ? # : #', obj, obj,
|
||||
JS_CLASS_REF(JSInt), JS_CLASS_REF(JSNumNotInt));
|
||||
break;
|
||||
case 'function':
|
||||
var signature =
|
||||
JS('', '#[#]', obj, JS_GET_NAME(JsGetName.SIGNATURE_NAME));
|
||||
if (signature != null) classRef = JS_CLASS_REF(Function);
|
||||
break;
|
||||
default:
|
||||
// The interceptors for native JavaScript types like bool, string, etc.
|
||||
// (excluding number and function, see above) are stored as a symbolized
|
||||
// property and can be accessed from the native value itself.
|
||||
classRef = JS('', '#[#]', obj, _extensionType);
|
||||
}
|
||||
}
|
||||
if (classRef == null) throw 'Unknown interceptor for object: ($obj)';
|
||||
return JS<Object>('!', '#.prototype', classRef);
|
||||
}
|
||||
|
||||
/// Returns the runtime representation of the type of obj.
|
||||
///
|
||||
/// The resulting object is used internally for runtime type checking. This is
|
||||
|
|
|
@ -21,12 +21,15 @@ import 'dart:_foreign_helper'
|
|||
spread;
|
||||
import 'dart:_interceptors'
|
||||
show
|
||||
JSArray,
|
||||
jsNull,
|
||||
JSFunction,
|
||||
NativeError,
|
||||
JavaScriptObject,
|
||||
LegacyJavaScriptObject;
|
||||
JSArray,
|
||||
JSInt,
|
||||
jsNull,
|
||||
JSNumNotInt,
|
||||
JSFunction,
|
||||
LegacyJavaScriptObject,
|
||||
NativeError;
|
||||
|
||||
import 'dart:_internal' as internal show LateError, Symbol;
|
||||
import 'dart:_js_helper'
|
||||
show
|
||||
|
|
|
@ -89,6 +89,9 @@ void nativeNonNullAsserts(bool enable) {
|
|||
_nativeNonNullAsserts = enable;
|
||||
}
|
||||
|
||||
/// A JavaScript Symbol used to store the Rti object on a native array.
|
||||
final arrayRti = JS('', r'Symbol("$ti")');
|
||||
|
||||
final metadata = JS('', 'Symbol("metadata")');
|
||||
|
||||
/// A javascript Symbol used to store a canonical version of T? on T.
|
||||
|
|
|
@ -7,6 +7,7 @@ library dart._foreign_helper;
|
|||
import 'dart:_interceptors' show JSArray;
|
||||
import 'dart:_js_helper' show notNull;
|
||||
import 'dart:_js_shared_embedded_names' show JsBuiltin, JsGetName;
|
||||
import 'dart:_runtime' as dart show getInterceptorForRti;
|
||||
import 'dart:_rti' show Rti;
|
||||
|
||||
/**
|
||||
|
@ -299,18 +300,7 @@ external JS_BUILTIN(String typeDescription, JsBuiltin builtin,
|
|||
/// Returns the interceptor for [object].
|
||||
///
|
||||
// TODO(nshahan) Replace calls at compile time?
|
||||
Object getInterceptor(obj) {
|
||||
var classRef;
|
||||
if (obj == null) {
|
||||
classRef = JS_CLASS_REF(Null);
|
||||
} else if (JS<String>('!', 'typeof #', obj) == 'function') {
|
||||
var signature = JS('', '#[#]', obj, JS_GET_NAME(JsGetName.SIGNATURE_NAME));
|
||||
// Dart functions are always tagged with a signature.
|
||||
if (signature != null) classRef = JS_CLASS_REF(Function);
|
||||
}
|
||||
if (classRef == null) throw 'Unknown interceptor for object: ($obj)';
|
||||
return JS<Object>('!', '#.prototype', classRef);
|
||||
}
|
||||
Object getInterceptor(obj) => dart.getInterceptorForRti(obj);
|
||||
|
||||
/// Returns the Rti object for the type for JavaScript arrays via JS-interop.
|
||||
///
|
||||
|
|
|
@ -7,10 +7,12 @@ library dart._interceptors;
|
|||
import 'dart:collection';
|
||||
import 'dart:_internal' hide Symbol;
|
||||
import 'dart:_js_helper';
|
||||
import 'dart:_foreign_helper' show JS, JS_GET_FLAG, JSExportName;
|
||||
import 'dart:_foreign_helper'
|
||||
show JS, JS_EMBEDDED_GLOBAL, JS_GET_FLAG, JSExportName;
|
||||
import 'dart:math' show Random, ln2;
|
||||
import 'dart:_rti' as rti show createRuntimeType, Rti;
|
||||
import 'dart:_runtime' as dart;
|
||||
import 'dart:_js_shared_embedded_names' show ARRAY_RTI_PROPERTY;
|
||||
|
||||
part 'js_array.dart';
|
||||
part 'js_number.dart';
|
||||
|
@ -115,6 +117,7 @@ class UnknownJavaScriptObject extends LegacyJavaScriptObject {
|
|||
const UnknownJavaScriptObject();
|
||||
}
|
||||
|
||||
@JsPeerInterface(name: 'Error')
|
||||
class NativeError extends Interceptor {
|
||||
String dartStack() => JS<String>('!', '#.stack', this);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
|
|||
// TODO(jmesserly): this uses special compiler magic to close over the
|
||||
// parameterized ES6 'JSArray' class.
|
||||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
if (JS_GET_FLAG('NEW_RUNTIME_TYPES'))
|
||||
JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY),
|
||||
JSArray<E>);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
|
@ -31,6 +34,9 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
|
|||
factory JSArray.fixed(list) {
|
||||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
if (JS_GET_FLAG('NEW_RUNTIME_TYPES'))
|
||||
JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY),
|
||||
JSArray<E>);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
|
@ -38,6 +44,9 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
|
|||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
JS('', r'#.immutable$list = Array', list);
|
||||
if (JS_GET_FLAG('NEW_RUNTIME_TYPES'))
|
||||
JS('', '#.# = #', list, JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY),
|
||||
JSArray<E>);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
|
@ -597,8 +606,7 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
|
|||
return ListMapView<E>(this);
|
||||
}
|
||||
|
||||
Type get runtimeType =>
|
||||
dart.wrapType(JS('', '#(#)', dart.getGenericClassStatic<List>(), E));
|
||||
Type get runtimeType => List<E>;
|
||||
|
||||
Iterable<E> followedBy(Iterable<E> other) =>
|
||||
FollowedByIterable<E>.firstEfficient(this, other);
|
||||
|
|
|
@ -16,7 +16,7 @@ class JSNumNotInt extends JSNumber implements double {}
|
|||
///
|
||||
/// These are made available as extension methods on `Number` in JS.
|
||||
@JsPeerInterface(name: 'Number')
|
||||
class JSNumber extends Interceptor implements int, double {
|
||||
class JSNumber extends Interceptor implements double {
|
||||
const JSNumber();
|
||||
|
||||
@notNull
|
||||
|
@ -482,7 +482,7 @@ class JSNumber extends Interceptor implements int, double {
|
|||
return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
|
||||
}
|
||||
|
||||
int b = this;
|
||||
int b = JS<int>('!', '#', this);
|
||||
if (b < 0 || b > m) {
|
||||
b %= m;
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ class JSNumber extends Interceptor implements int, double {
|
|||
if (this is! int) throwArgumentErrorValue(this);
|
||||
if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
|
||||
if (m == 1) return 0;
|
||||
int t = this;
|
||||
int t = JS<int>('!', '#', this);
|
||||
if ((t < 0) || (t >= m)) t %= m;
|
||||
if (t == 1) return 1;
|
||||
if ((t == 0) || (t.isEven && m.isEven)) {
|
||||
|
@ -587,7 +587,7 @@ class JSNumber extends Interceptor implements int, double {
|
|||
@notNull
|
||||
int gcd(@nullCheck int other) {
|
||||
if (this is! int) throwArgumentErrorValue(this);
|
||||
int x = this.abs();
|
||||
int x = JS<int>('!', '#', this).abs();
|
||||
int y = other.abs();
|
||||
if (x == 0) return y;
|
||||
if (y == 0) return x;
|
||||
|
|
Loading…
Reference in a new issue