mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Add runtime type representation for void
Change-Id: Id4eff63656fc5eacfa7aada6120d85acec735cad Reviewed-on: https://dart-review.googlesource.com/48426 Reviewed-by: Stephen Adams <sra@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
parent
477a773cdb
commit
a6a2152482
|
@ -620,6 +620,14 @@ abstract class RuntimeTypesEncoder {
|
|||
/// is a FutureOr type.
|
||||
jsAst.Template get templateForIsFutureOrType;
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the void type.
|
||||
jsAst.Template get templateForIsVoidType;
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the dynamic type.
|
||||
jsAst.Template get templateForIsDynamicType;
|
||||
|
||||
jsAst.Name get getFunctionThatReturnsNullName;
|
||||
|
||||
/// Returns a [jsAst.Expression] representing the given [type]. Type variables
|
||||
|
@ -1822,6 +1830,20 @@ class RuntimeTypesEncoderImpl implements RuntimeTypesEncoder {
|
|||
return _representationGenerator.templateForIsFutureOrType;
|
||||
}
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the void type.
|
||||
@override
|
||||
jsAst.Template get templateForIsVoidType {
|
||||
return _representationGenerator.templateForIsVoidType;
|
||||
}
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the dynamic type.
|
||||
@override
|
||||
jsAst.Template get templateForIsDynamicType {
|
||||
return _representationGenerator.templateForIsDynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
jsAst.Expression getTypeRepresentation(
|
||||
Emitter emitter, DartType type, OnVariableCallback onVariable,
|
||||
|
@ -2015,6 +2037,8 @@ class TypeRepresentationGenerator
|
|||
|
||||
jsAst.Expression getDynamicValue() => js('null');
|
||||
|
||||
jsAst.Expression getVoidValue() => js('-1');
|
||||
|
||||
@override
|
||||
jsAst.Expression visit(DartType type, Emitter emitter) =>
|
||||
type.accept(this, emitter);
|
||||
|
@ -2078,6 +2102,18 @@ class TypeRepresentationGenerator
|
|||
return jsAst.js.expressionTemplateFor("'${namer.futureOrTag}' in #");
|
||||
}
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the void type.
|
||||
jsAst.Template get templateForIsVoidType {
|
||||
return jsAst.js.expressionTemplateFor("# === -1");
|
||||
}
|
||||
|
||||
/// Returns the JavaScript template to determine at runtime if a type object
|
||||
/// is the dynamic type.
|
||||
jsAst.Template get templateForIsDynamicType {
|
||||
return jsAst.js.expressionTemplateFor("# == null");
|
||||
}
|
||||
|
||||
jsAst.Expression visitFunctionType(FunctionType type, Emitter emitter) {
|
||||
List<jsAst.Property> properties = <jsAst.Property>[];
|
||||
|
||||
|
@ -2102,7 +2138,7 @@ class TypeRepresentationGenerator
|
|||
visitList(type.typeVariables.map((v) => v.bound).toList(), emitter));
|
||||
}
|
||||
|
||||
if (type.returnType.isVoid) {
|
||||
if (!_strongMode && type.returnType.isVoid) {
|
||||
addProperty(namer.functionTypeVoidReturnTag, js('true'));
|
||||
} else if (!type.returnType.treatAsDynamic) {
|
||||
addProperty(
|
||||
|
@ -2140,12 +2176,11 @@ class TypeRepresentationGenerator
|
|||
|
||||
jsAst.Expression visitMalformedType(MalformedType type, Emitter emitter) {
|
||||
// Treat malformed types as dynamic at runtime.
|
||||
return js('null');
|
||||
return getDynamicValue();
|
||||
}
|
||||
|
||||
jsAst.Expression visitVoidType(VoidType type, Emitter emitter) {
|
||||
// TODO(ahe): Reify void type ("null" means "dynamic").
|
||||
return js('null');
|
||||
return _strongMode ? getVoidValue() : getDynamicValue();
|
||||
}
|
||||
|
||||
jsAst.Expression visitTypedefType(
|
||||
|
|
|
@ -339,6 +339,12 @@ class Emitter extends js_emitter.EmitterBase {
|
|||
case JsBuiltin.isFutureOrType:
|
||||
return backend.rtiEncoder.templateForIsFutureOrType;
|
||||
|
||||
case JsBuiltin.isVoidType:
|
||||
return backend.rtiEncoder.templateForIsVoidType;
|
||||
|
||||
case JsBuiltin.isDynamicType:
|
||||
return backend.rtiEncoder.templateForIsDynamicType;
|
||||
|
||||
case JsBuiltin.rawRtiToJsConstructorName:
|
||||
return jsAst.js.expressionTemplateFor("#.$typeNameProperty");
|
||||
|
||||
|
|
|
@ -129,6 +129,12 @@ class Emitter extends emitterTask.EmitterBase {
|
|||
case JsBuiltin.isFutureOrType:
|
||||
return _backend.rtiEncoder.templateForIsFutureOrType;
|
||||
|
||||
case JsBuiltin.isVoidType:
|
||||
return _backend.rtiEncoder.templateForIsVoidType;
|
||||
|
||||
case JsBuiltin.isDynamicType:
|
||||
return _backend.rtiEncoder.templateForIsDynamicType;
|
||||
|
||||
case JsBuiltin.rawRtiToJsConstructorName:
|
||||
return js.js.expressionTemplateFor("#.name");
|
||||
|
||||
|
|
|
@ -92,6 +92,9 @@ String isCheckPropertyToJsConstructorName(String isCheckProperty) {
|
|||
// TODO(floitsch): move this to foreign_helper.dart or similar.
|
||||
@ForceInline()
|
||||
bool isDartFunctionType(Object type) {
|
||||
// Function type test is using the `in` operator which doesn't work on
|
||||
// primitive types.
|
||||
assert(!(type == null || type is num || type is String));
|
||||
return JS_BUILTIN(
|
||||
'returns:bool;effects:none;depends:none', JsBuiltin.isFunctionType, type);
|
||||
}
|
||||
|
@ -100,10 +103,19 @@ bool isDartFunctionType(Object type) {
|
|||
// TODO(floitsch): move this to foreign_helper.dart or similar.
|
||||
@ForceInline()
|
||||
bool isDartFutureOrType(Object type) {
|
||||
// FutureOr test is using the `in` operator which doesn't work on primitive
|
||||
// types.
|
||||
assert(!(type == null || type is num || type is String));
|
||||
return JS_BUILTIN(
|
||||
'returns:bool;effects:none;depends:none', JsBuiltin.isFutureOrType, type);
|
||||
}
|
||||
|
||||
@ForceInline()
|
||||
bool isDartVoidTypeRti(Object type) {
|
||||
return JS_BUILTIN(
|
||||
'returns:bool;effects:none;depends:none', JsBuiltin.isVoidType, type);
|
||||
}
|
||||
|
||||
/// Retrieves the class name from type information stored on the constructor of
|
||||
/// [type].
|
||||
// TODO(floitsch): move this to foreign_helper.dart or similar.
|
||||
|
@ -162,6 +174,14 @@ bool isNullType(Object type) {
|
|||
JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
|
||||
}
|
||||
|
||||
/// Returns whether the given type is the dynamic type.
|
||||
// TODO(floitsch): move this to foreign_helper.dart or similar.
|
||||
@ForceInline()
|
||||
bool isDartDynamicTypeRti(type) {
|
||||
return JS_BUILTIN(
|
||||
'returns:bool;effects:none;depends:none', JsBuiltin.isDynamicType, type);
|
||||
}
|
||||
|
||||
/// Returns whether the given type is _the_ Dart Object type.
|
||||
// TODO(floitsch): move this to foreign_helper.dart or similar.
|
||||
@ForceInline()
|
||||
|
|
|
@ -215,9 +215,12 @@ String runtimeTypeToStringV1(var rti, {String onTypeVariable(int i)}) {
|
|||
}
|
||||
|
||||
String runtimeTypeToStringV2(var rti, List<String> genericContext) {
|
||||
if (rti == null) {
|
||||
if (isDartDynamicTypeRti(rti)) {
|
||||
return 'dynamic';
|
||||
}
|
||||
if (isDartVoidTypeRti(rti)) {
|
||||
return 'void';
|
||||
}
|
||||
if (isJsArray(rti)) {
|
||||
// A list representing a type with arguments.
|
||||
return _getRuntimeTypeAsStringV2(rti, genericContext);
|
||||
|
@ -706,13 +709,47 @@ computeSignature(var signature, var context, var contextName) {
|
|||
return invokeOn(signature, context, typeArguments);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a top type.
|
||||
///
|
||||
/// For Dart 1 this is either `dynamic` or `Object`. For Dart 2 this is either
|
||||
/// `dynamic`, `void` or `Object`.
|
||||
@ForceInline()
|
||||
bool isTopType(var type) {
|
||||
return JS_GET_FLAG('STRONG_MODE') ? isTopTypeV2(type) : isTopTypeV1(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a top type for
|
||||
/// Dart 1. That is, either `dynamic` or `Object`.
|
||||
@ForceInline()
|
||||
bool isTopTypeV1(var type) {
|
||||
return isDartDynamicTypeRti(type) || isDartObjectTypeRti(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a top type for
|
||||
/// Dart 2. That is, either `dynamic`, `void` or `Object`.
|
||||
@ForceInline()
|
||||
bool isTopTypeV2(var type) {
|
||||
return isDartDynamicTypeRti(type) ||
|
||||
isDartVoidTypeRti(type) ||
|
||||
isDartObjectTypeRti(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a supertype of
|
||||
/// [Null].
|
||||
@ForceInline()
|
||||
bool isSupertypeOfNull(var type) {
|
||||
return JS_GET_FLAG('STRONG_MODE')
|
||||
? isSupertypeOfNullBase(type) || isSupertypeOfNullRecursive(type)
|
||||
: isSupertypeOfNullBase(type);
|
||||
? isSupertypeOfNullBaseV2(type) || isSupertypeOfNullRecursive(type)
|
||||
: isSupertypeOfNullBaseV1(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a simple
|
||||
/// supertype of [Null].
|
||||
@ForceInline()
|
||||
bool isSupertypeOfNullBaseV1(var type) {
|
||||
return isDartDynamicTypeRti(type) ||
|
||||
isDartObjectTypeRti(type) ||
|
||||
isNullTypeRti(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a simple
|
||||
|
@ -721,9 +758,11 @@ bool isSupertypeOfNull(var type) {
|
|||
/// This method doesn't handle `FutureOr<Null>`. This is handle by
|
||||
/// [isSupertypeOfNullRecursive] because it requires a recursive check.
|
||||
@ForceInline()
|
||||
bool isSupertypeOfNullBase(var type) {
|
||||
// `null` means `dynamic`.
|
||||
return type == null || isDartObjectTypeRti(type) || isNullTypeRti(type);
|
||||
bool isSupertypeOfNullBaseV2(var type) {
|
||||
return isDartDynamicTypeRti(type) ||
|
||||
isDartObjectTypeRti(type) ||
|
||||
isNullTypeRti(type) ||
|
||||
isDartVoidTypeRti(type);
|
||||
}
|
||||
|
||||
/// Returns `true` if the runtime type representation [type] is a `FutureOr`
|
||||
|
@ -732,9 +771,14 @@ bool isSupertypeOfNullBase(var type) {
|
|||
/// This method is recursive to be able to handle both `FutureOr<Null>` and
|
||||
/// `FutureOr<FutureOr<Null>>` etc.
|
||||
bool isSupertypeOfNullRecursive(var type) {
|
||||
if (isGenericFunctionTypeParameter(type)) {
|
||||
// We need to check for function type variables because `isDartFutureOrType`
|
||||
// doesn't work on numbers.
|
||||
return false;
|
||||
}
|
||||
if (isDartFutureOrType(type)) {
|
||||
var typeArgument = getFutureOrArgument(type);
|
||||
return isSupertypeOfNullBase(type) ||
|
||||
return isSupertypeOfNullBaseV2(type) ||
|
||||
isSupertypeOfNullRecursive(typeArgument);
|
||||
}
|
||||
return false;
|
||||
|
@ -762,7 +806,7 @@ Object getFutureOrArgument(var type) {
|
|||
*/
|
||||
bool checkSubtypeOfRuntimeType(o, t) {
|
||||
if (o == null) return isSupertypeOfNull(t);
|
||||
if (t == null) return true;
|
||||
if (isTopType(t)) return true;
|
||||
// Get the runtime type information from the object here, because we may
|
||||
// overwrite o with the interceptor below.
|
||||
var rti = getRuntimeTypeInfo(o);
|
||||
|
@ -832,7 +876,7 @@ bool isSubtypeV1(var s, var t) {
|
|||
// Subtyping is reflexive.
|
||||
if (isIdentical(s, t)) return true;
|
||||
// If either type is dynamic, [s] is a subtype of [t].
|
||||
if (s == null || t == null) return true;
|
||||
if (isDartDynamicTypeRti(s) || isDartDynamicTypeRti(t)) return true;
|
||||
|
||||
// Generic function type parameters must match exactly, which would have
|
||||
// exited earlier. The de Bruijn indexing ensures the representation as a
|
||||
|
@ -886,12 +930,15 @@ bool isSubtypeV2(var s, var sEnv, var t, var tEnv) {
|
|||
if (isIdentical(s, t)) return true;
|
||||
|
||||
// [t] is a top type?
|
||||
if (t == null) return true;
|
||||
if (isDartObjectTypeRti(t)) return true;
|
||||
// TODO(sra): void is a top type.
|
||||
if (isTopTypeV2(t)) return true;
|
||||
|
||||
// [s] is a top type?
|
||||
if (s == null) {
|
||||
if (isTopTypeV2(s)) {
|
||||
if (isGenericFunctionTypeParameter(t)) {
|
||||
// We need to check for function type variables because
|
||||
// `isDartFutureOrType` doesn't work on numbers.
|
||||
return false;
|
||||
}
|
||||
if (isDartFutureOrType(t)) {
|
||||
// [t] is FutureOr<T>. Check [s] <: T.
|
||||
var tTypeArgument = getFutureOrArgument(t);
|
||||
|
@ -1158,12 +1205,8 @@ bool isFunctionSubtypeV2(var s, var sEnv, var t, var tEnv) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// 'void' is a top type, so use `null` (dynamic) in its place.
|
||||
// TODO(sra): Create a void type that can be used in all positions.
|
||||
var sReturnType =
|
||||
hasField(s, voidReturnTag) ? null : getField(s, returnTypeTag);
|
||||
var tReturnType =
|
||||
hasField(t, voidReturnTag) ? null : getField(t, returnTypeTag);
|
||||
var sReturnType = getField(s, returnTypeTag);
|
||||
var tReturnType = getField(t, returnTypeTag);
|
||||
if (!isSubtypeV2(sReturnType, sEnv, tReturnType, tEnv)) return false;
|
||||
|
||||
var requiredParametersTag =
|
||||
|
@ -1251,12 +1294,14 @@ bool namedParametersSubtypeCheckV2(var s, var sEnv, var t, var tEnv) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether [type] is the representation of a generic function type
|
||||
* parameter. Generic function type parameters are represented de Bruijn
|
||||
* indexes.
|
||||
*/
|
||||
/// Returns whether [type] is the representation of a generic function type
|
||||
/// parameter. Generic function type parameters are represented de Bruijn
|
||||
/// indexes.
|
||||
///
|
||||
/// This test is only valid if [type] is known _not_ to be the void rti, whose
|
||||
/// runtime representation is -1.
|
||||
bool isGenericFunctionTypeParameter(var type) {
|
||||
assert(!isDartVoidTypeRti(type));
|
||||
return type is num; // Actually int, but 'is num' is faster.
|
||||
}
|
||||
|
||||
|
@ -1362,7 +1407,8 @@ finishBindInstantiatedFunctionType(rti, result, parameters, int depth) {
|
|||
/// scope. This is subtracted off the de Bruijn index for the type parameter to
|
||||
/// arrive at an potential index into [parameters].
|
||||
bindInstantiatedType(rti, parameters, int depth) {
|
||||
if (rti == null) return rti; // dynamic.
|
||||
if (isDartDynamicTypeRti(rti)) return rti; // dynamic.
|
||||
if (isDartVoidTypeRti(rti)) return rti; // void.
|
||||
// Functions are constructors denoting the class of the constructor.
|
||||
if (isJsFunction(rti)) return rti;
|
||||
|
||||
|
|
|
@ -418,6 +418,16 @@ enum JsBuiltin {
|
|||
/// JS_BUILTIN('bool', JsBuiltin.isFutureOrType, o)
|
||||
isFutureOrType,
|
||||
|
||||
/// Returns true if the given type is the `void` type.
|
||||
///
|
||||
/// JS_BUILTIN('bool', JsBuiltin.isVoidType, o)
|
||||
isVoidType,
|
||||
|
||||
/// Returns true if the given type is the `dynamic` type.
|
||||
///
|
||||
/// JS_BUILTIN('bool', JsBuiltin.isDynamicType, o)
|
||||
isDynamicType,
|
||||
|
||||
/// Returns the JavaScript-constructor name given an rti encoding.
|
||||
///
|
||||
/// JS_BUILTIN('String', JsBuiltin.rawRtiToJsConstructorName, rti)
|
||||
|
|
Loading…
Reference in a new issue