blob: 982e018a50e1d64a2044508877cc70e310c0181e [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library js_backend.runtime_types_codegen;
import '../elements/entities.dart';
import '../elements/types.dart';
/// Data needed for generating a signature function for the function type of
/// a class.
class ClassFunctionType {
/// The `call` function that defines the function type.
final FunctionEntity callFunction;
/// The type of the `call` function.
final FunctionType callType;
/// The signature function for the function type.
///
/// This is used for Dart 2.
final FunctionEntity signatureFunction;
ClassFunctionType(this.callFunction, this.callType, this.signatureFunction);
}
/// A pair of a class that we need a check against and the type argument
/// substitution for this check.
class TypeCheck {
final ClassEntity cls;
final bool needsIs;
final Substitution substitution;
@override
final int hashCode = _nextHash = (_nextHash + 100003).toUnsigned(30);
static int _nextHash = 0;
TypeCheck(this.cls, this.substitution, {this.needsIs: true});
@override
String toString() =>
'TypeCheck(cls=$cls,needsIs=$needsIs,substitution=$substitution)';
}
/// [TypeCheck]s need for a single class.
class ClassChecks {
final Map<ClassEntity, TypeCheck> _map;
final ClassFunctionType functionType;
ClassChecks(this.functionType) : _map = <ClassEntity, TypeCheck>{};
const ClassChecks.empty()
: _map = const <ClassEntity, TypeCheck>{},
functionType = null;
void add(TypeCheck check) {
_map[check.cls] = check;
}
TypeCheck operator [](ClassEntity cls) => _map[cls];
Iterable<TypeCheck> get checks => _map.values;
@override
String toString() {
return 'ClassChecks($checks)';
}
}
/// For each class, stores the possible class subtype tests that could succeed.
abstract class TypeChecks {
/// Get the set of checks required for class [element].
ClassChecks operator [](ClassEntity element);
/// Get the iterable for all classes that need type checks.
Iterable<ClassEntity> get classes;
}
/// Representation of the substitution of type arguments when going from the
/// type of a class to one of its supertypes.
///
/// For `class B<T> extends A<List<T>, int>`, the substitution is the
/// representation of `(T) => [<List, T>, int]`. For more details of the
/// representation consult the documentation of [getSupertypeSubstitution].
//TODO(floitsch): Remove support for non-function substitutions.
class Substitution {
final bool isTrivial;
final bool isFunction;
final List<DartType> arguments;
final List<DartType> parameters;
final int length;
const Substitution.trivial()
: isTrivial = true,
isFunction = false,
length = null,
arguments = const <DartType>[],
parameters = const <DartType>[];
Substitution.list(this.arguments)
: isTrivial = false,
isFunction = false,
length = null,
parameters = const <DartType>[];
Substitution.function(this.arguments, this.parameters)
: isTrivial = false,
isFunction = true,
length = null;
Substitution.jsInterop(this.length)
: isTrivial = false,
isFunction = false,
arguments = const <DartType>[],
parameters = const <DartType>[];
bool get isJsInterop => length != null;
@override
String toString() => 'Substitution(isTrivial=$isTrivial,'
'isFunction=$isFunction,isJsInterop=$isJsInterop,arguments=$arguments,'
'parameters=$parameters,length=$length)';
}
/// Interface for computing substitutions need for runtime type checks.
abstract class RuntimeTypesSubstitutions {
bool isTrivialSubstitution(ClassEntity cls, ClassEntity check);
Substitution getSubstitution(ClassEntity cls, ClassEntity other);
Set<ClassEntity> getClassesUsedInSubstitutions(TypeChecks checks);
static bool hasTypeArguments(DartType type) {
if (type is InterfaceType) {
InterfaceType interfaceType = type;
return !interfaceType.treatAsRaw;
}
return false;
}
}