blob: 788a702253fc6d2e26e38420afe6cdcdf6b0103f [file] [log] [blame]
// Copyright (c) 2016, 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.
// @dart = 2.10
library entities;
import '../serialization/serialization.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'types.dart';
import 'entities_migrated.dart';
export 'entities_migrated.dart';
abstract class TypeVariableEntity extends Entity {
/// The class or generic method that declared this type variable.
Entity get typeDeclaration;
/// The index of this type variable in the type variables of its
/// [typeDeclaration].
int get index;
}
/// Stripped down super interface for function like entities.
///
/// Currently only [MethodElement] but later also kernel based Dart constructors
/// and methods and/or Dart-in-JS function-like properties.
abstract class FunctionEntity extends MemberEntity {
/// Whether this function is external, i.e. the body is not defined in terms
/// of Dart code.
bool /*!*/ get isExternal;
/// The structure of the function parameters.
ParameterStructure get parameterStructure;
/// The synchronous/asynchronous marker on this function.
AsyncMarker get asyncMarker;
}
/// Stripped down super interface for constructor like entities.
///
/// Currently only [ConstructorElement] but later also kernel based Dart
/// constructors and/or Dart-in-JS constructor-like properties.
// TODO(johnniwinther): Remove factory constructors from the set of
// constructors.
abstract class ConstructorEntity extends FunctionEntity {
/// Whether this is a generative constructor, possibly redirecting.
bool get isGenerativeConstructor;
/// Whether this is a factory constructor, possibly redirecting.
bool get isFactoryConstructor;
/// Whether this is a `fromEnvironment` const constructor in `int`, `bool` or
/// `String`.
bool get isFromEnvironmentConstructor;
}
/// The constructor body for a [ConstructorEntity].
///
/// This is used only in the backend to split encoding of a Dart constructor
/// into two JavaScript functions; the constructor and the constructor body.
// TODO(johnniwinther): Remove this when modelx is removed. Constructor bodies
// should then be created directly with the J-model.
abstract class ConstructorBodyEntity extends FunctionEntity {
/// The constructor for which this constructor body was created.
ConstructorEntity get constructor;
}
/// The structure of function parameters.
class ParameterStructure {
/// Tag used for identifying serialized [ParameterStructure] objects in a
/// debugging data stream.
static const String tag = 'parameter-structure';
/// The number of required positional parameters.
final int requiredPositionalParameters;
/// The number of positional parameters.
final int positionalParameters;
/// All named parameters sorted alphabetically.
final List<String> namedParameters;
/// The required named parameters.
final Set<String> requiredNamedParameters;
/// The number of type parameters.
final int typeParameters;
static const ParameterStructure getter =
ParameterStructure._(0, 0, [], {}, 0);
static const ParameterStructure setter =
ParameterStructure._(1, 1, [], {}, 0);
static const ParameterStructure zeroArguments =
ParameterStructure._(0, 0, [], {}, 0);
static const ParameterStructure oneArgument =
ParameterStructure._(1, 1, [], {}, 0);
static const ParameterStructure twoArguments =
ParameterStructure._(2, 2, [], {}, 0);
static const List<ParameterStructure> _simple = [
ParameterStructure._(0, 0, [], {}, 0),
ParameterStructure._(1, 1, [], {}, 0),
ParameterStructure._(2, 2, [], {}, 0),
ParameterStructure._(3, 3, [], {}, 0),
ParameterStructure._(4, 4, [], {}, 0),
ParameterStructure._(5, 5, [], {}, 0),
];
const ParameterStructure._(
this.requiredPositionalParameters,
this.positionalParameters,
this.namedParameters,
this.requiredNamedParameters,
this.typeParameters);
factory ParameterStructure(
int requiredPositionalParameters,
int positionalParameters,
List<String /*!*/ > namedParameters,
Set<String /*!*/ > requiredNamedParameters,
int typeParameters) {
// This simple canonicalization reduces the number of ParameterStructure
// objects by over 90%.
if (requiredPositionalParameters == positionalParameters &&
namedParameters.isEmpty &&
requiredNamedParameters.isEmpty &&
typeParameters == 0 &&
positionalParameters < _simple.length) {
return _simple[positionalParameters];
}
// Force sharing of empty collections.
if (namedParameters.isEmpty) namedParameters = const [];
if (requiredNamedParameters.isEmpty) requiredNamedParameters = const {};
return ParameterStructure._(
requiredPositionalParameters,
positionalParameters,
namedParameters,
requiredNamedParameters,
typeParameters,
);
}
factory ParameterStructure.fromType(FunctionType type) {
return ParameterStructure(
type.parameterTypes.length,
type.parameterTypes.length + type.optionalParameterTypes.length,
type.namedParameters,
type.requiredNamedParameters,
type.typeVariables.length);
}
/// Deserializes a [ParameterStructure] object from [source].
factory ParameterStructure.readFromDataSource(DataSourceReader source) {
source.begin(tag);
int requiredPositionalParameters = source.readInt();
int positionalParameters = source.readInt();
List<String> namedParameters = source.readStrings() /*!*/;
Set<String> requiredNamedParameters =
source.readStrings(emptyAsNull: true)?.toSet() ?? const <String>{};
int typeParameters = source.readInt();
source.end(tag);
return ParameterStructure(
requiredPositionalParameters,
positionalParameters,
namedParameters,
requiredNamedParameters,
typeParameters);
}
/// Serializes this [ParameterStructure] to [sink].
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeInt(requiredPositionalParameters);
sink.writeInt(positionalParameters);
sink.writeStrings(namedParameters);
sink.writeStrings(requiredNamedParameters);
sink.writeInt(typeParameters);
sink.end(tag);
}
/// The number of optional parameters (positional or named).
int get optionalParameters =>
(positionalParameters - requiredPositionalParameters) +
(namedParameters.length - requiredNamedParameters.length);
/// The total number of parameters (required or optional).
int get totalParameters => positionalParameters + namedParameters.length;
/// Returns the [CallStructure] corresponding to a call site passing all
/// parameters both required and optional.
CallStructure get callStructure {
return CallStructure(totalParameters, namedParameters, typeParameters);
}
@override
int get hashCode => Hashing.listHash(
namedParameters,
Hashing.setHash(
requiredNamedParameters,
Hashing.objectHash(
positionalParameters,
Hashing.objectHash(requiredPositionalParameters,
Hashing.objectHash(typeParameters)))));
@override
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! ParameterStructure) return false;
if (requiredPositionalParameters != other.requiredPositionalParameters ||
positionalParameters != other.positionalParameters ||
typeParameters != other.typeParameters ||
namedParameters.length != other.namedParameters.length ||
requiredNamedParameters.length !=
other.requiredNamedParameters.length) {
return false;
}
for (int i = 0; i < namedParameters.length; i++) {
if (namedParameters[i] != other.namedParameters[i]) {
return false;
}
}
for (String name in requiredNamedParameters) {
if (!other.requiredNamedParameters.contains(name)) return false;
}
return true;
}
/// Short textual representation use for testing.
String get shortText {
StringBuffer sb = StringBuffer();
if (typeParameters != 0) {
sb.write('<');
sb.write(typeParameters);
sb.write('>');
}
sb.write('(');
sb.write(positionalParameters);
for (var name in namedParameters) {
sb.write(',');
if (requiredNamedParameters.contains(name)) sb.write('req ');
sb.write(name);
}
sb.write(')');
return sb.toString();
}
@override
String toString() {
StringBuffer sb = StringBuffer();
sb.write('ParameterStructure(');
sb.write('requiredPositionalParameters=$requiredPositionalParameters,');
sb.write('positionalParameters=$positionalParameters,');
sb.write('namedParameters={${namedParameters.join(',')}},');
sb.write('requiredNamedParameters={${requiredNamedParameters.join(',')}},');
sb.write('typeParameters=$typeParameters)');
return sb.toString();
}
int get size => totalParameters + typeParameters;
}