Chromium Code Reviews| 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 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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(); |
| 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); | 350 if (member !== null) return computeType(member); |
|
ahe
2012/03/22 17:52:16
This is broken. It should be:
if (member !== null
| |
| 351 } | 351 } |
| 352 } | 352 } |
| 353 if (member !== null && member.kind == ElementKind.FUNCTION) { | 353 if (member !== null && member.kind == ElementKind.FUNCTION) { |
| 354 return computeType(member); | 354 return computeType(member); |
| 355 } | 355 } |
| 356 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 356 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
| 357 [classElement.name, name]); | 357 [classElement.name, name]); |
| 358 return types.dynamicType; | 358 return types.dynamicType; |
| 359 } | 359 } |
| 360 | 360 |
| 361 Link<Type> analyzeArguments(Link<Node> arguments) { | 361 void analyzeArguments(Send send, FunctionType funType) { |
| 362 LinkBuilder<Type> builder = new LinkBuilder<Type>(); | 362 Link<Node> arguments = send.arguments; |
| 363 while(!arguments.isEmpty()) { | 363 if (funType === null) { |
| 364 builder.addLast(analyze(arguments.head)); | 364 while(!arguments.isEmpty()) { |
| 365 arguments = arguments.tail; | 365 analyze(arguments.head); |
| 366 arguments = arguments.tail; | |
| 367 } | |
| 368 } else { | |
| 369 Link<Type> parameterTypes = funType.parameterTypes; | |
| 370 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { | |
| 371 checkAssignable(arguments.head, parameterTypes.head, | |
| 372 analyze(arguments.head)); | |
| 373 arguments = arguments.tail; | |
| 374 parameterTypes = parameterTypes.tail; | |
| 375 } | |
| 376 if (!arguments.isEmpty()) { | |
| 377 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); | |
| 378 } else if (!parameterTypes.isEmpty()) { | |
| 379 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, | |
| 380 [parameterTypes.head]); | |
| 381 } | |
| 366 } | 382 } |
| 367 return builder.toLink(); | |
| 368 } | 383 } |
| 369 | 384 |
| 370 Type visitSend(Send node) { | 385 Type visitSend(Send node) { |
| 371 if (Elements.isClosureSend(node, elements)) { | 386 if (Elements.isClosureSend(node, elements)) { |
| 372 // TODO(karlklose): Finish implementation. | 387 // TODO(karlklose): Finish implementation. |
| 373 return types.dynamicType; | 388 return types.dynamicType; |
| 374 } | 389 } |
| 375 | 390 |
| 376 Identifier selector = node.selector.asIdentifier(); | 391 Identifier selector = node.selector.asIdentifier(); |
| 377 String name = selector.source.stringValue; | 392 String name = selector.source.stringValue; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 } else if (node.isPropertyAccess) { | 424 } else if (node.isPropertyAccess) { |
| 410 if (node.receiver !== null) fail(node, 'cannot handle fields'); | 425 if (node.receiver !== null) fail(node, 'cannot handle fields'); |
| 411 Element element = elements[node]; | 426 Element element = elements[node]; |
| 412 if (element === null) fail(node.selector, 'unresolved property'); | 427 if (element === null) fail(node.selector, 'unresolved property'); |
| 413 return computeType(element); | 428 return computeType(element); |
| 414 | 429 |
| 415 } else if (node.isFunctionObjectInvocation) { | 430 } else if (node.isFunctionObjectInvocation) { |
| 416 fail(node.receiver, 'function object invocation unimplemented'); | 431 fail(node.receiver, 'function object invocation unimplemented'); |
| 417 | 432 |
| 418 } else { | 433 } else { |
| 419 Link<Type> argumentTypes = analyzeArguments(node.arguments); | 434 FunctionType computeFunType() { |
| 420 FunctionType funType; | 435 if (node.receiver !== null) { |
| 421 if (node.receiver !== null) { | 436 Type receiverType = analyze(node.receiver); |
| 422 Type receiverType = analyze(node.receiver); | 437 if (receiverType === types.dynamicType) return null; |
| 423 if (receiverType === types.dynamicType) return types.dynamicType; | 438 if (receiverType === null) { |
| 424 if (receiverType === null) { | 439 fail(node.receiver, 'receivertype is null'); |
| 425 fail(node.receiver, 'receivertype is null'); | 440 } |
| 426 } | 441 if (receiverType.element.kind !== ElementKind.CLASS) { |
| 427 if (receiverType.element.kind !== ElementKind.CLASS) { | 442 fail(node.receiver, 'receivertype is not a class'); |
| 428 fail(node.receiver, 'receivertype is not a class'); | 443 } |
| 429 } | 444 ClassElement classElement = receiverType.element; |
| 430 ClassElement classElement = receiverType.element; | 445 // TODO(karlklose): substitute type arguments. |
| 431 // TODO(karlklose): substitute type arguments. | 446 Type memberType = |
| 432 Type memberType = | 447 lookupMethodType(selector, classElement, selector.source); |
| 433 lookupMethodType(selector, classElement, selector.source); | 448 if (memberType === types.dynamicType) return null; |
| 434 if (memberType === types.dynamicType) return types.dynamicType; | 449 if (memberType is !FunctionType) { |
|
ahe
2012/03/22 17:52:16
Then you can remove this check.
| |
| 435 if (memberType is !FunctionType) { | 450 fail(node, 'can only handle function types'); |
|
ahe
2012/03/22 16:31:01
return null;
polux
2012/03/22 18:44:16
Done. Also fixed lookupMethodType as discussed.
O
| |
| 436 fail(node, 'can only handle function types'); | 451 } |
| 437 } | 452 return memberType; |
| 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 { | 453 } else { |
| 448 fail(node, 'unexpected element kind ${element.kind}'); | 454 Element element = elements[node]; |
| 455 if (element === null) { | |
| 456 fail(node, 'unresolved ${node.selector}'); | |
| 457 } else if (element.kind === ElementKind.FUNCTION) { | |
| 458 return computeType(element); | |
| 459 } else if (element.kind === ElementKind.FOREIGN) { | |
| 460 return null; | |
| 461 } else { | |
| 462 fail(node, 'unexpected element kind ${element.kind}'); | |
| 463 } | |
| 449 } | 464 } |
| 450 } | 465 } |
| 451 Link<Type> parameterTypes = funType.parameterTypes; | 466 FunctionType funType = computeFunType(); |
| 452 Link<Node> argumentNodes = node.arguments; | 467 analyzeArguments(node, funType); |
| 453 while (!argumentTypes.isEmpty() && !parameterTypes.isEmpty()) { | 468 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 } | 469 } |
| 468 } | 470 } |
| 469 | 471 |
| 470 visitSendSet(SendSet node) { | 472 visitSendSet(SendSet node) { |
| 471 Identifier selector = node.selector; | 473 Identifier selector = node.selector; |
| 472 final name = node.assignmentOperator.source.stringValue; | 474 final name = node.assignmentOperator.source.stringValue; |
| 473 if (name === '++' || name === '--') { | 475 if (name === '++' || name === '--') { |
| 474 final Element element = elements[node.selector]; | 476 final Element element = elements[node.selector]; |
| 475 final Type receiverType = computeType(element); | 477 final Type receiverType = computeType(element); |
| 476 // TODO(karlklose): this should be the return type instead of int. | 478 // TODO(karlklose): this should be the return type instead of int. |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 503 analyze(node.first); | 505 analyze(node.first); |
| 504 analyze(node.second); | 506 analyze(node.second); |
| 505 return stringType; | 507 return stringType; |
| 506 } | 508 } |
| 507 | 509 |
| 508 Type visitLiteralNull(LiteralNull node) { | 510 Type visitLiteralNull(LiteralNull node) { |
| 509 return types.dynamicType; | 511 return types.dynamicType; |
| 510 } | 512 } |
| 511 | 513 |
| 512 Type visitNewExpression(NewExpression node) { | 514 Type visitNewExpression(NewExpression node) { |
| 515 Element element = elements[node.send]; | |
| 516 analyzeArguments(node.send, computeType(element)); | |
| 513 return analyze(node.send.selector); | 517 return analyze(node.send.selector); |
| 514 } | 518 } |
| 515 | 519 |
| 516 Type visitLiteralList(LiteralList node) { | 520 Type visitLiteralList(LiteralList node) { |
| 517 return listType; | 521 return listType; |
| 518 } | 522 } |
| 519 | 523 |
| 520 Type visitNodeList(NodeList node) { | 524 Type visitNodeList(NodeList node) { |
| 521 Type type = StatementType.NOT_RETURNING; | 525 Type type = StatementType.NOT_RETURNING; |
| 522 bool reportedDeadCode = false; | 526 bool reportedDeadCode = false; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 } | 711 } |
| 708 | 712 |
| 709 visitCatchBlock(CatchBlock node) { | 713 visitCatchBlock(CatchBlock node) { |
| 710 fail(node); | 714 fail(node); |
| 711 } | 715 } |
| 712 | 716 |
| 713 visitTypedef(Typedef node) { | 717 visitTypedef(Typedef node) { |
| 714 fail(node); | 718 fail(node); |
| 715 } | 719 } |
| 716 } | 720 } |
| OLD | NEW |