| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 1418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1429 // If the mixin class is a mixin application typedef class, we insert a new | 1429 // If the mixin class is a mixin application typedef class, we insert a new |
| 1430 // synthesized mixin application class in the super chain of this mixin | 1430 // synthesized mixin application class in the super chain of this mixin |
| 1431 // application class. The new class will have the aliased mixin as actual | 1431 // application class. The new class will have the aliased mixin as actual |
| 1432 // mixin. | 1432 // mixin. |
| 1433 if (mixin_class.is_mixin_typedef()) { | 1433 if (mixin_class.is_mixin_typedef()) { |
| 1434 ApplyMixinTypedef(mixin_app_class); | 1434 ApplyMixinTypedef(mixin_app_class); |
| 1435 } | 1435 } |
| 1436 } | 1436 } |
| 1437 | 1437 |
| 1438 | 1438 |
| 1439 /* Support for mixin typedef. |
| 1440 Consider the following example: |
| 1441 |
| 1442 class I<T> { } |
| 1443 class J<T> { } |
| 1444 class S<T> { } |
| 1445 class M<T> { } |
| 1446 typedef A<U, V> = Object with M<Map<U, V>> implements I<V>; |
| 1447 typedef C<T, K> = S<T> with A<T, List<K>> implements J<K>; |
| 1448 |
| 1449 Before the call to ApplyMixinTypedef, the VM has already synthesized 2 mixin |
| 1450 application classes Object&M and S&A: |
| 1451 |
| 1452 Object&M<T> extends Object implements M<T> { ... members of M applied here ... } |
| 1453 A<U, V> extends Object&M<Map<U, V>> implements I<V> { } |
| 1454 |
| 1455 S&A<T`, U, V> extends S<T`> implements A<U, V> { } |
| 1456 C<T, K> extends S&A<T, T, List<K>> implements J<K> { } |
| 1457 |
| 1458 In theory, class A should be an alias of Object&M instead of extending it. |
| 1459 In practice, the additional class provides a hook for implemented interfaces |
| 1460 (e.g. I<V>) and for type argument substitution via the super type relation (e.g. |
| 1461 type parameter T of Object&M is substituted with Map<U, V>, U and V being the |
| 1462 type parameters of the typedef A). |
| 1463 |
| 1464 Similarly, class C should be an alias of S&A instead of extending it. |
| 1465 |
| 1466 Since A is used as a mixin, it must extend Object. The fact that it extends |
| 1467 Object&M must be hidden so that no error is wrongly reported. |
| 1468 |
| 1469 Now, A does not have any members to be mixed into S&A, because A is a typedef. |
| 1470 The members to be mixed in are actually those of M, and they should appear in a |
| 1471 scope where the type parameter T is visible. The class S&A declares the type |
| 1472 parameters of A, i.e. U and V, but not T. |
| 1473 |
| 1474 Therefore, the call to ApplyMixinTypedef inserts another synthesized class S&A` |
| 1475 as the superclass of S&A. The class S&A` declares a type argument T: |
| 1476 |
| 1477 Instead of |
| 1478 S&A<T`, U, V> extends S<T`> implements A<U, V> { } |
| 1479 |
| 1480 We now have: |
| 1481 S&A`<T`, T> extends S<T`> implements M<T> { ... members of M applied here ... } |
| 1482 S&A<T`, U, V> extends S&A`<T`, Map<U, V>> implements A<U, V> { } |
| 1483 |
| 1484 The main implementation difficulty resides in the fact that the type parameters |
| 1485 U and V in the super type S&A`<T`, Map<U, V>> of S&A refer to the type |
| 1486 parameters U and V of S&A, not to U and V of A. An instantiation step with |
| 1487 a properly crafted instantiator vector takes care of the required type parameter |
| 1488 substitution. |
| 1489 */ |
| 1439 void ClassFinalizer::ApplyMixinTypedef(const Class& mixin_app_class) { | 1490 void ClassFinalizer::ApplyMixinTypedef(const Class& mixin_app_class) { |
| 1440 // If this mixin typedef is aliasing another mixin typedef, another class | 1491 // If this mixin typedef is aliasing another mixin typedef, another class |
| 1441 // will be inserted via recursion. No need to check here. | 1492 // will be inserted via recursion. No need to check here. |
| 1442 const Type& mixin_type = Type::Handle(mixin_app_class.mixin()); | 1493 const Type& mixin_type = Type::Handle(mixin_app_class.mixin()); |
| 1443 const Class& mixin_class = Class::Handle(mixin_type.type_class()); | 1494 const Class& mixin_class = Class::Handle(mixin_type.type_class()); |
| 1444 ASSERT(mixin_class.is_mixin_typedef()); | 1495 ASSERT(mixin_class.is_mixin_typedef()); |
| 1445 const Class& aliased_mixin_app_class = Class::Handle( | 1496 const Class& aliased_mixin_app_class = Class::Handle( |
| 1446 mixin_class.SuperClass()); | 1497 mixin_class.SuperClass()); |
| 1447 const Type& aliased_mixin_type = Type::Handle( | 1498 const Type& aliased_mixin_type = Type::Handle( |
| 1448 aliased_mixin_app_class.mixin()); | 1499 aliased_mixin_app_class.mixin()); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 | 1620 |
| 1570 | 1621 |
| 1571 void ClassFinalizer::ApplyMixinType(const Class& mixin_app_class) { | 1622 void ClassFinalizer::ApplyMixinType(const Class& mixin_app_class) { |
| 1572 if (mixin_app_class.is_mixin_type_applied()) { | 1623 if (mixin_app_class.is_mixin_type_applied()) { |
| 1573 return; | 1624 return; |
| 1574 } | 1625 } |
| 1575 Type& mixin_type = Type::Handle(mixin_app_class.mixin()); | 1626 Type& mixin_type = Type::Handle(mixin_app_class.mixin()); |
| 1576 ASSERT(!mixin_type.IsNull()); | 1627 ASSERT(!mixin_type.IsNull()); |
| 1577 ASSERT(mixin_type.HasResolvedTypeClass()); | 1628 ASSERT(mixin_type.HasResolvedTypeClass()); |
| 1578 const Class& mixin_class = Class::Handle(mixin_type.type_class()); | 1629 const Class& mixin_class = Class::Handle(mixin_type.type_class()); |
| 1579 if (mixin_class.IsNullClass()) { | 1630 |
| 1580 const Script& script = Script::Handle(mixin_app_class.script()); | 1631 if (FLAG_trace_class_finalization) { |
| 1581 ReportError(Error::Handle(), // No previous error. | 1632 OS::Print("Applying mixin type '%s' to %s at pos %" Pd "\n", |
| 1582 script, mixin_app_class.token_pos(), | 1633 String::Handle(mixin_type.Name()).ToCString(), |
| 1583 "illegal mixin of 'Null'"); | 1634 mixin_app_class.ToCString(), |
| 1635 mixin_app_class.token_pos()); |
| 1584 } | 1636 } |
| 1585 // Check for illegal self references. | 1637 |
| 1638 // Check for illegal self references. This has to be done before checking |
| 1639 // that the super class of the mixin class is class Object. |
| 1586 GrowableArray<intptr_t> visited_mixins; | 1640 GrowableArray<intptr_t> visited_mixins; |
| 1587 if (!IsMixinCycleFree(mixin_class, &visited_mixins)) { | 1641 if (!IsMixinCycleFree(mixin_class, &visited_mixins)) { |
| 1588 const Script& script = Script::Handle(mixin_class.script()); | 1642 const Script& script = Script::Handle(mixin_class.script()); |
| 1589 const String& class_name = String::Handle(mixin_class.Name()); | 1643 const String& class_name = String::Handle(mixin_class.Name()); |
| 1590 ReportError(Error::Handle(), // No previous error. | 1644 ReportError(Error::Handle(), // No previous error. |
| 1591 script, mixin_class.token_pos(), | 1645 script, mixin_class.token_pos(), |
| 1592 "mixin class '%s' illegally refers to itself", | 1646 "mixin class '%s' illegally refers to itself", |
| 1593 class_name.ToCString()); | 1647 class_name.ToCString()); |
| 1594 } | 1648 } |
| 1595 | 1649 |
| 1596 if (FLAG_trace_class_finalization) { | |
| 1597 OS::Print("Applying mixin type '%s' to %s at pos %" Pd "\n", | |
| 1598 String::Handle(mixin_type.Name()).ToCString(), | |
| 1599 mixin_app_class.ToCString(), | |
| 1600 mixin_app_class.token_pos()); | |
| 1601 } | |
| 1602 | |
| 1603 // Check that the super class of the mixin class is class Object. | 1650 // Check that the super class of the mixin class is class Object. |
| 1604 Class& mixin_super_class = Class::Handle(mixin_class.SuperClass()); | 1651 Class& mixin_super_class = Class::Handle(mixin_class.SuperClass()); |
| 1605 // Skip over mixin application typedef classes, which are aliases (but are | 1652 // Skip over mixin application typedef classes, which are aliases (but are |
| 1606 // implemented as subclasses) of the mixin application classes they name. | 1653 // implemented as subclasses) of the mixin application classes they name. |
| 1607 if (!mixin_super_class.IsNull() && mixin_class.is_mixin_typedef()) { | 1654 if (!mixin_super_class.IsNull() && mixin_class.is_mixin_typedef()) { |
| 1608 while (mixin_super_class.is_mixin_typedef()) { | 1655 while (mixin_super_class.is_mixin_typedef()) { |
| 1609 mixin_super_class = mixin_super_class.SuperClass(); | 1656 mixin_super_class = mixin_super_class.SuperClass(); |
| 1610 } | 1657 } |
| 1611 mixin_super_class = mixin_super_class.SuperClass(); | 1658 mixin_super_class = mixin_super_class.SuperClass(); |
| 1612 } | 1659 } |
| 1613 if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) { | 1660 if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) { |
| 1614 const Script& script = Script::Handle(mixin_app_class.script()); | 1661 const Script& script = Script::Handle(mixin_app_class.script()); |
| 1615 const String& class_name = String::Handle(mixin_class.Name()); | 1662 const String& class_name = String::Handle(mixin_class.Name()); |
| 1616 ReportError(Error::Handle(), // No previous error. | 1663 ReportError(Error::Handle(), // No previous error. |
| 1617 script, mixin_app_class.token_pos(), | 1664 script, mixin_app_class.token_pos(), |
| 1618 "mixin class '%s' must extend class 'Object'", | 1665 "mixin class '%s' must extend class 'Object'", |
| 1619 class_name.ToCString()); | 1666 class_name.ToCString()); |
| 1620 } | 1667 } |
| 1621 | 1668 |
| 1622 // Copy type parameters to mixin application class. | 1669 // Copy type parameters to mixin application class. |
| 1623 CloneMixinAppTypeParameters(mixin_app_class); | 1670 CloneMixinAppTypeParameters(mixin_app_class); |
| 1624 | 1671 |
| 1672 // Verify that no restricted class is used as a mixin by checking the |
| 1673 // interfaces of the mixin application class, which implements its mixin. |
| 1674 GrowableArray<intptr_t> visited_interfaces; |
| 1675 ResolveSuperTypeAndInterfaces(mixin_app_class, &visited_interfaces); |
| 1676 |
| 1625 if (FLAG_trace_class_finalization) { | 1677 if (FLAG_trace_class_finalization) { |
| 1626 OS::Print("Done applying mixin type '%s' to class '%s' %s extending '%s'\n", | 1678 OS::Print("Done applying mixin type '%s' to class '%s' %s extending '%s'\n", |
| 1627 String::Handle(mixin_type.Name()).ToCString(), | 1679 String::Handle(mixin_type.Name()).ToCString(), |
| 1628 String::Handle(mixin_app_class.Name()).ToCString(), | 1680 String::Handle(mixin_app_class.Name()).ToCString(), |
| 1629 TypeArguments::Handle( | 1681 TypeArguments::Handle( |
| 1630 mixin_app_class.type_parameters()).ToCString(), | 1682 mixin_app_class.type_parameters()).ToCString(), |
| 1631 AbstractType::Handle(mixin_app_class.super_type()).ToCString()); | 1683 AbstractType::Handle(mixin_app_class.super_type()).ToCString()); |
| 1632 } | 1684 } |
| 1633 mixin_app_class.set_is_mixin_type_applied(); | 1685 mixin_app_class.set_is_mixin_type_applied(); |
| 1634 } | 1686 } |
| (...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2273 "'dynamic' may not be used as interface"); | 2325 "'dynamic' may not be used as interface"); |
| 2274 } | 2326 } |
| 2275 interface_class = interface.type_class(); | 2327 interface_class = interface.type_class(); |
| 2276 if (interface_class.IsSignatureClass()) { | 2328 if (interface_class.IsSignatureClass()) { |
| 2277 const Script& script = Script::Handle(cls.script()); | 2329 const Script& script = Script::Handle(cls.script()); |
| 2278 ReportError(Error::Handle(), // No previous error. | 2330 ReportError(Error::Handle(), // No previous error. |
| 2279 script, cls.token_pos(), | 2331 script, cls.token_pos(), |
| 2280 "function type alias '%s' may not be used as interface", | 2332 "function type alias '%s' may not be used as interface", |
| 2281 String::Handle(interface_class.Name()).ToCString()); | 2333 String::Handle(interface_class.Name()).ToCString()); |
| 2282 } | 2334 } |
| 2283 // Verify that unless cls belongs to core lib, it cannot extend or implement | 2335 // Verify that unless cls belongs to core lib, it cannot extend, implement, |
| 2284 // any of Null, bool, num, int, double, String, Function, dynamic. | 2336 // or mixin any of Null, bool, num, int, double, String, dynamic. |
| 2285 // The exception is signature classes, which are compiler generated and | |
| 2286 // represent a function type, therefore implementing the Function interface. | |
| 2287 if (!cls_belongs_to_core_lib) { | 2337 if (!cls_belongs_to_core_lib) { |
| 2288 if (interface.IsBoolType() || | 2338 if (interface.IsBoolType() || |
| 2289 interface.IsNullType() || | 2339 interface.IsNullType() || |
| 2290 interface.IsNumberType() || | 2340 interface.IsNumberType() || |
| 2291 interface.IsIntType() || | 2341 interface.IsIntType() || |
| 2292 interface.IsDoubleType() || | 2342 interface.IsDoubleType() || |
| 2293 interface.IsStringType() || | 2343 interface.IsStringType() || |
| 2294 interface.IsDynamicType()) { | 2344 interface.IsDynamicType()) { |
| 2295 const Script& script = Script::Handle(cls.script()); | 2345 const Script& script = Script::Handle(cls.script()); |
| 2296 ReportError(Error::Handle(), // No previous error. | 2346 const String& interface_name = String::Handle(interface_class.Name()); |
| 2297 script, cls.token_pos(), | 2347 if (cls.IsMixinApplication()) { |
| 2298 "'%s' is not allowed to extend or implement '%s'", | 2348 ReportError(Error::Handle(), // No previous error. |
| 2299 String::Handle(cls.Name()).ToCString(), | 2349 script, cls.token_pos(), |
| 2300 String::Handle(interface_class.Name()).ToCString()); | 2350 "illegal mixin of '%s'", |
| 2351 interface_name.ToCString()); |
| 2352 } else { |
| 2353 ReportError(Error::Handle(), // No previous error. |
| 2354 script, cls.token_pos(), |
| 2355 "'%s' is not allowed to extend or implement '%s'", |
| 2356 String::Handle(cls.Name()).ToCString(), |
| 2357 interface_name.ToCString()); |
| 2358 } |
| 2301 } | 2359 } |
| 2302 } | 2360 } |
| 2303 interface_class.set_is_implemented(); | 2361 interface_class.set_is_implemented(); |
| 2304 // Now resolve the super interfaces. | 2362 // Now resolve the super interfaces. |
| 2305 ResolveSuperTypeAndInterfaces(interface_class, visited); | 2363 ResolveSuperTypeAndInterfaces(interface_class, visited); |
| 2306 } | 2364 } |
| 2307 visited->RemoveLast(); | 2365 visited->RemoveLast(); |
| 2308 } | 2366 } |
| 2309 | 2367 |
| 2310 | 2368 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2529 expected_name ^= String::New("_offset"); | 2587 expected_name ^= String::New("_offset"); |
| 2530 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); | 2588 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); |
| 2531 field ^= fields_array.At(2); | 2589 field ^= fields_array.At(2); |
| 2532 ASSERT(field.Offset() == TypedDataView::length_offset()); | 2590 ASSERT(field.Offset() == TypedDataView::length_offset()); |
| 2533 name ^= field.name(); | 2591 name ^= field.name(); |
| 2534 ASSERT(name.Equals("length")); | 2592 ASSERT(name.Equals("length")); |
| 2535 #endif | 2593 #endif |
| 2536 } | 2594 } |
| 2537 | 2595 |
| 2538 } // namespace dart | 2596 } // namespace dart |
| OLD | NEW |