Index: compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
index 6ec0645eee0e00113015e07b0d74953b949fba3c..cb3b360b243223821d7f7ebe3d35926c89c213fe 100644 |
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
@@ -6,6 +6,7 @@ package com.google.dart.compiler.type; |
import com.google.common.annotations.VisibleForTesting; |
import com.google.common.base.Joiner; |
+import com.google.common.collect.ArrayListMultimap; |
import com.google.common.collect.LinkedListMultimap; |
import com.google.common.collect.Multimap; |
import com.google.dart.compiler.DartCompilationError; |
@@ -165,7 +166,6 @@ public class TypeAnalyzer implements DartCompilationPhase { |
private Type expected; |
private InterfaceType currentClass; |
private final ConcurrentHashMap<ClassElement, List<Element>> unimplementedElements; |
- private final Set<ClassElement> diagnosedAbstractClasses; |
private final InterfaceType boolType; |
private final InterfaceType numType; |
private final InterfaceType intType; |
@@ -185,7 +185,6 @@ public class TypeAnalyzer implements DartCompilationPhase { |
Set<ClassElement> diagnosedAbstractClasses) { |
this.context = context; |
this.unimplementedElements = unimplementedElements; |
- this.diagnosedAbstractClasses = diagnosedAbstractClasses; |
this.types = Types.getInstance(typeProvider); |
this.dynamicType = typeProvider.getDynamicType(); |
this.stringType = typeProvider.getStringType(); |
@@ -729,6 +728,20 @@ public class TypeAnalyzer implements DartCompilationPhase { |
} |
visit(node.getMembers()); |
checkInterfaceConstructors(element); |
+ // Report unimplemented members. |
+ if (!node.isAbstract()) { |
+ ClassElement cls = node.getSymbol(); |
+ List<Element> unimplementedMembers = findUnimplementedMembers(cls); |
+ if (unimplementedMembers.size() > 0) { |
+ StringBuilder sb = getUnimplementedMembersMessage(cls, unimplementedMembers); |
+ typeError( |
+ node.getName(), |
+ TypeErrorCode.ABSTRACT_CLASS_WITHOUT_ABSTRACT_MODIFIER, |
+ cls.getName(), |
+ sb); |
+ } |
+ } |
+ // Finish current class. |
setCurrentClass(null); |
return type; |
} |
@@ -1027,58 +1040,39 @@ public class TypeAnalyzer implements DartCompilationPhase { |
@Override |
public Type visitNewExpression(DartNewExpression node) { |
- ConstructorElement element = node.getSymbol(); |
- node.setReferencedElement(element); |
+ ConstructorElement constructorElement = node.getSymbol(); |
+ node.setReferencedElement(constructorElement); |
DartTypeNode typeNode = Types.constructorTypeNode(node); |
DartNode typeName = typeNode.getIdentifier(); |
Type type = validateTypeNode(typeNode, true); |
- if (element == null) { |
+ if (constructorElement == null) { |
visit(node.getArgs()); |
} else { |
- ClassElement cls = (ClassElement) element.getEnclosingElement(); |
- |
- List<Element> unimplementedMembers = findUnimplementedMembers(cls); |
- if (unimplementedMembers.size() > 0) { |
- if (diagnosedAbstractClasses.add(cls)) { |
- StringBuilder sb = new StringBuilder(); |
- for (Element member : unimplementedMembers) { |
- sb.append("\n # From "); |
- ClassElement enclosingElement = (ClassElement) member.getEnclosingElement(); |
- InterfaceType instance = types.asInstanceOf(cls.getType(), enclosingElement); |
- Type memberType = member.getType().subst(instance.getArguments(), |
- enclosingElement.getTypeParameters()); |
- sb.append(enclosingElement.getName()); |
- sb.append(":\n "); |
- if (memberType.getKind().equals(TypeKind.FUNCTION)) { |
- FunctionType ftype = (FunctionType) memberType; |
- sb.append(ftype.getReturnType()); |
- sb.append(" "); |
- sb.append(member.getName()); |
- String string = ftype.toString(); |
- sb.append(string, 0, string.lastIndexOf(" -> ")); |
- } else { |
- sb.append(memberType); |
- sb.append(" "); |
- sb.append(member.getName()); |
- } |
- } |
- DartNode clsNode = cls.getNode(); |
- if (clsNode != null) { |
- typeError(typeName, TypeErrorCode.CANNOT_INSTATIATE_ABSTRACT_CLASS, cls.getName()); |
- typeError(clsNode, TypeErrorCode.ABSTRACT_CLASS, cls.getName(), sb); |
- } else { |
- typeError(typeName, TypeErrorCode.ABSTRACT_CLASS, cls.getName(), sb); |
- } |
- } else { |
- typeError(typeName, TypeErrorCode.CANNOT_INSTATIATE_ABSTRACT_CLASS, cls.getName()); |
+ ClassElement cls = (ClassElement) constructorElement.getEnclosingElement(); |
+ // Add warning for instantiating abstract class. |
+ if (cls.isAbstract()) { |
+ ErrorCode errorCode = |
+ constructorElement.getModifiers().isFactory() |
+ ? TypeErrorCode.INSTANTIATION_OF_ABSTRACT_CLASS_USING_FACTORY |
+ : TypeErrorCode.INSTANTIATION_OF_ABSTRACT_CLASS; |
+ typeError(typeName, errorCode, cls.getName()); |
+ } else { |
+ List<Element> unimplementedMembers = findUnimplementedMembers(cls); |
+ if (unimplementedMembers.size() > 0) { |
+ StringBuilder sb = getUnimplementedMembersMessage(cls, unimplementedMembers); |
+ typeError( |
+ typeName, |
+ TypeErrorCode.INSTANTIATION_OF_CLASS_WITH_UNIMPLEMENTED_MEMBERS, |
+ cls.getName(), |
+ sb); |
} |
} |
- FunctionType ftype = (FunctionType) element.getType(); |
- if (TypeKind.of(type).equals(TypeKind.INTERFACE)) { |
- InterfaceType ifaceType = (InterfaceType)type; |
+ // Check type arguments. |
+ FunctionType ftype = (FunctionType) constructorElement.getType(); |
+ if (ftype != null && TypeKind.of(type).equals(TypeKind.INTERFACE)) { |
+ InterfaceType ifaceType = (InterfaceType) type; |
List<? extends Type> arguments = ifaceType.getArguments(); |
- ftype = (FunctionType) ftype.subst(arguments, |
- ifaceType.getElement().getTypeParameters()); |
+ ftype = (FunctionType) ftype.subst(arguments, ifaceType.getElement().getTypeParameters()); |
List<TypeVariable> typeVariables = ftype.getTypeVariables(); |
if (arguments.size() == typeVariables.size()) { |
ftype = (FunctionType) ftype.subst(arguments, typeVariables); |
@@ -1089,6 +1083,51 @@ public class TypeAnalyzer implements DartCompilationPhase { |
return type; |
} |
+ /** |
+ * @param cls the {@link ClassElement} which has unimplemented members. |
+ * @param unimplementedMembers the unimplemented members {@link Element}s. |
+ * @return the {@link StringBuilder} with message about unimplemented members. |
+ */ |
+ private StringBuilder getUnimplementedMembersMessage(ClassElement cls, |
+ List<Element> unimplementedMembers) { |
+ // Prepare groups of unimplemented members for each type. |
+ Multimap<String, String> membersByTypes = ArrayListMultimap.create(); |
+ for (Element member : unimplementedMembers) { |
+ ClassElement enclosingElement = (ClassElement) member.getEnclosingElement(); |
+ InterfaceType instance = types.asInstanceOf(cls.getType(), enclosingElement); |
+ Type memberType = member.getType().subst(instance.getArguments(), |
+ enclosingElement.getTypeParameters()); |
+ if (memberType.getKind().equals(TypeKind.FUNCTION)) { |
+ FunctionType ftype = (FunctionType) memberType; |
+ StringBuilder sb = new StringBuilder(); |
+ sb.append(ftype.getReturnType()); |
+ sb.append(" "); |
+ sb.append(member.getName()); |
+ String string = ftype.toString(); |
+ sb.append(string, 0, string.lastIndexOf(" -> ")); |
+ membersByTypes.put(enclosingElement.getName(), sb.toString()); |
+ } else { |
+ StringBuilder sb = new StringBuilder(); |
+ sb.append(memberType); |
+ sb.append(" "); |
+ sb.append(member.getName()); |
+ membersByTypes.put(enclosingElement.getName(), sb.toString()); |
+ } |
+ } |
+ // Output unimplemented members with grouping by class. |
+ StringBuilder sb = new StringBuilder(); |
+ for (String typeName : membersByTypes.keySet()) { |
+ sb.append("\n # From "); |
+ sb.append(typeName); |
+ sb.append(":"); |
+ for (String memberString : membersByTypes.get(typeName)) { |
+ sb.append("\n "); |
+ sb.append(memberString); |
+ } |
+ } |
+ return sb; |
+ } |
+ |
@Override |
public Type visitNullLiteral(DartNullLiteral node) { |
return nullType; |
@@ -1555,7 +1594,9 @@ public class TypeAnalyzer implements DartCompilationPhase { |
while (supertype != null) { |
ClassElement superclass = supertype.getElement(); |
for (Element member : superclass.getMembers()) { |
- superMembers.removeAll(member.getName()); |
+ if (!member.getModifiers().isAbstract()) { |
+ superMembers.removeAll(member.getName()); |
+ } |
} |
supertype = supertype.getElement().getSupertype(); |
} |