Produce run-time error when type parameters are accessed from static context.

BUG=dartbug.com/5231
TEST=

Review URL: https://chromiumcodereview.appspot.com//11416144

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15292 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index 8ed02f2..63e14f9 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -365,7 +365,8 @@
     Element constructor = treeElements[send];
     assert(constructor != null);
     assert(send.receiver == null);
-    if (constructor is !ErroneousElement) {
+    if (!Elements.isErroneousElement(constructor) &&
+        !Elements.isMalformedElement(constructor)) {
       makeConstructorPlaceholder(node.send.selector, constructor, type);
       // TODO(smok): Should this be in visitNamedArgument?
       // Field names can be exposed as names of optional arguments, e.g.
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index c6aa269..df07e95 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -120,6 +120,8 @@
       const ElementKind('ambiguous', ElementCategory.NONE);
   static const ElementKind ERROR =
       const ElementKind('error', ElementCategory.NONE);
+  static const ElementKind MALFORMED_TYPE =
+    const ElementKind('malformed', ElementCategory.NONE);
 
   toString() => id;
 }
@@ -200,6 +202,8 @@
   /** See [AmbiguousElement] for documentation. */
   bool isAmbiguous() => false;
 
+  bool isMalformed() => false;
+
   /**
    * Is [:true:] if this element has a corresponding patch.
    *
@@ -1319,6 +1323,23 @@
   bool impliesType() => true;
 }
 
+class MalformedTypeElement extends Element {
+  final TypeAnnotation typeNode;
+
+  MalformedTypeElement(this.typeNode, Element enclosing)
+      : super(const SourceString('malformed'),
+              ElementKind.MALFORMED_TYPE,
+              enclosing);
+
+  DartType computeType(compiler) => compiler.types.malformedType;
+
+  Node parseNode(_) => typeNode;
+
+  bool impliesType() => true;
+
+  bool isMalformed() => true;
+}
+
 /**
  * [TypeDeclarationElement] defines the common interface for class/interface
  * declarations and typedefs.
@@ -1724,8 +1745,11 @@
 }
 
 class Elements {
-  static bool isUnresolved(Element e) => e == null || e.isErroneous();
+  static bool isUnresolved(Element e) {
+    return e == null || e.isErroneous() || e.isMalformed();
+  }
   static bool isErroneousElement(Element e) => e != null && e.isErroneous();
+  static bool isMalformedElement(Element e) => e != null && e.isMalformed();
 
   static bool isClass(Element e) => e != null && e.kind == ElementKind.CLASS;
   static bool isTypedef(Element e) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 16ae7fb..691d73b 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -380,7 +380,8 @@
           kind == ElementKind.GETTER ||
           kind == ElementKind.SETTER ||
           kind == ElementKind.TYPEDEF ||
-          kind == ElementKind.LIBRARY) {
+          kind == ElementKind.LIBRARY ||
+          kind == ElementKind.MALFORMED_TYPE) {
         bool isNative = false;
         if (identical(kind, ElementKind.CLASS)) {
           ClassElement class_elt = element;
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index af4a600..713a03c 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1038,6 +1038,18 @@
 
   TypeResolver(this.compiler);
 
+  bool anyMalformedTypesInThere(Link<DartType> list) {
+    for (Link<DartType> link = list;
+        !link.isEmpty;
+        link = link.tail) {
+      DartType dtype = link.head;
+      if (dtype is MalformedType) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   Element resolveTypeName(Scope scope, TypeAnnotation node) {
     Identifier typeName = node.typeName.asIdentifier();
     Send send = node.typeName.asSend();
@@ -1081,6 +1093,7 @@
   DartType resolveTypeAnnotation(
       TypeAnnotation node,
       Scope scope,
+      bool inStaticContext,
       {onFailure(Node node, MessageKind kind, [List arguments]),
        whenResolved(Node node, DartType type)}) {
     if (onFailure == null) {
@@ -1092,11 +1105,12 @@
     if (scope == null) {
       compiler.internalError('resolveTypeAnnotation: no scope specified');
     }
-    return resolveTypeAnnotationInContext(scope, node, onFailure,
-                                          whenResolved);
+    return resolveTypeAnnotationInContext(scope, node, inStaticContext,
+        onFailure, whenResolved);
   }
 
   DartType resolveTypeAnnotationInContext(Scope scope, TypeAnnotation node,
+                                          bool inStaticContext,
                                           onFailure, whenResolved) {
     Element element = resolveTypeName(scope, node);
     DartType type;
@@ -1115,13 +1129,21 @@
         ClassElement cls = element;
         cls.ensureResolved(compiler);
         Link<DartType> arguments =
-            resolveTypeArguments(node, cls.typeVariables, scope,
+            resolveTypeArguments(node, cls.typeVariables,
+                                 inStaticContext, scope,
                                  onFailure, whenResolved);
         if (cls.typeVariables.isEmpty && arguments.isEmpty) {
           // Use the canonical type if it has no type parameters.
           type = cls.computeType(compiler);
         } else {
-          type = new InterfaceType(cls.declaration, arguments);
+          // In checked mode malformed-ness of the type argument bubbles up.
+          if (anyMalformedTypesInThere(arguments) &&
+              compiler.enableTypeAssertions) {
+            type = new MalformedType(
+                new MalformedTypeElement(node, element));
+          } else {
+            type = new InterfaceType(cls.declaration, arguments);
+          }
         }
       } else if (element.isTypedef()) {
         TypedefElement typdef = element;
@@ -1129,7 +1151,7 @@
         compiler.resolveTypedef(typdef);
         typdef.computeType(compiler);
         Link<DartType> arguments = resolveTypeArguments(
-            node, typdef.typeVariables,
+            node, typdef.typeVariables, inStaticContext,
             scope, onFailure, whenResolved);
         if (typdef.typeVariables.isEmpty && arguments.isEmpty) {
           // Return the canonical type if it has no type parameters.
@@ -1138,7 +1160,14 @@
           type = new TypedefType(typdef, arguments);
         }
       } else if (element.isTypeVariable()) {
-        type = element.computeType(compiler);
+        if (inStaticContext) {
+          compiler.reportWarning(node,
+              MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER.message(
+                  [element]));
+          type = new MalformedType(new MalformedTypeElement(node, element));
+        } else {
+          type = element.computeType(compiler);
+        }
       } else {
         compiler.cancel("unexpected element kind ${element.kind}",
                         node: node);
@@ -1150,6 +1179,7 @@
 
   Link<DartType> resolveTypeArguments(TypeAnnotation node,
                                       Link<DartType> typeVariables,
+                                      bool inStaticContext,
                                       Scope scope, onFailure, whenResolved) {
     if (node.typeArguments == null) {
       return const Link<DartType>();
@@ -1163,6 +1193,7 @@
       }
       DartType argType = resolveTypeAnnotationInContext(scope,
                                                     typeArguments.head,
+                                                    inStaticContext,
                                                     onFailure,
                                                     whenResolved);
       arguments.addLast(argType);
@@ -2057,21 +2088,10 @@
   }
 
   DartType resolveTypeAnnotation(TypeAnnotation node) {
-    // TODO(johnniwinther): Remove this together with the named arguments
-    // on [TypeResolver.resolveTypeAnnotation].
-    void checkAndUseType(TypeAnnotation annotation, DartType type) {
-      useType(annotation, type);
-      if (type != null &&
-          identical(type.kind, TypeKind.TYPE_VARIABLE) &&
-          enclosingElement.isInStaticMember()) {
-        warning(annotation, MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
-                [type]);
-      }
-    }
-
     Function report = typeRequired ? error : warning;
     DartType type = typeResolver.resolveTypeAnnotation(
-        node, scope, onFailure: report, whenResolved: checkAndUseType);
+        node, scope, enclosingElement.isInStaticMember(),
+        onFailure: report, whenResolved: useType);
     if (type == null) return null;
     if (inCheckContext) {
       compiler.enqueuer.resolution.registerIsCheck(type);
@@ -2438,7 +2458,8 @@
       TypeVariableElement variableElement = typeVariable.element;
       if (typeNode.bound != null) {
         DartType boundType = typeResolver.resolveTypeAnnotation(
-            typeNode.bound, scope, onFailure: warning);
+            typeNode.bound, scope, element.isInStaticMember(),
+            onFailure: warning);
         if (boundType != null && boundType.element == variableElement) {
           // TODO(johnniwinther): Check for more general cycles, like
           // [: <A extends B, B extends C, C extends B> :].
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index bee005e..cefee59 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -3423,7 +3423,8 @@
 
   visitNewExpression(NewExpression node) {
     Element element = elements[node.send];
-    if (!Elements.isErroneousElement(element)) {
+    if (!Elements.isErroneousElement(element) &&
+        !Elements.isMalformedElement(element)) {
       FunctionElement function = element;
       element = function.redirectionTarget;
     }
@@ -3445,6 +3446,10 @@
       ConstantHandler handler = compiler.constantHandler;
       Constant constant = handler.compileNodeWithDefinitions(node, elements);
       stack.add(graph.addConstant(constant));
+    } else if (Elements.isMalformedElement(element)) {
+      Message message =
+          MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER.message([element]);
+      generateRuntimeError(node.send, message.toString());
     } else {
       visitNewSend(node.send, elements.getType(node));
     }
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 7a8e0c3..b192c23 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -36,6 +36,7 @@
   static const TypeKind STATEMENT = const TypeKind('statement');
   static const TypeKind TYPEDEF = const TypeKind('typedef');
   static const TypeKind TYPE_VARIABLE = const TypeKind('type variable');
+  static const TypeKind MALFORMED_TYPE = const TypeKind('malformed');
   static const TypeKind VOID = const TypeKind('void');
 
   String toString() => id;
@@ -244,6 +245,24 @@
   return types;
 }
 
+class MalformedType extends DartType {
+  const MalformedType(this.element);
+
+  TypeKind get kind => TypeKind.MALFORMED_TYPE;
+
+  SourceString get name => element.name;
+
+  final MalformedTypeElement element;
+
+  DartType unalias(Compiler compiler) => this;
+
+  int get hashCode => 1733;
+
+  bool operator ==(other) => other is MalformedType;
+
+  String toString() => name.slowToString();
+}
+
 class InterfaceType extends DartType {
   final Element element;
   final Link<DartType> typeArguments;
@@ -486,6 +505,8 @@
 
     if (t is VoidType) {
       return false;
+    } else if (t is MalformedType) {
+      return false;
     } else if (t is InterfaceType) {
       if (s is !InterfaceType) return false;
       ClassElement tc = t.element;
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a2e4b35..b878b65 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -217,7 +217,6 @@
 Language/07_Classes/6_Constructors/2_Factories_A06_t04: Fail # TODO(ahe): Please triage this failure.
 Language/09_Generics/09_Generics_A03_t01: Fail # TODO(ahe): Please triage this failure.
 Language/09_Generics/09_Generics_A04_t06: Fail # TODO(ahe): Please triage this failure.
-Language/09_Generics/09_Generics_A05_t02: Fail # TODO(ahe): Please triage this failure.
 Language/11_Expressions/03_Numbers_A05_t02: Fail # TODO(ahe): Please triage this failure.
 Language/11_Expressions/06_Lists_A09_t01: Fail # TODO(ahe): Please triage this failure.
 Language/11_Expressions/06_Lists_A09_t04: Fail # TODO(ahe): Please triage this failure.
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 0fc8c70..ceece29 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -42,13 +42,6 @@
 type_variable_bounds2_test/03: Fail
 type_variable_bounds2_test/05: Fail
 type_variable_bounds2_test/06: Pass # For the wrong reasons.
-type_variable_scope_test/00: Fail
-type_variable_scope_test/01: Fail
-type_variable_scope_test/02: Fail
-type_variable_scope_test/03: Fail
-type_variable_scope_test/04: Fail
-type_variable_scope_test/05: Fail
-type_variable_scope2_test: Fail
 assign_top_method_negative_test: Pass # For the wrong reasons.
 f_bounded_quantification_test/01: Fail
 f_bounded_quantification_test/02: Fail
@@ -59,11 +52,6 @@
 factory1_test/00: Fail
 factory1_test/01: Fail
 
-type_parameter_test/01: Fail # Issue 4932
-type_parameter_test/02: Fail # Issue 4932
-type_parameter_test/03: Fail # Issue 4932
-type_parameter_test/04: Fail # Issue 4932
-
 super_call4_test: Fail # Badly generated noSuchMethod call.
 
 [ $compiler == dart2js && $unchecked ]