Treat ambiguous types as malformed.

BUG=
R=ahe@google.com

Review URL: https://codereview.chromium.org//21065002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@25605 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
johnniwinther@google.com
2013-07-30 05:59:15 +00:00
parent 947984f6f5
commit a7d13fa228
12 changed files with 39 additions and 238 deletions
@@ -86,21 +86,6 @@ abstract class DartType {
* by the user.
*/
DartType get userProvidedBadType => null;
/// Returns [:true:] if this type contains an ambiguous type.
bool get containsAmbiguousTypes {
return !forEachAmbiguousType((_) => false);
}
/**
* Calls [f] with each [AmbiguousType] within this type.
*
* If [f] returns [: false :], the traversal stops prematurely.
*
* [forEachAmbiguousType] returns [: false :] if the traversal was stopped
* prematurely.
*/
bool forEachAmbiguousType(bool f(AmbiguousType type)) => true;
/// Is [: true :] if this type has no explict type arguments.
bool get isRaw => true;
@@ -364,14 +349,6 @@ class MalformedType extends DartType {
}
}
class AmbiguousType extends MalformedType {
AmbiguousType(ErroneousElement element,
[Link<DartType> typeArguments = null])
: super(element, null, typeArguments);
bool forEachAmbiguousType(bool f(AmbiguousType type)) => f(this);
}
abstract class GenericType extends DartType {
final Link<DartType> typeArguments;
@@ -401,15 +378,6 @@ abstract class GenericType extends DartType {
return this;
}
bool forEachAmbiguousType(bool f(AmbiguousType type)) {
for (DartType typeArgument in typeArguments) {
if (!typeArgument.forEachAmbiguousType(f)) {
return false;
}
}
return true;
}
TypeVariableType get typeVariableOccurrence {
return _findTypeVariableOccurrence(typeArguments);
}
@@ -686,28 +654,6 @@ class FunctionType extends DartType {
return this;
}
bool forEachAmbiguousType(bool f(AmbiguousType type)) {
if (!returnType.forEachAmbiguousType(f)) {
return false;
}
for (DartType parameterType in parameterTypes) {
if (!parameterType.forEachAmbiguousType(f)) {
return false;
}
}
for (DartType parameterType in optionalParameterTypes) {
if (!parameterType.forEachAmbiguousType(f)) {
return false;
}
}
for (DartType parameterType in namedParameterTypes) {
if (!parameterType.forEachAmbiguousType(f)) {
return false;
}
}
return true;
}
DartType unalias(Compiler compiler) => this;
DartType get typeVariableOccurrence {
@@ -1238,23 +1184,6 @@ class Types {
return types;
}
/**
* Combine error messages in a type containing ambiguous types to a single
* message string.
*/
static String fetchReasonsFromAmbiguousType(DartType type) {
// TODO(johnniwinther): Figure out how to produce good error message in face
// of multiple errors, and how to ensure non-localized error messages.
var reasons = new List<String>();
type.forEachAmbiguousType((AmbiguousType ambiguousType) {
ErroneousElement error = ambiguousType.element;
Message message = error.messageKind.message(error.messageArguments);
reasons.add(message.toString());
return true;
});
return reasons.join(', ');
}
/**
* Returns the [ClassElement] which declares the type variables occurring in
* [type], or [:null:] if [type] does not contain type variables.
@@ -119,8 +119,6 @@ class ElementKind {
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;
}
@@ -105,23 +105,6 @@ class FunctionTypeCheckedModeHelper extends CheckedModeHelper {
}
}
class AmbiguousTypeCheckedModeHelper extends CheckedModeHelper {
const AmbiguousTypeCheckedModeHelper(SourceString name) : super(name);
void generateAdditionalArguments(SsaCodeGenerator codegen,
HTypeConversion node,
List<jsAst.Expression> arguments) {
DartType type = node.typeExpression;
assert(type.containsAmbiguousTypes);
String reasons = Types.fetchReasonsFromAmbiguousType(type);
arguments.add(js.string(quote('$type')));
arguments.add(js.string(quote(reasons)));
}
String quote(String string) => string.replaceAll('"', r'\"');
}
/*
* Invariants:
* canInline(function) implies canInline(function, insideLoop:true)
@@ -853,13 +836,6 @@ class JavaScriptBackend extends Backend {
// We also need the native variant of the check (for DOM types).
helper = getNativeCheckedModeHelper(type, typeCast: false);
if (helper != null) world.addToWorkList(helper.getElement(compiler));
if (type.containsAmbiguousTypes) {
enqueueInResolution(getThrowMalformedSubtypeError(), elements);
return;
}
} else if (type.containsAmbiguousTypes) {
registerThrowRuntimeError(elements);
return;
}
bool isTypeVariable = type.kind == TypeKind.TYPE_VARIABLE;
if (!type.isRaw || type.containsTypeVariables) {
@@ -1120,16 +1096,7 @@ class JavaScriptBackend extends Backend {
Element element = type.element;
bool nativeCheck = nativeCheckOnly ||
emitter.nativeEmitter.requiresNativeIsCheck(element);
if (type.containsAmbiguousTypes) {
// Check for malformed types first, because the type may be a list type
// with a malformed argument type.
if (nativeCheckOnly) return null;
return typeCast
? const AmbiguousTypeCheckedModeHelper(
const SourceString('malformedTypeCast'))
: const AmbiguousTypeCheckedModeHelper(
const SourceString('malformedTypeCheck'));
} else if (type == compiler.types.voidType) {
if (type == compiler.types.voidType) {
assert(!typeCast); // Cannot cast to void.
if (nativeCheckOnly) return null;
return const CheckedModeHelper(const SourceString('voidTypeCheck'));
@@ -1255,11 +1222,6 @@ class JavaScriptBackend extends Backend {
return compiler.findHelper(const SourceString('throwRuntimeError'));
}
Element getThrowMalformedSubtypeError() {
return compiler.findHelper(
const SourceString('throwMalformedSubtypeError'));
}
Element getThrowAbstractClassInstantiationError() {
return compiler.findHelper(
const SourceString('throwAbstractClassInstantiationError'));
@@ -724,8 +724,7 @@ class Namer implements ClosureNamer {
kind == ElementKind.GETTER ||
kind == ElementKind.SETTER ||
kind == ElementKind.TYPEDEF ||
kind == ElementKind.LIBRARY ||
kind == ElementKind.MALFORMED_TYPE) {
kind == ElementKind.LIBRARY) {
bool fixedName = false;
if (kind == ElementKind.CLASS) {
ClassElement classElement = element;
@@ -1428,8 +1428,7 @@ class TypeResolver {
}
DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
{bool malformedIsError: false,
bool ambiguousIsError: false}) {
{bool malformedIsError: false}) {
Identifier typeName;
SourceString prefixName;
Send send = node.typeName.asSend();
@@ -1446,10 +1445,8 @@ class TypeResolver {
DartType reportFailureAndCreateType(DualKind messageKind,
Map messageArguments,
{DartType userProvidedBadType,
bool isError: false,
bool isAmbiguous: false}) {
if (isError) {
{DartType userProvidedBadType}) {
if (malformedIsError) {
visitor.error(node, messageKind.error, messageArguments);
} else {
visitor.warning(node, messageKind.warning, messageArguments);
@@ -1459,9 +1456,7 @@ class TypeResolver {
visitor.enclosingElement);
var arguments = new LinkBuilder<DartType>();
resolveTypeArguments(visitor, node, null, arguments);
return isAmbiguous
? new AmbiguousType(erroneousElement, arguments.toLink())
: new MalformedType(erroneousElement,
return new MalformedType(erroneousElement,
userProvidedBadType, arguments.toLink());
}
@@ -1480,18 +1475,15 @@ class TypeResolver {
if (element == null) {
type = reportFailureAndCreateType(
MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName},
isError: malformedIsError);
MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName});
} else if (element.isAmbiguous()) {
AmbiguousElement ambiguous = element;
type = reportFailureAndCreateType(
ambiguous.messageKind, ambiguous.messageArguments,
isError: ambiguousIsError, isAmbiguous: true);
ambiguous.messageKind, ambiguous.messageArguments);
ambiguous.diagnose(visitor.mapping.currentElement, compiler);
} else if (!element.impliesType()) {
type = reportFailureAndCreateType(
MessageKind.NOT_A_TYPE, {'node': node.typeName},
isError: malformedIsError);
MessageKind.NOT_A_TYPE, {'node': node.typeName});
} else {
if (identical(element, compiler.types.voidType.element) ||
identical(element, compiler.dynamicClass)) {
@@ -1545,8 +1537,7 @@ class TypeResolver {
type = reportFailureAndCreateType(
MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
{'typeVariableName': node},
userProvidedBadType: element.computeType(compiler),
isError: malformedIsError);
userProvidedBadType: element.computeType(compiler));
} else {
type = element.computeType(compiler);
}
@@ -1570,8 +1561,7 @@ class TypeResolver {
MappingVisitor visitor,
TypeAnnotation node,
Link<DartType> typeVariables,
LinkBuilder<DartType> arguments,
{bool ambiguousIsError: false}) {
LinkBuilder<DartType> arguments) {
if (node.typeArguments == null) {
return false;
}
@@ -1584,8 +1574,7 @@ class TypeResolver {
typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT.warning);
typeArgumentCountMismatch = true;
}
DartType argType = resolveTypeAnnotation(visitor, typeArguments.head,
ambiguousIsError: ambiguousIsError);
DartType argType = resolveTypeAnnotation(visitor, typeArguments.head);
arguments.addLast(argType);
if (typeVariables != null && !typeVariables.isEmpty) {
typeVariables = typeVariables.tail;
@@ -2686,13 +2675,11 @@ class ResolverVisitor extends MappingVisitor<Element> {
}
DartType resolveTypeExpression(TypeAnnotation node) {
return resolveTypeAnnotation(node, isTypeExpression: true);
return resolveTypeAnnotation(node);
}
DartType resolveTypeAnnotation(TypeAnnotation node,
{bool isTypeExpression: false}) {
DartType type = typeResolver.resolveTypeAnnotation(
this, node, ambiguousIsError: isTypeExpression);
DartType resolveTypeAnnotation(TypeAnnotation node) {
DartType type = typeResolver.resolveTypeAnnotation(this, node);
if (type == null) return null;
if (inCheckContext) {
compiler.enqueuer.resolution.registerIsCheck(type, mapping);
@@ -2770,21 +2770,12 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
bool isNot = node.isIsNotCheck;
DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
type = type.unalias(compiler);
if (type.containsAmbiguousTypes) {
String reasons = Types.fetchReasonsFromAmbiguousType(type);
if (compiler.enableTypeAssertions) {
generateMalformedSubtypeError(node, expression, type, reasons);
} else {
generateRuntimeError(node, '$type is ambiguous: $reasons');
}
} else {
HInstruction instruction = buildIsNode(node, type, expression);
if (isNot) {
add(instruction);
instruction = new HNot(instruction);
}
push(instruction);
HInstruction instruction = buildIsNode(node, type, expression);
if (isNot) {
add(instruction);
instruction = new HNot(instruction);
}
push(instruction);
}
HLiteralList buildTypeVariableList(ClassElement contextClass) {
@@ -3409,11 +3400,6 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
}
}
/**
* Documentation wanted -- johnniwinther
*
* Invariant: [argument] must not be malformed in checked mode.
*/
HInstruction analyzeTypeArgument(DartType argument) {
if (argument.treatAsDynamic) {
// Represent [dynamic] as [null].
@@ -3464,11 +3450,6 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
pop();
}
/**
* Documentation wanted -- johnniwinther
*
* Invariant: [type] must not be malformed in checked mode.
*/
handleNewSend(NewExpression node, InterfaceType type) {
Send send = node.send;
bool isListConstructor = false;
@@ -3745,14 +3726,6 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
existingArguments: existingArguments);
}
void generateMalformedSubtypeError(Node node, HInstruction value,
DartType type, String reasons) {
HInstruction typeString = addConstantString(node, type.toString());
HInstruction reasonsString = addConstantString(node, reasons);
Element helper = backend.getThrowMalformedSubtypeError();
pushInvokeStatic(node, helper, [value, typeString, reasonsString]);
}
visitNewExpression(NewExpression node) {
Element element = elements[node.send];
final bool isSymbolConstructor = element == compiler.symbolConstructor;
@@ -3782,16 +3755,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
}
} else {
DartType type = elements.getType(node);
if (compiler.enableTypeAssertions && type.containsAmbiguousTypes) {
String reasons = Types.fetchReasonsFromAmbiguousType(type);
// TODO(johnniwinther): Change to resemble type errors from bounds check
// on type arguments.
generateRuntimeError(node, '$type is malformed: $reasons');
} else {
// TODO(karlklose): move this type registration to the codegen.
compiler.codegenWorld.instantiatedTypes.add(type);
handleNewSend(node, type);
}
// TODO(karlklose): move this type registration to the codegen.
compiler.codegenWorld.instantiatedTypes.add(type);
handleNewSend(node, type);
}
}
@@ -4952,21 +4918,6 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
void visitThen() {
CatchBlock catchBlock = link.head;
link = link.tail;
if (compiler.enableTypeAssertions) {
// In checked mode: throw a type error if the on-catch type is
// malformed.
if (catchBlock.onKeyword != null) {
DartType type = elements.getType(catchBlock.type);
if (type != null && type.containsAmbiguousTypes) {
String reasons = Types.fetchReasonsFromAmbiguousType(type);
generateMalformedSubtypeError(node,
unwrappedException, type, reasons);
pop();
return;
}
}
}
if (catchBlock.exception != null) {
localsHandler.updateLocal(elements[catchBlock.exception],
unwrappedException);
@@ -1117,9 +1117,6 @@ abstract class HInstruction implements Spannable {
// available.
assert(type.kind != TypeKind.TYPE_VARIABLE);
assert(type.isRaw || type.kind == TypeKind.FUNCTION);
if (type.containsAmbiguousTypes) {
return new HTypeConversion(type, kind, HType.UNKNOWN, this);
}
if (type.treatAsDynamic) return this;
if (identical(type.element, compiler.objectClass)) return this;
if (type.kind != TypeKind.INTERFACE) {
-37
View File
@@ -802,14 +802,6 @@ throwRuntimeError(message) {
throw new RuntimeError(message);
}
/**
* The SSA builder generates a call to this method when a malformed type is used
* in a subtype test.
*/
throwMalformedSubtypeError(value, type, reasons) {
throw new TypeErrorImplementation.malformedSubtype(value, type, reasons);
}
throwAbstractClassInstantiationError(className) {
throw new AbstractClassInstantiationError(className);
}
@@ -1801,16 +1793,6 @@ voidTypeCheck(value) {
throw new TypeErrorImplementation(value, 'void');
}
malformedTypeCheck(value, type, reasons) {
if (value == null) return value;
throwMalformedSubtypeError(value, type, reasons);
}
malformedTypeCast(value, type, reasons) {
if (value == null) return value;
throw new CastErrorImplementation.malformedTypeCast(value, type, reasons);
}
/**
* Special interface recognized by the compiler and implemented by DOM
* objects that support integer indexing. This interface is not
@@ -1833,14 +1815,6 @@ class TypeErrorImplementation implements TypeError {
: message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
"of type '$type'";
/**
* Type error caused by a subtype test on a malformed type.
*/
TypeErrorImplementation.malformedSubtype(Object value,
String type, String reasons)
: message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
"of type '$type' because '$type' is malformed: $reasons.";
String toString() => message;
}
@@ -1856,17 +1830,6 @@ class CastErrorImplementation implements CastError {
: message = "CastError: Casting value of type $actualType to"
" incompatible type $expectedType";
/**
* Cast error caused by a type cast to a malformed type.
*/
CastErrorImplementation.malformedTypeCast(Object value,
String type, String reasons)
: message = "CastError: Type '${Primitives.objectTypeName(value)}' "
"cannot be cast to type '$type' because '$type' is "
"malformed: $reasons.";
String toString() => message;
}
+11
View File
@@ -558,6 +558,15 @@ Language/11_Expressions/11_Instance_Creation_A04_t02: Fail # co19 issue 466
Language/11_Expressions/11_Instance_Creation_A04_t03: Fail # co19 issue 466
Language/11_Expressions/11_Instance_Creation_A04_t04: Fail # co19 issue 466
Language/13_Libraries_and_Scripts/1_Imports_A03_t02: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t05: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t22: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t25: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t42: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t45: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t62: Fail # 481
Language/13_Libraries_and_Scripts/1_Imports_A03_t65: Fail # 481
[ $compiler == dart2js && $checked ]
Language/03_Overview/1_Scoping_A02_t30: Fail # co19 issue 463
@@ -567,6 +576,8 @@ Language/11_Expressions/32_Type_Cast_A05_t02: Fail # co19 issue 463
Language/11_Expressions/32_Type_Cast_A05_t04: Fail # co19 issue 463
Language/14_Types/8_Parameterized_Types_A02_t01: Fail # co19 issue 463
Language/13_Libraries_and_Scripts/1_Imports_A03_t31: Fail # 481
[ $compiler == dart2js && $unchecked ]
LibTest/core/List/setRange_A05_t01: Fail # setRange throws StateError if there aren't enough elements in the iterable. Issue 402
+2
View File
@@ -20,6 +20,7 @@ mixin_super_constructor_named_test: Fail
mixin_super_constructor_positionals_test: Fail
function_type_alias6_test/00: Fail # Issue 11986
function_type_alias9_test/00: Crash # Issue 11986
library_ambiguous_test/04: Fail # Issue 12105
[ $compiler == none ]
mixin_super_constructor_named_test: Fail
@@ -28,6 +29,7 @@ built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
library_juxtaposition_test: Fail # Issue 6877
pseudo_kw_illegal_test/14: Fail # Issue 356
bound_closure_equality_test: Fail # Issue 10849
library_ambiguous_test/04: Fail # Issue 12105
# These bugs refer currently ongoing language discussions.
constructor5_test: Fail # (Discussion ongoing)
+2
View File
@@ -275,6 +275,8 @@ getter_no_setter_test/none: fail
const_constructor_mixin_test/01: fail
const_constructor_mixin3_test/01: fail
library_ambiguous_test/04: Fail # Issue 12106
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
+1 -1
View File
@@ -17,7 +17,7 @@ main() {
print(bar()); /// 01: compile-time error
print(baz()); /// 02: compile-time error
print(bay()); /// 03: compile-time error
print(main is bax); /// 04: compile-time error
print(main is bax); /// 04: static type warning
var x = new X(); /// 05: continued
print("No error expected if ambiguous definitions are not used.");
}