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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/resolution/members.dart

Issue 26232003: Support type promotion in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated to latest spec change Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/typechecker.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of resolution; 5 part of resolution;
6 6
7 abstract class TreeElements { 7 abstract class TreeElements {
8 Element get currentElement; 8 Element get currentElement;
9 Set<Node> get superUses; 9 Set<Node> get superUses;
10 10
(...skipping 21 matching lines...) Expand all
32 * Returns [:true:] if [node] is a type literal. 32 * Returns [:true:] if [node] is a type literal.
33 * 33 *
34 * Resolution marks this by setting the type on the node to be the 34 * Resolution marks this by setting the type on the node to be the
35 * [:Type:] type. 35 * [:Type:] type.
36 */ 36 */
37 bool isTypeLiteral(Send node); 37 bool isTypeLiteral(Send node);
38 38
39 /// Register additional dependencies required by [currentElement]. 39 /// Register additional dependencies required by [currentElement].
40 /// For example, elements that are used by a backend. 40 /// For example, elements that are used by a backend.
41 void registerDependency(Element element); 41 void registerDependency(Element element);
42
43 /// Returns [:true:] if [element] is potentially mutated anywhere in its
44 /// scope.
45 bool isPotentiallyMutated(VariableElement element);
46
47 /// Returns [:true:] if [element] is potentially mutated in [node].
48 bool isPotentiallyMutatedIn(Node node, VariableElement element);
49
50 /// Returns [:true:] if [element] is potentially mutated in a closure.
51 bool isPotentiallyMutatedInClosure(VariableElement element);
52
53 /// Returns [:true:] if [element] is accessed by a closure in [node].
54 bool isAccessedByClosureIn(Node node, VariableElement element);
42 } 55 }
43 56
44 class TreeElementMapping implements TreeElements { 57 class TreeElementMapping implements TreeElements {
45 final Element currentElement; 58 final Element currentElement;
46 final Map<Spannable, Selector> selectors = new Map<Spannable, Selector>(); 59 final Map<Spannable, Selector> selectors = new Map<Spannable, Selector>();
47 final Map<Node, DartType> types = new Map<Node, DartType>(); 60 final Map<Node, DartType> types = new Map<Node, DartType>();
48 final Set<Node> superUses = new Set<Node>(); 61 final Set<Node> superUses = new Set<Node>();
49 final Set<Element> otherDependencies = new Set<Element>(); 62 final Set<Element> otherDependencies = new Set<Element>();
50 final Map<Node, Constant> constants = new Map<Node, Constant>(); 63 final Map<Node, Constant> constants = new Map<Node, Constant>();
64 final Set<VariableElement> potentiallyMutated = new Set<VariableElement>();
65 final Map<Node, Set<VariableElement>> potentiallyMutatedIn =
66 new Map<Node, Set<VariableElement>>();
67 final Set<VariableElement> potentiallyMutatedInClosure =
68 new Set<VariableElement>();
69 final Map<Node, Set<VariableElement>> accessedByClosureIn =
70 new Map<Node, Set<VariableElement>>();
51 final int hashCode = ++hashCodeCounter; 71 final int hashCode = ++hashCodeCounter;
52 static int hashCodeCounter = 0; 72 static int hashCodeCounter = 0;
53 73
54 TreeElementMapping(this.currentElement); 74 TreeElementMapping(this.currentElement);
55 75
56 operator []=(Node node, Element element) { 76 operator []=(Node node, Element element) {
57 assert(invariant(node, () { 77 assert(invariant(node, () {
58 FunctionExpression functionExpression = node.asFunctionExpression(); 78 FunctionExpression functionExpression = node.asFunctionExpression();
59 if (functionExpression != null) { 79 if (functionExpression != null) {
60 return !functionExpression.modifiers.isExternal(); 80 return !functionExpression.modifiers.isExternal();
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 } 171 }
152 172
153 bool isTypeLiteral(Send node) { 173 bool isTypeLiteral(Send node) {
154 return getType(node) != null; 174 return getType(node) != null;
155 } 175 }
156 176
157 void registerDependency(Element element) { 177 void registerDependency(Element element) {
158 otherDependencies.add(element.implementation); 178 otherDependencies.add(element.implementation);
159 } 179 }
160 180
181 bool isPotentiallyMutated(VariableElement element) {
182 return potentiallyMutated.contains(element);
183 }
184
185 void setPotentiallyMutated(VariableElement element) {
186 potentiallyMutated.add(element);
187 }
188
189 bool isPotentiallyMutatedIn(Node node, VariableElement element) {
190 Set<Element> mutatedIn = potentiallyMutatedIn[node];
191 return mutatedIn != null && mutatedIn.contains(element);
192 }
193
194 void setPotentiallyMutatedIn(Node node, VariableElement element) {
195 potentiallyMutatedIn.putIfAbsent(
196 node, () => new Set<VariableElement>()).add(element);
197 }
198
199 bool isPotentiallyMutatedInClosure(VariableElement element) {
200 return potentiallyMutatedInClosure.contains(element);
201 }
202
203 void setPotentiallyMutatedInClosure(VariableElement element) {
204 potentiallyMutatedInClosure.add(element);
205 }
206
207 bool isAccessedByClosureIn(Node node, VariableElement element) {
208 Set<Element> accessedIn = accessedByClosureIn[node];
209 return accessedIn != null && accessedIn.contains(element);
210 }
211
212 void setAccessedByClosureIn(Node node, VariableElement element) {
213 accessedByClosureIn.putIfAbsent(
214 node, () => new Set<VariableElement>()).add(element);
215 }
216
161 String toString() => 'TreeElementMapping($currentElement)'; 217 String toString() => 'TreeElementMapping($currentElement)';
162 } 218 }
163 219
164 class ResolverTask extends CompilerTask { 220 class ResolverTask extends CompilerTask {
165 ResolverTask(Compiler compiler) : super(compiler); 221 ResolverTask(Compiler compiler) : super(compiler);
166 222
167 String get name => 'Resolver'; 223 String get name => 'Resolver';
168 224
169 TreeElements resolve(Element element) { 225 TreeElements resolve(Element element) {
170 return measure(() { 226 return measure(() {
(...skipping 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after
1838 bool sendIsMemberAccess = false; 1894 bool sendIsMemberAccess = false;
1839 StatementScope statementScope; 1895 StatementScope statementScope;
1840 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION 1896 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
1841 | ElementCategory.IMPLIES_TYPE; 1897 | ElementCategory.IMPLIES_TYPE;
1842 1898
1843 /// When visiting the type declaration of the variable in a [ForIn] loop, 1899 /// When visiting the type declaration of the variable in a [ForIn] loop,
1844 /// the initializer of the variable is implicit and we should not emit an 1900 /// the initializer of the variable is implicit and we should not emit an
1845 /// error when verifying that all final variables are initialized. 1901 /// error when verifying that all final variables are initialized.
1846 bool allowFinalWithoutInitializer = false; 1902 bool allowFinalWithoutInitializer = false;
1847 1903
1904 /// The nodes for which variable access and mutation must be registered in
1905 /// order to determine when the static type of variables types is promoted.
1906 Link<Node> promotionScope = const Link<Node>();
1907
1908 bool isPotentiallyMutableTarget(Element target) {
1909 if (target == null) return false;
1910 return (target.isVariable() || target.isParameter()) &&
1911 !(target.modifiers.isFinal() || target.modifiers.isConst());
1912 }
1913
1848 // TODO(ahe): Find a way to share this with runtime implementation. 1914 // TODO(ahe): Find a way to share this with runtime implementation.
1849 static final RegExp symbolValidationPattern = 1915 static final RegExp symbolValidationPattern =
1850 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' 1916 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
1851 r'-|' 1917 r'-|'
1852 r'unary-|' 1918 r'unary-|'
1853 r'\[\]=|' 1919 r'\[\]=|'
1854 r'~|' 1920 r'~|'
1855 r'==|' 1921 r'==|'
1856 r'\[\]|' 1922 r'\[\]|'
1857 r'\*|' 1923 r'\*|'
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1936 } 2002 }
1937 2003
1938 inStaticContext(action()) { 2004 inStaticContext(action()) {
1939 bool wasInstanceContext = inInstanceContext; 2005 bool wasInstanceContext = inInstanceContext;
1940 inInstanceContext = false; 2006 inInstanceContext = false;
1941 var result = action(); 2007 var result = action();
1942 inInstanceContext = wasInstanceContext; 2008 inInstanceContext = wasInstanceContext;
1943 return result; 2009 return result;
1944 } 2010 }
1945 2011
2012 doInPromotionScope(Node node, action()) {
2013 promotionScope = promotionScope.prepend(node);
2014 var result = action();
2015 promotionScope = promotionScope.tail;
2016 return result;
2017 }
2018
1946 visitInStaticContext(Node node) { 2019 visitInStaticContext(Node node) {
1947 inStaticContext(() => visit(node)); 2020 inStaticContext(() => visit(node));
1948 } 2021 }
1949 2022
1950 ErroneousElement warnAndCreateErroneousElement(Node node, 2023 ErroneousElement warnAndCreateErroneousElement(Node node,
1951 SourceString name, 2024 SourceString name,
1952 DualKind kind, 2025 DualKind kind,
1953 [Map arguments = const {}]) { 2026 [Map arguments = const {}]) {
1954 ResolutionWarning warning = new ResolutionWarning( 2027 ResolutionWarning warning = new ResolutionWarning(
1955 kind.warning, arguments, compiler.terseDiagnostics); 2028 kind.warning, arguments, compiler.terseDiagnostics);
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
2178 statementScope = oldStatementScope; 2251 statementScope = oldStatementScope;
2179 2252
2180 scope = oldScope; 2253 scope = oldScope;
2181 enclosingElement = previousEnclosingElement; 2254 enclosingElement = previousEnclosingElement;
2182 2255
2183 world.registerClosure(function, mapping); 2256 world.registerClosure(function, mapping);
2184 world.registerInstantiatedClass(compiler.functionClass, mapping); 2257 world.registerInstantiatedClass(compiler.functionClass, mapping);
2185 } 2258 }
2186 2259
2187 visitIf(If node) { 2260 visitIf(If node) {
2188 visit(node.condition); 2261 doInPromotionScope(node.condition.expression, () => visit(node.condition));
2189 visitIn(node.thenPart, new BlockScope(scope)); 2262 doInPromotionScope(node.thenPart,
2263 () => visitIn(node.thenPart, new BlockScope(scope)));
2190 visitIn(node.elsePart, new BlockScope(scope)); 2264 visitIn(node.elsePart, new BlockScope(scope));
2191 } 2265 }
2192 2266
2193 static bool isLogicalOperator(Identifier op) { 2267 static bool isLogicalOperator(Identifier op) {
2194 String str = op.source.stringValue; 2268 String str = op.source.stringValue;
2195 return (identical(str, '&&') || str == '||' || str == '!'); 2269 return (identical(str, '&&') || str == '||' || str == '!');
2196 } 2270 }
2197 2271
2198 Element resolveSend(Send node) { 2272 Element resolveSend(Send node) {
2199 Selector selector = resolveSelector(node, null); 2273 Selector selector = resolveSelector(node, null);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
2405 } else if (!seenNamedArguments.isEmpty) { 2479 } else if (!seenNamedArguments.isEmpty) {
2406 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); 2480 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
2407 } 2481 }
2408 } 2482 }
2409 sendIsMemberAccess = oldSendIsMemberAccess; 2483 sendIsMemberAccess = oldSendIsMemberAccess;
2410 } 2484 }
2411 2485
2412 visitSend(Send node) { 2486 visitSend(Send node) {
2413 bool oldSendIsMemberAccess = sendIsMemberAccess; 2487 bool oldSendIsMemberAccess = sendIsMemberAccess;
2414 sendIsMemberAccess = node.isPropertyAccess || node.isCall; 2488 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
2415 Element target = resolveSend(node); 2489 Element target;
2490 if (node.isLogicalAnd) {
2491 target = doInPromotionScope(node.receiver, () => resolveSend(node));
2492 } else {
2493 target = resolveSend(node);
2494 }
2416 sendIsMemberAccess = oldSendIsMemberAccess; 2495 sendIsMemberAccess = oldSendIsMemberAccess;
2417 2496
2418 if (target != null 2497 if (target != null
2419 && target == compiler.mirrorSystemGetNameFunction 2498 && target == compiler.mirrorSystemGetNameFunction
2420 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { 2499 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
2421 compiler.reportHint( 2500 compiler.reportHint(
2422 node.selector, MessageKind.STATIC_FUNCTION_BLOAT, 2501 node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
2423 {'class': compiler.mirrorSystemClass.name, 2502 {'class': compiler.mirrorSystemClass.name,
2424 'name': compiler.mirrorSystemGetNameFunction.name}); 2503 'name': compiler.mirrorSystemGetNameFunction.name});
2425 } 2504 }
(...skipping 19 matching lines...) Expand all
2445 world.registerTypeLiteral(target, mapping); 2524 world.registerTypeLiteral(target, mapping);
2446 } else if (target.impliesType() && !sendIsMemberAccess) { 2525 } else if (target.impliesType() && !sendIsMemberAccess) {
2447 // Set the type of the node to [Type] to mark this send as a 2526 // Set the type of the node to [Type] to mark this send as a
2448 // type literal. 2527 // type literal.
2449 mapping.setType(node, compiler.typeClass.computeType(compiler)); 2528 mapping.setType(node, compiler.typeClass.computeType(compiler));
2450 world.registerTypeLiteral(target, mapping); 2529 world.registerTypeLiteral(target, mapping);
2451 2530
2452 // Don't try to make constants of calls to type literals. 2531 // Don't try to make constants of calls to type literals.
2453 analyzeConstant(node, isConst: !node.isCall); 2532 analyzeConstant(node, isConst: !node.isCall);
2454 } 2533 }
2534 if (isPotentiallyMutableTarget(target)) {
2535 if (enclosingElement != target.enclosingElement) {
2536 for (Node scope in promotionScope) {
2537 mapping.setAccessedByClosureIn(scope, target);
2538 }
2539 }
2540 }
2455 } 2541 }
2456 2542
2457 bool resolvedArguments = false; 2543 bool resolvedArguments = false;
2458 if (node.isOperator) { 2544 if (node.isOperator) {
2459 String operatorString = node.selector.asOperator().source.stringValue; 2545 String operatorString = node.selector.asOperator().source.stringValue;
2460 if (identical(operatorString, 'is')) { 2546 if (identical(operatorString, 'is')) {
2547 // TODO(johnniwinther): Use seen type tests to avoid registration of
2548 // mutation/access to unpromoted variables.
2461 DartType type = 2549 DartType type =
2462 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast); 2550 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast);
2463 if (type != null) { 2551 if (type != null) {
2464 compiler.enqueuer.resolution.registerIsCheck(type, mapping); 2552 compiler.enqueuer.resolution.registerIsCheck(type, mapping);
2465 } 2553 }
2466 resolvedArguments = true; 2554 resolvedArguments = true;
2467 } else if (identical(operatorString, 'as')) { 2555 } else if (identical(operatorString, 'as')) {
2468 DartType type = resolveTypeExpression(node.arguments.head); 2556 DartType type = resolveTypeExpression(node.arguments.head);
2469 if (type != null) { 2557 if (type != null) {
2470 compiler.enqueuer.resolution.registerAsCheck(type, mapping); 2558 compiler.enqueuer.resolution.registerAsCheck(type, mapping);
2471 } 2559 }
2472 resolvedArguments = true; 2560 resolvedArguments = true;
2561 } else if (identical(operatorString, '&&')) {
2562 doInPromotionScope(node.arguments.head,
2563 () => resolveArguments(node.argumentsNode));
2564 resolvedArguments = true;
2473 } 2565 }
2474 } 2566 }
2475 2567
2476 if (!resolvedArguments) { 2568 if (!resolvedArguments) {
2477 resolveArguments(node.argumentsNode); 2569 resolveArguments(node.argumentsNode);
2478 } 2570 }
2479 2571
2480 // If the selector is null, it means that we will not be generating 2572 // If the selector is null, it means that we will not be generating
2481 // code for this as a send. 2573 // code for this as a send.
2482 Selector selector = mapping.getSelector(node); 2574 Selector selector = mapping.getSelector(node);
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
2565 compiler.backend.registerThrowNoSuchMethod(mapping); 2657 compiler.backend.registerThrowNoSuchMethod(mapping);
2566 } else if (target.modifiers.isFinal() || 2658 } else if (target.modifiers.isFinal() ||
2567 target.modifiers.isConst() || 2659 target.modifiers.isConst() ||
2568 (target.isFunction() && 2660 (target.isFunction() &&
2569 Elements.isStaticOrTopLevelFunction(target) && 2661 Elements.isStaticOrTopLevelFunction(target) &&
2570 !target.isSetter())) { 2662 !target.isSetter())) {
2571 setter = warnAndCreateErroneousElement( 2663 setter = warnAndCreateErroneousElement(
2572 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER); 2664 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
2573 compiler.backend.registerThrowNoSuchMethod(mapping); 2665 compiler.backend.registerThrowNoSuchMethod(mapping);
2574 } 2666 }
2667 if (isPotentiallyMutableTarget(target)) {
2668 mapping.setPotentiallyMutated(target);
2669 if (enclosingElement != target.enclosingElement) {
2670 mapping.setPotentiallyMutatedInClosure(target);
2671 }
2672 for (Node scope in promotionScope) {
2673 mapping.setPotentiallyMutatedIn(scope, target);
2674 }
2675 }
2575 } 2676 }
2576 2677
2577 visit(node.argumentsNode); 2678 visit(node.argumentsNode);
2578 2679
2579 // TODO(ngeoffray): Check if the target can be assigned. 2680 // TODO(ngeoffray): Check if the target can be assigned.
2580 // TODO(ngeoffray): Warn if target is null and the send is 2681 // TODO(ngeoffray): Warn if target is null and the send is
2581 // unqualified. 2682 // unqualified.
2582 2683
2583 Selector selector = mapping.getSelector(node); 2684 Selector selector = mapping.getSelector(node);
2584 if (isComplex) { 2685 if (isComplex) {
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
2995 mapping.setType(node, listType); 3096 mapping.setType(node, listType);
2996 world.registerInstantiatedType(listType, mapping); 3097 world.registerInstantiatedType(listType, mapping);
2997 compiler.backend.registerRequiredType(listType, enclosingElement); 3098 compiler.backend.registerRequiredType(listType, enclosingElement);
2998 visit(node.elements); 3099 visit(node.elements);
2999 if (node.isConst()) { 3100 if (node.isConst()) {
3000 analyzeConstant(node); 3101 analyzeConstant(node);
3001 } 3102 }
3002 } 3103 }
3003 3104
3004 visitConditional(Conditional node) { 3105 visitConditional(Conditional node) {
3005 node.visitChildren(this); 3106 doInPromotionScope(node.condition, () => visit(node.condition));
3107 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
3108 visit(node.elseExpression);
3006 } 3109 }
3007 3110
3008 visitStringInterpolation(StringInterpolation node) { 3111 visitStringInterpolation(StringInterpolation node) {
3009 world.registerInstantiatedClass(compiler.stringClass, mapping); 3112 world.registerInstantiatedClass(compiler.stringClass, mapping);
3010 compiler.backend.registerStringInterpolation(mapping); 3113 compiler.backend.registerStringInterpolation(mapping);
3011 node.visitChildren(this); 3114 node.visitChildren(this);
3012 } 3115 }
3013 3116
3014 visitStringInterpolationPart(StringInterpolationPart node) { 3117 visitStringInterpolationPart(StringInterpolationPart node) {
3015 registerImplicitInvocation(const SourceString('toString'), 0); 3118 registerImplicitInvocation(const SourceString('toString'), 0);
(...skipping 1522 matching lines...) Expand 10 before | Expand all | Expand 10 after
4538 return finishConstructorReference(visit(expression), 4641 return finishConstructorReference(visit(expression),
4539 expression, expression); 4642 expression, expression);
4540 } 4643 }
4541 } 4644 }
4542 4645
4543 /// Looks up [name] in [scope] and unwraps the result. 4646 /// Looks up [name] in [scope] and unwraps the result.
4544 Element lookupInScope(Compiler compiler, Node node, 4647 Element lookupInScope(Compiler compiler, Node node,
4545 Scope scope, SourceString name) { 4648 Scope scope, SourceString name) {
4546 return Elements.unwrap(scope.lookup(name), compiler, node); 4649 return Elements.unwrap(scope.lookup(name), compiler, node);
4547 } 4650 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/typechecker.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698