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 c9761333d2a33ed23b0db34c9bfc79ffed9ce477..b5762cd79361bf69eef54e2dd7e8c03b55452ca1 100644 |
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
@@ -604,6 +604,45 @@ 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; |
+ } |
+ case INTERFACE: { |
+ InterfaceType iType = (InterfaceType)bound; |
+ for (Type argument : iType.getArguments()) { |
+ checkCyclicBound(variable, argument); |
+ } |
+ break; |
+ } |
+ case FUNCTION_ALIAS: { |
+ FunctionAliasType fType = (FunctionAliasType)bound; |
+ for (Type argument: fType.getArguments()) { |
+ checkCyclicBound(variable, argument); |
+ } |
+ } |
+ } |
+ } |
+ |
Type typeOf(DartNode node) { |
if (node == null) { |
return dynamicType; |
@@ -713,6 +752,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()); |
@@ -883,7 +923,6 @@ public class TypeAnalyzer implements DartCompilationPhase { |
typeError(iterableExpression, TypeErrorCode.FOR_IN_WITH_ITERATOR_FIELD); |
} |
} |
- |
return typeAsVoid(node); |
} |
@@ -914,6 +953,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); |
} |