OLD | NEW |
---|---|
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 Loading... | |
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 = | 59 final Map<Spannable, Selector> selectors = |
47 new LinkedHashMap<Spannable, Selector>(); | 60 new LinkedHashMap<Spannable, Selector>(); |
48 final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>(); | 61 final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>(); |
49 final Set<Node> superUses = new LinkedHashSet<Node>(); | 62 final Set<Node> superUses = new LinkedHashSet<Node>(); |
50 final Set<Element> otherDependencies = new LinkedHashSet<Element>(); | 63 final Set<Element> otherDependencies = new LinkedHashSet<Element>(); |
51 final Map<Node, Constant> constants = new Map<Node, Constant>(); | 64 final Map<Node, Constant> constants = new Map<Node, Constant>(); |
65 final Set<VariableElement> potentiallyMutated = new Set<VariableElement>(); | |
66 final Map<Node, Set<VariableElement>> potentiallyMutatedIn = | |
67 new Map<Node, Set<VariableElement>>(); | |
68 final Set<VariableElement> potentiallyMutatedInClosure = | |
69 new Set<VariableElement>(); | |
70 final Map<Node, Set<VariableElement>> accessedByClosureIn = | |
71 new Map<Node, Set<VariableElement>>(); | |
52 final int hashCode = ++hashCodeCounter; | 72 final int hashCode = ++hashCodeCounter; |
53 static int hashCodeCounter = 0; | 73 static int hashCodeCounter = 0; |
54 | 74 |
55 TreeElementMapping(this.currentElement); | 75 TreeElementMapping(this.currentElement); |
56 | 76 |
57 operator []=(Node node, Element element) { | 77 operator []=(Node node, Element element) { |
58 assert(invariant(node, () { | 78 assert(invariant(node, () { |
59 FunctionExpression functionExpression = node.asFunctionExpression(); | 79 FunctionExpression functionExpression = node.asFunctionExpression(); |
60 if (functionExpression != null) { | 80 if (functionExpression != null) { |
61 return !functionExpression.modifiers.isExternal(); | 81 return !functionExpression.modifiers.isExternal(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 } | 172 } |
153 | 173 |
154 bool isTypeLiteral(Send node) { | 174 bool isTypeLiteral(Send node) { |
155 return getType(node) != null; | 175 return getType(node) != null; |
156 } | 176 } |
157 | 177 |
158 void registerDependency(Element element) { | 178 void registerDependency(Element element) { |
159 otherDependencies.add(element.implementation); | 179 otherDependencies.add(element.implementation); |
160 } | 180 } |
161 | 181 |
182 bool isPotentiallyMutated(VariableElement element) { | |
183 return potentiallyMutated.contains(element); | |
184 } | |
185 | |
186 void setPotentiallyMutated(VariableElement element) { | |
187 potentiallyMutated.add(element); | |
188 } | |
189 | |
190 bool isPotentiallyMutatedIn(Node node, VariableElement element) { | |
191 Set<Element> mutatedIn = potentiallyMutatedIn[node]; | |
192 return mutatedIn != null && mutatedIn.contains(element); | |
193 } | |
194 | |
195 void setPotentiallyMutatedIn(Node node, VariableElement element) { | |
196 potentiallyMutatedIn.putIfAbsent( | |
197 node, () => new Set<VariableElement>()).add(element); | |
198 } | |
199 | |
200 bool isPotentiallyMutatedInClosure(VariableElement element) { | |
201 return potentiallyMutatedInClosure.contains(element); | |
202 } | |
203 | |
204 void setPotentiallyMutatedInClosure(VariableElement element) { | |
205 potentiallyMutatedInClosure.add(element); | |
206 } | |
207 | |
208 bool isAccessedByClosureIn(Node node, VariableElement element) { | |
209 Set<Element> accessedIn = accessedByClosureIn[node]; | |
210 return accessedIn != null && accessedIn.contains(element); | |
211 } | |
212 | |
213 void setAccessedByClosureIn(Node node, VariableElement element) { | |
214 accessedByClosureIn.putIfAbsent( | |
215 node, () => new Set<VariableElement>()).add(element); | |
216 } | |
217 | |
162 String toString() => 'TreeElementMapping($currentElement)'; | 218 String toString() => 'TreeElementMapping($currentElement)'; |
163 } | 219 } |
164 | 220 |
165 class ResolverTask extends CompilerTask { | 221 class ResolverTask extends CompilerTask { |
166 ResolverTask(Compiler compiler) : super(compiler); | 222 ResolverTask(Compiler compiler) : super(compiler); |
167 | 223 |
168 String get name => 'Resolver'; | 224 String get name => 'Resolver'; |
169 | 225 |
170 TreeElements resolve(Element element) { | 226 TreeElements resolve(Element element) { |
171 return measure(() { | 227 return measure(() { |
(...skipping 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1839 bool sendIsMemberAccess = false; | 1895 bool sendIsMemberAccess = false; |
1840 StatementScope statementScope; | 1896 StatementScope statementScope; |
1841 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION | 1897 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION |
1842 | ElementCategory.IMPLIES_TYPE; | 1898 | ElementCategory.IMPLIES_TYPE; |
1843 | 1899 |
1844 /// When visiting the type declaration of the variable in a [ForIn] loop, | 1900 /// When visiting the type declaration of the variable in a [ForIn] loop, |
1845 /// the initializer of the variable is implicit and we should not emit an | 1901 /// the initializer of the variable is implicit and we should not emit an |
1846 /// error when verifying that all final variables are initialized. | 1902 /// error when verifying that all final variables are initialized. |
1847 bool allowFinalWithoutInitializer = false; | 1903 bool allowFinalWithoutInitializer = false; |
1848 | 1904 |
1905 /// The nodes for which variable access and mutation must be registed in order | |
karlklose
2013/10/15 11:56:17
'registed' -> 'registered'.
Johnni Winther
2013/10/15 15:57:00
Done.
| |
1906 /// to determine when variable types are promoted. | |
karlklose
2013/10/15 11:56:17
'when the static type of variables is promoted.'
Johnni Winther
2013/10/15 15:57:00
Done.
| |
1907 Link<Node> promotionScope = const Link<Node>(); | |
1908 | |
1909 bool isPotentiallyMutableTarget(Element target) { | |
1910 if (target == null) return false; | |
1911 return (target.isVariable() || target.isParameter()) && | |
1912 !(target.modifiers.isFinal() || target.modifiers.isConst()); | |
1913 } | |
1914 | |
1849 // TODO(ahe): Find a way to share this with runtime implementation. | 1915 // TODO(ahe): Find a way to share this with runtime implementation. |
1850 static final RegExp symbolValidationPattern = | 1916 static final RegExp symbolValidationPattern = |
1851 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' | 1917 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' |
1852 r'-|' | 1918 r'-|' |
1853 r'unary-|' | 1919 r'unary-|' |
1854 r'\[\]=|' | 1920 r'\[\]=|' |
1855 r'~|' | 1921 r'~|' |
1856 r'==|' | 1922 r'==|' |
1857 r'\[\]|' | 1923 r'\[\]|' |
1858 r'\*|' | 1924 r'\*|' |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1937 } | 2003 } |
1938 | 2004 |
1939 inStaticContext(action()) { | 2005 inStaticContext(action()) { |
1940 bool wasInstanceContext = inInstanceContext; | 2006 bool wasInstanceContext = inInstanceContext; |
1941 inInstanceContext = false; | 2007 inInstanceContext = false; |
1942 var result = action(); | 2008 var result = action(); |
1943 inInstanceContext = wasInstanceContext; | 2009 inInstanceContext = wasInstanceContext; |
1944 return result; | 2010 return result; |
1945 } | 2011 } |
1946 | 2012 |
2013 doInPromotionScope(Node node, action()) { | |
2014 promotionScope = promotionScope.prepend(node); | |
2015 var result = action(); | |
2016 promotionScope = promotionScope.tail; | |
2017 return result; | |
2018 } | |
2019 | |
1947 visitInStaticContext(Node node) { | 2020 visitInStaticContext(Node node) { |
1948 inStaticContext(() => visit(node)); | 2021 inStaticContext(() => visit(node)); |
1949 } | 2022 } |
1950 | 2023 |
1951 ErroneousElement warnAndCreateErroneousElement(Node node, | 2024 ErroneousElement warnAndCreateErroneousElement(Node node, |
1952 SourceString name, | 2025 SourceString name, |
1953 DualKind kind, | 2026 DualKind kind, |
1954 [Map arguments = const {}]) { | 2027 [Map arguments = const {}]) { |
1955 ResolutionWarning warning = new ResolutionWarning( | 2028 ResolutionWarning warning = new ResolutionWarning( |
1956 kind.warning, arguments, compiler.terseDiagnostics); | 2029 kind.warning, arguments, compiler.terseDiagnostics); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2179 statementScope = oldStatementScope; | 2252 statementScope = oldStatementScope; |
2180 | 2253 |
2181 scope = oldScope; | 2254 scope = oldScope; |
2182 enclosingElement = previousEnclosingElement; | 2255 enclosingElement = previousEnclosingElement; |
2183 | 2256 |
2184 world.registerClosure(function, mapping); | 2257 world.registerClosure(function, mapping); |
2185 world.registerInstantiatedClass(compiler.functionClass, mapping); | 2258 world.registerInstantiatedClass(compiler.functionClass, mapping); |
2186 } | 2259 } |
2187 | 2260 |
2188 visitIf(If node) { | 2261 visitIf(If node) { |
2189 visit(node.condition); | 2262 doInPromotionScope(node.condition.expression, () => visit(node.condition)); |
2190 visitIn(node.thenPart, new BlockScope(scope)); | 2263 doInPromotionScope(node.thenPart, () => |
karlklose
2013/10/15 11:56:17
Break line before closure.
Johnni Winther
2013/10/15 15:57:00
Done.
| |
2264 visitIn(node.thenPart, new BlockScope(scope))); | |
2191 visitIn(node.elsePart, new BlockScope(scope)); | 2265 visitIn(node.elsePart, new BlockScope(scope)); |
2192 } | 2266 } |
2193 | 2267 |
2194 static bool isLogicalOperator(Identifier op) { | 2268 static bool isLogicalOperator(Identifier op) { |
2195 String str = op.source.stringValue; | 2269 String str = op.source.stringValue; |
2196 return (identical(str, '&&') || str == '||' || str == '!'); | 2270 return (identical(str, '&&') || str == '||' || str == '!'); |
2197 } | 2271 } |
2198 | 2272 |
2199 Element resolveSend(Send node) { | 2273 Element resolveSend(Send node) { |
2200 Selector selector = resolveSelector(node, null); | 2274 Selector selector = resolveSelector(node, null); |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2406 } else if (!seenNamedArguments.isEmpty) { | 2480 } else if (!seenNamedArguments.isEmpty) { |
2407 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); | 2481 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); |
2408 } | 2482 } |
2409 } | 2483 } |
2410 sendIsMemberAccess = oldSendIsMemberAccess; | 2484 sendIsMemberAccess = oldSendIsMemberAccess; |
2411 } | 2485 } |
2412 | 2486 |
2413 visitSend(Send node) { | 2487 visitSend(Send node) { |
2414 bool oldSendIsMemberAccess = sendIsMemberAccess; | 2488 bool oldSendIsMemberAccess = sendIsMemberAccess; |
2415 sendIsMemberAccess = node.isPropertyAccess || node.isCall; | 2489 sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
2416 Element target = resolveSend(node); | 2490 Element target; |
2491 if (node.isLogicalAnd) { | |
2492 target = doInPromotionScope(node.receiver, () => resolveSend(node)); | |
2493 } else { | |
2494 target = resolveSend(node); | |
2495 } | |
2417 sendIsMemberAccess = oldSendIsMemberAccess; | 2496 sendIsMemberAccess = oldSendIsMemberAccess; |
2418 | 2497 |
2419 if (target != null | 2498 if (target != null |
2420 && target == compiler.mirrorSystemGetNameFunction | 2499 && target == compiler.mirrorSystemGetNameFunction |
2421 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { | 2500 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { |
2422 compiler.reportHint( | 2501 compiler.reportHint( |
2423 node.selector, MessageKind.STATIC_FUNCTION_BLOAT, | 2502 node.selector, MessageKind.STATIC_FUNCTION_BLOAT, |
2424 {'class': compiler.mirrorSystemClass.name, | 2503 {'class': compiler.mirrorSystemClass.name, |
2425 'name': compiler.mirrorSystemGetNameFunction.name}); | 2504 'name': compiler.mirrorSystemGetNameFunction.name}); |
2426 } | 2505 } |
(...skipping 19 matching lines...) Expand all Loading... | |
2446 world.registerTypeLiteral(target, mapping); | 2525 world.registerTypeLiteral(target, mapping); |
2447 } else if (target.impliesType() && !sendIsMemberAccess) { | 2526 } else if (target.impliesType() && !sendIsMemberAccess) { |
2448 // Set the type of the node to [Type] to mark this send as a | 2527 // Set the type of the node to [Type] to mark this send as a |
2449 // type literal. | 2528 // type literal. |
2450 mapping.setType(node, compiler.typeClass.computeType(compiler)); | 2529 mapping.setType(node, compiler.typeClass.computeType(compiler)); |
2451 world.registerTypeLiteral(target, mapping); | 2530 world.registerTypeLiteral(target, mapping); |
2452 | 2531 |
2453 // Don't try to make constants of calls to type literals. | 2532 // Don't try to make constants of calls to type literals. |
2454 analyzeConstant(node, isConst: !node.isCall); | 2533 analyzeConstant(node, isConst: !node.isCall); |
2455 } | 2534 } |
2535 if (isPotentiallyMutableTarget(target)) { | |
2536 if (enclosingElement != target.enclosingElement) { | |
2537 for (Node scope in promotionScope) { | |
2538 mapping.setAccessedByClosureIn(scope, target); | |
2539 } | |
2540 } | |
2541 } | |
2456 } | 2542 } |
2457 | 2543 |
2458 bool resolvedArguments = false; | 2544 bool resolvedArguments = false; |
2459 if (node.isOperator) { | 2545 if (node.isOperator) { |
2460 String operatorString = node.selector.asOperator().source.stringValue; | 2546 String operatorString = node.selector.asOperator().source.stringValue; |
2461 if (identical(operatorString, 'is')) { | 2547 if (identical(operatorString, 'is')) { |
2462 DartType type = | 2548 DartType type = |
2463 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast); | 2549 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast); |
2464 if (type != null) { | 2550 if (type != null) { |
2465 compiler.enqueuer.resolution.registerIsCheck(type, mapping); | 2551 compiler.enqueuer.resolution.registerIsCheck(type, mapping); |
2466 } | 2552 } |
2467 resolvedArguments = true; | 2553 resolvedArguments = true; |
2468 } else if (identical(operatorString, 'as')) { | 2554 } else if (identical(operatorString, 'as')) { |
2469 DartType type = resolveTypeExpression(node.arguments.head); | 2555 DartType type = resolveTypeExpression(node.arguments.head); |
2470 if (type != null) { | 2556 if (type != null) { |
2471 compiler.enqueuer.resolution.registerAsCheck(type, mapping); | 2557 compiler.enqueuer.resolution.registerAsCheck(type, mapping); |
2472 } | 2558 } |
2473 resolvedArguments = true; | 2559 resolvedArguments = true; |
2560 } else if (identical(operatorString, '&&')) { | |
2561 doInPromotionScope(node.arguments.head, | |
2562 () => resolveArguments(node.argumentsNode)); | |
2563 resolvedArguments = true; | |
2474 } | 2564 } |
2475 } | 2565 } |
2476 | 2566 |
2477 if (!resolvedArguments) { | 2567 if (!resolvedArguments) { |
2478 resolveArguments(node.argumentsNode); | 2568 resolveArguments(node.argumentsNode); |
2479 } | 2569 } |
2480 | 2570 |
2481 // If the selector is null, it means that we will not be generating | 2571 // If the selector is null, it means that we will not be generating |
2482 // code for this as a send. | 2572 // code for this as a send. |
2483 Selector selector = mapping.getSelector(node); | 2573 Selector selector = mapping.getSelector(node); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2566 compiler.backend.registerThrowNoSuchMethod(mapping); | 2656 compiler.backend.registerThrowNoSuchMethod(mapping); |
2567 } else if (target.modifiers.isFinal() || | 2657 } else if (target.modifiers.isFinal() || |
2568 target.modifiers.isConst() || | 2658 target.modifiers.isConst() || |
2569 (target.isFunction() && | 2659 (target.isFunction() && |
2570 Elements.isStaticOrTopLevelFunction(target) && | 2660 Elements.isStaticOrTopLevelFunction(target) && |
2571 !target.isSetter())) { | 2661 !target.isSetter())) { |
2572 setter = warnAndCreateErroneousElement( | 2662 setter = warnAndCreateErroneousElement( |
2573 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER); | 2663 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER); |
2574 compiler.backend.registerThrowNoSuchMethod(mapping); | 2664 compiler.backend.registerThrowNoSuchMethod(mapping); |
2575 } | 2665 } |
2666 if (isPotentiallyMutableTarget(target)) { | |
2667 mapping.setPotentiallyMutated(target); | |
2668 if (enclosingElement != target.enclosingElement) { | |
2669 mapping.setPotentiallyMutatedInClosure(target); | |
2670 } | |
2671 for (Node scope in promotionScope) { | |
2672 mapping.setPotentiallyMutatedIn(scope, target); | |
2673 } | |
2674 } | |
2576 } | 2675 } |
2577 | 2676 |
2578 visit(node.argumentsNode); | 2677 visit(node.argumentsNode); |
2579 | 2678 |
2580 // TODO(ngeoffray): Check if the target can be assigned. | 2679 // TODO(ngeoffray): Check if the target can be assigned. |
2581 // TODO(ngeoffray): Warn if target is null and the send is | 2680 // TODO(ngeoffray): Warn if target is null and the send is |
2582 // unqualified. | 2681 // unqualified. |
2583 | 2682 |
2584 Selector selector = mapping.getSelector(node); | 2683 Selector selector = mapping.getSelector(node); |
2585 if (isComplex) { | 2684 if (isComplex) { |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2992 mapping.setType(node, listType); | 3091 mapping.setType(node, listType); |
2993 world.registerInstantiatedType(listType, mapping); | 3092 world.registerInstantiatedType(listType, mapping); |
2994 compiler.backend.registerRequiredType(listType, enclosingElement); | 3093 compiler.backend.registerRequiredType(listType, enclosingElement); |
2995 visit(node.elements); | 3094 visit(node.elements); |
2996 if (node.isConst()) { | 3095 if (node.isConst()) { |
2997 analyzeConstant(node); | 3096 analyzeConstant(node); |
2998 } | 3097 } |
2999 } | 3098 } |
3000 | 3099 |
3001 visitConditional(Conditional node) { | 3100 visitConditional(Conditional node) { |
3002 node.visitChildren(this); | 3101 doInPromotionScope(node.condition, () => visit(node.condition)); |
3102 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression)); | |
3103 visit(node.elseExpression); | |
3003 } | 3104 } |
3004 | 3105 |
3005 visitStringInterpolation(StringInterpolation node) { | 3106 visitStringInterpolation(StringInterpolation node) { |
3006 world.registerInstantiatedClass(compiler.stringClass, mapping); | 3107 world.registerInstantiatedClass(compiler.stringClass, mapping); |
3007 compiler.backend.registerStringInterpolation(mapping); | 3108 compiler.backend.registerStringInterpolation(mapping); |
3008 node.visitChildren(this); | 3109 node.visitChildren(this); |
3009 } | 3110 } |
3010 | 3111 |
3011 visitStringInterpolationPart(StringInterpolationPart node) { | 3112 visitStringInterpolationPart(StringInterpolationPart node) { |
3012 registerImplicitInvocation(const SourceString('toString'), 0); | 3113 registerImplicitInvocation(const SourceString('toString'), 0); |
(...skipping 1507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4520 return finishConstructorReference(visit(expression), | 4621 return finishConstructorReference(visit(expression), |
4521 expression, expression); | 4622 expression, expression); |
4522 } | 4623 } |
4523 } | 4624 } |
4524 | 4625 |
4525 /// Looks up [name] in [scope] and unwraps the result. | 4626 /// Looks up [name] in [scope] and unwraps the result. |
4526 Element lookupInScope(Compiler compiler, Node node, | 4627 Element lookupInScope(Compiler compiler, Node node, |
4527 Scope scope, SourceString name) { | 4628 Scope scope, SourceString name) { |
4528 return Elements.unwrap(scope.lookup(name), compiler, node); | 4629 return Elements.unwrap(scope.lookup(name), compiler, node); |
4529 } | 4630 } |
OLD | NEW |