| // 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 |
| |
| // TODO(sigmund): rename universe => world |
| /// Describes individual features that may be seen in a program. Most features |
| /// can be described only by name using the [Feature] enum, some features are |
| /// expressed including details on how they are used. For example, whether a |
| /// list literal was constant or empty. |
| /// |
| /// The use of these features is typically discovered in an early phase of the |
| /// compilation pipeline, for example during resolution. |
| library compiler.universe.feature; |
| |
| import '../elements/types.dart'; |
| import '../ir/runtime_type_analysis.dart'; |
| import '../serialization/serialization.dart'; |
| import '../util/util.dart'; |
| |
| /// A language feature that may be seen in the program. |
| // TODO(johnniwinther): Should mirror usage be part of this? |
| enum Feature { |
| /// An assert statement with no message. |
| ASSERT, |
| |
| /// An assert statement with a message. |
| ASSERT_WITH_MESSAGE, |
| |
| /// A method with an `async` body modifier. |
| ASYNC, |
| |
| /// An asynchronous for in statement like `await for (var e in i) {}`. |
| ASYNC_FOR_IN, |
| |
| /// A method with an `async*` body modifier. |
| ASYNC_STAR, |
| |
| /// A catch statement. |
| CATCH_STATEMENT, |
| |
| /// A fall through in a switch case. |
| FALL_THROUGH_ERROR, |
| |
| /// A field without an initializer. |
| FIELD_WITHOUT_INITIALIZER, |
| |
| /// A field whose initialization is not a constant. |
| LAZY_FIELD, |
| |
| /// A local variable without an initializer. |
| LOCAL_WITHOUT_INITIALIZER, |
| |
| /// Access to `loadLibrary` on a deferred import. |
| LOAD_LIBRARY, |
| |
| /// A catch clause with a variable for the stack trace. |
| STACK_TRACE_IN_CATCH, |
| |
| /// String interpolation. |
| STRING_INTERPOLATION, |
| |
| /// String juxtaposition. |
| STRING_JUXTAPOSITION, |
| |
| /// An implicit call to `super.noSuchMethod`, like calling an unresolved |
| /// super method. |
| SUPER_NO_SUCH_METHOD, |
| |
| /// An synchronous for in statement, like `for (var e in i) {}`. |
| SYNC_FOR_IN, |
| |
| /// A method with a `sync*` body modifier. |
| SYNC_STAR, |
| |
| /// A throw expression. |
| THROW_EXPRESSION, |
| |
| /// An implicit throw of a `NoSuchMethodError`, like calling an unresolved |
| /// static method. |
| THROW_NO_SUCH_METHOD, |
| |
| /// An implicit throw of a runtime error, like in a runtime type check. |
| THROW_RUNTIME_ERROR, |
| |
| /// An implicit throw of a `UnsupportedError`, like calling `new |
| /// bool.fromEnvironment`. |
| THROW_UNSUPPORTED_ERROR, |
| |
| /// The need for a type variable bound check, like instantiation of a generic |
| /// type whose type variable have non-trivial bounds. |
| TYPE_VARIABLE_BOUNDS_CHECK, |
| } |
| |
| /// Describes a use of a map literal in the program. |
| class MapLiteralUse { |
| final InterfaceType type; |
| final bool isConstant; |
| final bool isEmpty; |
| |
| MapLiteralUse(this.type, {this.isConstant = false, this.isEmpty = false}); |
| |
| @override |
| int get hashCode { |
| return type.hashCode * 13 + |
| isConstant.hashCode * 17 + |
| isEmpty.hashCode * 19; |
| } |
| |
| @override |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! MapLiteralUse) return false; |
| return type == other.type && |
| isConstant == other.isConstant && |
| isEmpty == other.isEmpty; |
| } |
| |
| @override |
| String toString() { |
| return 'MapLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)'; |
| } |
| } |
| |
| /// Describes a use of a set literal in the program. |
| class SetLiteralUse { |
| final InterfaceType type; |
| final bool isConstant; |
| final bool isEmpty; |
| |
| SetLiteralUse(this.type, {this.isConstant = false, this.isEmpty = false}); |
| |
| @override |
| int get hashCode => |
| type.hashCode * 13 + isConstant.hashCode * 17 + isEmpty.hashCode * 19; |
| |
| @override |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! SetLiteralUse) return false; |
| return type == other.type && |
| isConstant == other.isConstant && |
| isEmpty == other.isEmpty; |
| } |
| |
| @override |
| String toString() => |
| 'SetLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)'; |
| } |
| |
| /// Describes the use of a list literal in the program. |
| class ListLiteralUse { |
| final InterfaceType type; |
| final bool isConstant; |
| final bool isEmpty; |
| |
| ListLiteralUse(this.type, {this.isConstant = false, this.isEmpty = false}); |
| |
| @override |
| int get hashCode { |
| return type.hashCode * 13 + |
| isConstant.hashCode * 17 + |
| isEmpty.hashCode * 19; |
| } |
| |
| @override |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! ListLiteralUse) return false; |
| return type == other.type && |
| isConstant == other.isConstant && |
| isEmpty == other.isEmpty; |
| } |
| |
| @override |
| String toString() { |
| return 'ListLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)'; |
| } |
| } |
| |
| /// A use of `Object.runtimeType`. |
| class RuntimeTypeUse { |
| /// The use kind of `Object.runtimeType`. |
| final RuntimeTypeUseKind kind; |
| |
| /// The static type of the receiver. |
| final DartType receiverType; |
| |
| /// The static type of the argument if [kind] is `RuntimeTypeUseKind.equals`. |
| final DartType argumentType; |
| |
| RuntimeTypeUse(this.kind, this.receiverType, this.argumentType); |
| |
| @override |
| int get hashCode => |
| kind.hashCode * 13 + |
| receiverType.hashCode * 17 + |
| argumentType.hashCode * 19; |
| |
| @override |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! RuntimeTypeUse) return false; |
| return kind == other.kind && |
| receiverType == other.receiverType && |
| argumentType == other.argumentType; |
| } |
| |
| /// Short textual representation use for testing. |
| String get shortText { |
| StringBuffer sb = StringBuffer(); |
| switch (kind) { |
| case RuntimeTypeUseKind.string: |
| sb.write('string:'); |
| sb.write(receiverType); |
| break; |
| case RuntimeTypeUseKind.equals: |
| sb.write('equals:'); |
| sb.write(receiverType); |
| sb.write('=='); |
| sb.write(argumentType); |
| break; |
| case RuntimeTypeUseKind.unknown: |
| sb.write('unknown:'); |
| sb.write(receiverType); |
| break; |
| } |
| return sb.toString(); |
| } |
| |
| @override |
| String toString() => 'RuntimeTypeUse(kind=$kind,receiver=$receiverType' |
| ',argument=$argumentType)'; |
| } |
| |
| /// A generic instantiation of an expression of type [functionType] with the |
| /// given [typeArguments]. |
| class GenericInstantiation { |
| static const String tag = 'generic-instantiation'; |
| |
| /// The static type of the instantiated expression. |
| final FunctionType functionType; |
| |
| /// The type arguments of the instantiation. |
| final List<DartType> typeArguments; |
| |
| GenericInstantiation(this.functionType, this.typeArguments); |
| |
| factory GenericInstantiation.readFromDataSource(DataSourceReader source) { |
| source.begin(tag); |
| DartType functionType = source.readDartType(); |
| List<DartType> typeArguments = source.readDartTypes(); |
| source.end(tag); |
| return GenericInstantiation(functionType, typeArguments); |
| } |
| |
| void writeToDataSink(DataSinkWriter sink) { |
| sink.begin(tag); |
| sink.writeDartType(functionType); |
| sink.writeDartTypes(typeArguments); |
| sink.end(tag); |
| } |
| |
| /// Short textual representation use for testing. |
| String get shortText => '<${typeArguments.join(',')}>'; |
| |
| @override |
| int get hashCode => |
| Hashing.listHash(typeArguments, Hashing.objectHash(functionType)); |
| |
| @override |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| if (other is! GenericInstantiation) return false; |
| if (functionType == other.functionType && |
| equalElements(typeArguments, other.typeArguments)) { |
| assert( |
| this.hashCode == other.hashCode, |
| '\nthis: ${this.hashCode} $this' |
| '\nthis: ${other.hashCode} $other'); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| @override |
| String toString() { |
| return 'GenericInstantiation(' |
| 'functionType:$functionType,' |
| 'typeArguments:$typeArguments' |
| ')'; |
| } |
| } |