Make _FunctionType fields use WasmObjectArray instead of List

This reduces flute's complex.dart slightly

  complex.wasm: 1601793  -> 1596131 (-0.35%)
  complex.wasm.unopt: 3570856 -> 3562573 (-0.23%)

And makes the code probably slightly faster

Change-Id: I5b5cb8f95509930ce23c7d4bc0385740ad9f429b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340562
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Martin Kustermann 2023-12-08 18:48:00 +00:00 committed by Commit Queue
parent 9d949a2498
commit e0485a4fc0
7 changed files with 226 additions and 150 deletions

View file

@ -664,21 +664,11 @@ class ClosureLayouter extends RecursiveVisitor {
b.local_get(preciseClosure);
b.struct_get(genericClosureStruct, FieldIndex.closureRuntimeType);
// Put type arguments into a `List<_Type>`.
ClassInfo listInfo = translator.classInfo[translator.fixedLengthListClass]!;
translator.functions.allocateClass(listInfo.classId);
Constant typeConstant = TypeLiteralConstant(
InterfaceType(translator.typeClass, Nullability.nonNullable));
b.i32_const(listInfo.classId);
b.i32_const(initialIdentityHash);
translator.constants
.instantiateConstant(instantiationFunction, b, typeConstant, typeType);
b.i64_const(typeCount);
// Put type arguments into a `WasmObjectArray<_Type>`.
for (int i = 0; i < typeCount; i++) {
b.local_get(typeParam(i));
}
b.array_new_fixed(translator.listArrayType, typeCount);
b.struct_new(listInfo.struct);
b.array_new_fixed(translator.typeArrayType, typeCount);
// Call [_TypeUniverse.substituteFunctionTypeArgument].
b.call(translator.functions

View file

@ -2930,6 +2930,16 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
(w.ValueType elementType, int i) => wrap(expressions[i], elementType),
isGrowable: isGrowable);
w.ValueType makeArrayFromExpressions(
List<Expression> expressions, InterfaceType elementType) {
return translator.makeArray(
function,
translator.arrayTypeForDartType(elementType),
expressions.length, (w.ValueType elementType, int i) {
wrap(expressions[i], elementType);
});
}
@override
w.ValueType visitMapLiteral(MapLiteral node, w.ValueType expectedType) {
types.makeType(this, node.keyType);

View file

@ -60,37 +60,38 @@ class Constants {
/// Makes a type list [ListConstant].
ListConstant makeTypeList(Iterable<DartType> types) => ListConstant(
InterfaceType(translator.typeClass, Nullability.nonNullable),
types.map((t) => TypeLiteralConstant(t)).toList());
translator.typeType, types.map((t) => TypeLiteralConstant(t)).toList());
InstanceConstant makeTypeArray(Iterable<DartType> types) =>
InstanceConstant(translator.wasmObjectArrayClass.reference, [
InterfaceType(translator.typeClass, Nullability.nonNullable)
], {
translator.wasmObjectArrayValueField.fieldReference: makeTypeList(types)
});
/// Makes a `WasmObjectArray<_Type>` [InstanceConstant].
InstanceConstant makeTypeArray(Iterable<DartType> types) => makeArrayOf(
translator.typeType, types.map((t) => TypeLiteralConstant(t)).toList());
/// Makes a `_NamedParameter` [InstanceConstant].
InstanceConstant makeNamedParameterConstant(NamedType n) {
Class namedParameter = translator.namedParameterClass;
assert(namedParameter.fields[0].name.text == 'name' &&
namedParameter.fields[1].name.text == 'type' &&
namedParameter.fields[2].name.text == 'isRequired');
Reference namedParameterName = namedParameter.fields[0].fieldReference;
Reference namedParameterType = namedParameter.fields[1].fieldReference;
Reference namedParameterIsRequired =
namedParameter.fields[2].fieldReference;
return InstanceConstant(namedParameter.reference, [], {
namedParameterName: StringConstant(n.name),
namedParameterType: TypeLiteralConstant(n.type),
namedParameterIsRequired: BoolConstant(n.isRequired)
});
}
InstanceConstant makeNamedParameterConstant(NamedType n) =>
InstanceConstant(translator.namedParameterClass.reference, const [], {
translator.namedParameterNameField.fieldReference:
StringConstant(n.name),
translator.namedParameterTypeField.fieldReference:
TypeLiteralConstant(n.type),
translator.namedParameterIsRequiredField.fieldReference:
BoolConstant(n.isRequired),
});
/// Makes a [ListConstant] of `_NamedParameters` to initialize a [FunctionType].
ListConstant makeNamedParametersList(FunctionType type) => ListConstant(
translator.types.namedParameterType,
type.namedParameters.map(makeNamedParameterConstant).toList());
/// Creates a `WasmObjectArray<_NamedParameter>` to be used as field of
/// `_FunctionType`.
InstanceConstant makeNamedParametersArray(FunctionType type) => makeArrayOf(
translator.namedParameterType,
[for (final n in type.namedParameters) makeNamedParameterConstant(n)]);
/// Creates a `WasmObjectArray<T>` with the given [Constant]s
InstanceConstant makeArrayOf(
InterfaceType elementType, List<Constant> entries) =>
InstanceConstant(translator.wasmObjectArrayClass.reference, [
elementType,
], {
translator.wasmObjectArrayValueField.fieldReference:
ListConstant(elementType, entries),
});
/// Ensure that the constant has a Wasm global assigned.
///
@ -771,18 +772,18 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
ConstantInfo? _makeFunctionType(
TypeLiteralConstant constant, FunctionType type, ClassInfo info) {
int typeParameterOffset = types.computeFunctionTypeParameterOffset(type);
ListConstant typeParameterBoundsConstant =
constants.makeTypeList(type.typeParameters.map((p) => p.bound));
ListConstant typeParameterDefaultsConstant =
constants.makeTypeList(type.typeParameters.map((p) => p.defaultType));
InstanceConstant typeParameterBoundsConstant =
constants.makeTypeArray(type.typeParameters.map((p) => p.bound));
InstanceConstant typeParameterDefaultsConstant =
constants.makeTypeArray(type.typeParameters.map((p) => p.defaultType));
TypeLiteralConstant returnTypeConstant =
TypeLiteralConstant(type.returnType);
ListConstant positionalParametersConstant =
constants.makeTypeList(type.positionalParameters);
InstanceConstant positionalParametersConstant =
constants.makeTypeArray(type.positionalParameters);
IntConstant requiredParameterCountConstant =
IntConstant(type.requiredParameterCount);
ListConstant namedParametersConstant =
constants.makeNamedParametersList(type);
InstanceConstant namedParametersConstant =
constants.makeNamedParametersArray(type);
ensureConstant(typeParameterBoundsConstant);
ensureConstant(typeParameterDefaultsConstant);
ensureConstant(returnTypeConstant);
@ -794,14 +795,14 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
b.i32_const(initialIdentityHash);
b.i32_const(types.encodedNullability(type));
b.i64_const(typeParameterOffset);
constants.instantiateConstant(
function, b, typeParameterBoundsConstant, types.typeListExpectedType);
constants.instantiateConstant(function, b, typeParameterBoundsConstant,
types.typeArrayExpectedType);
constants.instantiateConstant(function, b, typeParameterDefaultsConstant,
types.typeListExpectedType);
types.typeArrayExpectedType);
constants.instantiateConstant(
function, b, returnTypeConstant, types.nonNullableTypeType);
constants.instantiateConstant(function, b, positionalParametersConstant,
types.typeListExpectedType);
types.typeArrayExpectedType);
constants.instantiateConstant(
function, b, requiredParameterCountConstant, w.NumType.i64);
constants.instantiateConstant(function, b, namedParametersConstant,

View file

@ -65,6 +65,8 @@ mixin KernelNodes {
// dart:core runtime type classes
late final Class typeClass = index.getClass("dart:core", "_Type");
late final InterfaceType typeType =
InterfaceType(typeClass, Nullability.nonNullable);
late final Class abstractFunctionTypeClass =
index.getClass("dart:core", "_AbstractFunctionType");
late final Class functionTypeClass =
@ -79,6 +81,14 @@ mixin KernelNodes {
index.getClass("dart:core", "_InterfaceTypeParameterType");
late final Class namedParameterClass =
index.getClass("dart:core", "_NamedParameter");
late final Field namedParameterNameField =
index.getField("dart:core", "_NamedParameter", "name");
late final Field namedParameterTypeField =
index.getField("dart:core", "_NamedParameter", "type");
late final Field namedParameterIsRequiredField =
index.getField("dart:core", "_NamedParameter", "isRequired");
late final InterfaceType namedParameterType =
InterfaceType(namedParameterClass, Nullability.nonNullable);
late final Class bottomTypeClass = index.getClass("dart:core", "_BottomType");
late final Class topTypeClass = index.getClass("dart:core", "_TopType");
late final Class stackTraceClass = index.getClass("dart:core", "StackTrace");

View file

@ -120,6 +120,8 @@ class Translator with KernelNodes {
late final ClassInfo closureInfo = classInfo[closureClass]!;
late final ClassInfo stackTraceInfo = classInfo[stackTraceClass]!;
late final ClassInfo recordInfo = classInfo[coreTypes.recordClass]!;
late final w.ArrayType typeArrayType =
arrayTypeForDartType(InterfaceType(typeClass, Nullability.nonNullable));
late final w.ArrayType listArrayType = (classInfo[listBaseClass]!
.struct
.fields[FieldIndex.listArray]
@ -977,19 +979,30 @@ class Translator with KernelNodes {
final ClassInfo info = classInfo[cls]!;
functions.allocateClass(info.classId);
final w.ArrayType arrayType = listArrayType;
final w.ValueType elementType = arrayType.elementType.type.unpacked;
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
generateType(b);
b.i64_const(length);
makeArray(function, arrayType, length, generateItem);
b.struct_new(info.struct);
return info.nonNullableType;
}
w.ValueType makeArray(w.FunctionBuilder function, w.ArrayType arrayType,
int length, void Function(w.ValueType, int) generateItem) {
final b = function.body;
final w.ValueType elementType = arrayType.elementType.type.unpacked;
final arrayTypeRef = w.RefType.def(arrayType, nullable: false);
if (length > maxArrayNewFixedLength) {
// Too long for `array.new_fixed`. Set elements individually.
b.i32_const(length);
b.array_new_default(arrayType);
if (length > 0) {
final w.Local arrayLocal =
function.addLocal(w.RefType.def(arrayType, nullable: false));
final w.Local arrayLocal = function.addLocal(arrayTypeRef);
b.local_set(arrayLocal);
for (int i = 0; i < length; i++) {
b.local_get(arrayLocal);
@ -1005,9 +1018,7 @@ class Translator with KernelNodes {
}
b.array_new_fixed(arrayType, length);
}
b.struct_new(info.struct);
return info.nonNullableType;
return arrayTypeRef;
}
/// Indexes a Dart `List` on the stack.

View file

@ -68,7 +68,7 @@ class Types {
late final w.ValueType typeArrayExpectedType =
w.RefType.def(typeArrayArrayType, nullable: false);
/// Wasm value type of `List<_NamedParameter>`
/// Wasm value type of `WasmObjectArray<_NamedParameter>`
late final w.ValueType namedParametersExpectedType = classAndFieldToType(
translator.functionTypeClass, FieldIndex.functionTypeNamedParameters);
@ -501,27 +501,27 @@ class Types {
b.i32_const(encodedNullability(type));
b.i64_const(typeParameterOffset);
// List<_Type> typeParameterBounds
_makeTypeList(codeGen, type.typeParameters.map((p) => p.bound));
// WasmObjectArray<_Type> typeParameterBounds
_makeTypeArray(codeGen, type.typeParameters.map((p) => p.bound));
// List<_Type> typeParameterDefaults
_makeTypeList(codeGen, type.typeParameters.map((p) => p.defaultType));
// WasmObjectArray<_Type> typeParameterDefaults
_makeTypeArray(codeGen, type.typeParameters.map((p) => p.defaultType));
// _Type returnType
makeType(codeGen, type.returnType);
// List<_Type> positionalParameters
_makeTypeList(codeGen, type.positionalParameters);
// WasmObjectArray<_Type> positionalParameters
_makeTypeArray(codeGen, type.positionalParameters);
// int requiredParameterCount
b.i64_const(type.requiredParameterCount);
// List<_NamedParameter> namedParameters
// WasmObjectArray<_NamedParameter> namedParameters
if (type.namedParameters.every((n) => _isTypeConstant(n.type))) {
translator.constants.instantiateConstant(
codeGen.function,
b,
translator.constants.makeNamedParametersList(type),
translator.constants.makeNamedParametersArray(type),
namedParametersExpectedType);
} else {
Class namedParameterClass = translator.namedParameterClass;
@ -542,7 +542,7 @@ class Types {
])));
}
w.ValueType namedParametersListType =
codeGen.makeListFromExpressions(expressions, namedParameterType);
codeGen.makeArrayFromExpressions(expressions, namedParameterType);
translator.convertType(codeGen.function, namedParametersListType,
namedParametersExpectedType);
}

View file

@ -14,7 +14,7 @@ part of 'core_patch.dart';
@pragma("wasm:prefer-inline")
_Type _literal<T>() => unsafeCast(T);
extension _IndexWasmArrayOfTypes on WasmObjectArray<_Type> {
extension on WasmObjectArray<_Type> {
@pragma("wasm:prefer-inline")
_Type operator [](int index) => read(index);
@ -26,6 +26,56 @@ extension _IndexWasmArrayOfTypes on WasmObjectArray<_Type> {
@pragma("wasm:prefer-inline")
bool get isNotEmpty => length != 0;
@pragma("wasm:prefer-inline")
WasmObjectArray<_Type> map(_Type Function(_Type) fun) {
if (isEmpty) return const WasmObjectArray<_Type>.literal(<_Type>[]);
final mapped = WasmObjectArray<_Type>(length, fun(this[0]));
for (int i = 1; i < length; ++i) {
mapped[i] = fun(this[i]);
}
return mapped;
}
}
extension on WasmObjectArray<_NamedParameter> {
@pragma("wasm:prefer-inline")
_NamedParameter operator [](int index) => read(index);
@pragma("wasm:prefer-inline")
void operator []=(int index, _NamedParameter value) => write(index, value);
@pragma("wasm:prefer-inline")
bool get isEmpty => length == 0;
@pragma("wasm:prefer-inline")
bool get isNotEmpty => length != 0;
@pragma("wasm:prefer-inline")
WasmObjectArray<_NamedParameter> map(
_NamedParameter Function(_NamedParameter) fun) {
if (isEmpty)
return const WasmObjectArray<_NamedParameter>.literal(
<_NamedParameter>[]);
final mapped = WasmObjectArray<_NamedParameter>(length, this[0]);
for (int i = 0; i < length; ++i) {
mapped[i] = fun(this[i]);
}
return mapped;
}
}
// TODO: Remove any occurence of `List`s in this file.
extension on List<_Type> {
@pragma("wasm:prefer-inline")
WasmObjectArray<_Type> toWasmArray() {
if (isEmpty) return const WasmObjectArray<_Type>.literal(<_Type>[]);
final result = WasmObjectArray<_Type>(length, this[0]);
for (int i = 1; i < length; ++i) {
result[i] = this[i];
}
return result;
}
}
// Direct getter to bypass the covariance check and the bounds check when
@ -359,12 +409,12 @@ class _FunctionType extends _Type {
// an `i64` in every function type object for this. Consider alternative
// representations that don't have this overhead in the common case.
final int typeParameterOffset;
final List<_Type> typeParameterBounds;
final List<_Type> typeParameterDefaults;
final WasmObjectArray<_Type> typeParameterBounds;
final WasmObjectArray<_Type> typeParameterDefaults;
final _Type returnType;
final List<_Type> positionalParameters;
final WasmObjectArray<_Type> positionalParameters;
final int requiredParameterCount;
final List<_NamedParameter> namedParameters;
final WasmObjectArray<_NamedParameter> namedParameters;
@pragma("wasm:entry-point")
const _FunctionType(
@ -409,20 +459,17 @@ class _FunctionType extends _Type {
if (requiredParameterCount != other.requiredParameterCount) return false;
if (namedParameters.length != other.namedParameters.length) return false;
for (int i = 0; i < typeParameterBounds.length; i++) {
if (typeParameterBounds._getUnchecked(i) !=
other.typeParameterBounds._getUnchecked(i)) {
if (typeParameterBounds[i] != other.typeParameterBounds[i]) {
return false;
}
}
for (int i = 0; i < positionalParameters.length; i++) {
if (positionalParameters._getUnchecked(i) !=
other.positionalParameters._getUnchecked(i)) {
if (positionalParameters[i] != other.positionalParameters[i]) {
return false;
}
}
for (int i = 0; i < namedParameters.length; i++) {
if (namedParameters._getUnchecked(i) !=
other.namedParameters._getUnchecked(i)) {
if (namedParameters[i] != other.namedParameters[i]) {
return false;
}
}
@ -433,16 +480,16 @@ class _FunctionType extends _Type {
int get hashCode {
int hash = mix64(ClassID.cidFunctionType);
for (int i = 0; i < typeParameterBounds.length; i++) {
hash = mix64(hash ^ typeParameterBounds._getUnchecked(i).hashCode);
hash = mix64(hash ^ typeParameterBounds[i].hashCode);
}
hash = mix64(hash ^ (isDeclaredNullable ? 1 : 0));
hash = mix64(hash ^ returnType.hashCode);
for (int i = 0; i < positionalParameters.length; i++) {
hash = mix64(hash ^ positionalParameters._getUnchecked(i).hashCode);
hash = mix64(hash ^ positionalParameters[i].hashCode);
}
hash = mix64(hash ^ requiredParameterCount);
for (int i = 0; i < namedParameters.length; i++) {
hash = mix64(hash ^ namedParameters._getUnchecked(i).hashCode);
hash = mix64(hash ^ namedParameters[i].hashCode);
}
return hash;
}
@ -455,7 +502,7 @@ class _FunctionType extends _Type {
for (int i = 0; i < typeParameterBounds.length; i++) {
if (i > 0) s.write(", ");
s.write("X${typeParameterOffset + i}");
final bound = typeParameterBounds._getUnchecked(i);
final bound = typeParameterBounds[i];
if (!(bound.isTop && bound.isDeclaredNullable)) {
s.write(" extends ");
s.write(bound);
@ -467,7 +514,7 @@ class _FunctionType extends _Type {
for (int i = 0; i < positionalParameters.length; i++) {
if (i > 0) s.write(", ");
if (i == requiredParameterCount) s.write("[");
s.write(positionalParameters._getUnchecked(i));
s.write(positionalParameters[i]);
}
if (requiredParameterCount < positionalParameters.length) s.write("]");
if (namedParameters.isNotEmpty) {
@ -475,7 +522,7 @@ class _FunctionType extends _Type {
s.write("{");
for (int i = 0; i < namedParameters.length; i++) {
if (i > 0) s.write(", ");
s.write(namedParameters._getUnchecked(i));
s.write(namedParameters[i]);
}
s.write("}");
}
@ -628,8 +675,7 @@ class _Environment {
/// Look up the bound of a type parameter in its adjusted environment.
_Type lookupAdjusted(_FunctionTypeParameterType param) {
return type.typeParameterBounds
._getUnchecked(param.index - type.typeParameterOffset);
return type.typeParameterBounds[param.index - type.typeParameterOffset];
}
}
@ -648,26 +694,26 @@ class _TypeUniverse {
}
static _Type substituteInterfaceTypeParameter(
_InterfaceTypeParameterType typeParameter, List<_Type> substitutions) {
_InterfaceTypeParameterType typeParameter,
WasmObjectArray<_Type> substitutions) {
// If the type parameter is non-nullable, or the substitution type is
// nullable, then just return the substitution type. Otherwise, we return
// [type] as nullable.
// Note: This will throw if the required nullability is impossible to
// generate.
_Type substitution =
substitutions._getUnchecked(typeParameter.environmentIndex);
_Type substitution = substitutions[typeParameter.environmentIndex];
if (typeParameter.isDeclaredNullable) return substitution.asNullable;
return substitution;
}
static _Type substituteFunctionTypeParameter(
_FunctionTypeParameterType typeParameter,
List<_Type> substitutions,
WasmObjectArray<_Type> substitutions,
_FunctionType? rootFunction) {
if (rootFunction != null &&
typeParameter.index >= rootFunction.typeParameterOffset) {
_Type substitution = substitutions._getUnchecked(
typeParameter.index - rootFunction.typeParameterOffset);
_Type substitution =
substitutions[typeParameter.index - rootFunction.typeParameterOffset];
if (typeParameter.isDeclaredNullable) return substitution.asNullable;
return substitution;
} else {
@ -677,7 +723,7 @@ class _TypeUniverse {
@pragma("wasm:entry-point")
static _FunctionType substituteFunctionTypeArgument(
_FunctionType functionType, List<_Type> substitutions) {
_FunctionType functionType, WasmObjectArray<_Type> substitutions) {
return substituteTypeArgument(functionType, substitutions, functionType)
.as<_FunctionType>();
}
@ -690,8 +736,8 @@ class _TypeUniverse {
/// are being substituted, or `null` when inside a nested function type that
/// is guaranteed not to contain any type parameter types that are to be
/// substituted.
static _Type substituteTypeArgument(
_Type type, List<_Type> substitutions, _FunctionType? rootFunction) {
static _Type substituteTypeArgument(_Type type,
WasmObjectArray<_Type> substitutions, _FunctionType? rootFunction) {
if (type.isBottom || type.isTop) {
return type;
} else if (type.isFutureOr) {
@ -728,34 +774,45 @@ class _TypeUniverse {
// type parameter types as referring to the root function.
rootFunction = null;
}
final WasmObjectArray<_Type> bounds;
if (isRoot) {
bounds = const WasmObjectArray<_Type>.literal(<_Type>[]);
} else {
bounds = functionType.typeParameterBounds.map((_Type type) =>
substituteTypeArgument(type, substitutions, rootFunction));
}
final WasmObjectArray<_Type> defaults;
if (isRoot) {
defaults = const WasmObjectArray<_Type>.literal(<_Type>[]);
} else {
defaults = functionType.typeParameterDefaults.map((_Type type) =>
substituteTypeArgument(type, substitutions, rootFunction));
}
final WasmObjectArray<_Type> positionals =
functionType.positionalParameters.map((_Type type) =>
substituteTypeArgument(type, substitutions, rootFunction));
final WasmObjectArray<_NamedParameter> named = functionType
.namedParameters
.map((_NamedParameter named) => _NamedParameter(
named.name,
substituteTypeArgument(named.type, substitutions, rootFunction),
named.isRequired));
final returnType = substituteTypeArgument(
functionType.returnType, substitutions, rootFunction);
return _FunctionType(
functionType.typeParameterOffset,
isRoot
? const []
: functionType.typeParameterBounds
.map((type) =>
substituteTypeArgument(type, substitutions, rootFunction))
.toList(),
isRoot
? const []
: functionType.typeParameterDefaults
.map((type) =>
substituteTypeArgument(type, substitutions, rootFunction))
.toList(),
substituteTypeArgument(
functionType.returnType, substitutions, rootFunction),
functionType.positionalParameters
.map((type) =>
substituteTypeArgument(type, substitutions, rootFunction))
.toList(),
bounds,
defaults,
returnType,
positionals,
functionType.requiredParameterCount,
functionType.namedParameters
.map((named) => _NamedParameter(
named.name,
substituteTypeArgument(
named.type, substitutions, rootFunction),
named.isRequired))
.toList(),
named,
functionType.isDeclaredNullable);
} else if (type.isFunctionTypeParameterType) {
return substituteFunctionTypeParameter(
@ -834,12 +891,10 @@ class _TypeUniverse {
// If we have empty type arguments then create a list of dynamic type
// arguments.
// TODO(askesc): Use Wasm arrays more widely to avoid creating a
// temporary list here.
List<_Type> typeArgumentsForSubstitution =
WasmObjectArray<_Type> typeArgumentsForSubstitution =
substitutions.isNotEmpty && sTypeArguments.isEmpty
? List.filled(substitutions.length, _literal<dynamic>())
: List.generate(sTypeArguments.length, (i) => sTypeArguments[i]);
? WasmObjectArray<_Type>(substitutions.length, _literal<dynamic>())
: sTypeArguments;
// Finally substitute arguments. We must do this upfront so we can normalize
// the type.
@ -866,8 +921,8 @@ class _TypeUniverse {
int tTypeParameterCount = t.typeParameterBounds.length;
if (sTypeParameterCount != tTypeParameterCount) return false;
for (int i = 0; i < sTypeParameterCount; i++) {
if (!areEquivalent(s.typeParameterBounds._getUnchecked(i), sEnv,
t.typeParameterBounds._getUnchecked(i), tEnv)) {
if (!areEquivalent(
s.typeParameterBounds[i], sEnv, t.typeParameterBounds[i], tEnv)) {
return false;
}
}
@ -883,8 +938,8 @@ class _TypeUniverse {
// Check [s] has enough required and optional positional arguments to
// potentially be a valid subtype of [t].
List<_Type> sPositional = s.positionalParameters;
List<_Type> tPositional = t.positionalParameters;
WasmObjectArray<_Type> sPositional = s.positionalParameters;
WasmObjectArray<_Type> tPositional = t.positionalParameters;
int sPositionalLength = sPositional.length;
int tPositionalLength = tPositional.length;
if (sPositionalLength < tPositionalLength) {
@ -894,8 +949,8 @@ class _TypeUniverse {
// Check all [t] positional arguments are subtypes of [s] positional
// arguments.
for (int i = 0; i < tPositionalLength; i++) {
_Type sParameter = sPositional._getUnchecked(i);
_Type tParameter = tPositional._getUnchecked(i);
_Type sParameter = sPositional[i];
_Type tParameter = tPositional[i];
if (!isSubtype(tParameter, tEnv, sParameter, sEnv)) {
return false;
}
@ -903,17 +958,17 @@ class _TypeUniverse {
// Check that [t]'s named arguments are subtypes of [s]'s named arguments.
// This logic assumes the named arguments are stored in sorted order.
List<_NamedParameter> sNamed = s.namedParameters;
List<_NamedParameter> tNamed = t.namedParameters;
WasmObjectArray<_NamedParameter> sNamed = s.namedParameters;
WasmObjectArray<_NamedParameter> tNamed = t.namedParameters;
int sNamedLength = sNamed.length;
int tNamedLength = tNamed.length;
int sIndex = 0;
for (int tIndex = 0; tIndex < tNamedLength; tIndex++) {
_NamedParameter tNamedParameter = tNamed._getUnchecked(tIndex);
_NamedParameter tNamedParameter = tNamed[tIndex];
String tName = tNamedParameter.name;
while (true) {
if (sIndex >= sNamedLength) return false;
_NamedParameter sNamedParameter = sNamed._getUnchecked(sIndex);
_NamedParameter sNamedParameter = sNamed[sIndex];
String sName = sNamedParameter.name;
sIndex++;
int sNameComparedToTName = sName.compareTo(tName);
@ -933,7 +988,7 @@ class _TypeUniverse {
}
}
while (sIndex < sNamedLength) {
if (sNamed._getUnchecked(sIndex).isRequired) return false;
if (sNamed[sIndex].isRequired) return false;
sIndex++;
}
return true;
@ -1133,7 +1188,10 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
List<Object?> positionalArguments, List<dynamic> namedArguments) {
// Check type args, add default types to the type list if its empty
if (typeArguments.isEmpty) {
typeArguments.addAll(functionType.typeParameterDefaults);
final defaults = functionType.typeParameterDefaults;
for (int i = 0; i < defaults.length; ++i) {
typeArguments.add(defaults[i]);
}
} else if (typeArguments.length !=
functionType.typeParameterDefaults.length) {
return false;
@ -1150,8 +1208,7 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
int namedParamIdx = 0;
int namedArgIdx = 0;
while (namedParamIdx < functionType.namedParameters.length) {
_NamedParameter param =
functionType.namedParameters._getUnchecked(namedParamIdx);
_NamedParameter param = functionType.namedParameters[namedParamIdx];
if (namedArgIdx * 2 >= namedArguments.length) {
if (param.isRequired) {
@ -1204,12 +1261,11 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
assert(functionType.typeParameterBounds.length == typeArguments.length);
if (!typeArguments.isEmpty) {
for (int i = 0; i < typeArguments.length; i += 1) {
final typeArgument = typeArguments._getUnchecked(i);
final typesAsArray = typeArguments.toWasmArray();
for (int i = 0; i < typesAsArray.length; i += 1) {
final typeArgument = typesAsArray[i];
final paramBound = _TypeUniverse.substituteTypeArgument(
functionType.typeParameterBounds._getUnchecked(i),
typeArguments,
functionType);
functionType.typeParameterBounds[i], typesAsArray, functionType);
if (!_typeUniverse.isSubtype(typeArgument, null, paramBound, null)) {
final stackTrace = StackTrace.current;
final typeError = _TypeError.fromMessageAndStackTrace(
@ -1221,13 +1277,13 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
}
functionType = _TypeUniverse.substituteFunctionTypeArgument(
functionType, typeArguments);
functionType, typesAsArray);
}
// Check positional arguments
for (int i = 0; i < positionalArguments.length; i += 1) {
final Object? arg = positionalArguments._getUnchecked(i);
final _Type paramTy = functionType.positionalParameters._getUnchecked(i);
final _Type paramTy = functionType.positionalParameters[i];
if (!_isSubtype(arg, paramTy)) {
// TODO(50991): Positional parameter names not available in runtime
_TypeError._throwArgumentTypeCheckError(
@ -1242,11 +1298,9 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
while (namedArgIdx * 2 < namedArguments.length) {
final String argName = _symbolToString(
namedArguments._getUnchecked(namedArgIdx * 2) as Symbol);
if (argName ==
functionType.namedParameters._getUnchecked(namedParamIdx).name) {
if (argName == functionType.namedParameters[namedParamIdx].name) {
final arg = namedArguments._getUnchecked(namedArgIdx * 2 + 1);
final paramTy =
functionType.namedParameters._getUnchecked(namedParamIdx).type;
final paramTy = functionType.namedParameters[namedParamIdx].type;
if (!_isSubtype(arg, paramTy)) {
_TypeError._throwArgumentTypeCheckError(
arg, paramTy, argName, StackTrace.current);