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

Side by Side 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: Cleanup. 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library related_types;
sigurdm 2015/09/11 11:43:28 Do we want to also provide these hints outside dar
Johnni Winther 2015/09/11 12:31:22 Potentially, as an opt-in.
6
7 import 'package:compiler/src/compiler.dart';
8 import 'package:compiler/src/core_types.dart';
9 import 'package:compiler/src/dart_types.dart';
10 import 'package:compiler/src/diagnostics/messages.dart';
11 import 'package:compiler/src/elements/elements.dart';
12 import 'package:compiler/src/resolution/semantic_visitor.dart';
13 import 'package:compiler/src/tree/tree.dart';
14 import 'package:compiler/src/universe/universe.dart';
15 import 'package:compiler/src/world.dart';
16
17 /// Check all loader libraries in [compiler] for unrelated types.
sigurdm 2015/09/11 11:43:28 loader => loaded
Johnni Winther 2015/09/11 12:31:22 Done.
18 void checkRelatedTypes(Compiler compiler) {
19 for (LibraryElement library in compiler.libraryLoader.libraries) {
20 checkLibraryElement(compiler, library);
21 }
22 }
23
24 /// Check [library] for unrelated types.
25 void checkLibraryElement(Compiler compiler, LibraryElement library) {
26 library.forEachLocalMember((Element element) {
27 if (element.isClass) {
28 ClassElement cls = element;
29 cls.forEachLocalMember((MemberElement member) {
30 checkMemberElement(compiler, member);
31 });
32 } else if (!element.isTypedef) {
33 checkMemberElement(compiler, element);
34 }
35 });
36 }
37
38 /// Check [member] for unrelated types.
39 void checkMemberElement(Compiler compiler, MemberElement member) {
40 if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
41
42 ResolvedAst resolvedAst = member.resolvedAst;
43 RelatedTypesChecker relatedTypesChecker =
44 new RelatedTypesChecker(compiler, resolvedAst);
45 if (resolvedAst.node != null) {
46 compiler.withCurrentElement(member.implementation, () {
47 relatedTypesChecker.apply(resolvedAst.node);
48 });
49 }
50 }
51
52 class RelatedTypesChecker extends TraversalVisitor<DartType, dynamic> {
53 final Compiler compiler;
54 final ResolvedAst resolvedAst;
55
56 RelatedTypesChecker(this.compiler, ResolvedAst resolvedAst)
57 : this.resolvedAst = resolvedAst,
58 super(resolvedAst.elements);
59
60 ClassWorld get world => compiler.world;
61
62 CoreTypes get coreTypes => compiler.coreTypes;
63
64 InterfaceType get thisType => resolvedAst.element.enclosingClass.thisType;
65
66 /// Returns `true` if there exists no common subtype of [left] and [right].
67 bool hasEmptyIntersection(DartType left, DartType right) {
68 if (left == right) return false;
69 if (left == null || right == null) return false;
70 ClassElement leftClass = const ClassFinder().findClass(left);
71 ClassElement rightClass = const ClassFinder().findClass(right);
72 if (leftClass != null && rightClass != null) {
73 return !world.haveAnyCommonSubtypes(leftClass, rightClass);
74 }
75 return false;
76 }
77
78 /// Checks that there exists a common subtype of [left] and [right] or report
79 /// a hint otherwise.
80 void checkRelated(Node node, DartType left, DartType right) {
81 if (hasEmptyIntersection(left, right)) {
82 compiler.reportHint(
83 node, MessageKind.NO_COMMON_SUBTYPES, {'left': left, 'right': right});
84 }
85 }
86
87 /// Check weakly typed collection methods, like `Map.containsKey`,
88 /// `Map.containsValue` and `Iterable.contains`.
89 void checkDynamicInvoke(
90 Node node,
91 DartType receiverType,
92 List<DartType> argumentTypes,
93 Selector selector) {
94 if (selector.name == 'containsKey' &&
95 selector.callStructure == CallStructure.ONE_ARG) {
96 InterfaceType mapType = findMapType(receiverType);
97 if (mapType != null) {
98 DartType keyType = findMapKeyType(mapType);
99 checkRelated(node, keyType, argumentTypes.first);
100 }
101 } else if (selector.name == 'containsValue' &&
102 selector.callStructure == CallStructure.ONE_ARG) {
103 InterfaceType mapType = findMapType(receiverType);
104 if (mapType != null) {
105 DartType valueType = findMapValueType(mapType);
106 checkRelated(node, valueType, argumentTypes.first);
107 }
108 } else if (selector.name == 'contains' &&
109 selector.callStructure == CallStructure.ONE_ARG) {
110 InterfaceType iterableType = findIterableType(receiverType);
111 if (iterableType != null) {
112 DartType elementType = findIterableElementType(iterableType);
113 checkRelated(node, elementType, argumentTypes.first);
114 }
115 } else if (selector.name == 'remove' &&
116 selector.callStructure == CallStructure.ONE_ARG) {
117 InterfaceType mapType = findMapType(receiverType);
118 if (mapType != null) {
119 DartType keyType = findMapKeyType(mapType);
120 checkRelated(node, keyType, argumentTypes.first);
121 }
122 InterfaceType listType = findListType(receiverType);
123 if (listType != null) {
124 DartType valueType = findListElementType(listType);
125 checkRelated(node, valueType, argumentTypes.first);
126 }
127 }
128 }
129
130 /// Return the interface type implemented by [type] or `null` if no interface
131 /// type is implied by [type].
132 InterfaceType findInterfaceType(DartType type) {
133 if (type.treatAsDynamic) return null;
134 type = Types.computeUnaliasedBound(compiler, type);
135 if (type.treatAsDynamic) return null;
136 return Types.computeInterfaceType(compiler, type);
137 }
138
139 /// Returns the supertype of [receiver] that implements [cls], if any.
140 InterfaceType findClassType(DartType receiver, ClassElement cls) {
141 InterfaceType interfaceType = findInterfaceType(receiver);
142 if (interfaceType == null) return null;
143 InterfaceType mapType = interfaceType.asInstanceOf(cls);
144 if (mapType == null) return null;
145 return mapType;
146 }
147
148 /// Returns the supertype of [receiver] that implements `Iterable`, if any.
149 InterfaceType findIterableType(DartType receiver) {
150 return findClassType(receiver, compiler.iterableClass);
151 }
152
153 /// Returns the element type of the supertype of [receiver] that implements
154 /// `Iterable`, if any.
155 DartType findIterableElementType(InterfaceType iterableType) {
156 if (iterableType == null) return null;
157 return iterableType.typeArguments[0];
158 }
159
160 /// Returns the supertype of [receiver] that implements `Map`, if any.
161 InterfaceType findMapType(DartType receiver) {
162 return findClassType(receiver, compiler.mapClass);
163 }
164
165 /// Returns the key type of the supertype of [receiver] that implements
166 /// `Map`, if any.
167 DartType findMapKeyType(InterfaceType mapType) {
168 if (mapType == null) return null;
169 return mapType.typeArguments[0];
170 }
171
172 /// Returns the value type of the supertype of [receiver] that implements
173 /// `Map`, if any.
174 DartType findMapValueType(InterfaceType mapType) {
175 if (mapType == null) return null;
176 return mapType.typeArguments[1];
177 }
178
179 /// Returns the supertype of [receiver] that implements `List`, if any.
180 InterfaceType findListType(DartType receiver) {
181 return findClassType(receiver, compiler.listClass);
182 }
183
184 /// Returns the element type of the supertype of [receiver] that implements
185 /// `List`, if any.
186 DartType findListElementType(InterfaceType listType) {
187 if (listType == null) return null;
188 return listType.typeArguments[0];
189 }
190
191 /// Returns the implied return type of [type] or `dynamic` if no return type
192 /// is implied.
193 DartType findReturnType(DartType type) {
194 if (type is FunctionType) {
195 return type.returnType;
196 }
197 return const DynamicType();
198 }
199
200 /// Visits [arguments] and returns the list of their corresponding types.
201 List<DartType> findArgumentTypes(NodeList arguments) {
202 List<DartType> argumentTypes = <DartType>[];
203 for (Node argument in arguments) {
204 argumentTypes.add(apply(argument));
205 }
206 return argumentTypes;
207 }
208
209 /// Finds the [MemberSignature] of the [name] property on [type], if any.
210 MemberSignature lookupInterfaceMember(DartType type, Name name) {
211 InterfaceType interfaceType = findInterfaceType(type);
212 if (interfaceType == null) return null;
213 return interfaceType.lookupInterfaceMember(name);
214 }
215
216 /// Returns the type of an access of the [name] property on [type], or
217 /// `dynamic` if no property was found.
218 DartType lookupInterfaceMemberAccessType(DartType type, Name name) {
219 MemberSignature member = lookupInterfaceMember(type, name);
220 if (member == null) return const DynamicType();
221 return member.type;
222 }
223
224 /// Returns the function type of the [name] property on [type], or
225 /// `dynamic` if no property was found.
226 FunctionType lookupInterfaceMemberInvocationType(DartType type, Name name) {
227 MemberSignature member = lookupInterfaceMember(type, name);
228 if (member == null) return null;
229 return member.functionType;
230 }
231
232 DartType apply(Node node, [_]) {
233 DartType type = node.accept(this);
234 if (type == null) {
235 type = const DynamicType();
236 }
237 return type;
238 }
239
240 @override
241 DartType visitEquals(Send node, Node left, Node right, _) {
242 DartType leftType = apply(left);
243 DartType rightType = apply(right);
244 checkRelated(node, leftType, rightType);
245 return coreTypes.boolType;
246 }
247
248 @override
249 DartType visitNotEquals(Send node, Node left, Node right, _) {
250 DartType leftType = apply(left);
251 DartType rightType = apply(right);
252 checkRelated(node, leftType, rightType);
253 return coreTypes.boolType;
254 }
255
256 @override
257 DartType visitIndex(Send node, Node receiver, Node index, _) {
258 DartType receiverType = apply(receiver);
259 DartType indexType = apply(index);
260 InterfaceType mapType = findMapType(receiverType);
261 DartType keyType = findMapKeyType(mapType);
262 DartType valueType = findMapValueType(mapType);
263 checkRelated(index, keyType, indexType);
264 return valueType;
265 }
266
267 @override
268 DartType visitLiteralInt(LiteralInt node) {
269 return coreTypes.intType;
270 }
271
272 @override
273 DartType visitLiteralString(LiteralString node) {
274 return coreTypes.stringType;
275 }
276
277 @override
278 DartType visitLiteralBool(LiteralBool node) {
279 return coreTypes.boolType;
280 }
281
282 @override
283 DartType visitLiteralMap(LiteralMap node) {
284 return elements.getType(node);
285 }
286
287 @override
288 DartType visitLiteralList(LiteralList node) {
289 return elements.getType(node);
290 }
291
292 @override
293 DartType visitLiteralNull(LiteralNull node) {
294 return elements.getType(node);
295 }
296
297 @override
298 DartType visitLocalVariableGet(Send node, LocalVariableElement variable, _) {
299 return variable.type;
300 }
301
302 @override
303 DartType visitLocalFunctionGet(Send node, LocalFunctionElement function, _) {
304 return function.type;
305 }
306
307 @override
308 DartType visitParameterGet(Send node, ParameterElement parameter, _) {
309 return parameter.type;
310 }
311
312 @override
313 DartType visitThisPropertyGet(Send node, Name name, _) {
314 return lookupInterfaceMemberAccessType(thisType, name);
315 }
316
317 @override
318 DartType visitDynamicPropertyGet(Send node, Node receiver, Name name, _) {
319 DartType receiverType = apply(receiver);
320 return lookupInterfaceMemberAccessType(receiverType, name);
321 }
322
323 @override
324 DartType visitIfNotNullDynamicPropertyGet(
325 Send node, Node receiver, Name name, _) {
326 DartType receiverType = apply(receiver);
327 return lookupInterfaceMemberAccessType(receiverType, name);
328 }
329
330 @override
331 DartType visitStaticFieldGet(Send node, FieldElement field, _) {
332 return field.type;
333 }
334
335 @override
336 DartType visitTopLevelFieldGet(Send node, FieldElement field, _) {
337 return field.type;
338 }
339
340 @override
341 DartType visitDynamicPropertyInvoke(
342 Send node,
343 Node receiver,
344 NodeList arguments,
345 Selector selector, _) {
346 DartType receiverType = apply(receiver);
347 List<DartType> argumentTypes = findArgumentTypes(arguments);
348 FunctionType methodType = lookupInterfaceMemberInvocationType(
349 receiverType, selector.memberName);
350 checkDynamicInvoke(node, receiverType, argumentTypes, selector);
351 return findReturnType(methodType);
352 }
353
354 @override
355 DartType visitThisPropertyInvoke(
356 Send node,
357 NodeList arguments,
358 Selector selector, _) {
359 DartType receiverType = thisType;
360 List<DartType> argumentTypes = findArgumentTypes(arguments);
361 FunctionType methodType = lookupInterfaceMemberInvocationType(
362 receiverType, selector.memberName);
363 checkDynamicInvoke(node, receiverType, argumentTypes, selector);
364 return findReturnType(methodType);
365 }
366
367 @override
368 DartType visitIfNotNullDynamicPropertyInvoke(
369 Send node,
370 Node receiver,
371 NodeList arguments,
372 Selector selector, _) {
373 DartType receiverType = apply(receiver);
374 List<DartType> argumentTypes = findArgumentTypes(arguments);
375 FunctionType methodType = lookupInterfaceMemberInvocationType(
376 receiverType, selector.memberName);
377 checkDynamicInvoke(node, receiverType, argumentTypes, selector);
378 return findReturnType(methodType);
379 }
380
381 @override
382 DartType visitTopLevelFunctionInvoke(
383 Send node,
384 MethodElement function,
385 NodeList arguments,
386 CallStructure callStructure, _) {
387 apply(arguments);
388 return findReturnType(function.type);
389 }
390
391 @override
392 DartType visitStaticFunctionInvoke(
393 Send node,
394 MethodElement function,
395 NodeList arguments,
396 CallStructure callStructure, _) {
397 apply(arguments);
398 return findReturnType(function.type);
399 }
400 }
401
402 /// Computes the [ClassElement] implied by a type.
403 // TODO(johnniwinther): Handle type variables, function types and typedefs.
404 class ClassFinder extends BaseDartTypeVisitor<ClassElement, dynamic> {
405 const ClassFinder();
406
407 ClassElement findClass(DartType type) => type.accept(this, null);
408
409 @override
410 ClassElement visitType(DartType type, _) => null;
411
412 @override
413 ClassElement visitInterfaceType(InterfaceType type, _) {
414 return type.element;
415 }
416 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698