Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Unified Diff: tests/compiler/dart2js/related_types.dart

Issue 1338683002: Add related types check to analyze_dart2js_test (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tests/compiler/dart2js/memory_compiler.dart ('k') | tests/compiler/dart2js/related_types_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tests/compiler/dart2js/related_types.dart
diff --git a/tests/compiler/dart2js/related_types.dart b/tests/compiler/dart2js/related_types.dart
new file mode 100644
index 0000000000000000000000000000000000000000..299b97ab70c827364c95688818f4208ba9695e39
--- /dev/null
+++ b/tests/compiler/dart2js/related_types.dart
@@ -0,0 +1,413 @@
+// Copyright (c) 2015, 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 related_types;
+
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/core_types.dart';
+import 'package:compiler/src/dart_types.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/resolution/semantic_visitor.dart';
+import 'package:compiler/src/tree/tree.dart';
+import 'package:compiler/src/universe/universe.dart';
+import 'package:compiler/src/world.dart';
+
+/// Check all loaded libraries in [compiler] for unrelated types.
+void checkRelatedTypes(Compiler compiler) {
+ for (LibraryElement library in compiler.libraryLoader.libraries) {
+ checkLibraryElement(compiler, library);
+ }
+}
+
+/// Check [library] for unrelated types.
+void checkLibraryElement(Compiler compiler, LibraryElement library) {
+ library.forEachLocalMember((Element element) {
+ if (element.isClass) {
+ ClassElement cls = element;
+ cls.forEachLocalMember((MemberElement member) {
+ checkMemberElement(compiler, member);
+ });
+ } else if (!element.isTypedef) {
+ checkMemberElement(compiler, element);
+ }
+ });
+}
+
+/// Check [member] for unrelated types.
+void checkMemberElement(Compiler compiler, MemberElement member) {
+ if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
+
+ ResolvedAst resolvedAst = member.resolvedAst;
+ RelatedTypesChecker relatedTypesChecker =
+ new RelatedTypesChecker(compiler, resolvedAst);
+ if (resolvedAst.node != null) {
+ compiler.withCurrentElement(member.implementation, () {
+ relatedTypesChecker.apply(resolvedAst.node);
+ });
+ }
+}
+
+class RelatedTypesChecker extends TraversalVisitor<DartType, dynamic> {
+ final Compiler compiler;
+ final ResolvedAst resolvedAst;
+
+ RelatedTypesChecker(this.compiler, ResolvedAst resolvedAst)
+ : this.resolvedAst = resolvedAst,
+ super(resolvedAst.elements);
+
+ ClassWorld get world => compiler.world;
+
+ CoreTypes get coreTypes => compiler.coreTypes;
+
+ InterfaceType get thisType => resolvedAst.element.enclosingClass.thisType;
+
+ /// Returns `true` if there exists no common subtype of [left] and [right].
+ bool hasEmptyIntersection(DartType left, DartType right) {
+ if (left == right) return false;
+ if (left == null || right == null) return false;
+ ClassElement leftClass = const ClassFinder().findClass(left);
+ ClassElement rightClass = const ClassFinder().findClass(right);
+ if (leftClass != null && rightClass != null) {
+ return !world.haveAnyCommonSubtypes(leftClass, rightClass);
+ }
+ return false;
+ }
+
+ /// Checks that there exists a common subtype of [left] and [right] or report
+ /// a hint otherwise.
+ void checkRelated(Node node, DartType left, DartType right) {
+ if (hasEmptyIntersection(left, right)) {
+ compiler.reportHint(
+ node, MessageKind.NO_COMMON_SUBTYPES, {'left': left, 'right': right});
+ }
+ }
+
+ /// Check weakly typed collection methods, like `Map.containsKey`,
+ /// `Map.containsValue` and `Iterable.contains`.
+ void checkDynamicInvoke(
+ Node node,
+ DartType receiverType,
+ List<DartType> argumentTypes,
+ Selector selector) {
+ if (selector.name == 'containsKey' &&
+ selector.callStructure == CallStructure.ONE_ARG) {
+ InterfaceType mapType = findMapType(receiverType);
+ if (mapType != null) {
+ DartType keyType = findMapKeyType(mapType);
+ checkRelated(node, keyType, argumentTypes.first);
+ }
+ } else if (selector.name == 'containsValue' &&
+ selector.callStructure == CallStructure.ONE_ARG) {
+ InterfaceType mapType = findMapType(receiverType);
+ if (mapType != null) {
+ DartType valueType = findMapValueType(mapType);
+ checkRelated(node, valueType, argumentTypes.first);
+ }
+ } else if (selector.name == 'contains' &&
+ selector.callStructure == CallStructure.ONE_ARG) {
+ InterfaceType iterableType = findIterableType(receiverType);
+ if (iterableType != null) {
+ DartType elementType = findIterableElementType(iterableType);
+ checkRelated(node, elementType, argumentTypes.first);
+ }
+ } else if (selector.name == 'remove' &&
+ selector.callStructure == CallStructure.ONE_ARG) {
+ InterfaceType mapType = findMapType(receiverType);
+ if (mapType != null) {
+ DartType keyType = findMapKeyType(mapType);
+ checkRelated(node, keyType, argumentTypes.first);
+ }
+ InterfaceType listType = findListType(receiverType);
+ if (listType != null) {
+ DartType valueType = findListElementType(listType);
+ checkRelated(node, valueType, argumentTypes.first);
+ }
+ }
+ }
+
+ /// Return the interface type implemented by [type] or `null` if no interface
+ /// type is implied by [type].
+ InterfaceType findInterfaceType(DartType type) {
+ return Types.computeInterfaceType(compiler, type);
+ }
+
+ /// Returns the supertype of [receiver] that implements [cls], if any.
+ InterfaceType findClassType(DartType receiver, ClassElement cls) {
+ InterfaceType interfaceType = findInterfaceType(receiver);
+ if (interfaceType == null) return null;
+ InterfaceType mapType = interfaceType.asInstanceOf(cls);
+ if (mapType == null) return null;
+ return mapType;
+ }
+
+ /// Returns the supertype of [receiver] that implements `Iterable`, if any.
+ InterfaceType findIterableType(DartType receiver) {
+ return findClassType(receiver, compiler.iterableClass);
+ }
+
+ /// Returns the element type of the supertype of [receiver] that implements
+ /// `Iterable`, if any.
+ DartType findIterableElementType(InterfaceType iterableType) {
+ if (iterableType == null) return null;
+ return iterableType.typeArguments[0];
+ }
+
+ /// Returns the supertype of [receiver] that implements `Map`, if any.
+ InterfaceType findMapType(DartType receiver) {
+ return findClassType(receiver, compiler.mapClass);
+ }
+
+ /// Returns the key type of the supertype of [receiver] that implements
+ /// `Map`, if any.
+ DartType findMapKeyType(InterfaceType mapType) {
+ if (mapType == null) return null;
+ return mapType.typeArguments[0];
+ }
+
+ /// Returns the value type of the supertype of [receiver] that implements
+ /// `Map`, if any.
+ DartType findMapValueType(InterfaceType mapType) {
+ if (mapType == null) return null;
+ return mapType.typeArguments[1];
+ }
+
+ /// Returns the supertype of [receiver] that implements `List`, if any.
+ InterfaceType findListType(DartType receiver) {
+ return findClassType(receiver, compiler.listClass);
+ }
+
+ /// Returns the element type of the supertype of [receiver] that implements
+ /// `List`, if any.
+ DartType findListElementType(InterfaceType listType) {
+ if (listType == null) return null;
+ return listType.typeArguments[0];
+ }
+
+ /// Returns the implied return type of [type] or `dynamic` if no return type
+ /// is implied.
+ DartType findReturnType(DartType type) {
+ if (type is FunctionType) {
+ return type.returnType;
+ }
+ return const DynamicType();
+ }
+
+ /// Visits [arguments] and returns the list of their corresponding types.
+ List<DartType> findArgumentTypes(NodeList arguments) {
+ List<DartType> argumentTypes = <DartType>[];
+ for (Node argument in arguments) {
+ argumentTypes.add(apply(argument));
+ }
+ return argumentTypes;
+ }
+
+ /// Finds the [MemberSignature] of the [name] property on [type], if any.
+ MemberSignature lookupInterfaceMember(DartType type, Name name) {
+ InterfaceType interfaceType = findInterfaceType(type);
+ if (interfaceType == null) return null;
+ return interfaceType.lookupInterfaceMember(name);
+ }
+
+ /// Returns the type of an access of the [name] property on [type], or
+ /// `dynamic` if no property was found.
+ DartType lookupInterfaceMemberAccessType(DartType type, Name name) {
+ MemberSignature member = lookupInterfaceMember(type, name);
+ if (member == null) return const DynamicType();
+ return member.type;
+ }
+
+ /// Returns the function type of the [name] property on [type], or
+ /// `dynamic` if no property was found.
+ FunctionType lookupInterfaceMemberInvocationType(DartType type, Name name) {
+ MemberSignature member = lookupInterfaceMember(type, name);
+ if (member == null) return null;
+ return member.functionType;
+ }
+
+ DartType apply(Node node, [_]) {
+ DartType type = node.accept(this);
+ if (type == null) {
+ type = const DynamicType();
+ }
+ return type;
+ }
+
+ @override
+ DartType visitEquals(Send node, Node left, Node right, _) {
+ DartType leftType = apply(left);
+ DartType rightType = apply(right);
+ checkRelated(node, leftType, rightType);
+ return coreTypes.boolType;
+ }
+
+ @override
+ DartType visitNotEquals(Send node, Node left, Node right, _) {
+ DartType leftType = apply(left);
+ DartType rightType = apply(right);
+ checkRelated(node, leftType, rightType);
+ return coreTypes.boolType;
+ }
+
+ @override
+ DartType visitIndex(Send node, Node receiver, Node index, _) {
+ DartType receiverType = apply(receiver);
+ DartType indexType = apply(index);
+ InterfaceType mapType = findMapType(receiverType);
+ DartType keyType = findMapKeyType(mapType);
+ DartType valueType = findMapValueType(mapType);
+ checkRelated(index, keyType, indexType);
+ return valueType;
+ }
+
+ @override
+ DartType visitLiteralInt(LiteralInt node) {
+ return coreTypes.intType;
+ }
+
+ @override
+ DartType visitLiteralString(LiteralString node) {
+ return coreTypes.stringType;
+ }
+
+ @override
+ DartType visitLiteralBool(LiteralBool node) {
+ return coreTypes.boolType;
+ }
+
+ @override
+ DartType visitLiteralMap(LiteralMap node) {
+ return elements.getType(node);
+ }
+
+ @override
+ DartType visitLiteralList(LiteralList node) {
+ return elements.getType(node);
+ }
+
+ @override
+ DartType visitLiteralNull(LiteralNull node) {
+ return elements.getType(node);
+ }
+
+ @override
+ DartType visitLocalVariableGet(Send node, LocalVariableElement variable, _) {
+ return variable.type;
+ }
+
+ @override
+ DartType visitLocalFunctionGet(Send node, LocalFunctionElement function, _) {
+ return function.type;
+ }
+
+ @override
+ DartType visitParameterGet(Send node, ParameterElement parameter, _) {
+ return parameter.type;
+ }
+
+ @override
+ DartType visitThisPropertyGet(Send node, Name name, _) {
+ return lookupInterfaceMemberAccessType(thisType, name);
+ }
+
+ @override
+ DartType visitDynamicPropertyGet(Send node, Node receiver, Name name, _) {
+ DartType receiverType = apply(receiver);
+ return lookupInterfaceMemberAccessType(receiverType, name);
+ }
+
+ @override
+ DartType visitIfNotNullDynamicPropertyGet(
+ Send node, Node receiver, Name name, _) {
+ DartType receiverType = apply(receiver);
+ return lookupInterfaceMemberAccessType(receiverType, name);
+ }
+
+ @override
+ DartType visitStaticFieldGet(Send node, FieldElement field, _) {
+ return field.type;
+ }
+
+ @override
+ DartType visitTopLevelFieldGet(Send node, FieldElement field, _) {
+ return field.type;
+ }
+
+ @override
+ DartType visitDynamicPropertyInvoke(
+ Send node,
+ Node receiver,
+ NodeList arguments,
+ Selector selector, _) {
+ DartType receiverType = apply(receiver);
+ List<DartType> argumentTypes = findArgumentTypes(arguments);
+ FunctionType methodType = lookupInterfaceMemberInvocationType(
+ receiverType, selector.memberName);
+ checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+ return findReturnType(methodType);
+ }
+
+ @override
+ DartType visitThisPropertyInvoke(
+ Send node,
+ NodeList arguments,
+ Selector selector, _) {
+ DartType receiverType = thisType;
+ List<DartType> argumentTypes = findArgumentTypes(arguments);
+ FunctionType methodType = lookupInterfaceMemberInvocationType(
+ receiverType, selector.memberName);
+ checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+ return findReturnType(methodType);
+ }
+
+ @override
+ DartType visitIfNotNullDynamicPropertyInvoke(
+ Send node,
+ Node receiver,
+ NodeList arguments,
+ Selector selector, _) {
+ DartType receiverType = apply(receiver);
+ List<DartType> argumentTypes = findArgumentTypes(arguments);
+ FunctionType methodType = lookupInterfaceMemberInvocationType(
+ receiverType, selector.memberName);
+ checkDynamicInvoke(node, receiverType, argumentTypes, selector);
+ return findReturnType(methodType);
+ }
+
+ @override
+ DartType visitTopLevelFunctionInvoke(
+ Send node,
+ MethodElement function,
+ NodeList arguments,
+ CallStructure callStructure, _) {
+ apply(arguments);
+ return findReturnType(function.type);
+ }
+
+ @override
+ DartType visitStaticFunctionInvoke(
+ Send node,
+ MethodElement function,
+ NodeList arguments,
+ CallStructure callStructure, _) {
+ apply(arguments);
+ return findReturnType(function.type);
+ }
+}
+
+/// Computes the [ClassElement] implied by a type.
+// TODO(johnniwinther): Handle type variables, function types and typedefs.
+class ClassFinder extends BaseDartTypeVisitor<ClassElement, dynamic> {
+ const ClassFinder();
+
+ ClassElement findClass(DartType type) => type.accept(this, null);
+
+ @override
+ ClassElement visitType(DartType type, _) => null;
+
+ @override
+ ClassElement visitInterfaceType(InterfaceType type, _) {
+ return type.element;
+ }
+}
« no previous file with comments | « tests/compiler/dart2js/memory_compiler.dart ('k') | tests/compiler/dart2js/related_types_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698