| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class TypeCheckerTask extends CompilerTask { | 5 class TypeCheckerTask extends CompilerTask { |
| 6 TypeCheckerTask(Compiler compiler) : super(compiler); | 6 TypeCheckerTask(Compiler compiler) : super(compiler); |
| 7 String get name() => "Type checker"; | 7 String get name() => "Type checker"; |
| 8 | 8 |
| 9 static final bool LOG_FAILURES = false; | 9 static final bool LOG_FAILURES = false; |
| 10 | 10 |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 Type visitLoop(Loop node) { | 336 Type visitLoop(Loop node) { |
| 337 fail(node, 'internal error'); | 337 fail(node, 'internal error'); |
| 338 } | 338 } |
| 339 | 339 |
| 340 Type lookupMethodType(Node node, ClassElement classElement, | 340 Type lookupMethodType(Node node, ClassElement classElement, |
| 341 SourceString name) { | 341 SourceString name) { |
| 342 Element member = classElement.lookupLocalMember(name); | 342 Element member = classElement.lookupLocalMember(name); |
| 343 if (member === null) { | 343 if (member === null) { |
| 344 classElement.ensureResolved(compiler); | 344 classElement.ensureResolved(compiler); |
| 345 for (Link<Type> supertypes = classElement.allSupertypes; | 345 for (Link<Type> supertypes = classElement.allSupertypes; |
| 346 !supertypes.isEmpty(); | 346 !supertypes.isEmpty() && member === null; |
| 347 supertypes = supertypes.tail) { | 347 supertypes = supertypes.tail) { |
| 348 ClassElement lookupTarget = supertypes.head.element; | 348 ClassElement lookupTarget = supertypes.head.element; |
| 349 member = lookupTarget.lookupLocalMember(name); | 349 member = lookupTarget.lookupLocalMember(name); |
| 350 if (member !== null) return computeType(member); | |
| 351 } | 350 } |
| 352 } | 351 } |
| 353 if (member !== null && member.kind == ElementKind.FUNCTION) { | 352 if (member !== null && member.kind == ElementKind.FUNCTION) { |
| 354 return computeType(member); | 353 return computeType(member); |
| 355 } | 354 } |
| 356 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 355 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
| 357 [classElement.name, name]); | 356 [classElement.name, name]); |
| 358 return types.dynamicType; | 357 return types.dynamicType; |
| 359 } | 358 } |
| 360 | 359 |
| 361 Link<Type> analyzeArguments(Link<Node> arguments) { | 360 void analyzeArguments(Send send, FunctionType funType) { |
| 362 LinkBuilder<Type> builder = new LinkBuilder<Type>(); | 361 Link<Node> arguments = send.arguments; |
| 363 while(!arguments.isEmpty()) { | 362 if (funType === null) { |
| 364 builder.addLast(analyze(arguments.head)); | 363 while(!arguments.isEmpty()) { |
| 365 arguments = arguments.tail; | 364 analyze(arguments.head); |
| 365 arguments = arguments.tail; |
| 366 } |
| 367 } else { |
| 368 Link<Type> parameterTypes = funType.parameterTypes; |
| 369 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { |
| 370 checkAssignable(arguments.head, parameterTypes.head, |
| 371 analyze(arguments.head)); |
| 372 arguments = arguments.tail; |
| 373 parameterTypes = parameterTypes.tail; |
| 374 } |
| 375 if (!arguments.isEmpty()) { |
| 376 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); |
| 377 } else if (!parameterTypes.isEmpty()) { |
| 378 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, |
| 379 [parameterTypes.head]); |
| 380 } |
| 366 } | 381 } |
| 367 return builder.toLink(); | |
| 368 } | 382 } |
| 369 | 383 |
| 370 Type visitSend(Send node) { | 384 Type visitSend(Send node) { |
| 371 if (Elements.isClosureSend(node, elements)) { | 385 if (Elements.isClosureSend(node, elements)) { |
| 372 // TODO(karlklose): Finish implementation. | 386 // TODO(karlklose): Finish implementation. |
| 373 return types.dynamicType; | 387 return types.dynamicType; |
| 374 } | 388 } |
| 375 | 389 |
| 376 Identifier selector = node.selector.asIdentifier(); | 390 Identifier selector = node.selector.asIdentifier(); |
| 377 String name = selector.source.stringValue; | 391 String name = selector.source.stringValue; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 } else if (node.isPropertyAccess) { | 423 } else if (node.isPropertyAccess) { |
| 410 if (node.receiver !== null) fail(node, 'cannot handle fields'); | 424 if (node.receiver !== null) fail(node, 'cannot handle fields'); |
| 411 Element element = elements[node]; | 425 Element element = elements[node]; |
| 412 if (element === null) fail(node.selector, 'unresolved property'); | 426 if (element === null) fail(node.selector, 'unresolved property'); |
| 413 return computeType(element); | 427 return computeType(element); |
| 414 | 428 |
| 415 } else if (node.isFunctionObjectInvocation) { | 429 } else if (node.isFunctionObjectInvocation) { |
| 416 fail(node.receiver, 'function object invocation unimplemented'); | 430 fail(node.receiver, 'function object invocation unimplemented'); |
| 417 | 431 |
| 418 } else { | 432 } else { |
| 419 Link<Type> argumentTypes = analyzeArguments(node.arguments); | 433 FunctionType computeFunType() { |
| 420 FunctionType funType; | 434 if (node.receiver !== null) { |
| 421 if (node.receiver !== null) { | 435 Type receiverType = analyze(node.receiver); |
| 422 Type receiverType = analyze(node.receiver); | 436 if (receiverType === types.dynamicType) return null; |
| 423 if (receiverType === types.dynamicType) return types.dynamicType; | 437 if (receiverType === null) { |
| 424 if (receiverType === null) { | 438 fail(node.receiver, 'receivertype is null'); |
| 425 fail(node.receiver, 'receivertype is null'); | 439 } |
| 426 } | 440 if (receiverType.element.kind !== ElementKind.CLASS) { |
| 427 if (receiverType.element.kind !== ElementKind.CLASS) { | 441 fail(node.receiver, 'receivertype is not a class'); |
| 428 fail(node.receiver, 'receivertype is not a class'); | 442 } |
| 429 } | 443 ClassElement classElement = receiverType.element; |
| 430 ClassElement classElement = receiverType.element; | 444 // TODO(karlklose): substitute type arguments. |
| 431 // TODO(karlklose): substitute type arguments. | 445 Type memberType = |
| 432 Type memberType = | 446 lookupMethodType(selector, classElement, selector.source); |
| 433 lookupMethodType(selector, classElement, selector.source); | 447 if (memberType === types.dynamicType) return null; |
| 434 if (memberType === types.dynamicType) return types.dynamicType; | 448 return memberType; |
| 435 if (memberType is !FunctionType) { | |
| 436 fail(node, 'can only handle function types'); | |
| 437 } | |
| 438 funType = memberType; | |
| 439 } else { | |
| 440 Element element = elements[node]; | |
| 441 if (element === null) { | |
| 442 fail(node, 'unresolved ${node.selector}'); | |
| 443 } else if (element.kind === ElementKind.FUNCTION) { | |
| 444 funType = computeType(element); | |
| 445 } else if (element.kind === ElementKind.FOREIGN) { | |
| 446 return types.dynamicType; | |
| 447 } else { | 449 } else { |
| 448 fail(node, 'unexpected element kind ${element.kind}'); | 450 Element element = elements[node]; |
| 451 if (element === null) { |
| 452 fail(node, 'unresolved ${node.selector}'); |
| 453 } else if (element.kind === ElementKind.FUNCTION) { |
| 454 return computeType(element); |
| 455 } else if (element.kind === ElementKind.FOREIGN) { |
| 456 return null; |
| 457 } else { |
| 458 fail(node, 'unexpected element kind ${element.kind}'); |
| 459 } |
| 449 } | 460 } |
| 450 } | 461 } |
| 451 Link<Type> parameterTypes = funType.parameterTypes; | 462 FunctionType funType = computeFunType(); |
| 452 Link<Node> argumentNodes = node.arguments; | 463 analyzeArguments(node, funType); |
| 453 while (!argumentTypes.isEmpty() && !parameterTypes.isEmpty()) { | 464 return (funType !== null) ? funType.returnType : types.dynamicType; |
| 454 checkAssignable(argumentNodes.head, parameterTypes.head, | |
| 455 argumentTypes.head); | |
| 456 argumentTypes = argumentTypes.tail; | |
| 457 parameterTypes = parameterTypes.tail; | |
| 458 argumentNodes = argumentNodes.tail; | |
| 459 } | |
| 460 if (!argumentTypes.isEmpty()) { | |
| 461 reportTypeWarning(argumentNodes.head, MessageKind.ADDITIONAL_ARGUMENT); | |
| 462 } else if (!parameterTypes.isEmpty()) { | |
| 463 reportTypeWarning(node, MessageKind.MISSING_ARGUMENT, | |
| 464 [parameterTypes.head]); | |
| 465 } | |
| 466 return funType.returnType; | |
| 467 } | 465 } |
| 468 } | 466 } |
| 469 | 467 |
| 470 visitSendSet(SendSet node) { | 468 visitSendSet(SendSet node) { |
| 471 Identifier selector = node.selector; | 469 Identifier selector = node.selector; |
| 472 final name = node.assignmentOperator.source.stringValue; | 470 final name = node.assignmentOperator.source.stringValue; |
| 473 if (name === '++' || name === '--') { | 471 if (name === '++' || name === '--') { |
| 474 final Element element = elements[node.selector]; | 472 final Element element = elements[node.selector]; |
| 475 final Type receiverType = computeType(element); | 473 final Type receiverType = computeType(element); |
| 476 // TODO(karlklose): this should be the return type instead of int. | 474 // TODO(karlklose): this should be the return type instead of int. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 503 analyze(node.first); | 501 analyze(node.first); |
| 504 analyze(node.second); | 502 analyze(node.second); |
| 505 return stringType; | 503 return stringType; |
| 506 } | 504 } |
| 507 | 505 |
| 508 Type visitLiteralNull(LiteralNull node) { | 506 Type visitLiteralNull(LiteralNull node) { |
| 509 return types.dynamicType; | 507 return types.dynamicType; |
| 510 } | 508 } |
| 511 | 509 |
| 512 Type visitNewExpression(NewExpression node) { | 510 Type visitNewExpression(NewExpression node) { |
| 511 Element element = elements[node.send]; |
| 512 analyzeArguments(node.send, computeType(element)); |
| 513 return analyze(node.send.selector); | 513 return analyze(node.send.selector); |
| 514 } | 514 } |
| 515 | 515 |
| 516 Type visitLiteralList(LiteralList node) { | 516 Type visitLiteralList(LiteralList node) { |
| 517 return listType; | 517 return listType; |
| 518 } | 518 } |
| 519 | 519 |
| 520 Type visitNodeList(NodeList node) { | 520 Type visitNodeList(NodeList node) { |
| 521 Type type = StatementType.NOT_RETURNING; | 521 Type type = StatementType.NOT_RETURNING; |
| 522 bool reportedDeadCode = false; | 522 bool reportedDeadCode = false; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 } | 707 } |
| 708 | 708 |
| 709 visitCatchBlock(CatchBlock node) { | 709 visitCatchBlock(CatchBlock node) { |
| 710 fail(node); | 710 fail(node); |
| 711 } | 711 } |
| 712 | 712 |
| 713 visitTypedef(Typedef node) { | 713 visitTypedef(Typedef node) { |
| 714 fail(node); | 714 fail(node); |
| 715 } | 715 } |
| 716 } | 716 } |
| OLD | NEW |