| 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 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 compiler.withCurrentElement(element, () => measure(() { | 538 compiler.withCurrentElement(element, () => measure(() { |
| 539 assert(element.resolutionState == STATE_NOT_STARTED); | 539 assert(element.resolutionState == STATE_NOT_STARTED); |
| 540 element.resolutionState = STATE_STARTED; | 540 element.resolutionState = STATE_STARTED; |
| 541 Node tree = element.parseNode(compiler); | 541 Node tree = element.parseNode(compiler); |
| 542 loadSupertypes(element, tree); | 542 loadSupertypes(element, tree); |
| 543 | 543 |
| 544 ClassResolverVisitor visitor = | 544 ClassResolverVisitor visitor = |
| 545 new ClassResolverVisitor(compiler, element); | 545 new ClassResolverVisitor(compiler, element); |
| 546 visitor.visit(tree); | 546 visitor.visit(tree); |
| 547 element.resolutionState = STATE_DONE; | 547 element.resolutionState = STATE_DONE; |
| 548 compiler.onClassResolved(element); |
| 548 })); | 549 })); |
| 549 if (element.isPatched) { | 550 if (element.isPatched) { |
| 550 // Ensure handling patch after origin. | 551 // Ensure handling patch after origin. |
| 551 element.patch.ensureResolved(compiler); | 552 element.patch.ensureResolved(compiler); |
| 552 } | 553 } |
| 553 } else { // Handle patch classes: | 554 } else { // Handle patch classes: |
| 554 element.resolutionState = STATE_STARTED; | 555 element.resolutionState = STATE_STARTED; |
| 555 // Ensure handling origin before patch. | 556 // Ensure handling origin before patch. |
| 556 element.origin.ensureResolved(compiler); | 557 element.origin.ensureResolved(compiler); |
| 557 // Ensure that the type is computed. | 558 // Ensure that the type is computed. |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 | 690 |
| 690 // If the name could not be deconstructed, this is is from a | 691 // If the name could not be deconstructed, this is is from a |
| 691 // factory method from a deprecated interface implementation. | 692 // factory method from a deprecated interface implementation. |
| 692 if (name == null) return; | 693 if (name == null) return; |
| 693 | 694 |
| 694 Element otherMember = holder.lookupLocalMember(name); | 695 Element otherMember = holder.lookupLocalMember(name); |
| 695 if (otherMember != null) { | 696 if (otherMember != null) { |
| 696 if (compiler.onDeprecatedFeature(member, 'conflicting constructor')) { | 697 if (compiler.onDeprecatedFeature(member, 'conflicting constructor')) { |
| 697 compiler.reportMessage( | 698 compiler.reportMessage( |
| 698 compiler.spanFromElement(otherMember), | 699 compiler.spanFromElement(otherMember), |
| 700 // Using GENERIC as this message is temporary. |
| 699 MessageKind.GENERIC.error({'text': 'This member conflicts with a' | 701 MessageKind.GENERIC.error({'text': 'This member conflicts with a' |
| 700 ' constructor.'}), | 702 ' constructor.'}), |
| 701 Diagnostic.INFO); | 703 Diagnostic.INFO); |
| 702 } | 704 } |
| 703 } | 705 } |
| 704 } | 706 } |
| 705 | 707 |
| 706 void checkAbstractField(Element member) { | 708 void checkAbstractField(Element member) { |
| 707 // Only check for getters. The test can only fail if there is both a setter | 709 // Only check for getters. The test can only fail if there is both a setter |
| 708 // and a getter with the same name, and we only need to check each abstract | 710 // and a getter with the same name, and we only need to check each abstract |
| (...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1612 bool inCatchBlock; | 1614 bool inCatchBlock; |
| 1613 Scope scope; | 1615 Scope scope; |
| 1614 ClassElement currentClass; | 1616 ClassElement currentClass; |
| 1615 ExpressionStatement currentExpressionStatement; | 1617 ExpressionStatement currentExpressionStatement; |
| 1616 bool typeRequired = false; | 1618 bool typeRequired = false; |
| 1617 bool sendIsMemberAccess = false; | 1619 bool sendIsMemberAccess = false; |
| 1618 StatementScope statementScope; | 1620 StatementScope statementScope; |
| 1619 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION | 1621 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION |
| 1620 | ElementCategory.IMPLIES_TYPE; | 1622 | ElementCategory.IMPLIES_TYPE; |
| 1621 | 1623 |
| 1624 // TODO(ahe): Find a way to share this with runtime implementation. |
| 1625 static final RegExp symbolValidationPattern = |
| 1626 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' |
| 1627 r'-|' |
| 1628 r'unary-|' |
| 1629 r'\[\]=|' |
| 1630 r'~|' |
| 1631 r'==|' |
| 1632 r'\[\]|' |
| 1633 r'\*|' |
| 1634 r'/|' |
| 1635 r'%|' |
| 1636 r'~/|' |
| 1637 r'\+|' |
| 1638 r'<<|' |
| 1639 r'>>|' |
| 1640 r'>=|' |
| 1641 r'>|' |
| 1642 r'<=|' |
| 1643 r'<|' |
| 1644 r'&|' |
| 1645 r'\^|' |
| 1646 r'\|' |
| 1647 r')$'); |
| 1648 |
| 1622 ResolverVisitor(Compiler compiler, Element element, this.mapping) | 1649 ResolverVisitor(Compiler compiler, Element element, this.mapping) |
| 1623 : this.enclosingElement = element, | 1650 : this.enclosingElement = element, |
| 1624 // When the element is a field, we are actually resolving its | 1651 // When the element is a field, we are actually resolving its |
| 1625 // initial value, which should not have access to instance | 1652 // initial value, which should not have access to instance |
| 1626 // fields. | 1653 // fields. |
| 1627 inInstanceContext = (element.isInstanceMember() && !element.isField()) | 1654 inInstanceContext = (element.isInstanceMember() && !element.isField()) |
| 1628 || element.isGenerativeConstructor(), | 1655 || element.isGenerativeConstructor(), |
| 1629 this.currentClass = element.isMember() ? element.getEnclosingClass() | 1656 this.currentClass = element.isMember() ? element.getEnclosingClass() |
| 1630 : null, | 1657 : null, |
| 1631 this.statementScope = new StatementScope(), | 1658 this.statementScope = new StatementScope(), |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1975 } | 2002 } |
| 1976 | 2003 |
| 1977 var oldCategory = allowedCategory; | 2004 var oldCategory = allowedCategory; |
| 1978 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; | 2005 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; |
| 1979 Element resolvedReceiver = visit(node.receiver); | 2006 Element resolvedReceiver = visit(node.receiver); |
| 1980 allowedCategory = oldCategory; | 2007 allowedCategory = oldCategory; |
| 1981 | 2008 |
| 1982 Element target; | 2009 Element target; |
| 1983 SourceString name = node.selector.asIdentifier().source; | 2010 SourceString name = node.selector.asIdentifier().source; |
| 1984 if (identical(name.stringValue, 'this')) { | 2011 if (identical(name.stringValue, 'this')) { |
| 2012 // TODO(ahe): Why is this using GENERIC? |
| 1985 error(node.selector, MessageKind.GENERIC, | 2013 error(node.selector, MessageKind.GENERIC, |
| 1986 {'text': "expected an identifier"}); | 2014 {'text': "expected an identifier"}); |
| 1987 } else if (node.isSuperCall) { | 2015 } else if (node.isSuperCall) { |
| 1988 if (node.isOperator) { | 2016 if (node.isOperator) { |
| 1989 if (isUserDefinableOperator(name.stringValue)) { | 2017 if (isUserDefinableOperator(name.stringValue)) { |
| 1990 name = selector.name; | 2018 name = selector.name; |
| 1991 } else { | 2019 } else { |
| 1992 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); | 2020 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); |
| 1993 } | 2021 } |
| 1994 } | 2022 } |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2155 } | 2183 } |
| 2156 } | 2184 } |
| 2157 } | 2185 } |
| 2158 | 2186 |
| 2159 visitSend(Send node) { | 2187 visitSend(Send node) { |
| 2160 bool oldSendIsMemberAccess = sendIsMemberAccess; | 2188 bool oldSendIsMemberAccess = sendIsMemberAccess; |
| 2161 sendIsMemberAccess = node.isPropertyAccess || node.isCall; | 2189 sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| 2162 Element target = resolveSend(node); | 2190 Element target = resolveSend(node); |
| 2163 sendIsMemberAccess = oldSendIsMemberAccess; | 2191 sendIsMemberAccess = oldSendIsMemberAccess; |
| 2164 | 2192 |
| 2193 if (target != null && target == compiler.mirrorSystemGetNameFunction) { |
| 2194 compiler.reportWarningCode( |
| 2195 node.selector, MessageKind.STATIC_FUNCTION_BLOAT, |
| 2196 {'class': compiler.mirrorSystemClass.name, |
| 2197 'name': compiler.mirrorSystemGetNameFunction.name}); |
| 2198 } |
| 2199 |
| 2165 if (!Elements.isUnresolved(target)) { | 2200 if (!Elements.isUnresolved(target)) { |
| 2166 if (target.isAbstractField()) { | 2201 if (target.isAbstractField()) { |
| 2167 AbstractFieldElement field = target; | 2202 AbstractFieldElement field = target; |
| 2168 target = field.getter; | 2203 target = field.getter; |
| 2169 if (target == null && !inInstanceContext) { | 2204 if (target == null && !inInstanceContext) { |
| 2170 compiler.backend.registerThrowNoSuchMethod(mapping); | 2205 compiler.backend.registerThrowNoSuchMethod(mapping); |
| 2171 target = | 2206 target = |
| 2172 warnAndCreateErroneousElement(node.selector, field.name, | 2207 warnAndCreateErroneousElement(node.selector, field.name, |
| 2173 MessageKind.CANNOT_RESOLVE_GETTER); | 2208 MessageKind.CANNOT_RESOLVE_GETTER); |
| 2174 } | 2209 } |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2404 | 2439 |
| 2405 visitReturn(Return node) { | 2440 visitReturn(Return node) { |
| 2406 if (node.isRedirectingFactoryBody) { | 2441 if (node.isRedirectingFactoryBody) { |
| 2407 handleRedirectingFactoryBody(node); | 2442 handleRedirectingFactoryBody(node); |
| 2408 } else { | 2443 } else { |
| 2409 visit(node.expression); | 2444 visit(node.expression); |
| 2410 } | 2445 } |
| 2411 } | 2446 } |
| 2412 | 2447 |
| 2413 void handleRedirectingFactoryBody(Return node) { | 2448 void handleRedirectingFactoryBody(Return node) { |
| 2449 final isSymbolConstructor = enclosingElement == compiler.symbolConstructor; |
| 2414 if (!enclosingElement.isFactoryConstructor()) { | 2450 if (!enclosingElement.isFactoryConstructor()) { |
| 2415 compiler.reportErrorCode( | 2451 compiler.reportErrorCode( |
| 2416 node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY); | 2452 node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY); |
| 2417 compiler.reportErrorCode( | 2453 compiler.reportErrorCode( |
| 2418 enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD); | 2454 enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD); |
| 2419 } | 2455 } |
| 2420 Element redirectionTarget = resolveRedirectingFactory(node); | 2456 Element redirectionTarget = resolveRedirectingFactory(node); |
| 2421 var type = mapping.getType(node.expression); | 2457 var type = mapping.getType(node.expression); |
| 2422 if (type is InterfaceType && !type.isRaw) { | 2458 if (type is InterfaceType && !type.isRaw) { |
| 2423 unimplemented(node.expression, 'type arguments on redirecting factory'); | 2459 unimplemented(node.expression, 'type arguments on redirecting factory'); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2438 FunctionElement targetImplementation = redirectionTarget.implementation; | 2474 FunctionElement targetImplementation = redirectionTarget.implementation; |
| 2439 FunctionExpression function = targetImplementation.parseNode(compiler); | 2475 FunctionExpression function = targetImplementation.parseNode(compiler); |
| 2440 if (function.body != null && function.body.asReturn() != null | 2476 if (function.body != null && function.body.asReturn() != null |
| 2441 && function.body.asReturn().isRedirectingFactoryBody) { | 2477 && function.body.asReturn().isRedirectingFactoryBody) { |
| 2442 unimplemented(node.expression, 'redirecing to redirecting factory'); | 2478 unimplemented(node.expression, 'redirecing to redirecting factory'); |
| 2443 } | 2479 } |
| 2444 } | 2480 } |
| 2445 world.registerStaticUse(redirectionTarget); | 2481 world.registerStaticUse(redirectionTarget); |
| 2446 world.registerInstantiatedClass( | 2482 world.registerInstantiatedClass( |
| 2447 redirectionTarget.enclosingElement.declaration, mapping); | 2483 redirectionTarget.enclosingElement.declaration, mapping); |
| 2484 if (isSymbolConstructor) { |
| 2485 // Make sure that collection_dev.Symbol.validated is registered. |
| 2486 assert(invariant(node, compiler.symbolValidatedConstructor != null)); |
| 2487 world.registerStaticUse(compiler.symbolValidatedConstructor); |
| 2488 } |
| 2448 } | 2489 } |
| 2449 | 2490 |
| 2450 visitThrow(Throw node) { | 2491 visitThrow(Throw node) { |
| 2451 if (!inCatchBlock && node.expression == null) { | 2492 if (!inCatchBlock && node.expression == null) { |
| 2452 error(node, MessageKind.THROW_WITHOUT_EXPRESSION); | 2493 error(node, MessageKind.THROW_WITHOUT_EXPRESSION); |
| 2453 } | 2494 } |
| 2454 // We don't know ahead of time whether we will need the throw in a statement | 2495 // We don't know ahead of time whether we will need the throw in a statement |
| 2455 // context or an expression context, so we register both here, even though | 2496 // context or an expression context, so we register both here, even though |
| 2456 // we may not need ThrowExpression. | 2497 // we may not need ThrowExpression. |
| 2457 compiler.backend.registerWrapException(mapping); | 2498 compiler.backend.registerWrapException(mapping); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2483 visitParenthesizedExpression(ParenthesizedExpression node) { | 2524 visitParenthesizedExpression(ParenthesizedExpression node) { |
| 2484 bool oldSendIsMemberAccess = sendIsMemberAccess; | 2525 bool oldSendIsMemberAccess = sendIsMemberAccess; |
| 2485 sendIsMemberAccess = false; | 2526 sendIsMemberAccess = false; |
| 2486 visit(node.expression); | 2527 visit(node.expression); |
| 2487 sendIsMemberAccess = oldSendIsMemberAccess; | 2528 sendIsMemberAccess = oldSendIsMemberAccess; |
| 2488 } | 2529 } |
| 2489 | 2530 |
| 2490 visitNewExpression(NewExpression node) { | 2531 visitNewExpression(NewExpression node) { |
| 2491 Node selector = node.send.selector; | 2532 Node selector = node.send.selector; |
| 2492 FunctionElement constructor = resolveConstructor(node); | 2533 FunctionElement constructor = resolveConstructor(node); |
| 2534 final bool isSymbolConstructor = constructor == compiler.symbolConstructor; |
| 2535 if (!node.isConst() && isSymbolConstructor) { |
| 2536 compiler.reportWarningCode( |
| 2537 node.newToken, MessageKind.NON_CONST_BLOAT, |
| 2538 {'name': compiler.symbolClass.name}); |
| 2539 } |
| 2493 resolveSelector(node.send); | 2540 resolveSelector(node.send); |
| 2494 resolveArguments(node.send.argumentsNode); | 2541 resolveArguments(node.send.argumentsNode); |
| 2495 useElement(node.send, constructor); | 2542 useElement(node.send, constructor); |
| 2496 if (Elements.isUnresolved(constructor)) return constructor; | 2543 if (Elements.isUnresolved(constructor)) return constructor; |
| 2497 Selector callSelector = mapping.getSelector(node.send); | 2544 Selector callSelector = mapping.getSelector(node.send); |
| 2498 if (!callSelector.applies(constructor, compiler)) { | 2545 if (!callSelector.applies(constructor, compiler)) { |
| 2499 warnArgumentMismatch(node.send, constructor); | 2546 warnArgumentMismatch(node.send, constructor); |
| 2500 compiler.backend.registerThrowNoSuchMethod(mapping); | 2547 compiler.backend.registerThrowNoSuchMethod(mapping); |
| 2501 } | 2548 } |
| 2502 compiler.withCurrentElement(constructor, () { | 2549 compiler.withCurrentElement(constructor, () { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2525 compiler.backend.registerAbstractClassInstantiation(mapping); | 2572 compiler.backend.registerAbstractClassInstantiation(mapping); |
| 2526 } | 2573 } |
| 2527 // [cls] might be the declaration element and we want to include injected | 2574 // [cls] might be the declaration element and we want to include injected |
| 2528 // members. | 2575 // members. |
| 2529 cls.implementation.forEachInstanceField( | 2576 cls.implementation.forEachInstanceField( |
| 2530 (ClassElement enclosingClass, Element member) { | 2577 (ClassElement enclosingClass, Element member) { |
| 2531 world.addToWorkList(member); | 2578 world.addToWorkList(member); |
| 2532 }, | 2579 }, |
| 2533 includeBackendMembers: false, | 2580 includeBackendMembers: false, |
| 2534 includeSuperMembers: true); | 2581 includeSuperMembers: true); |
| 2582 |
| 2583 if (node.isConst() && isSymbolConstructor) { |
| 2584 Node argumentNode = node.send.arguments.head; |
| 2585 Constant name = compiler.metadataHandler.compileNodeWithDefinitions( |
| 2586 argumentNode, mapping, isConst: true); |
| 2587 if (!name.isString()) { |
| 2588 DartType type = name.computeType(compiler); |
| 2589 compiler.reportErrorCode(argumentNode, MessageKind.STRING_EXPECTED, |
| 2590 {'type': type}); |
| 2591 } else { |
| 2592 validateSymbol(argumentNode, name.toDartString().slowToString()); |
| 2593 } |
| 2594 } |
| 2595 |
| 2535 return null; | 2596 return null; |
| 2536 } | 2597 } |
| 2537 | 2598 |
| 2599 void validateSymbol(Node node, String name) { |
| 2600 if (name.isEmpty) return; |
| 2601 if (name.startsWith('_')) { |
| 2602 compiler.reportErrorCode(node, MessageKind.PRIVATE_IDENTIFIER, |
| 2603 {'value': name}); |
| 2604 return; |
| 2605 } |
| 2606 if (!symbolValidationPattern.hasMatch(name)) { |
| 2607 compiler.reportErrorCode(node, MessageKind.INVALID_SYMBOL, |
| 2608 {'value': name}); |
| 2609 } |
| 2610 } |
| 2611 |
| 2612 |
| 2538 /** | 2613 /** |
| 2539 * Try to resolve the constructor that is referred to by [node]. | 2614 * Try to resolve the constructor that is referred to by [node]. |
| 2540 * Note: this function may return an ErroneousFunctionElement instead of | 2615 * Note: this function may return an ErroneousFunctionElement instead of |
| 2541 * [null], if there is no corresponding constructor, class or library. | 2616 * [null], if there is no corresponding constructor, class or library. |
| 2542 */ | 2617 */ |
| 2543 FunctionElement resolveConstructor(NewExpression node) { | 2618 FunctionElement resolveConstructor(NewExpression node) { |
| 2544 return node.accept(new ConstructorResolver(compiler, this)); | 2619 return node.accept(new ConstructorResolver(compiler, this)); |
| 2545 } | 2620 } |
| 2546 | 2621 |
| 2547 FunctionElement resolveRedirectingFactory(Return node) { | 2622 FunctionElement resolveRedirectingFactory(Return node) { |
| (...skipping 1329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3877 return e; | 3952 return e; |
| 3878 } | 3953 } |
| 3879 | 3954 |
| 3880 /// Assumed to be called by [resolveRedirectingFactory]. | 3955 /// Assumed to be called by [resolveRedirectingFactory]. |
| 3881 Element visitReturn(Return node) { | 3956 Element visitReturn(Return node) { |
| 3882 Node expression = node.expression; | 3957 Node expression = node.expression; |
| 3883 return finishConstructorReference(visit(expression), | 3958 return finishConstructorReference(visit(expression), |
| 3884 expression, expression); | 3959 expression, expression); |
| 3885 } | 3960 } |
| 3886 } | 3961 } |
| OLD | NEW |