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 ]