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 c3151530f65bd9c55b207c7a51a1ee61ef4edc09..c92bc7958e02ff5819cca0f012df6d91cb234090 100644 |
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
@@ -655,6 +655,34 @@ public class TypeAnalyzer implements DartCompilationPhase { |
} |
} |
+ /* Check for a type variable is repeated in its own bounds: |
+ * e.g. Foo<T extends T> |
+ */ |
+ private void checkCyclicBounds(List<? extends Type> arguments) { |
+ for (Type argument : arguments) { |
+ if (TypeKind.of(argument).equals(TypeKind.VARIABLE)) { |
+ TypeVariable typeVar = (TypeVariable) argument; |
+ checkCyclicBound(typeVar, typeVar.getTypeVariableElement().getBound()); |
+ } |
+ } |
+ } |
+ |
+ private void checkCyclicBound(TypeVariable variable, Type bound) { |
+ switch(TypeKind.of(bound)) { |
+ case VARIABLE: { |
+ TypeVariable boundType = (TypeVariable)bound; |
+ if (boundType.equals(variable)) { |
+ onError(boundType.getElement().getNode(), |
+ TypeErrorCode.CYCLIC_REFERENCE_TO_TYPE_VARIABLE, |
+ boundType.getElement().getOriginalSymbolName()); |
+ } |
+ break; |
+ } |
+ default: |
+ break; |
+ } |
+ } |
+ |
Type typeOf(DartNode node) { |
if (node == null) { |
return dynamicType; |
@@ -764,6 +792,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
public Type visitClass(DartClass node) { |
ClassElement element = node.getSymbol(); |
InterfaceType type = element.getType(); |
+ checkCyclicBounds(type.getArguments()); |
findUnimplementedMembers(element); |
setCurrentClass(type); |
visit(node.getTypeParameters()); |
@@ -934,7 +963,6 @@ public class TypeAnalyzer implements DartCompilationPhase { |
typeError(iterableExpression, TypeErrorCode.FOR_IN_WITH_ITERATOR_FIELD); |
} |
} |
- |
return typeAsVoid(node); |
} |
@@ -965,6 +993,10 @@ public class TypeAnalyzer implements DartCompilationPhase { |
@Override |
public Type visitFunctionTypeAlias(DartFunctionTypeAlias node) { |
+ if (TypeKind.of(node.getSymbol().getType()).equals(TypeKind.FUNCTION_ALIAS)) { |
+ FunctionAliasType type = node.getSymbol().getType(); |
+ checkCyclicBounds(type.getElement().getTypeParameters()); |
+ } |
return typeAsVoid(node); |
} |