| 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);
|
| }
|
|
|
|
|