Index: sdk/lib/_internal/compiler/implementation/typechecker.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/typechecker.dart (revision 22847) |
+++ sdk/lib/_internal/compiler/implementation/typechecker.dart (working copy) |
@@ -18,22 +18,6 @@ |
} |
/** |
- * Class used to report different warnings for differrent kinds of members. |
- */ |
-class MemberKind { |
- static const MemberKind METHOD = const MemberKind("method"); |
- static const MemberKind OPERATOR = const MemberKind("operator"); |
- static const MemberKind PROPERTY = const MemberKind("property"); |
- |
- final String name; |
- |
- const MemberKind(this.name); |
- |
- String toString() => name; |
-} |
- |
- |
-/** |
* [ElementAccess] represents the access of [element], either as a property |
* access or invocation. |
*/ |
@@ -65,8 +49,6 @@ |
Element get element => member.element; |
DartType computeType(Compiler compiler) => member.computeType(compiler); |
- |
- String toString() => 'MemberAccess($member)'; |
} |
/// An access of an unresolved element. |
@@ -78,8 +60,6 @@ |
DartType computeType(Compiler compiler) => compiler.types.dynamicType; |
bool isCallable(Compiler compiler) => true; |
- |
- String toString() => 'DynamicAccess'; |
} |
/** |
@@ -93,19 +73,7 @@ |
assert(element != null); |
} |
- DartType computeType(Compiler compiler) { |
- if (element.isGetter()) { |
- FunctionType functionType = element.computeType(compiler); |
- return functionType.returnType; |
- } else if (element.isSetter()) { |
- FunctionType functionType = element.computeType(compiler); |
- return functionType.parameterTypes.head; |
- } else { |
- return element.computeType(compiler); |
- } |
- } |
- |
- String toString() => 'ResolvedAccess($element)'; |
+ DartType computeType(Compiler compiler) => element.computeType(compiler); |
} |
/** |
@@ -121,25 +89,8 @@ |
Element get element => type.element; |
DartType computeType(Compiler compiler) => type; |
- |
- String toString() => 'TypeAccess($type)'; |
} |
-/** |
- * An access of a type literal. |
- */ |
-class TypeLiteralAccess extends ElementAccess { |
- final Element element; |
- TypeLiteralAccess(Element this.element) { |
- assert(element != null); |
- } |
- |
- DartType computeType(Compiler compiler) => |
- compiler.typeClass.computeType(compiler); |
- |
- String toString() => 'TypeLiteralAccess($element)'; |
-} |
- |
class TypeCheckerVisitor implements Visitor<DartType> { |
final Compiler compiler; |
final TreeElements elements; |
@@ -147,7 +98,7 @@ |
Node lastSeenNode; |
DartType expectedReturnType; |
- final ClassElement currentClass; |
+ ClassElement currentClass; |
Link<DartType> cascadeTypes = const Link<DartType>(); |
@@ -158,10 +109,7 @@ |
DartType objectType; |
DartType listType; |
- TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) |
- : this.elements = elements, |
- currentClass = elements.currentElement != null |
- ? elements.currentElement.getEnclosingClass() : null { |
+ TypeCheckerVisitor(this.compiler, this.elements, this.types) { |
intType = compiler.intClass.computeType(compiler); |
doubleType = compiler.doubleClass.computeType(compiler); |
boolType = compiler.boolClass.computeType(compiler); |
@@ -174,11 +122,6 @@ |
compiler.reportWarning(node, new TypeWarning(kind, arguments)); |
} |
- reportTypeInfo(Spannable node, MessageKind kind, [Map arguments = const {}]) { |
- compiler.reportDiagnostic(compiler.spanFromSpannable(node), |
- 'Info: ${kind.message(arguments)}', api.Diagnostic.INFO); |
- } |
- |
// TODO(karlklose): remove these functions. |
DartType unhandledStatement() => StatementType.NOT_RETURNING; |
DartType unhandledExpression() => types.dynamicType; |
@@ -217,17 +160,15 @@ |
* Check if a value of type t can be assigned to a variable, |
* parameter or return value of type s. |
*/ |
- bool checkAssignable(Node node, DartType from, DartType to) { |
- if (!types.isAssignable(from, to)) { |
+ checkAssignable(Node node, DartType s, DartType t) { |
+ if (!types.isAssignable(s, t)) { |
reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, |
- {'fromType': from, 'toType': to}); |
- return false; |
+ {'fromType': s, 'toType': t}); |
} |
- return true; |
} |
checkCondition(Expression condition) { |
- checkAssignable(condition, analyze(condition), boolType); |
+ checkAssignable(condition, boolType, analyze(condition)); |
} |
void pushCascadeType(DartType type) { |
@@ -319,6 +260,7 @@ |
} |
DartType previous = expectedReturnType; |
expectedReturnType = returnType; |
+ if (element.isMember()) currentClass = element.getEnclosingClass(); |
StatementType bodyType = analyze(node.body); |
if (returnType != types.voidType && returnType != types.dynamicType |
&& bodyType != StatementType.RETURNING) { |
@@ -355,8 +297,7 @@ |
return unhandledStatement(); |
} |
- ElementAccess lookupMember(Node node, DartType type, SourceString name, |
- MemberKind memberKind) { |
+ ElementAccess lookupMethod(Node node, DartType type, SourceString name) { |
if (identical(type, types.dynamicType)) { |
return const DynamicAccess(); |
} |
@@ -364,35 +305,17 @@ |
if (member != null) { |
return new MemberAccess(member); |
} |
- switch (memberKind) { |
- case MemberKind.METHOD: |
- reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
- {'className': type.name, 'memberName': name}); |
- break; |
- case MemberKind.OPERATOR: |
- reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND, |
- {'className': type.name, 'memberName': name}); |
- break; |
- case MemberKind.PROPERTY: |
- reportTypeWarning(node, MessageKind.PROPERTY_NOT_FOUND, |
- {'className': type.name, 'memberName': name}); |
- break; |
- } |
+ reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
+ {'className': type.name, 'memberName': name}); |
return const DynamicAccess(); |
} |
- DartType lookupMemberType(Node node, DartType type, SourceString name, |
- MemberKind memberKind) { |
- return lookupMember(node, type, name, memberKind).computeType(compiler); |
- } |
- |
- void analyzeArguments(Send send, Element element, DartType type, |
- [LinkBuilder<DartType> argumentTypes]) { |
+ // TODO(johnniwinther): Provide the element from which the type came in order |
+ // to give better error messages. |
+ void analyzeArguments(Send send, DartType type) { |
Link<Node> arguments = send.arguments; |
DartType unaliasedType = type.unalias(compiler); |
if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { |
- assert(invariant(send, element != null, message: 'No element for $send')); |
- bool error = false; |
FunctionType funType = unaliasedType; |
Link<DartType> parameterTypes = funType.parameterTypes; |
Link<DartType> optionalParameterTypes = funType.optionalParameterTypes; |
@@ -405,80 +328,57 @@ |
DartType namedParameterType = |
funType.getNamedParameterType(argumentName); |
if (namedParameterType == null) { |
- error = true; |
// TODO(johnniwinther): Provide better information on the called |
// function. |
reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND, |
{'argumentName': argumentName}); |
- DartType argumentType = analyze(argument); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
+ analyze(argument); |
} else { |
- DartType argumentType = analyze(argument); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, argumentType, namedParameterType)) { |
- error = true; |
- } |
+ checkAssignable(argument, namedParameterType, analyze(argument)); |
} |
} else { |
if (parameterTypes.isEmpty) { |
if (optionalParameterTypes.isEmpty) { |
- error = true; |
// TODO(johnniwinther): Provide better information on the |
// called function. |
reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT); |
- DartType argumentType = analyze(argument); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
+ analyze(argument); |
} else { |
- DartType argumentType = analyze(argument); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, |
- argumentType, optionalParameterTypes.head)) { |
- error = true; |
- } |
+ checkAssignable(argument, optionalParameterTypes.head, |
+ analyze(argument)); |
optionalParameterTypes = optionalParameterTypes.tail; |
} |
} else { |
- DartType argumentType = analyze(argument); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, argumentType, parameterTypes.head)) { |
- error = true; |
- } |
+ checkAssignable(argument, parameterTypes.head, analyze(argument)); |
parameterTypes = parameterTypes.tail; |
} |
} |
arguments = arguments.tail; |
} |
if (!parameterTypes.isEmpty) { |
- error = true; |
// TODO(johnniwinther): Provide better information on the called |
// function. |
reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, |
{'argumentType': parameterTypes.head}); |
} |
- if (error) { |
- reportTypeInfo(element, MessageKind.THIS_IS_THE_METHOD); |
- } |
} else { |
while(!arguments.isEmpty) { |
- DartType argumentType = analyze(arguments.head); |
- if (argumentTypes != null) argumentTypes.addLast(argumentType); |
+ analyze(arguments.head); |
arguments = arguments.tail; |
} |
} |
} |
- DartType analyzeInvocation(Send node, ElementAccess elementAccess, |
- [LinkBuilder<DartType> argumentTypes]) { |
+ DartType analyzeInvocation(Send node, ElementAccess elementAccess) { |
DartType type = elementAccess.computeType(compiler); |
if (elementAccess.isCallable(compiler)) { |
- analyzeArguments(node, elementAccess.element, type, argumentTypes); |
+ analyzeArguments(node, type); |
} else { |
reportTypeWarning(node, MessageKind.NOT_CALLABLE, |
{'elementName': elementAccess.element.name}); |
- analyzeArguments(node, elementAccess.element, types.dynamicType, |
- argumentTypes); |
+ analyzeArguments(node, types.dynamicType); |
} |
if (identical(type.kind, TypeKind.FUNCTION)) { |
FunctionType funType = type; |
@@ -488,104 +388,6 @@ |
} |
} |
- /** |
- * Computes the [ElementAccess] for [name] on the [node] possibly using the |
- * [element] provided for [node] by the resolver. |
- */ |
- ElementAccess computeAccess(Send node, SourceString name, Element element, |
- MemberKind memberKind) { |
- if (node.receiver != null) { |
- Element receiverElement = elements[node.receiver]; |
- if (receiverElement != null) { |
- if (receiverElement.isPrefix()) { |
- assert(invariant(node, element != null, |
- message: 'Prefixed node has no element.')); |
- return computeResolvedAccess(node, name, element, memberKind); |
- } |
- } |
- // e.foo() for some expression e. |
- DartType receiverType = analyze(node.receiver); |
- if (receiverType.isDynamic || |
- receiverType.isMalformed || |
- receiverType.isVoid) { |
- return const DynamicAccess(); |
- } |
- TypeKind receiverKind = receiverType.kind; |
- if (identical(receiverKind, TypeKind.TYPEDEF)) { |
- // TODO(johnniwinther): handle typedefs. |
- return const DynamicAccess(); |
- } |
- if (identical(receiverKind, TypeKind.FUNCTION)) { |
- // TODO(johnniwinther): handle functions. |
- return const DynamicAccess(); |
- } |
- if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) { |
- // TODO(johnniwinther): handle type variables. |
- return const DynamicAccess(); |
- } |
- assert(invariant(node.receiver, |
- identical(receiverKind, TypeKind.INTERFACE), |
- message: "interface type expected, got ${receiverKind}")); |
- return lookupMember(node, receiverType, name, memberKind); |
- } else { |
- return computeResolvedAccess(node, name, element, memberKind); |
- } |
- } |
- |
- /** |
- * Computes the [ElementAccess] for [name] on the [node] using the [element] |
- * provided for [node] by the resolver. |
- */ |
- ElementAccess computeResolvedAccess(Send node, SourceString name, |
- Element element, MemberKind memberKind) { |
- if (Elements.isUnresolved(element)) { |
- // foo() where foo is unresolved. |
- return const DynamicAccess(); |
- } else if (element.isMember()) { |
- // foo() where foo is an instance member. |
- return lookupMember(node, currentClass.computeType(compiler), |
- name, memberKind); |
- } else if (element.isFunction()) { |
- // foo() where foo is a method in the same class. |
- return new ResolvedAccess(element); |
- } else if (element.isVariable() || |
- element.isParameter() || |
- element.isField()) { |
- // foo() where foo is a field in the same class. |
- return new ResolvedAccess(element); |
- } else if (element.impliesType()) { |
- // The literal `Foo` where Foo is a class, a typedef, or a type variable. |
- if (elements.getType(node) != null) { |
- assert(invariant(node, identical(compiler.typeClass, |
- elements.getType(node).element), |
- message: 'Expected type literal type: ' |
- '${elements.getType(node)}')); |
- return new TypeLiteralAccess(element); |
- } |
- return new ResolvedAccess(element); |
- } else if (element.isGetter() || element.isSetter()) { |
- return new ResolvedAccess(element); |
- } else { |
- compiler.internalErrorOnElement( |
- element, 'unexpected element kind ${element.kind}'); |
- } |
- } |
- |
- /** |
- * Computes the type of the access of [name] on the [node] possibly using the |
- * [element] provided for [node] by the resolver. |
- */ |
- DartType computeAccessType(Send node, SourceString name, Element element, |
- MemberKind memberKind) { |
- DartType type = |
- computeAccess(node, name, element, memberKind).computeType(compiler); |
- if (type == null) { |
- compiler.internalError('type is null on access of $name on $node', |
- node: node); |
- } |
- return type; |
- } |
- |
DartType visitSend(Send node) { |
Element element = elements[node]; |
@@ -606,252 +408,117 @@ |
if (node.isOperator && identical(name, 'is')) { |
analyze(node.receiver); |
return boolType; |
- } if (node.isOperator && identical(name, 'as')) { |
- analyze(node.receiver); |
- return elements.getType(node.arguments.head); |
} else if (node.isOperator) { |
- final Node receiver = node.receiver; |
- final DartType receiverType = analyze(receiver); |
- if (identical(name, '==') || identical(name, '!=') |
- // TODO(johnniwinther): Remove these. |
- || identical(name, '===') || identical(name, '!==')) { |
- // Analyze argument. |
- analyze(node.arguments.head); |
+ final Node firstArgument = node.receiver; |
+ final DartType firstArgumentType = analyze(node.receiver); |
+ final arguments = node.arguments; |
+ final Node secondArgument = arguments.isEmpty ? null : arguments.head; |
+ final DartType secondArgumentType = |
+ analyzeWithDefault(secondArgument, null); |
+ |
+ if (identical(name, '+') || identical(name, '=') || |
+ identical(name, '-') || identical(name, '*') || |
+ identical(name, '/') || identical(name, '%') || |
+ identical(name, '~/') || identical(name, '|') || |
+ identical(name, '&') || identical(name, '^') || |
+ identical(name, '~')|| identical(name, '<<') || |
+ identical(name, '>>') || identical(name, '[]')) { |
+ return types.dynamicType; |
+ } else if (identical(name, '<') || identical(name, '>') || |
+ identical(name, '<=') || identical(name, '>=') || |
+ identical(name, '==') || identical(name, '!=') || |
+ identical(name, '===') || identical(name, '!==')) { |
return boolType; |
} else if (identical(name, '||') || |
- identical(name, '&&')) { |
- checkAssignable(receiver, receiverType, boolType); |
- final Node argument = node.arguments.head; |
- final DartType argumentType = analyze(argument); |
- checkAssignable(argument, argumentType, boolType); |
+ identical(name, '&&') || |
+ identical(name, '!')) { |
+ checkAssignable(firstArgument, boolType, firstArgumentType); |
+ if (!arguments.isEmpty) { |
+ // TODO(karlklose): check number of arguments in validator. |
+ checkAssignable(secondArgument, boolType, secondArgumentType); |
+ } |
return boolType; |
- } else if (identical(name, '!')) { |
- checkAssignable(receiver, receiverType, boolType); |
- return boolType; |
- } else if (identical(name, '?')) { |
- return boolType; |
+ } else { |
+ return unhandledExpression(); |
} |
- SourceString operatorName = selector.source; |
- if (identical(name, '-') && node.arguments.isEmpty) { |
- operatorName = const SourceString('unary-'); |
- } |
- assert(invariant(node, |
- identical(name, '+') || identical(name, '=') || |
- identical(name, '-') || identical(name, '*') || |
- identical(name, '/') || identical(name, '%') || |
- identical(name, '~/') || identical(name, '|') || |
- identical(name, '&') || identical(name, '^') || |
- identical(name, '~')|| identical(name, '<<') || |
- identical(name, '>>') || |
- identical(name, '<') || identical(name, '>') || |
- identical(name, '<=') || identical(name, '>=') || |
- identical(name, '[]'), |
- message: 'Unexpected operator $name')); |
- ElementAccess access = lookupMember(node, receiverType, |
- operatorName, MemberKind.OPERATOR); |
- LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>(); |
- DartType resultType = |
- analyzeInvocation(node, access, argumentTypesBuilder); |
- if (identical(receiverType.element, compiler.intClass)) { |
- if (identical(name, '+') || |
- identical(operatorName, const SourceString('-')) || |
- identical(name, '*') || |
- identical(name, '%')) { |
- DartType argumentType = argumentTypesBuilder.toLink().head; |
- if (identical(argumentType.element, compiler.intClass)) { |
- return intType; |
- } else if (identical(argumentType.element, compiler.doubleClass)) { |
- return doubleType; |
- } |
- } |
- } |
- return resultType; |
} else if (node.isPropertyAccess) { |
- ElementAccess access = |
- computeAccess(node, selector.source, element, MemberKind.PROPERTY); |
- return access.computeType(compiler); |
+ if (node.receiver != null) { |
+ // TODO(karlklose): we cannot handle fields. |
+ return unhandledExpression(); |
+ } |
+ if (element == null) return types.dynamicType; |
+ return computeType(element); |
+ |
} else if (node.isFunctionObjectInvocation) { |
return unhandledExpression(); |
} else { |
- ElementAccess access = |
- computeAccess(node, selector.source, element, MemberKind.METHOD); |
- return analyzeInvocation(node, access); |
- } |
- } |
- |
- /** |
- * Checks [: target o= value :] for some operator o, and returns the type |
- * of the result. This method also handles increment/decrement expressions |
- * like [: target++ :]. |
- */ |
- DartType checkAssignmentOperator(SendSet node, |
- SourceString operatorName, |
- Node valueNode, |
- DartType value) { |
- assert(invariant(node, !node.isIndex)); |
- Element element = elements[node]; |
- Identifier selector = node.selector; |
- DartType target = |
- computeAccessType(node, selector.source, element, MemberKind.PROPERTY); |
- // [operator] is the type of operator+ or operator- on [target]. |
- DartType operator = |
- lookupMemberType(node, target, operatorName, MemberKind.OPERATOR); |
- if (operator is FunctionType) { |
- FunctionType operatorType = operator; |
- // [result] is the type of target o value. |
- DartType result = operatorType.returnType; |
- DartType operatorArgument = operatorType.parameterTypes.head; |
- // Check target o value. |
- bool validValue = checkAssignable(valueNode, value, operatorArgument); |
- if (validValue || !(node.isPrefix || node.isPostfix)) { |
- // Check target = result. |
- checkAssignable(node.assignmentOperator, result, target); |
- } |
- return node.isPostfix ? target : result; |
- } |
- return types.dynamicType; |
- } |
- |
- /** |
- * Checks [: base[key] o= value :] for some operator o, and returns the type |
- * of the result. This method also handles increment/decrement expressions |
- * like [: base[key]++ :]. |
- */ |
- DartType checkIndexAssignmentOperator(SendSet node, |
- SourceString operatorName, |
- Node valueNode, |
- DartType value) { |
- assert(invariant(node, node.isIndex)); |
- final DartType base = analyze(node.receiver); |
- final Node keyNode = node.arguments.head; |
- final DartType key = analyze(keyNode); |
- |
- // [indexGet] is the type of operator[] on [base]. |
- DartType indexGet = lookupMemberType( |
- node, base, const SourceString('[]'), MemberKind.OPERATOR); |
- if (indexGet is FunctionType) { |
- FunctionType indexGetType = indexGet; |
- DartType indexGetKey = indexGetType.parameterTypes.head; |
- // Check base[key]. |
- bool validKey = checkAssignable(keyNode, key, indexGetKey); |
- |
- // [element] is the type of base[key]. |
- DartType element = indexGetType.returnType; |
- // [operator] is the type of operator o on [element]. |
- DartType operator = lookupMemberType( |
- node, element, operatorName, MemberKind.OPERATOR); |
- if (operator is FunctionType) { |
- FunctionType operatorType = operator; |
- |
- // Check base[key] o value. |
- DartType operatorArgument = operatorType.parameterTypes.head; |
- bool validValue = checkAssignable(valueNode, value, operatorArgument); |
- |
- // [result] is the type of base[key] o value. |
- DartType result = operatorType.returnType; |
- |
- // [indexSet] is the type of operator[]= on [base]. |
- DartType indexSet = lookupMemberType( |
- node, base, const SourceString('[]='), MemberKind.OPERATOR); |
- if (indexSet is FunctionType) { |
- FunctionType indexSetType = indexSet; |
- DartType indexSetKey = indexSetType.parameterTypes.head; |
- DartType indexSetValue = |
- indexSetType.parameterTypes.tail.head; |
- |
- if (validKey || indexGetKey != indexSetKey) { |
- // Only check base[key] on []= if base[key] was valid for [] or |
- // if the key types differ. |
- checkAssignable(keyNode, key, indexSetKey); |
+ ElementAccess computeMethod() { |
+ if (node.receiver != null) { |
+ // e.foo() for some expression e. |
+ DartType receiverType = analyze(node.receiver); |
+ if (receiverType.element == compiler.dynamicClass || |
+ receiverType == null || |
+ receiverType.isMalformed || |
+ receiverType.isVoid) { |
+ return const DynamicAccess(); |
} |
- // Check base[key] = result |
- if (validValue || !(node.isPrefix || node.isPostfix)) { |
- checkAssignable(node.assignmentOperator, result, indexSetValue); |
+ TypeKind receiverKind = receiverType.kind; |
+ if (identical(receiverKind, TypeKind.TYPEDEF)) { |
+ // TODO(karlklose): handle typedefs. |
+ return const DynamicAccess(); |
} |
+ if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) { |
+ // TODO(karlklose): handle type variables. |
+ return const DynamicAccess(); |
+ } |
+ if (identical(receiverKind, TypeKind.FUNCTION)) { |
+ // TODO(karlklose): handle getters. |
+ return const DynamicAccess(); |
+ } |
+ assert(invariant(node.receiver, |
+ identical(receiverKind, TypeKind.INTERFACE), |
+ message: "interface type expected, got ${receiverKind}")); |
+ return lookupMethod(selector, receiverType, selector.source); |
+ } else { |
+ if (Elements.isUnresolved(element)) { |
+ // foo() where foo is unresolved. |
+ return const DynamicAccess(); |
+ } else if (element.isFunction()) { |
+ // foo() where foo is a method in the same class. |
+ return new ResolvedAccess(element); |
+ } else if (element.isVariable() || element.isField()) { |
+ // foo() where foo is a field in the same class. |
+ return new ResolvedAccess(element); |
+ } else if (element.isGetter()) { |
+ // TODO(karlklose): handle getters. |
+ return const DynamicAccess(); |
+ } else if (element.isClass()) { |
+ // TODO(karlklose): handle type literals. |
+ return const DynamicAccess(); |
+ } else { |
+ compiler.internalErrorOnElement( |
+ element, 'unexpected element kind ${element.kind}'); |
+ } |
} |
- return node.isPostfix ? element : result; |
} |
+ return analyzeInvocation(node, computeMethod()); |
} |
- return types.dynamicType; |
} |
visitSendSet(SendSet node) { |
- Element element = elements[node]; |
Identifier selector = node.selector; |
final name = node.assignmentOperator.source.stringValue; |
- if (identical(name, '=')) { |
- // e1 = value |
- if (node.isIndex) { |
- // base[key] = value |
- final DartType base = analyze(node.receiver); |
- final Node keyNode = node.arguments.head; |
- final DartType key = analyze(keyNode); |
- final Node valueNode = node.arguments.tail.head; |
- final DartType value = analyze(valueNode); |
- DartType indexSet = lookupMemberType( |
- node, base, const SourceString('[]='), MemberKind.OPERATOR); |
- if (indexSet is FunctionType) { |
- FunctionType indexSetType = indexSet; |
- DartType indexSetKey = indexSetType.parameterTypes.head; |
- checkAssignable(keyNode, key, indexSetKey); |
- DartType indexSetValue = indexSetType.parameterTypes.tail.head; |
- checkAssignable(node.assignmentOperator, value, indexSetValue); |
- } |
- return value; |
- } else { |
- // target = value |
- DartType target = computeAccessType(node, selector.source, |
- element, MemberKind.PROPERTY); |
- final Node valueNode = node.arguments.head; |
- final DartType value = analyze(valueNode); |
- checkAssignable(node.assignmentOperator, value, target); |
- return value; |
- } |
- } else if (identical(name, '++') || identical(name, '--')) { |
- // e++ or e-- |
- SourceString operatorName = identical(name, '++') |
- ? const SourceString('+') : const SourceString('-'); |
- if (node.isIndex) { |
- // base[key]++, base[key]--, ++base[key], or --base[key] |
- return checkIndexAssignmentOperator( |
- node, operatorName, node.assignmentOperator, intType); |
- } else { |
- // target++, target--, ++target, or --target |
- return checkAssignmentOperator( |
- node, operatorName, node.assignmentOperator, intType); |
- } |
+ if (identical(name, '++') || identical(name, '--')) { |
+ final Element element = elements[node.selector]; |
+ final DartType receiverType = computeType(element); |
+ // TODO(karlklose): this should be the return type instead of int. |
+ return node.isPrefix ? intType : receiverType; |
} else { |
- // e1 o= e2 for some operator o. |
- SourceString operatorName; |
- switch (name) { |
- case '+=': operatorName = const SourceString('+'); break; |
- case '-=': operatorName = const SourceString('-'); break; |
- case '*=': operatorName = const SourceString('*'); break; |
- case '/=': operatorName = const SourceString('/'); break; |
- case '%=': operatorName = const SourceString('%'); break; |
- case '~/=': operatorName = const SourceString('~/'); break; |
- case '&=': operatorName = const SourceString('&'); break; |
- case '|=': operatorName = const SourceString('|'); break; |
- case '^=': operatorName = const SourceString('^'); break; |
- case '<<=': operatorName = const SourceString('<<'); break; |
- case '>>=': operatorName = const SourceString('>>'); break; |
- default: |
- compiler.internalError( |
- 'Unexpected assignment operator $name', node: node); |
- } |
- if (node.isIndex) { |
- // base[key] o= value for some operator o. |
- final Node valueNode = node.arguments.tail.head; |
- final DartType value = analyze(valueNode); |
- return checkIndexAssignmentOperator( |
- node, operatorName, valueNode, value); |
- } else { |
- // target o= value for some operator o. |
- final Node valueNode = node.arguments.head; |
- final DartType value = analyze(valueNode); |
- return checkAssignmentOperator(node, operatorName, valueNode, value); |
- } |
+ DartType targetType = computeType(elements[node]); |
+ Node value = node.arguments.head; |
+ checkAssignable(value, targetType, analyze(value)); |
+ return targetType; |
} |
} |
@@ -883,30 +550,11 @@ |
DartType visitNewExpression(NewExpression node) { |
Element element = elements[node.send]; |
- DartType constructorType = computeType(element); |
- DartType newType = elements.getType(node); |
- // TODO(johnniwinther): Use [:lookupMember:] to account for type variable |
- // substitution of parameter types. |
- if (identical(newType.kind, TypeKind.INTERFACE)) { |
- InterfaceType newInterfaceType = newType; |
- constructorType = constructorType.subst( |
- newInterfaceType.typeArguments, |
- newInterfaceType.element.typeVariables); |
- } |
- analyzeArguments(node.send, element, constructorType); |
- return newType; |
+ analyzeArguments(node.send, computeType(element)); |
+ return analyze(node.send.selector); |
} |
DartType visitLiteralList(LiteralList node) { |
- InterfaceType listType = elements.getType(node); |
- DartType listElementType = listType.typeArguments.head; |
- for (Link<Node> link = node.elements.nodes; |
- !link.isEmpty; |
- link = link.tail) { |
- Node element = link.head; |
- DartType elementType = analyze(element); |
- checkAssignable(element, elementType, listElementType); |
- } |
return listType; |
} |
@@ -962,7 +610,7 @@ |
&& !types.isAssignable(expressionType, types.voidType)) { |
reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID); |
} else { |
- checkAssignable(expression, expressionType, expectedReturnType); |
+ checkAssignable(expression, expectedReturnType, expressionType); |
} |
// Let f be the function immediately enclosing a return statement of the |
@@ -982,7 +630,6 @@ |
return types.dynamicType; |
} |
- // TODO(johnniwinther): Remove this. |
DartType computeType(Element element) { |
if (Elements.isUnresolved(element)) return types.dynamicType; |
DartType result = element.computeType(compiler); |
@@ -1005,12 +652,12 @@ |
} |
for (Link<Node> link = node.definitions.nodes; !link.isEmpty; |
link = link.tail) { |
- Node definition = link.head; |
- compiler.ensure(definition is Identifier || definition is SendSet); |
- if (definition is Send) { |
- SendSet initialization = definition; |
- DartType initializer = analyzeNonVoid(initialization.arguments.head); |
- checkAssignable(initialization.assignmentOperator, initializer, type); |
+ Node initialization = link.head; |
+ compiler.ensure(initialization is Identifier |
+ || initialization is Send); |
+ if (initialization is Send) { |
+ DartType initializer = analyzeNonVoid(link.head); |
+ checkAssignable(node, type, initializer); |
} |
} |
return StatementType.NOT_RETURNING; |
@@ -1086,19 +733,7 @@ |
} |
visitLiteralMap(LiteralMap node) { |
- InterfaceType mapType = elements.getType(node); |
- DartType mapKeyType = mapType.typeArguments.head; |
- DartType mapValueType = mapType.typeArguments.tail.head; |
- for (Link<Node> link = node.entries.nodes; |
- !link.isEmpty; |
- link = link.tail) { |
- LiteralMapEntry entry = link.head; |
- DartType keyType = analyze(entry.key); |
- checkAssignable(entry.key, keyType, mapKeyType); |
- DartType valueType = analyze(entry.value); |
- checkAssignable(entry.value, valueType, mapValueType); |
- } |
- return mapType; |
+ return unhandledExpression(); |
} |
visitLiteralMapEntry(LiteralMapEntry node) { |