| Index: sdk/lib/_internal/compiler/implementation/native/behavior.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/native/behavior.dart b/sdk/lib/_internal/compiler/implementation/native/behavior.dart
|
| deleted file mode 100644
|
| index 328f42594b20560f745bf85ad738c345dfaf97b0..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/compiler/implementation/native/behavior.dart
|
| +++ /dev/null
|
| @@ -1,438 +0,0 @@
|
| -// Copyright (c) 2014, 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.
|
| -
|
| -part of native;
|
| -
|
| -/// This class is a temporary work-around until we get a more powerful DartType.
|
| -class SpecialType {
|
| -final String name;
|
| -const SpecialType._(this.name);
|
| -
|
| -/// The type Object, but no subtypes:
|
| -static const JsObject = const SpecialType._('=Object');
|
| -
|
| -int get hashCode => name.hashCode;
|
| -}
|
| -
|
| -/**
|
| - * A summary of the behavior of a native element.
|
| - *
|
| - * Native code can return values of one type and cause native subtypes of
|
| - * another type to be instantiated. By default, we compute both from the
|
| - * declared type.
|
| - *
|
| - * A field might yield any native type that 'is' the field type.
|
| - *
|
| - * A method might create and return instances of native subclasses of its
|
| - * declared return type, and a callback argument may be called with instances of
|
| - * the callback parameter type (e.g. Event).
|
| - *
|
| - * If there is one or more `@Creates` annotations, the union of the named types
|
| - * replaces the inferred instantiated type, and the return type is ignored for
|
| - * the purpose of inferring instantiated types.
|
| - *
|
| - * @Creates('IDBCursor') // Created asynchronously.
|
| - * @Creates('IDBRequest') // Created synchronously (for return value).
|
| - * IDBRequest openCursor();
|
| - *
|
| - * If there is one or more `@Returns` annotations, the union of the named types
|
| - * replaces the declared return type.
|
| - *
|
| - * @Returns('IDBRequest')
|
| - * IDBRequest openCursor();
|
| - *
|
| - * Types in annotations are non-nullable, so include `@Returns('Null')` if
|
| - * `null` may be returned.
|
| - */
|
| -class NativeBehavior {
|
| -
|
| - /// [DartType]s or [SpecialType]s returned or yielded by the native element.
|
| - final List typesReturned = [];
|
| -
|
| - /// [DartType]s or [SpecialType]s instantiated by the native element.
|
| - final List typesInstantiated = [];
|
| -
|
| - // If this behavior is for a JS expression, [codeTemplate] contains the
|
| - // parsed tree.
|
| - js.Template codeTemplate;
|
| -
|
| - final SideEffects sideEffects = new SideEffects.empty();
|
| -
|
| - static NativeBehavior NONE = new NativeBehavior();
|
| -
|
| - /// Processes the type specification string of a call to JS and stores the
|
| - /// result in the [typesReturned] and [typesInstantiated].
|
| - ///
|
| - /// Two forms of the string is supported:
|
| - /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
|
| - /// which defines the types returned and for the later form also created by
|
| - /// the call to JS.
|
| - /// 2) A sequence of the form '<tag>:<type-string>;' where <tag> is either
|
| - /// 'returns' or 'creates' and where <type-string> is a type string like in
|
| - /// 1). The type string marked by 'returns' defines the types returned and
|
| - /// 'creates' defines the types created by the call to JS. Each tag kind
|
| - /// can only occur once in the sequence.
|
| - ///
|
| - /// [specString] is the specification string, [resolveType] resolves named
|
| - /// types into type values, [typesReturned] and [typesInstantiated] collects
|
| - /// the types defined by the specification string, and [objectType] and
|
| - /// [nullType] define the types for `Object` and `Null`, respectively. The
|
| - /// latter is used for the type strings of the form '' and 'var'.
|
| - // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
|
| - static void processSpecString(
|
| - DiagnosticListener listener,
|
| - Spannable spannable,
|
| - String specString,
|
| - {dynamic resolveType(String typeString),
|
| - List typesReturned, List typesInstantiated,
|
| - objectType, nullType}) {
|
| -
|
| - /// Resolve a type string of one of the three forms:
|
| - /// * 'void' - in which case [onVoid] is called,
|
| - /// * '' or 'var' - in which case [onVar] is called,
|
| - /// * 'T1|...|Tn' - in which case [onType] is called for each Ti.
|
| - void resolveTypesString(String typesString,
|
| - {onVoid(), onVar(), onType(type)}) {
|
| - // Various things that are not in fact types.
|
| - if (typesString == 'void') {
|
| - if (onVoid != null) {
|
| - onVoid();
|
| - }
|
| - return;
|
| - }
|
| - if (typesString == '' || typesString == 'var') {
|
| - if (onVar != null) {
|
| - onVar();
|
| - }
|
| - return;
|
| - }
|
| - for (final typeString in typesString.split('|')) {
|
| - onType(resolveType(typeString));
|
| - }
|
| - }
|
| -
|
| - if (specString.contains(':')) {
|
| - /// Find and remove a substring of the form 'tag:<type-string>;' from
|
| - /// [specString].
|
| - String getTypesString(String tag) {
|
| - String marker = '$tag:';
|
| - int startPos = specString.indexOf(marker);
|
| - if (startPos == -1) return null;
|
| - int endPos = specString.indexOf(';', startPos);
|
| - if (endPos == -1) return null;
|
| - String typeString =
|
| - specString.substring(startPos + marker.length, endPos);
|
| - specString = '${specString.substring(0, startPos)}'
|
| - '${specString.substring(endPos + 1)}'.trim();
|
| - return typeString;
|
| - }
|
| -
|
| - String returns = getTypesString('returns');
|
| - if (returns != null) {
|
| - resolveTypesString(returns, onVar: () {
|
| - typesReturned.add(objectType);
|
| - typesReturned.add(nullType);
|
| - }, onType: (type) {
|
| - typesReturned.add(type);
|
| - });
|
| - }
|
| -
|
| - String creates = getTypesString('creates');
|
| - if (creates != null) {
|
| - resolveTypesString(creates, onVoid: () {
|
| - listener.internalError(spannable,
|
| - "Invalid type string 'creates:$creates'");
|
| - }, onVar: () {
|
| - listener.internalError(spannable,
|
| - "Invalid type string 'creates:$creates'");
|
| - }, onType: (type) {
|
| - typesInstantiated.add(type);
|
| - });
|
| - }
|
| -
|
| - if (!specString.isEmpty) {
|
| - listener.internalError(spannable, "Invalid JS type string.");
|
| - }
|
| - } else {
|
| - resolveTypesString(specString, onVar: () {
|
| - typesReturned.add(objectType);
|
| - typesReturned.add(nullType);
|
| - }, onType: (type) {
|
| - typesInstantiated.add(type);
|
| - typesReturned.add(type);
|
| - });
|
| - }
|
| - }
|
| -
|
| - static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
|
| - // The first argument of a JS-call is a string encoding various attributes
|
| - // of the code.
|
| - //
|
| - // 'Type1|Type2'. A union type.
|
| - // '=Object'. A JavaScript Object, no subtype.
|
| -
|
| - var argNodes = jsCall.arguments;
|
| - if (argNodes.isEmpty) {
|
| - compiler.internalError(jsCall, "JS expression has no type.");
|
| - }
|
| -
|
| - var code = argNodes.tail.head;
|
| - if (code is !StringNode || code.isInterpolation) {
|
| - compiler.internalError(code, 'JS code must be a string literal.');
|
| - }
|
| -
|
| - LiteralString specLiteral = argNodes.head.asLiteralString();
|
| - if (specLiteral == null) {
|
| - // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
|
| - // is not very satisfactory because it does not work for void, dynamic.
|
| - compiler.internalError(argNodes.head, "Unexpected JS first argument.");
|
| - }
|
| -
|
| - NativeBehavior behavior = new NativeBehavior();
|
| - behavior.codeTemplate =
|
| - js.js.parseForeignJS(code.dartString.slowToString());
|
| - new SideEffectsVisitor(behavior.sideEffects)
|
| - .visit(behavior.codeTemplate.ast);
|
| -
|
| - String specString = specLiteral.dartString.slowToString();
|
| -
|
| - resolveType(String typeString) {
|
| - return _parseType(
|
| - typeString,
|
| - compiler,
|
| - (name) => resolver.resolveTypeFromString(specLiteral, name),
|
| - jsCall);
|
| - }
|
| -
|
| - processSpecString(compiler, jsCall,
|
| - specString,
|
| - resolveType: resolveType,
|
| - typesReturned: behavior.typesReturned,
|
| - typesInstantiated: behavior.typesInstantiated,
|
| - objectType: compiler.objectClass.computeType(compiler),
|
| - nullType: compiler.nullClass.computeType(compiler));
|
| -
|
| - return behavior;
|
| - }
|
| -
|
| - static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall,
|
| - Compiler compiler,
|
| - resolver) {
|
| - // The first argument of a JS-embedded global call is a string encoding
|
| - // the type of the code.
|
| - //
|
| - // 'Type1|Type2'. A union type.
|
| - // '=Object'. A JavaScript Object, no subtype.
|
| -
|
| - Link<Node> argNodes = jsGlobalCall.arguments;
|
| - if (argNodes.isEmpty) {
|
| - compiler.internalError(jsGlobalCall,
|
| - "JS embedded global expression has no type.");
|
| - }
|
| -
|
| - // We don't check the given name. That needs to be done at a later point.
|
| - // This is, because we want to allow non-literals as names.
|
| - if (argNodes.tail.isEmpty) {
|
| - compiler.internalError(jsGlobalCall, 'Embedded Global is missing name');
|
| - }
|
| -
|
| - if (!argNodes.tail.tail.isEmpty) {
|
| - compiler.internalError(argNodes.tail.tail.head,
|
| - 'Embedded Global has more than 2 arguments');
|
| - }
|
| -
|
| - LiteralString specLiteral = argNodes.head.asLiteralString();
|
| - if (specLiteral == null) {
|
| - // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
|
| - // is not very satisfactory because it does not work for void, dynamic.
|
| - compiler.internalError(argNodes.head, "Unexpected first argument.");
|
| - }
|
| -
|
| - NativeBehavior behavior = new NativeBehavior();
|
| -
|
| - String specString = specLiteral.dartString.slowToString();
|
| -
|
| - resolveType(String typeString) {
|
| - return _parseType(
|
| - typeString,
|
| - compiler,
|
| - (name) => resolver.resolveTypeFromString(specLiteral, name),
|
| - jsGlobalCall);
|
| - }
|
| -
|
| - processSpecString(compiler, jsGlobalCall,
|
| - specString,
|
| - resolveType: resolveType,
|
| - typesReturned: behavior.typesReturned,
|
| - typesInstantiated: behavior.typesInstantiated,
|
| - objectType: compiler.objectClass.computeType(compiler),
|
| - nullType: compiler.nullClass.computeType(compiler));
|
| -
|
| - return behavior;
|
| - }
|
| -
|
| - static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
|
| - FunctionType type = method.computeType(compiler);
|
| - var behavior = new NativeBehavior();
|
| - behavior.typesReturned.add(type.returnType);
|
| - if (!type.returnType.isVoid) {
|
| - // Declared types are nullable.
|
| - behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
|
| - }
|
| - behavior._capture(type, compiler);
|
| -
|
| - // TODO(sra): Optional arguments are currently missing from the
|
| - // DartType. This should be fixed so the following work-around can be
|
| - // removed.
|
| - method.functionSignature.forEachOptionalParameter(
|
| - (ParameterElement parameter) {
|
| - behavior._escape(parameter.type, compiler);
|
| - });
|
| -
|
| - behavior._overrideWithAnnotations(method, compiler);
|
| - return behavior;
|
| - }
|
| -
|
| - static NativeBehavior ofFieldLoad(Element field, Compiler compiler) {
|
| - DartType type = field.computeType(compiler);
|
| - var behavior = new NativeBehavior();
|
| - behavior.typesReturned.add(type);
|
| - // Declared types are nullable.
|
| - behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
|
| - behavior._capture(type, compiler);
|
| - behavior._overrideWithAnnotations(field, compiler);
|
| - return behavior;
|
| - }
|
| -
|
| - static NativeBehavior ofFieldStore(Element field, Compiler compiler) {
|
| - DartType type = field.computeType(compiler);
|
| - var behavior = new NativeBehavior();
|
| - behavior._escape(type, compiler);
|
| - // We don't override the default behaviour - the annotations apply to
|
| - // loading the field.
|
| - return behavior;
|
| - }
|
| -
|
| - void _overrideWithAnnotations(Element element, Compiler compiler) {
|
| - if (element.metadata.isEmpty) return;
|
| -
|
| - DartType lookup(String name) {
|
| - Element e = element.buildScope().lookup(name);
|
| - if (e == null) return null;
|
| - if (e is! ClassElement) return null;
|
| - ClassElement cls = e;
|
| - cls.ensureResolved(compiler);
|
| - return cls.thisType;
|
| - }
|
| -
|
| - NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer;
|
| - var creates = _collect(element, compiler, enqueuer.annotationCreatesClass,
|
| - lookup);
|
| - var returns = _collect(element, compiler, enqueuer.annotationReturnsClass,
|
| - lookup);
|
| -
|
| - if (creates != null) {
|
| - typesInstantiated..clear()..addAll(creates);
|
| - }
|
| - if (returns != null) {
|
| - typesReturned..clear()..addAll(returns);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns a list of type constraints from the annotations of
|
| - * [annotationClass].
|
| - * Returns `null` if no constraints.
|
| - */
|
| - static _collect(Element element, Compiler compiler, Element annotationClass,
|
| - lookup(str)) {
|
| - var types = null;
|
| - for (Link<MetadataAnnotation> link = element.metadata;
|
| - !link.isEmpty;
|
| - link = link.tail) {
|
| - MetadataAnnotation annotation = link.head.ensureResolved(compiler);
|
| - ConstantValue value = annotation.constant.value;
|
| - if (!value.isConstructedObject) continue;
|
| - ConstructedConstantValue constructedObject = value;
|
| - if (constructedObject.type.element != annotationClass) continue;
|
| -
|
| - List<ConstantValue> fields = constructedObject.fields;
|
| - // TODO(sra): Better validation of the constant.
|
| - if (fields.length != 1 || !fields[0].isString) {
|
| - PartialMetadataAnnotation partial = annotation;
|
| - compiler.internalError(annotation,
|
| - 'Annotations needs one string: ${partial.parseNode(compiler)}');
|
| - }
|
| - StringConstantValue specStringConstant = fields[0];
|
| - String specString = specStringConstant.toDartString().slowToString();
|
| - for (final typeString in specString.split('|')) {
|
| - var type = _parseType(typeString, compiler, lookup, annotation);
|
| - if (types == null) types = [];
|
| - types.add(type);
|
| - }
|
| - }
|
| - return types;
|
| - }
|
| -
|
| - /// Models the behavior of having intances of [type] escape from Dart code
|
| - /// into native code.
|
| - void _escape(DartType type, Compiler compiler) {
|
| - type = type.unalias(compiler);
|
| - if (type is FunctionType) {
|
| - FunctionType functionType = type;
|
| - // A function might be called from native code, passing us novel
|
| - // parameters.
|
| - _escape(functionType.returnType, compiler);
|
| - for (DartType parameter in functionType.parameterTypes) {
|
| - _capture(parameter, compiler);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// Models the behavior of Dart code receiving instances and methods of [type]
|
| - /// from native code. We usually start the analysis by capturing a native
|
| - /// method that has been used.
|
| - void _capture(DartType type, Compiler compiler) {
|
| - type = type.unalias(compiler);
|
| - if (type is FunctionType) {
|
| - FunctionType functionType = type;
|
| - _capture(functionType.returnType, compiler);
|
| - for (DartType parameter in functionType.parameterTypes) {
|
| - _escape(parameter, compiler);
|
| - }
|
| - } else {
|
| - typesInstantiated.add(type);
|
| - }
|
| - }
|
| -
|
| - static _parseType(String typeString, Compiler compiler,
|
| - lookup(name), locationNodeOrElement) {
|
| - if (typeString == '=Object') return SpecialType.JsObject;
|
| - if (typeString == 'dynamic') {
|
| - return const DynamicType();
|
| - }
|
| - DartType type = lookup(typeString);
|
| - if (type != null) return type;
|
| -
|
| - int index = typeString.indexOf('<');
|
| - if (index < 1) {
|
| - compiler.internalError(
|
| - _errorNode(locationNodeOrElement, compiler),
|
| - "Type '$typeString' not found.");
|
| - }
|
| - type = lookup(typeString.substring(0, index));
|
| - if (type != null) {
|
| - // TODO(sra): Parse type parameters.
|
| - return type;
|
| - }
|
| - compiler.internalError(
|
| - _errorNode(locationNodeOrElement, compiler),
|
| - "Type '$typeString' not found.");
|
| - }
|
| -
|
| - static _errorNode(locationNodeOrElement, compiler) {
|
| - if (locationNodeOrElement is Node) return locationNodeOrElement;
|
| - return locationNodeOrElement.parseNode(compiler);
|
| - }
|
| -}
|
|
|