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