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 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 const Script& script = Script::Handle(interface.script()); | 393 const Script& script = Script::Handle(interface.script()); |
394 ReportError(script, unresolved_factory_class.token_pos(), | 394 ReportError(script, unresolved_factory_class.token_pos(), |
395 "mismatch in number or names of type parameters between " | 395 "mismatch in number or names of type parameters between " |
396 "interface '%s' and default factory class '%s'", | 396 "interface '%s' and default factory class '%s'", |
397 interface_name.ToCString(), | 397 interface_name.ToCString(), |
398 factory_name.ToCString()); | 398 factory_name.ToCString()); |
399 } | 399 } |
400 } | 400 } |
401 | 401 |
402 | 402 |
| 403 void ClassFinalizer::ResolveRedirectingFactoryTarget( |
| 404 const Class& cls, |
| 405 const Function& factory, |
| 406 const GrowableObjectArray& visited_factories) { |
| 407 ASSERT(factory.IsRedirectingFactory()); |
| 408 |
| 409 // Check for redirection cycle. |
| 410 for (int i = 0; i < visited_factories.Length(); i++) { |
| 411 if (visited_factories.At(i) == factory.raw()) { |
| 412 // TODO(regis): Throw or report error? |
| 413 const Script& script = Script::Handle(cls.script()); |
| 414 ReportError(script, factory.token_pos(), |
| 415 "factory '%s' illegally redirects to itself", |
| 416 String::Handle(factory.name()).ToCString()); |
| 417 } |
| 418 } |
| 419 visited_factories.Add(factory); |
| 420 |
| 421 // Check if target is already resolved. |
| 422 Type& type = Type::Handle(factory.RedirectionType()); |
| 423 Function& target = Function::Handle(factory.RedirectionTarget()); |
| 424 if (type.IsMalformed()) { |
| 425 // Already resolved to a malformed type. Will throw on usage. |
| 426 ASSERT(target.IsNull()); |
| 427 return; |
| 428 } |
| 429 if (!target.IsNull()) { |
| 430 // Already resolved. |
| 431 return; |
| 432 } |
| 433 |
| 434 // Target is not resolved yet. |
| 435 if (FLAG_trace_class_finalization) { |
| 436 OS::Print("Resolving redirecting factory: %s\n", |
| 437 String::Handle(factory.name()).ToCString()); |
| 438 } |
| 439 ResolveType(cls, type, kCanonicalize); |
| 440 type ^= FinalizeType(cls, type, kCanonicalize); |
| 441 factory.SetRedirectionType(type); |
| 442 if (type.IsMalformed()) { |
| 443 ASSERT(target.IsNull()); |
| 444 factory.SetRedirectionTarget(target); |
| 445 return; |
| 446 } |
| 447 const Class& target_class = Class::Handle(type.type_class()); |
| 448 String& target_class_name = String::Handle(target_class.Name()); |
| 449 const String& period = String::Handle(Symbols::Dot()); |
| 450 String& target_name = String::Handle( |
| 451 String::Concat(target_class_name, period)); |
| 452 const String& identifier = String::Handle(factory.RedirectionIdentifier()); |
| 453 if (!identifier.IsNull()) { |
| 454 target_name = String::Concat(target_name, identifier); |
| 455 } |
| 456 |
| 457 // Verify that the target constructor of the redirection exists. |
| 458 target = target_class.LookupConstructor(target_name); |
| 459 if (target.IsNull()) { |
| 460 target = target_class.LookupFactory(target_name); |
| 461 } |
| 462 if (target.IsNull()) { |
| 463 const String& user_visible_target_name = |
| 464 identifier.IsNull() ? target_class_name : target_name; |
| 465 const Script& script = Script::Handle(cls.script()); |
| 466 // TODO(regis): Instead of reporting an error, should we replace the type |
| 467 // with a malformed type and compile a throw? We should then also do it |
| 468 // below for incompatible signatures. Wait for spec to stabilize. |
| 469 ReportError(script, factory.token_pos(), |
| 470 "class '%s' has no constructor or factory named '%s'", |
| 471 target_class_name.ToCString(), |
| 472 user_visible_target_name.ToCString()); |
| 473 } |
| 474 |
| 475 // Verify that the target is compatible with the redirecting factory. |
| 476 if (!target.HasCompatibleParametersWith(factory)) { |
| 477 const Script& script = Script::Handle(cls.script()); |
| 478 ReportError(script, factory.token_pos(), |
| 479 "constructor '%s' has incompatible parameters with redirecting " |
| 480 "factory '%s'", |
| 481 String::Handle(target.name()).ToCString(), |
| 482 String::Handle(factory.name()).ToCString()); |
| 483 } |
| 484 |
| 485 // Verify that the target is const if the the redirecting factory is const. |
| 486 if (factory.is_const() && !target.is_const()) { |
| 487 const Script& script = Script::Handle(cls.script()); |
| 488 ReportError(script, factory.token_pos(), |
| 489 "constructor '%s' must be const as required by redirecting" |
| 490 "const factory '%s'", |
| 491 String::Handle(target.name()).ToCString(), |
| 492 String::Handle(factory.name()).ToCString()); |
| 493 } |
| 494 |
| 495 // Update redirection data with resolved target. |
| 496 factory.SetRedirectionTarget(target); |
| 497 factory.SetRedirectionIdentifier(String::Handle()); // Not needed anymore. |
| 498 if (!target.IsRedirectingFactory()) { |
| 499 return; |
| 500 } |
| 501 |
| 502 // 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 |
| 504 // of the redirection chain. |
| 505 ResolveRedirectingFactoryTarget(target_class, target, visited_factories); |
| 506 Type& target_type = Type::Handle(target.RedirectionType()); |
| 507 const Function& target_target = Function::Handle(target.RedirectionTarget()); |
| 508 if (target_target.IsNull()) { |
| 509 ASSERT(target_type.IsMalformed()); |
| 510 } else { |
| 511 if (!target_type.IsInstantiated()) { |
| 512 const AbstractTypeArguments& type_args = AbstractTypeArguments::Handle( |
| 513 type.arguments()); |
| 514 target_type ^= target_type.InstantiateFrom(type_args); |
| 515 // TODO(regis): Do we need to check bounds? |
| 516 target_type ^= FinalizeType(cls, target_type, kCanonicalize); |
| 517 } |
| 518 } |
| 519 factory.SetRedirectionType(target_type); |
| 520 factory.SetRedirectionTarget(target_target); |
| 521 } |
| 522 |
| 523 |
403 void ClassFinalizer::ResolveType(const Class& cls, | 524 void ClassFinalizer::ResolveType(const Class& cls, |
404 const AbstractType& type, | 525 const AbstractType& type, |
405 FinalizationKind finalization) { | 526 FinalizationKind finalization) { |
406 if (type.IsResolved() || type.IsFinalized()) { | 527 if (type.IsResolved() || type.IsFinalized()) { |
407 return; | 528 return; |
408 } | 529 } |
409 if (FLAG_trace_type_finalization) { | 530 if (FLAG_trace_type_finalization) { |
410 OS::Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString()); | 531 OS::Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString()); |
411 } | 532 } |
412 | 533 |
(...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 const String& super_class_name = String::Handle(super_class.Name()); | 1048 const String& super_class_name = String::Handle(super_class.Name()); |
928 const Script& script = Script::Handle(cls.script()); | 1049 const Script& script = Script::Handle(cls.script()); |
929 ReportError(script, function.token_pos(), | 1050 ReportError(script, function.token_pos(), |
930 "static function '%s' of class '%s' conflicts with " | 1051 "static function '%s' of class '%s' conflicts with " |
931 "instance member '%s' of super class '%s'", | 1052 "instance member '%s' of super class '%s'", |
932 function_name.ToCString(), | 1053 function_name.ToCString(), |
933 class_name.ToCString(), | 1054 class_name.ToCString(), |
934 function_name.ToCString(), | 1055 function_name.ToCString(), |
935 super_class_name.ToCString()); | 1056 super_class_name.ToCString()); |
936 } | 1057 } |
| 1058 if (function.IsRedirectingFactory()) { |
| 1059 const GrowableObjectArray& redirecting_factories = |
| 1060 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
| 1061 ResolveRedirectingFactoryTarget(cls, function, redirecting_factories); |
| 1062 } |
937 } else { | 1063 } else { |
938 for (int i = 0; i < interfaces.Length(); i++) { | 1064 for (int i = 0; i < interfaces.Length(); i++) { |
939 super_class ^= interfaces.At(i); | 1065 super_class ^= interfaces.At(i); |
940 overridden_function = super_class.LookupDynamicFunction(function_name); | 1066 overridden_function = super_class.LookupDynamicFunction(function_name); |
941 if (!overridden_function.IsNull() && | 1067 if (!overridden_function.IsNull() && |
942 !function.HasCompatibleParametersWith(overridden_function)) { | 1068 !function.HasCompatibleParametersWith(overridden_function)) { |
943 // Function types are purposely not checked for subtyping. | 1069 // Function types are purposely not checked for subtyping. |
944 const String& class_name = String::Handle(cls.Name()); | 1070 const String& class_name = String::Handle(cls.Name()); |
945 const String& super_class_name = String::Handle(super_class.Name()); | 1071 const String& super_class_name = String::Handle(super_class.Name()); |
946 const Script& script = Script::Handle(cls.script()); | 1072 const Script& script = Script::Handle(cls.script()); |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1406 void ClassFinalizer::ReportError(const char* format, ...) { | 1532 void ClassFinalizer::ReportError(const char* format, ...) { |
1407 va_list args; | 1533 va_list args; |
1408 va_start(args, format); | 1534 va_start(args, format); |
1409 const Error& error = Error::Handle( | 1535 const Error& error = Error::Handle( |
1410 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); | 1536 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); |
1411 va_end(args); | 1537 va_end(args); |
1412 ReportError(error); | 1538 ReportError(error); |
1413 } | 1539 } |
1414 | 1540 |
1415 } // namespace dart | 1541 } // namespace dart |
OLD | NEW |