Start reporting errors for mixin super-class constraints and implements clauses.
R=brianwilkerson@google.com, paulberry@google.com
Change-Id: I6e6e3edc16737b1d3f665982f7560b46d8b71f01
Reviewed-on: https://dart-review.googlesource.com/72522
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 4422437..17387f6 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -130,7 +130,6 @@
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
- CompileTimeErrorCode.EXTENDS_ENUM,
CompileTimeErrorCode.EXTENDS_NON_CLASS,
CompileTimeErrorCode.EXTERNAL_CONSTRUCTOR_WITH_FIELD_INITIALIZERS,
CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS,
@@ -150,8 +149,6 @@
CompileTimeErrorCode.ILLEGAL_MIXIN,
CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
- CompileTimeErrorCode.IMPLEMENTS_DYNAMIC,
- CompileTimeErrorCode.IMPLEMENTS_ENUM,
CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
CompileTimeErrorCode.IMPLEMENTS_REPEATED,
CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS,
@@ -203,9 +200,11 @@
CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS,
- CompileTimeErrorCode.MIXIN_OF_ENUM,
CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
CompileTimeErrorCode.MIXIN_REFERENCES_SUPER,
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS,
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS,
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS,
CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS,
CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS,
CompileTimeErrorCode.MULTIPLE_SUPER_INITIALIZERS,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 9fc3e5f..15245a4 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6613,16 +6613,19 @@
List<InterfaceType> get superclassConstraints {
if (_superclassConstraints == null) {
if (_unlinkedClass != null) {
+ List<InterfaceType> constraints;
if (_unlinkedClass.superclassConstraints.isNotEmpty) {
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
- _superclassConstraints = _unlinkedClass.superclassConstraints
+ constraints = _unlinkedClass.superclassConstraints
.map((EntityRef t) => context.resolveTypeRef(this, t))
.where(_isClassInterfaceType)
.cast<InterfaceType>()
.toList(growable: false);
- } else {
- _superclassConstraints = [context.typeProvider.objectType];
}
+ if (constraints == null || constraints.isEmpty) {
+ constraints = [context.typeProvider.objectType];
+ }
+ _superclassConstraints = constraints;
}
}
return _superclassConstraints ?? const <InterfaceType>[];
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index eea7df0..7663cc3 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -944,15 +944,6 @@
correction: "Try exporting the library that the part is a part of.");
/**
- * Enum proposal: It is a compile-time error to subclass, mix-in or implement
- * an enum.
- */
- static const CompileTimeErrorCode EXTENDS_ENUM = const CompileTimeErrorCode(
- 'EXTENDS_ENUM', "Classes can't extend an enum.",
- correction:
- "Try specifying a different superclass, or removing the extends clause.");
-
- /**
* 7.9 Superclasses: It is a compile-time error if the extends clause of a
* class <i>C</i> includes a type expression that does not denote a class
* available in the lexical scope of <i>C</i>.
@@ -1009,8 +1000,8 @@
* See [IMPLEMENTS_DEFERRED_CLASS], and [MIXIN_DEFERRED_CLASS].
*/
static const CompileTimeErrorCode EXTENDS_DEFERRED_CLASS =
- const CompileTimeErrorCode('EXTENDS_DEFERRED_CLASS',
- "This class can't extend the deferred class '{0}'.",
+ const CompileTimeErrorCode(
+ 'EXTENDS_DEFERRED_CLASS', "Classes can't extend deferred classes.",
correction: "Try specifying a different superclass, or "
"removing the extends clause.");
@@ -1169,14 +1160,11 @@
* of a class <i>C</i> specifies a malformed type or deferred type as a
* superinterface.
*
- * Parameters:
- * 0: the name of the type that is deferred
- *
* See [EXTENDS_DEFERRED_CLASS], and [MIXIN_DEFERRED_CLASS].
*/
static const CompileTimeErrorCode IMPLEMENTS_DEFERRED_CLASS =
const CompileTimeErrorCode('IMPLEMENTS_DEFERRED_CLASS',
- "This class can't implement the deferred class '{0}'.",
+ "Classes and mixins can't implement deferred classes.",
correction: "Try specifying a different interface, "
"removing the class from the list, or "
"changing the import to not be deferred.");
@@ -1207,33 +1195,13 @@
* See [EXTENDS_DISALLOWED_CLASS].
*/
static const CompileTimeErrorCode IMPLEMENTS_DISALLOWED_CLASS =
- const CompileTimeErrorCode(
- 'IMPLEMENTS_DISALLOWED_CLASS', "Classes can't implement '{0}'.",
+ const CompileTimeErrorCode('IMPLEMENTS_DISALLOWED_CLASS',
+ "Classes and mixins can't implement '{0}'.",
correction: "Try specifying a different interface, or "
"remove the class from the list.");
/**
* 7.10 Superinterfaces: It is a compile-time error if the implements clause
- * of a class includes type dynamic.
- */
- static const CompileTimeErrorCode IMPLEMENTS_DYNAMIC =
- const CompileTimeErrorCode(
- 'IMPLEMENTS_DYNAMIC', "Classes can't implement 'dynamic'.",
- correction:
- "Try specifying an interface, or remove 'dynamic' from the list.");
-
- /**
- * Enum proposal: It is a compile-time error to subclass, mix-in or implement
- * an enum.
- */
- static const CompileTimeErrorCode IMPLEMENTS_ENUM =
- const CompileTimeErrorCode(
- 'IMPLEMENTS_ENUM', "Classes can't implement an enum.",
- correction:
- "Try specifying an interface, or remove the enum from the list.");
-
- /**
- * 7.10 Superinterfaces: It is a compile-time error if the implements clause
* of a class <i>C</i> includes a type expression that does not denote a class
* available in the lexical scope of <i>C</i>.
*
@@ -1241,8 +1209,8 @@
* 0: the name of the interface that was not found
*/
static const CompileTimeErrorCode IMPLEMENTS_NON_CLASS =
- const CompileTimeErrorCode(
- 'IMPLEMENTS_NON_CLASS', "Classes can only implement other classes.",
+ const CompileTimeErrorCode('IMPLEMENTS_NON_CLASS',
+ "Classes and mixins can only implement classes.",
correction:
"Try specifying a class, or remove the name from the list.");
@@ -1718,8 +1686,8 @@
* See [EXTENDS_DEFERRED_CLASS], and [IMPLEMENTS_DEFERRED_CLASS].
*/
static const CompileTimeErrorCode MIXIN_DEFERRED_CLASS =
- const CompileTimeErrorCode('MIXIN_DEFERRED_CLASS',
- "This class can't mixin the deferred class '{0}'.",
+ const CompileTimeErrorCode(
+ 'MIXIN_DEFERRED_CLASS', "Classes can't mixin deferred classes.",
correction: "Try changing the import to not be deferred.");
/**
@@ -1799,13 +1767,6 @@
'MIXIN_OF_DISALLOWED_CLASS', "Classes can't mixin '{0}'.");
/**
- * Enum proposal: It is a compile-time error to subclass, mix-in or implement
- * an enum.
- */
- static const CompileTimeErrorCode MIXIN_OF_ENUM = const CompileTimeErrorCode(
- 'MIXIN_OF_ENUM', "Classes can't mixin an enum.");
-
- /**
* 9.1 Mixin Application: It is a compile-time error if <i>M</i> does not
* denote a class or mixin available in the immediately enclosing scope.
*/
@@ -1823,6 +1784,22 @@
"The class '{0}' can't be used as a mixin because it references "
"'super'.");
+ static const CompileTimeErrorCode
+ MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS = const CompileTimeErrorCode(
+ 'MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS',
+ "Deferred classes can't be used as super-class constraints.",
+ correction: "Try changing the import to not be deferred.");
+
+ static const CompileTimeErrorCode
+ MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS =
+ const CompileTimeErrorCode(
+ 'MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS',
+ "'{0}' can't be used as a super-class constraint.");
+
+ static const CompileTimeErrorCode MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS =
+ const CompileTimeErrorCode('MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS',
+ "Only classes can be used as super-class constraints.");
+
/**
* 9.1 Mixin Application: It is a compile-time error if <i>S</i> does not
* denote a class available in the immediately enclosing scope.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index aae070c..f18c8d2 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1048,6 +1048,40 @@
}
@override
+ Object visitMixinDeclaration(MixinDeclaration node) {
+ // TODO(scheglov) Verify for all mixin errors.
+// ClassElementImpl outerClass = _enclosingClass;
+ try {
+// _isInNativeClass = node.nativeClause != null;
+// _enclosingClass = AbstractClassElementImpl.getImpl(node.declaredElement);
+// _checkDuplicateClassMembers(node);
+// _checkForBuiltInIdentifierAsName(
+// node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME);
+// _checkForMemberWithClassName();
+// _checkForNoDefaultSuperConstructorImplicit(node);
+// _checkForConflictingTypeVariableErrorCodes(node);
+
+ OnClause onClause = node.onClause;
+ ImplementsClause implementsClause = node.implementsClause;
+
+ // Only do error checks only if there is a non-null clause.
+ if (onClause != null || implementsClause != null) {
+ _checkMixinInheritance(node, onClause, implementsClause);
+ }
+// visitClassDeclarationIncrementally(node);
+// _checkForFinalNotInitializedInClass(node);
+// _checkForDuplicateDefinitionInheritance();
+// _checkForConflictingInstanceMethodSetter(node);
+// _checkForBadFunctionUse(node);
+ return super.visitMixinDeclaration(node);
+ } finally {
+// _isInNativeClass = false;
+// _initialFieldElementsMap = null;
+// _enclosingClass = outerClass;
+ }
+ }
+
+ @override
Object visitNativeClause(NativeClause node) {
// TODO(brianwilkerson) Figure out the right rule for when 'native' is
// allowed.
@@ -3280,8 +3314,7 @@
return false;
}
if (typeName.isDeferred) {
- _errorReporter
- .reportErrorForNode(errorCode, typeName, [typeName.name.name]);
+ _errorReporter.reportErrorForNode(errorCode, typeName);
return true;
}
return false;
@@ -4919,6 +4952,39 @@
}
/**
+ * Verify that all classes of the given [onClause] are valid.
+ *
+ * See [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR],
+ * [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT], and
+ * [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER].
+ */
+ bool _checkForOnClauseErrorCodes(OnClause onClause) {
+ if (onClause == null) {
+ return false;
+ }
+ bool problemReported = false;
+ for (TypeName typeName in onClause.superclassConstraints) {
+ DartType type = typeName.type;
+ if (type is InterfaceType) {
+ if (_checkForExtendsOrImplementsDisallowedClass(
+ typeName,
+ CompileTimeErrorCode
+ .MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS)) {
+ problemReported = true;
+ } else {
+ if (_checkForExtendsOrImplementsDeferredClass(
+ typeName,
+ CompileTimeErrorCode
+ .MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS)) {
+ problemReported = true;
+ }
+ }
+ }
+ }
+ return problemReported;
+ }
+
+ /**
* Verify the given operator-method [declaration], does not have an optional
* parameter. This method assumes that the method declaration was tested to be
* an operator declaration before being called.
@@ -5889,6 +5955,35 @@
}
/**
+ * Checks the class for problems with the superclass, mixins, or implemented
+ * interfaces.
+ */
+ void _checkMixinInheritance(MixinDeclaration node, OnClause onClause,
+ ImplementsClause implementsClause) {
+ // TODO(scheglov) Verify for all mixin errors.
+ // Only check for all of the inheritance logic around clauses if there
+ // isn't an error code such as "Cannot implement double" already.
+ if (!_checkForOnClauseErrorCodes(onClause) &&
+ !_checkForImplementsDisallowedClass(implementsClause)) {
+// _checkForImplicitDynamicType(superclass);
+// _checkForExtendsDeferredClass(superclass);
+ _checkForImplementsDeferredClass(implementsClause);
+// _checkForNonAbstractClassInheritsAbstractMember(node.name);
+// _checkForInconsistentMethodInheritance();
+// _checkForRecursiveInterfaceInheritance(_enclosingClass);
+// _checkForConflictingGetterAndMethod();
+// _checkForConflictingInstanceGetterAndSuperclassMember();
+// _checkImplementsSuperClass(implementsClause);
+// _checkForMixinHasNoConstructors(node);
+// _checkMixinInference(node, onClause);
+// _checkForMixinWithConflictingPrivateMember(onClause, superclass);
+// if (!disableConflictingGenericsCheck) {
+// _checkForConflictingGenerics(node);
+// }
+ }
+ }
+
+ /**
* Verify that the given [typeArguments] are all within their bounds, as
* defined by the given [element].
*
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8329fb9..957c45d6 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -9748,8 +9748,7 @@
ErrorCode errorCode = (withClause == null
? CompileTimeErrorCode.EXTENDS_NON_CLASS
: CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
- superclassType = _resolveType(extendsClause.superclass, errorCode,
- CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
+ superclassType = _resolveType(extendsClause.superclass, errorCode);
}
if (classElement != null) {
if (superclassType == null) {
@@ -9794,8 +9793,7 @@
Object visitClassTypeAlias(ClassTypeAlias node) {
super.visitClassTypeAlias(node);
ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
- InterfaceType superclassType = _resolveType(node.superclass, errorCode,
- CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
+ InterfaceType superclassType = _resolveType(node.superclass, errorCode);
if (superclassType == null) {
superclassType = typeProvider.objectType;
}
@@ -10261,11 +10259,8 @@
ClassElementImpl classElement, ImplementsClause clause) {
if (clause != null) {
NodeList<TypeName> interfaces = clause.interfaces;
- List<InterfaceType> interfaceTypes = _resolveTypes(
- interfaces,
- CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
- CompileTimeErrorCode.IMPLEMENTS_ENUM,
- CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
+ List<InterfaceType> interfaceTypes =
+ _resolveTypes(interfaces, CompileTimeErrorCode.IMPLEMENTS_NON_CLASS);
if (classElement != null) {
classElement.interfaces = interfaceTypes;
}
@@ -10298,12 +10293,10 @@
void _resolveOnClause(MixinElementImpl classElement, OnClause clause) {
List<InterfaceType> types;
if (clause != null) {
- types = _resolveTypes(
- clause.superclassConstraints,
- CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
- CompileTimeErrorCode.MIXIN_OF_ENUM,
- CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
- } else {
+ types = _resolveTypes(clause.superclassConstraints,
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS);
+ }
+ if (types == null || types.isEmpty) {
types = [typeProvider.objectType];
}
classElement.superclassConstraints = types;
@@ -10319,13 +10312,12 @@
* @param dynamicTypeError the error to produce if the type name is "dynamic"
* @return the type specified by the type name
*/
- InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError,
- ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
+ InterfaceType _resolveType(TypeName typeName, ErrorCode errorCode) {
DartType type = typeName.type;
if (type is InterfaceType) {
ClassElement element = type.element;
if (element != null && element.isEnum) {
- errorReporter.reportErrorForNode(enumTypeError, typeName);
+ errorReporter.reportErrorForNode(errorCode, typeName);
return null;
}
return type;
@@ -10333,14 +10325,8 @@
// If the type is not an InterfaceType, then visitTypeName() sets the type
// to be a DynamicTypeImpl
Identifier name = typeName.name;
- // TODO(mfairhurst) differentiate between dynamic via clean path, and error
- // types, and then check `type.isDynamic`. However, if we do that now, then
- // [nonTypeError] will never be reported because non types are resolved to
- // dynamic.
- if (name.name == Keyword.DYNAMIC.lexeme) {
- errorReporter.reportErrorForNode(dynamicTypeError, name, [name.name]);
- } else if (!nameScope.shouldIgnoreUndefined(name)) {
- errorReporter.reportErrorForNode(nonTypeError, name, [name.name]);
+ if (!nameScope.shouldIgnoreUndefined(name)) {
+ errorReporter.reportErrorForNode(errorCode, name, [name.name]);
}
return null;
}
@@ -10356,14 +10342,10 @@
* @return an array containing all of the types that were resolved.
*/
List<InterfaceType> _resolveTypes(
- NodeList<TypeName> typeNames,
- ErrorCode nonTypeError,
- ErrorCode enumTypeError,
- ErrorCode dynamicTypeError) {
+ NodeList<TypeName> typeNames, ErrorCode errorCode) {
List<InterfaceType> types = new List<InterfaceType>();
for (TypeName typeName in typeNames) {
- InterfaceType type =
- _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError);
+ InterfaceType type = _resolveType(typeName, errorCode);
if (type != null) {
types.add(type);
}
@@ -10374,10 +10356,7 @@
void _resolveWithClause(ClassElementImpl classElement, WithClause clause) {
if (clause != null) {
List<InterfaceType> mixinTypes = _resolveTypes(
- clause.mixinTypes,
- CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
- CompileTimeErrorCode.MIXIN_OF_ENUM,
- CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
+ clause.mixinTypes, CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
classElement.mixins = mixinTypes;
}
}
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 5aac04e..4d6b0b7 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -2320,26 +2320,26 @@
verify([source]);
}
- test_extendsEnum() async {
- Source source = addSource(r'''
-enum E { ONE }
-class A extends E {}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.EXTENDS_ENUM]);
- verify([source]);
- }
-
- test_extendsNonClass_class() async {
- Source source = addSource(r'''
-int A;
-class B extends A {}''');
+ test_extendsNonClass_dynamic() async {
+ Source source = addSource("class B extends dynamic {}");
await computeAnalysisResult(source);
assertErrors(source, [CompileTimeErrorCode.EXTENDS_NON_CLASS]);
verify([source]);
}
- test_extendsNonClass_dynamic() async {
- Source source = addSource("class B extends dynamic {}");
+ test_extendsNonClass_enum() async {
+ Source source = addSource(r'''
+enum E { ONE }
+class A extends E {}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.EXTENDS_NON_CLASS]);
+ verify([source]);
+ }
+
+ test_extendsNonClass_variable() async {
+ Source source = addSource(r'''
+int A;
+class B extends A {}''');
await computeAnalysisResult(source);
assertErrors(source, [CompileTimeErrorCode.EXTENDS_NON_CLASS]);
verify([source]);
@@ -3003,22 +3003,6 @@
verify([source]);
}
- test_implementsDynamic() async {
- Source source = addSource("class A implements dynamic {}");
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.IMPLEMENTS_DYNAMIC]);
- verify([source]);
- }
-
- test_implementsEnum() async {
- Source source = addSource(r'''
-enum E { ONE }
-class A implements E {}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.IMPLEMENTS_ENUM]);
- verify([source]);
- }
-
test_implementsNonClass_class() async {
Source source = addSource(r'''
int A;
@@ -3028,6 +3012,22 @@
verify([source]);
}
+ test_implementsNonClass_dynamic() async {
+ Source source = addSource("class A implements dynamic {}");
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.IMPLEMENTS_NON_CLASS]);
+ verify([source]);
+ }
+
+ test_implementsNonClass_enum() async {
+ Source source = addSource(r'''
+enum E { ONE }
+class A implements E {}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.IMPLEMENTS_NON_CLASS]);
+ verify([source]);
+ }
+
test_implementsNonClass_typeAlias() async {
Source source = addSource(r'''
class A {}
@@ -4535,15 +4535,6 @@
verify([source]);
}
- test_mixinOfEnum() async {
- Source source = addSource(r'''
-enum E { ONE }
-class A extends Object with E {}''');
- await computeAnalysisResult(source);
- assertErrors(source, [CompileTimeErrorCode.MIXIN_OF_ENUM]);
- verify([source]);
- }
-
@failingTest
test_mixinOfNonClass() async {
// TODO(brianwilkerson) Compare with MIXIN_WITH_NON_CLASS_SUPERCLASS.
@@ -4564,6 +4555,15 @@
verify([source]);
}
+ test_mixinOfNonClass_enum() async {
+ Source source = addSource(r'''
+enum E { ONE }
+class A extends Object with E {}''');
+ await computeAnalysisResult(source);
+ assertErrors(source, [CompileTimeErrorCode.MIXIN_OF_NON_CLASS]);
+ verify([source]);
+ }
+
test_mixinOfNonClass_typeAlias() async {
Source source = addSource(r'''
class A {}
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index aa03f21..73c70d6 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -321,7 +321,7 @@
class Duration implements Comparable<Duration> {}
class Exception {
- factory Exception([var message]);
+ factory Exception([var message]) => null;
}
external bool identical(Object a, Object b);
diff --git a/pkg/analyzer/test/src/dart/resolution/find_element.dart b/pkg/analyzer/test/src/dart/resolution/find_element.dart
index ff87f0e..df7c82b 100644
--- a/pkg/analyzer/test/src/dart/resolution/find_element.dart
+++ b/pkg/analyzer/test/src/dart/resolution/find_element.dart
@@ -21,6 +21,15 @@
fail('Not found class: $name');
}
+ ClassElement enum_(String name) {
+ for (var enum_ in unitElement.enums) {
+ if (enum_.name == name) {
+ return enum_;
+ }
+ }
+ fail('Not found enum: $name');
+ }
+
ExportElement export(String targetUri) {
ExportElement exportElement;
for (var export in unitElement.library.exports) {
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 205c71f..047499e 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -1,3 +1,4 @@
+import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,7 +13,11 @@
});
}
-abstract class AssignmentResolutionMixin implements ResolutionTest {
+@reflectiveTest
+class MixinDriverResolutionTest extends DriverResolutionTest
+ with MixinResolutionMixin {}
+
+abstract class MixinResolutionMixin implements ResolutionTest {
test_accessor_getter() async {
addTestFile(r'''
mixin M {
@@ -20,6 +25,7 @@
}
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
@@ -44,6 +50,7 @@
}
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
@@ -64,6 +71,7 @@
}
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
@@ -89,6 +97,7 @@
mixin M {}
''');
await resolveTestFile();
+ assertNoTestErrors();
var aRef = findNode.commentReference('a]').identifier;
assertElement(aRef, findElement.topGet('a'));
@@ -100,6 +109,7 @@
mixin M {}
''');
await resolveTestFile();
+ assertNoTestErrors();
var mixin = findNode.mixin('mixin M');
var element = findElement.mixin('M');
@@ -109,6 +119,151 @@
assertElementTypes(element.superclassConstraints, [objectType]);
}
+ test_error_implementsClause_deferredClass() async {
+ addTestFile(r'''
+import 'dart:math' deferred as math;
+mixin M implements math.Random {}
+''');
+ await resolveTestFile();
+ var mathImport = findElement.import('dart:math');
+ var randomElement = mathImport.importedLibrary.getType('Random');
+
+ assertTestErrors([
+ CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.interfaces, [randomElement.type]);
+
+ var typeRef = findNode.typeName('Random {}');
+ assertTypeName(typeRef, randomElement, 'Random',
+ expectedPrefix: mathImport.prefix);
+ }
+
+ test_error_implementsClause_disallowedClass_int() async {
+ addTestFile(r'''
+mixin M implements int {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.interfaces, [intType]);
+
+ var typeRef = findNode.typeName('int {}');
+ assertTypeName(typeRef, intElement, 'int');
+ }
+
+ test_error_implementsClause_nonClass_void() async {
+ addTestFile(r'''
+mixin M implements void {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.interfaces, []);
+
+ var typeRef = findNode.typeName('void {}');
+ assertTypeName(typeRef, null, 'void');
+ }
+
+ test_error_onClause_deferredClass() async {
+ addTestFile(r'''
+import 'dart:math' deferred as math;
+mixin M on math.Random {}
+''');
+ await resolveTestFile();
+ var mathImport = findElement.import('dart:math');
+ var randomElement = mathImport.importedLibrary.getType('Random');
+
+ assertTestErrors([
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.superclassConstraints, [randomElement.type]);
+
+ var typeRef = findNode.typeName('Random {}');
+ assertTypeName(typeRef, randomElement, 'Random',
+ expectedPrefix: mathImport.prefix);
+ }
+
+ test_error_onClause_disallowedClass_int() async {
+ addTestFile(r'''
+mixin M on int {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.superclassConstraints, [intType]);
+
+ var typeRef = findNode.typeName('int {}');
+ assertTypeName(typeRef, intElement, 'int');
+ }
+
+ test_error_onClause_nonClass_dynamic() async {
+ addTestFile(r'''
+mixin M on dynamic {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.superclassConstraints, [objectType]);
+
+ var typeRef = findNode.typeName('dynamic {}');
+ assertTypeName(typeRef, dynamicElement, 'dynamic');
+ }
+
+ test_error_onClause_nonClass_enum() async {
+ addTestFile(r'''
+enum E {E1, E2, E3}
+mixin M on E {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.superclassConstraints, [objectType]);
+
+ var typeRef = findNode.typeName('E {}');
+ assertTypeName(typeRef, findElement.enum_('E'), 'E');
+ }
+
+ test_error_onClause_nonClass_void() async {
+ addTestFile(r'''
+mixin M on void {}
+''');
+ await resolveTestFile();
+
+ assertTestErrors([
+ CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_CLASS,
+ ]);
+
+ var element = findElement.mixin('M');
+ assertElementTypes(element.superclassConstraints, [objectType]);
+
+ var typeRef = findNode.typeName('void {}');
+ assertTypeName(typeRef, null, 'void');
+ }
+
test_field() async {
addTestFile(r'''
mixin M<T> {
@@ -116,6 +271,7 @@
}
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
@@ -155,6 +311,7 @@
mixin M implements A, B {} // M
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
assertElementTypes(element.interfaces, [
@@ -177,6 +334,7 @@
mixin M {}
''');
await resolveTestFile();
+ assertNoTestErrors();
var a = findElement.topGet('a');
var element = findElement.mixin('M');
@@ -198,6 +356,7 @@
mixin M on A, B {} // M
''');
await resolveTestFile();
+ assertNoTestErrors();
var element = findElement.mixin('M');
assertElementTypes(element.superclassConstraints, [
@@ -214,9 +373,5 @@
}
@reflectiveTest
-class MixinDriverResolutionTest extends DriverResolutionTest
- with AssignmentResolutionMixin {}
-
-@reflectiveTest
class MixinTaskResolutionTest extends TaskResolutionTest
- with AssignmentResolutionMixin {}
+ with MixinResolutionMixin {}
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index b93718a..a7751c1 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -6,10 +6,12 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/error/hint_codes.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
+import '../../../generated/test_support.dart';
import 'find_element.dart';
import 'find_node.dart';
@@ -31,6 +33,8 @@
InterfaceType get doubleType => typeProvider.doubleType;
+ Element get dynamicElement => typeProvider.dynamicType.element;
+
ClassElement get intElement => typeProvider.intType.element;
InterfaceType get intType => typeProvider.intType;
@@ -84,6 +88,31 @@
expect(element.enclosingElement, expectedEnclosing);
}
+ /**
+ * Assert that the number of error codes in reported [errors] matches the
+ * number of [expected] error codes. The order of errors is ignored.
+ */
+ void assertErrors(List<AnalysisError> errors,
+ [List<ErrorCode> expected = const <ErrorCode>[]]) {
+ var errorListener = new GatheringErrorListener();
+ for (AnalysisError error in result.errors) {
+ ErrorCode errorCode = error.errorCode;
+ if (errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+ errorCode == HintCode.UNUSED_CATCH_STACK ||
+ errorCode == HintCode.UNUSED_ELEMENT ||
+ errorCode == HintCode.UNUSED_FIELD ||
+ errorCode == HintCode.UNUSED_LOCAL_VARIABLE) {
+ continue;
+ }
+ errorListener.onError(error);
+ }
+ errorListener.assertErrorsWithCodes(expected);
+ }
+
+ void assertHasTestErrors() {
+ expect(result.errors, isNotEmpty);
+ }
+
void assertIdentifierTopGetRef(SimpleIdentifier ref, String name) {
var getter = findElement.topGet(name);
assertElement(ref, getter);
@@ -107,6 +136,14 @@
expect(actual.baseElement, same(expectedBase));
}
+ void assertNoTestErrors() {
+ expect(result.errors, isEmpty);
+ }
+
+ void assertTestErrors(List<ErrorCode> expected) {
+ assertErrors(result.errors, expected);
+ }
+
void assertTopGetRef(String search, String name) {
var ref = findNode.simple(search);
assertIdentifierTopGetRef(ref, name);
@@ -179,7 +216,7 @@
Future<TestAnalysisResult> resolveFile(String path);
- Future resolveTestFile() async {
+ Future<void> resolveTestFile() async {
var path = convertPath('/test/lib/test.dart');
result = await resolveFile(path);
findNode = new FindNode(result.content, result.unit);
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
new file mode 100644
index 0000000..51477cf
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'assignment_test.dart' as assignment_test;
+import 'mixin_test.dart' as mixin_test;
+
+main() {
+ defineReflectiveSuite(() {
+ assignment_test.main();
+ mixin_test.main();
+ }, name: 'resolution');
+}
diff --git a/pkg/analyzer/test/src/dart/test_all.dart b/pkg/analyzer/test/src/dart/test_all.dart
index 78ac68f..7855e3e 100644
--- a/pkg/analyzer/test/src/dart/test_all.dart
+++ b/pkg/analyzer/test/src/dart/test_all.dart
@@ -10,6 +10,7 @@
import 'ast/test_all.dart' as ast;
import 'constant/test_all.dart' as constant;
import 'element/test_all.dart' as element;
+import 'resolution/test_all.dart' as resolution;
import 'sdk/test_all.dart' as sdk;
/// Utility for manually running all tests.
@@ -19,6 +20,7 @@
ast.main();
constant.main();
element.main();
+ resolution.main();
sdk.main();
}, name: 'dart');
}