| 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 #include "vm/class_finalizer.h" | 5 #include "vm/class_finalizer.h" |
| 6 | 6 |
| 7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
| 8 #include "vm/heap.h" | 8 #include "vm/heap.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 | 402 |
| 403 void ClassFinalizer::ResolveRedirectingFactoryTarget( | 403 void ClassFinalizer::ResolveRedirectingFactoryTarget( |
| 404 const Class& cls, | 404 const Class& cls, |
| 405 const Function& factory, | 405 const Function& factory, |
| 406 const GrowableObjectArray& visited_factories) { | 406 const GrowableObjectArray& visited_factories) { |
| 407 ASSERT(factory.IsRedirectingFactory()); | 407 ASSERT(factory.IsRedirectingFactory()); |
| 408 | 408 |
| 409 // Check for redirection cycle. | 409 // Check for redirection cycle. |
| 410 for (int i = 0; i < visited_factories.Length(); i++) { | 410 for (int i = 0; i < visited_factories.Length(); i++) { |
| 411 if (visited_factories.At(i) == factory.raw()) { | 411 if (visited_factories.At(i) == factory.raw()) { |
| 412 // TODO(regis): Throw or report error? | 412 // A redirection cycle is reported as a compile-time error. |
| 413 const Script& script = Script::Handle(cls.script()); | 413 const Script& script = Script::Handle(cls.script()); |
| 414 ReportError(script, factory.token_pos(), | 414 ReportError(script, factory.token_pos(), |
| 415 "factory '%s' illegally redirects to itself", | 415 "factory '%s' illegally redirects to itself", |
| 416 String::Handle(factory.name()).ToCString()); | 416 String::Handle(factory.name()).ToCString()); |
| 417 } | 417 } |
| 418 } | 418 } |
| 419 visited_factories.Add(factory); | 419 visited_factories.Add(factory); |
| 420 | 420 |
| 421 // Check if target is already resolved. | 421 // Check if target is already resolved. |
| 422 Type& type = Type::Handle(factory.RedirectionType()); | 422 Type& type = Type::Handle(factory.RedirectionType()); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 433 | 433 |
| 434 // Target is not resolved yet. | 434 // Target is not resolved yet. |
| 435 if (FLAG_trace_class_finalization) { | 435 if (FLAG_trace_class_finalization) { |
| 436 OS::Print("Resolving redirecting factory: %s\n", | 436 OS::Print("Resolving redirecting factory: %s\n", |
| 437 String::Handle(factory.name()).ToCString()); | 437 String::Handle(factory.name()).ToCString()); |
| 438 } | 438 } |
| 439 ResolveType(cls, type, kCanonicalize); | 439 ResolveType(cls, type, kCanonicalize); |
| 440 type ^= FinalizeType(cls, type, kCanonicalize); | 440 type ^= FinalizeType(cls, type, kCanonicalize); |
| 441 factory.SetRedirectionType(type); | 441 factory.SetRedirectionType(type); |
| 442 if (type.IsMalformed()) { | 442 if (type.IsMalformed()) { |
| 443 ASSERT(target.IsNull()); | 443 ASSERT(factory.RedirectionTarget() == Function::null()); |
| 444 factory.SetRedirectionTarget(target); | |
| 445 return; | 444 return; |
| 446 } | 445 } |
| 447 const Class& target_class = Class::Handle(type.type_class()); | 446 const Class& target_class = Class::Handle(type.type_class()); |
| 448 String& target_class_name = String::Handle(target_class.Name()); | 447 String& target_class_name = String::Handle(target_class.Name()); |
| 449 const String& period = String::Handle(Symbols::Dot()); | 448 const String& period = String::Handle(Symbols::Dot()); |
| 450 String& target_name = String::Handle( | 449 String& target_name = String::Handle( |
| 451 String::Concat(target_class_name, period)); | 450 String::Concat(target_class_name, period)); |
| 452 const String& identifier = String::Handle(factory.RedirectionIdentifier()); | 451 const String& identifier = String::Handle(factory.RedirectionIdentifier()); |
| 453 if (!identifier.IsNull()) { | 452 if (!identifier.IsNull()) { |
| 454 target_name = String::Concat(target_name, identifier); | 453 target_name = String::Concat(target_name, identifier); |
| 455 } | 454 } |
| 456 | 455 |
| 457 // Verify that the target constructor of the redirection exists. | 456 // Verify that the target constructor of the redirection exists. |
| 458 target = target_class.LookupConstructor(target_name); | 457 target = target_class.LookupConstructor(target_name); |
| 459 if (target.IsNull()) { | 458 if (target.IsNull()) { |
| 460 target = target_class.LookupFactory(target_name); | 459 target = target_class.LookupFactory(target_name); |
| 461 } | 460 } |
| 462 if (target.IsNull()) { | 461 if (target.IsNull()) { |
| 463 const String& user_visible_target_name = | 462 const String& user_visible_target_name = |
| 464 identifier.IsNull() ? target_class_name : target_name; | 463 identifier.IsNull() ? target_class_name : target_name; |
| 465 const Script& script = Script::Handle(cls.script()); | 464 // Replace the type with a malformed type and compile a throw when called. |
| 466 // TODO(regis): Instead of reporting an error, should we replace the type | 465 FinalizeMalformedType(Error::Handle(), // No previous error. |
| 467 // with a malformed type and compile a throw? We should then also do it | 466 cls, type, kCanonicalize, |
| 468 // below for incompatible signatures. Wait for spec to stabilize. | 467 "class '%s' has no constructor or factory named '%s'", |
| 469 ReportError(script, factory.token_pos(), | 468 target_class_name.ToCString(), |
| 470 "class '%s' has no constructor or factory named '%s'", | 469 user_visible_target_name.ToCString()); |
| 471 target_class_name.ToCString(), | 470 factory.SetRedirectionType(type); |
| 472 user_visible_target_name.ToCString()); | 471 ASSERT(factory.RedirectionTarget() == Function::null()); |
| 472 return; |
| 473 } | 473 } |
| 474 | 474 |
| 475 // Verify that the target is compatible with the redirecting factory. | 475 // Verify that the target is compatible with the redirecting factory. |
| 476 if (!target.HasCompatibleParametersWith(factory)) { | 476 if (!target.HasCompatibleParametersWith(factory)) { |
| 477 const Script& script = Script::Handle(cls.script()); | 477 FinalizeMalformedType(Error::Handle(), // No previous error. |
| 478 ReportError(script, factory.token_pos(), | 478 cls, type, kCanonicalize, |
| 479 "constructor '%s' has incompatible parameters with redirecting " | 479 "constructor '%s' has incompatible parameters with " |
| 480 "factory '%s'", | 480 "redirecting factory '%s'", |
| 481 String::Handle(target.name()).ToCString(), | 481 String::Handle(target.name()).ToCString(), |
| 482 String::Handle(factory.name()).ToCString()); | 482 String::Handle(factory.name()).ToCString()); |
| 483 factory.SetRedirectionType(type); |
| 484 ASSERT(factory.RedirectionTarget() == Function::null()); |
| 485 return; |
| 483 } | 486 } |
| 484 | 487 |
| 485 // Verify that the target is const if the the redirecting factory is const. | 488 // Verify that the target is const if the the redirecting factory is const. |
| 486 if (factory.is_const() && !target.is_const()) { | 489 if (factory.is_const() && !target.is_const()) { |
| 487 const Script& script = Script::Handle(cls.script()); | 490 const Script& script = Script::Handle(cls.script()); |
| 488 ReportError(script, factory.token_pos(), | 491 ReportError(script, factory.token_pos(), |
| 489 "constructor '%s' must be const as required by redirecting" | 492 "constructor '%s' must be const as required by redirecting" |
| 490 "const factory '%s'", | 493 "const factory '%s'", |
| 491 String::Handle(target.name()).ToCString(), | 494 String::Handle(target.name()).ToCString(), |
| 492 String::Handle(factory.name()).ToCString()); | 495 String::Handle(factory.name()).ToCString()); |
| 493 } | 496 } |
| 494 | 497 |
| 495 // Update redirection data with resolved target. | 498 // Update redirection data with resolved target. |
| 496 factory.SetRedirectionTarget(target); | 499 factory.SetRedirectionTarget(target); |
| 497 factory.SetRedirectionIdentifier(String::Handle()); // Not needed anymore. | 500 factory.SetRedirectionIdentifier(String::Handle()); // Not needed anymore. |
| 498 if (!target.IsRedirectingFactory()) { | 501 if (!target.IsRedirectingFactory()) { |
| 499 return; | 502 return; |
| 500 } | 503 } |
| 501 | 504 |
| 502 // The target is itself a redirecting factory. Recursively resolve its own | 505 // The target is itself a redirecting factory. Recursively resolve its own |
| 503 // target and update the current redirection data to point to the end target | 506 // target and update the current redirection data to point to the end target |
| 504 // of the redirection chain. | 507 // of the redirection chain. |
| 505 ResolveRedirectingFactoryTarget(target_class, target, visited_factories); | 508 ResolveRedirectingFactoryTarget(target_class, target, visited_factories); |
| 506 Type& target_type = Type::Handle(target.RedirectionType()); | 509 Type& target_type = Type::Handle(target.RedirectionType()); |
| 507 const Function& target_target = Function::Handle(target.RedirectionTarget()); | 510 Function& target_target = Function::Handle(target.RedirectionTarget()); |
| 508 if (target_target.IsNull()) { | 511 if (target_target.IsNull()) { |
| 509 ASSERT(target_type.IsMalformed()); | 512 ASSERT(target_type.IsMalformed()); |
| 510 } else { | 513 } else { |
| 514 // If the target type refers to type parameters, substitute them with the |
| 515 // type arguments of the redirection type. |
| 511 if (!target_type.IsInstantiated()) { | 516 if (!target_type.IsInstantiated()) { |
| 512 const AbstractTypeArguments& type_args = AbstractTypeArguments::Handle( | 517 const AbstractTypeArguments& type_args = AbstractTypeArguments::Handle( |
| 513 type.arguments()); | 518 type.arguments()); |
| 514 target_type ^= target_type.InstantiateFrom(type_args); | 519 target_type ^= target_type.InstantiateFrom(type_args); |
| 515 // TODO(regis): Do we need to check bounds? | 520 // TODO(regis): Check bounds in checked mode. |
| 516 target_type ^= FinalizeType(cls, target_type, kCanonicalize); | 521 target_type ^= FinalizeType(cls, target_type, kCanonicalize); |
| 522 if (target_type.IsMalformed()) { |
| 523 target_target = Function::null(); |
| 524 } |
| 517 } | 525 } |
| 518 } | 526 } |
| 519 factory.SetRedirectionType(target_type); | 527 factory.SetRedirectionType(target_type); |
| 520 factory.SetRedirectionTarget(target_target); | 528 factory.SetRedirectionTarget(target_target); |
| 521 } | 529 } |
| 522 | 530 |
| 523 | 531 |
| 524 void ClassFinalizer::ResolveType(const Class& cls, | 532 void ClassFinalizer::ResolveType(const Class& cls, |
| 525 const AbstractType& type, | 533 const AbstractType& type, |
| 526 FinalizationKind finalization) { | 534 FinalizationKind finalization) { |
| (...skipping 1005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 void ClassFinalizer::ReportError(const char* format, ...) { | 1540 void ClassFinalizer::ReportError(const char* format, ...) { |
| 1533 va_list args; | 1541 va_list args; |
| 1534 va_start(args, format); | 1542 va_start(args, format); |
| 1535 const Error& error = Error::Handle( | 1543 const Error& error = Error::Handle( |
| 1536 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); | 1544 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); |
| 1537 va_end(args); | 1545 va_end(args); |
| 1538 ReportError(error); | 1546 ReportError(error); |
| 1539 } | 1547 } |
| 1540 | 1548 |
| 1541 } // namespace dart | 1549 } // namespace dart |
| OLD | NEW |