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

Side by Side Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 2986063002: Avoid issuing incorrect errors when super mixins are enabled (Closed)
Patch Set: Coment Created 3 years, 4 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
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
6 // refactored to fit into analyzer. 6 // refactored to fit into analyzer.
7 library analyzer.src.task.strong.checker; 7 library analyzer.src.task.strong.checker;
8 8
9 import 'dart:collection'; 9 import 'dart:collection';
10 import 'package:analyzer/analyzer.dart'; 10 import 'package:analyzer/analyzer.dart';
(...skipping 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1399 1399
1400 // For members of the superclass, we may need to add checks because this 1400 // For members of the superclass, we may need to add checks because this
1401 // class adds a new unsafe interface. Collect those checks. 1401 // class adds a new unsafe interface. Collect those checks.
1402 checks = _findSuperclassCovariantChecks( 1402 checks = _findSuperclassCovariantChecks(
1403 element, allCovariant, seenConcreteMembers); 1403 element, allCovariant, seenConcreteMembers);
1404 // Store the checks on the class declaration, it will need to ensure the 1404 // Store the checks on the class declaration, it will need to ensure the
1405 // inherited members are appropriately guarded to ensure soundness. 1405 // inherited members are appropriately guarded to ensure soundness.
1406 setSuperclassCovariantParameters(node, checks); 1406 setSuperclassCovariantParameters(node, checks);
1407 } 1407 }
1408 1408
1409 /// For each member of this class and non-overridden inherited member, we 1409 /// For each member of this class and non-overridden inherited member, we
Jennifer Messerly 2017/07/27 21:07:58 fyi: this function is also doing a "concrete membe
1410 /// check to see if any generic super interface permits an unsound call to the 1410 /// check to see if any generic super interface permits an unsound call to the
1411 /// concrete member. For example: 1411 /// concrete member. For example:
1412 /// 1412 ///
1413 /// We must check non-overridden inherited members because this class could 1413 /// We must check non-overridden inherited members because this class could
1414 /// contain a new interface that permits unsound access to that member. In 1414 /// contain a new interface that permits unsound access to that member. In
1415 /// those cases, the class is expected to insert stub that checks the type 1415 /// those cases, the class is expected to insert stub that checks the type
1416 /// before calling `super`. For example: 1416 /// before calling `super`. For example:
1417 /// 1417 ///
1418 /// class C<T> { 1418 /// class C<T> {
1419 /// add(T t) {} 1419 /// add(T t) {}
(...skipping 20 matching lines...) Expand all
1440 var oldCovariant = _findAllGenericInterfaces(type); 1440 var oldCovariant = _findAllGenericInterfaces(type);
1441 var newCovariant = allCovariant.difference(oldCovariant); 1441 var newCovariant = allCovariant.difference(oldCovariant);
1442 if (newCovariant.isEmpty) return; 1442 if (newCovariant.isEmpty) return;
1443 1443
1444 void visitSuper(InterfaceType type) { 1444 void visitSuper(InterfaceType type) {
1445 var element = type.element; 1445 var element = type.element;
1446 if (visited.add(element)) { 1446 if (visited.add(element)) {
1447 var members = _getConcreteMembers(type, seenConcreteMembers); 1447 var members = _getConcreteMembers(type, seenConcreteMembers);
1448 _findCovariantChecks(members, newCovariant, superChecks); 1448 _findCovariantChecks(members, newCovariant, superChecks);
1449 _findCovariantChecks(members, oldCovariant, existingChecks); 1449 _findCovariantChecks(members, oldCovariant, existingChecks);
1450 element.mixins.reversed.forEach(visitSuper); 1450 element.mixins.reversed.forEach(visitSuper);
Jennifer Messerly 2017/07/27 21:07:58 this could be problematic
1451 var s = element.supertype; 1451 var s = element.supertype;
1452 if (s != null) visitSuper(s); 1452 if (s != null) visitSuper(s);
1453 } 1453 }
1454 } 1454 }
1455 1455
1456 visitSuper(type); 1456 visitSuper(type);
1457 } 1457 }
1458 1458
1459 element.mixins.reversed.forEach(visitImmediateSuper); 1459 element.mixins.reversed.forEach(visitImmediateSuper);
1460 var s = element.supertype; 1460 var s = element.supertype;
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
1630 var interfaces = _collectInterfacesToCheck(element.type); 1630 var interfaces = _collectInterfacesToCheck(element.type);
1631 var visitedClasses = new Set<InterfaceType>(); 1631 var visitedClasses = new Set<InterfaceType>();
1632 var visitedMembers = new HashSet<String>(); 1632 var visitedMembers = new HashSet<String>();
1633 1633
1634 // Checks all most-derived concrete members on this `type`. We skip over 1634 // Checks all most-derived concrete members on this `type`. We skip over
1635 // members that are already `visitedMembers`, because they were overridden 1635 // members that are already `visitedMembers`, because they were overridden
1636 // and we've already checked that member. 1636 // and we've already checked that member.
1637 // 1637 //
1638 // Because of that, it is important we visit types in the order that they 1638 // Because of that, it is important we visit types in the order that they
1639 // will override members. 1639 // will override members.
1640 void checkType(InterfaceType type, AstNode location) { 1640 // If checkingMixin is true, then we are checking [type] in a mixin position
1641 // and hence should consider its own mixins and superclass as abstract.
1642 void checkType(InterfaceType type, AstNode location,
1643 {bool checkingMixin: false}) {
1641 // Skip `Object` because we don't need to check those members here. 1644 // Skip `Object` because we don't need to check those members here.
1642 // (because `Object` is the root of everything, it will be checked in 1645 // (because `Object` is the root of everything, it will be checked in
1643 // _checkSuperOverrides for all classes). 1646 // _checkSuperOverrides for all classes).
1644 if (type == null || type.isObject || !visitedClasses.add(type)) return; 1647 if (type == null || type.isObject || !visitedClasses.add(type)) return;
1645 1648
1646 // Check `member` against all `interfaces`. 1649 // Check `member` against all `interfaces`.
1647 void checkOverride(ExecutableElement member, [AstNode loc]) { 1650 void checkOverride(ExecutableElement member, [AstNode loc]) {
1648 if (!visitedMembers.add(member.name)) return; 1651 if (!visitedMembers.add(member.name)) return;
1649 for (var interface in interfaces) { 1652 for (var interface in interfaces) {
1650 if (_checkMemberOverride(member, interface, loc ?? location) == 1653 if (_checkMemberOverride(member, interface, loc ?? location) ==
(...skipping 11 matching lines...) Expand all
1662 // Otherwise, we'll use the `extends` or `with` clause. 1665 // Otherwise, we'll use the `extends` or `with` clause.
1663 var isRootClass = identical(location, node); 1666 var isRootClass = identical(location, node);
1664 1667
1665 // Check direct overrides on the class. 1668 // Check direct overrides on the class.
1666 if (isRootClass) { 1669 if (isRootClass) {
1667 _checkClassMembers(node, checkOverride); 1670 _checkClassMembers(node, checkOverride);
1668 } else { 1671 } else {
1669 _checkTypeMembers(type, checkOverride); 1672 _checkTypeMembers(type, checkOverride);
1670 } 1673 }
1671 1674
1672 // Check mixin members against interfaces. 1675 // If we are currently checking a mixin, then its own mixins and
1673 // 1676 // superclass are abstract, and we should not check their members.
1674 // We visit mixins in reverse order to reflect how they override 1677 // This should only happen when super mixins is enabled, and we
1675 // eachother. 1678 // don't do proper checking for super mixins (we don't check that
1676 for (int i = type.mixins.length - 1; i >= 0; i--) { 1679 // the contract implied by the mixin declaration is satisfied by
1677 checkType(type.mixins[i], 1680 // the mixin use), but this prevents us from erroneously
1678 isRootClass ? _withClause(node).mixinTypes[i] : location); 1681 // rejecting some super mixin patterns.
1682 // If this is a mixin application (class A = Object with B)
1683 // however, then we do still need to treat the mixin as concrete.
1684 if (!checkingMixin || type.element.isMixinApplication) {
1685 // Check mixin members against interfaces.
1686 //
1687 // We visit mixins in reverse order to reflect how they override
1688 // eachother.
1689 for (int i = type.mixins.length - 1; i >= 0; i--) {
1690 checkType(type.mixins[i],
1691 isRootClass ? _withClause(node).mixinTypes[i] : location,
1692 checkingMixin: true);
1693 }
1694
1695 // Check members on the superclass.
1696 checkType(type.superclass,
1697 isRootClass ? _extendsErrorLocation(node) : location,
1698 checkingMixin: checkingMixin);
1679 } 1699 }
1680
1681 // Check members on the superclass.
1682 checkType(type.superclass,
1683 isRootClass ? _extendsErrorLocation(node) : location);
1684 } 1700 }
1685 1701
1686 checkType(element.type, node); 1702 checkType(element.type, node);
1687 } 1703 }
1688 1704
1689 /// Gets the set of all interfaces on [type] that should be checked to see 1705 /// Gets the set of all interfaces on [type] that should be checked to see
1690 /// if type's members are overriding them correctly. 1706 /// if type's members are overriding them correctly.
1691 /// 1707 ///
1692 /// In particular, we need to check these overrides for the definitions in 1708 /// In particular, we need to check these overrides for the definitions in
1693 /// the class itself and each its superclasses (and mixins). 1709 /// the class itself and each its superclasses (and mixins).
(...skipping 23 matching lines...) Expand all
1717 // Check all interfaces reachable from the `implements` clause in the 1733 // Check all interfaces reachable from the `implements` clause in the
1718 // current class against definitions here and in superclasses. 1734 // current class against definitions here and in superclasses.
1719 type.interfaces.forEach(collectInterfaces); 1735 type.interfaces.forEach(collectInterfaces);
1720 1736
1721 // Also collect interfaces from any abstract mixins or superclasses. 1737 // Also collect interfaces from any abstract mixins or superclasses.
1722 // 1738 //
1723 // For a concrete mixin/superclass, we'll check that we override the 1739 // For a concrete mixin/superclass, we'll check that we override the
1724 // concrete members in _checkSuperOverrides and 1740 // concrete members in _checkSuperOverrides and
1725 // _checkMixinApplicationOverrides. But for abstract classes, we need to 1741 // _checkMixinApplicationOverrides. But for abstract classes, we need to
1726 // consider any abstract members it got from its interfaces. 1742 // consider any abstract members it got from its interfaces.
1727 for (var s in _getSuperclasses(type, (t) => t.element.isAbstract)) { 1743 for (var s in _getSuperclasses(type, (t) => t.element.isAbstract)) {
Jennifer Messerly 2017/07/27 21:07:58 based on comments below, this call site may need t
1728 s.interfaces.forEach(collectInterfaces); 1744 s.interfaces.forEach(collectInterfaces);
1729 } 1745 }
1730 return interfaces; 1746 return interfaces;
1731 } 1747 }
1732 1748
1733 /// Visits each member on the class [node] and calls [checkMember] with the 1749 /// Visits each member on the class [node] and calls [checkMember] with the
1734 /// corresponding instance element and AST node (for error reporting). 1750 /// corresponding instance element and AST node (for error reporting).
1735 /// 1751 ///
1736 /// See also [_checkTypeMembers], which is used when the class AST node is not 1752 /// See also [_checkTypeMembers], which is used when the class AST node is not
1737 /// available. 1753 /// available.
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1902 /// class Grandparent { 1918 /// class Grandparent {
1903 /// m(A a) {} 1919 /// m(A a) {}
1904 /// } 1920 /// }
1905 /// class Parent extends Grandparent { 1921 /// class Parent extends Grandparent {
1906 /// m(A a) {} 1922 /// m(A a) {}
1907 /// } 1923 /// }
1908 /// class Test extends Parent { 1924 /// class Test extends Parent {
1909 /// m(B a) {} // invalid override 1925 /// m(B a) {} // invalid override
1910 /// } 1926 /// }
1911 void _checkSuperOverrides(Declaration node, ClassElement element) { 1927 void _checkSuperOverrides(Declaration node, ClassElement element) {
1912 var superclasses = _getSuperclasses(element.type); 1928 var superclasses = _getSuperclasses(element.type);
Jennifer Messerly 2017/07/27 21:07:58 this set of concrete superclasses also contains mi
1913 _checkClassMembers(node, (member, loc) { 1929 _checkClassMembers(node, (member, loc) {
1914 for (var s in superclasses) { 1930 for (var s in superclasses) {
1915 if (_checkConcreteMemberOverride(member, s, loc)) break; 1931 if (_checkConcreteMemberOverride(member, s, loc)) break;
Jennifer Messerly 2017/07/27 21:07:58 in particular, we'll break out of the loop once we
1916 } 1932 }
1917 }); 1933 });
1918 } 1934 }
1919 1935
1920 /// Collects all superclasses of [type], including any mixin application 1936 /// Collects all superclasses of [type], including any mixin application
1921 /// classes. 1937 /// classes.
1922 /// 1938 ///
1923 /// The search can be pruned by passing a [visitSuperclasses] function and 1939 /// The search can be pruned by passing a [visitSuperclasses] function and
1924 /// having it return `false` for types that should not be further explored. 1940 /// having it return `false` for types that should not be further explored.
1925 Iterable<InterfaceType> _getSuperclasses(InterfaceType type, 1941 Iterable<InterfaceType> _getSuperclasses(InterfaceType type,
1926 [bool visitSuperclasses(InterfaceType t)]) { 1942 [bool visitSuperclasses(InterfaceType t)]) {
1927 var superclasses = new Set<InterfaceType>(); 1943 var superclasses = new Set<InterfaceType>();
1928 visit(InterfaceType t) { 1944 visit(InterfaceType t) {
1929 if ((visitSuperclasses == null || visitSuperclasses(t)) && 1945 if ((visitSuperclasses == null || visitSuperclasses(t)) &&
1930 superclasses.add(t)) { 1946 superclasses.add(t)) {
1931 t.mixins.reversed.forEach(visit); 1947 t.mixins.reversed.forEach(visit);
Jennifer Messerly 2017/07/27 21:07:58 this may be the problematic location
1932 var s = t.superclass; 1948 var s = t.superclass;
1933 if (s != null && !s.isObject) visit(s); 1949 if (s != null && !s.isObject) visit(s);
1934 } 1950 }
1935 } 1951 }
1936 1952
1937 type.mixins.reversed.forEach(visit); 1953 type.mixins.reversed.forEach(visit);
1938 var s = type.superclass; 1954 var s = type.superclass;
1939 if (s != null && !s.isObject) visit(s); 1955 if (s != null && !s.isObject) visit(s);
1940 1956
1941 // Make sure we record Object last, and not when we visit our mixins. 1957 // Make sure we record Object last, and not when we visit our mixins.
(...skipping 16 matching lines...) Expand all
1958 } 1974 }
1959 1975
1960 /// If node is a [ClassDeclaration] returns its members, otherwise if node is 1976 /// If node is a [ClassDeclaration] returns its members, otherwise if node is
1961 /// a [ClassTypeAlias] this returns an empty list. 1977 /// a [ClassTypeAlias] this returns an empty list.
1962 WithClause _withClause(Declaration node) { 1978 WithClause _withClause(Declaration node) {
1963 return node is ClassDeclaration 1979 return node is ClassDeclaration
1964 ? node.withClause 1980 ? node.withClause
1965 : (node as ClassTypeAlias).withClause; 1981 : (node as ClassTypeAlias).withClause;
1966 } 1982 }
1967 } 1983 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698