| 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 library dart2js.resolution.compute_members; | 5 library dart2js.resolution.compute_members; |
| 6 | 6 |
| 7 import '../common/names.dart' show | 7 import '../common/names.dart' show |
| 8 Identifiers; | 8 Identifiers; |
| 9 import '../compiler.dart' show | 9 import '../compiler.dart' show |
| 10 Compiler; | 10 Compiler; |
| 11 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
| 12 import '../diagnostics/diagnostic_listener.dart' show |
| 13 DiagnosticMessage; |
| 12 import '../diagnostics/invariant.dart' show | 14 import '../diagnostics/invariant.dart' show |
| 13 invariant; | 15 invariant; |
| 14 import '../diagnostics/messages.dart' show | 16 import '../diagnostics/messages.dart' show |
| 15 MessageKind; | 17 MessageKind; |
| 16 import '../elements/elements.dart' show | 18 import '../elements/elements.dart' show |
| 17 ClassElement, | 19 ClassElement, |
| 18 Element, | 20 Element, |
| 19 LibraryElement, | 21 LibraryElement, |
| 20 Member, | 22 Member, |
| 21 MemberElement, | 23 MemberElement, |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 interfaceMember.declarer.element == cls) { | 249 interfaceMember.declarer.element == cls) { |
| 248 // Abstract method declared in [cls]. | 250 // Abstract method declared in [cls]. |
| 249 MessageKind kind = MessageKind.ABSTRACT_METHOD; | 251 MessageKind kind = MessageKind.ABSTRACT_METHOD; |
| 250 if (interfaceMember.isSetter) { | 252 if (interfaceMember.isSetter) { |
| 251 kind = MessageKind.ABSTRACT_SETTER; | 253 kind = MessageKind.ABSTRACT_SETTER; |
| 252 } else if (interfaceMember.isGetter) { | 254 } else if (interfaceMember.isGetter) { |
| 253 kind = MessageKind.ABSTRACT_GETTER; | 255 kind = MessageKind.ABSTRACT_GETTER; |
| 254 } | 256 } |
| 255 reportMessage( | 257 reportMessage( |
| 256 interfaceMember.element, MessageKind.ABSTRACT_METHOD, () { | 258 interfaceMember.element, MessageKind.ABSTRACT_METHOD, () { |
| 257 compiler.reportWarning( | 259 compiler.reportWarningMessage( |
| 258 interfaceMember.element, kind, | 260 interfaceMember.element, kind, |
| 259 {'class': cls.name, 'name': name.text}); | 261 {'class': cls.name, 'name': name.text}); |
| 260 }); | 262 }); |
| 261 } else { | 263 } else { |
| 262 reportWarning(MessageKind singleKind, | 264 reportWarning(MessageKind singleKind, |
| 263 MessageKind multipleKind, | 265 MessageKind multipleKind, |
| 264 MessageKind explicitlyDeclaredKind, | 266 MessageKind explicitlyDeclaredKind, |
| 265 [MessageKind implicitlyDeclaredKind]) { | 267 [MessageKind implicitlyDeclaredKind]) { |
| 266 Member inherited = interfaceMember.declarations.first; | 268 Member inherited = interfaceMember.declarations.first; |
| 267 reportMessage( | 269 reportMessage( |
| 268 interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () { | 270 interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () { |
| 269 compiler.reportWarning(cls, | 271 DiagnosticMessage warning = compiler.createMessage( |
| 272 cls, |
| 270 interfaceMember.declarations.length == 1 | 273 interfaceMember.declarations.length == 1 |
| 271 ? singleKind : multipleKind, | 274 ? singleKind : multipleKind, |
| 272 {'class': cls.name, | 275 {'class': cls.name, |
| 273 'name': name.text, | 276 'name': name.text, |
| 274 'method': interfaceMember, | 277 'method': interfaceMember, |
| 275 'declarer': inherited.declarer}); | 278 'declarer': inherited.declarer}); |
| 279 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 276 for (Member inherited in interfaceMember.declarations) { | 280 for (Member inherited in interfaceMember.declarations) { |
| 277 compiler.reportInfo(inherited.element, | 281 infos.add(compiler.createMessage( |
| 282 inherited.element, |
| 278 inherited.isDeclaredByField ? | 283 inherited.isDeclaredByField ? |
| 279 implicitlyDeclaredKind : explicitlyDeclaredKind, | 284 implicitlyDeclaredKind : explicitlyDeclaredKind, |
| 280 {'class': inherited.declarer.name, | 285 {'class': inherited.declarer.name, |
| 281 'name': name.text}); | 286 'name': name.text})); |
| 282 } | 287 } |
| 288 compiler.reportWarning(warning, infos); |
| 283 }); | 289 }); |
| 284 } | 290 } |
| 285 if (interfaceMember.isSetter) { | 291 if (interfaceMember.isSetter) { |
| 286 reportWarning(MessageKind.UNIMPLEMENTED_SETTER_ONE, | 292 reportWarning(MessageKind.UNIMPLEMENTED_SETTER_ONE, |
| 287 MessageKind.UNIMPLEMENTED_SETTER, | 293 MessageKind.UNIMPLEMENTED_SETTER, |
| 288 MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER, | 294 MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER, |
| 289 MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER); | 295 MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER); |
| 290 } else if (interfaceMember.isGetter) { | 296 } else if (interfaceMember.isGetter) { |
| 291 reportWarning(MessageKind.UNIMPLEMENTED_GETTER_ONE, | 297 reportWarning(MessageKind.UNIMPLEMENTED_GETTER_ONE, |
| 292 MessageKind.UNIMPLEMENTED_GETTER, | 298 MessageKind.UNIMPLEMENTED_GETTER, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 307 void checkImplementsFunctionWithCall() { | 313 void checkImplementsFunctionWithCall() { |
| 308 assert(!cls.isAbstract); | 314 assert(!cls.isAbstract); |
| 309 | 315 |
| 310 if (cls.asInstanceOf(compiler.functionClass) == null) return; | 316 if (cls.asInstanceOf(compiler.functionClass) == null) return; |
| 311 if (cls.lookupMember(Identifiers.call) != null) return; | 317 if (cls.lookupMember(Identifiers.call) != null) return; |
| 312 // TODO(johnniwinther): Make separate methods for backend exceptions. | 318 // TODO(johnniwinther): Make separate methods for backend exceptions. |
| 313 // Avoid warnings on backend implementation classes for closures. | 319 // Avoid warnings on backend implementation classes for closures. |
| 314 if (compiler.backend.isBackendLibrary(cls.library)) return; | 320 if (compiler.backend.isBackendLibrary(cls.library)) return; |
| 315 | 321 |
| 316 reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () { | 322 reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () { |
| 317 compiler.reportWarning(cls, MessageKind.UNIMPLEMENTED_METHOD_ONE, | 323 compiler.reportWarningMessage( |
| 324 cls, |
| 325 MessageKind.UNIMPLEMENTED_METHOD_ONE, |
| 318 {'class': cls.name, | 326 {'class': cls.name, |
| 319 'name': Identifiers.call, | 327 'name': Identifiers.call, |
| 320 'method': Identifiers.call, | 328 'method': Identifiers.call, |
| 321 'declarer': compiler.functionClass.name}); | 329 'declarer': compiler.functionClass.name}); |
| 322 }); | 330 }); |
| 323 } | 331 } |
| 324 | 332 |
| 325 /// Checks that a class member exists for every interface member. | 333 /// Checks that a class member exists for every interface member. |
| 326 void checkInterfaceImplementation(); | 334 void checkInterfaceImplementation(); |
| 327 | 335 |
| 328 /// Check that [declared] is a valid override of [superMember]. | 336 /// Check that [declared] is a valid override of [superMember]. |
| 329 void checkValidOverride(Member declared, MemberSignature superMember) { | 337 void checkValidOverride(Member declared, MemberSignature superMember) { |
| 330 if (superMember == null) { | 338 if (superMember == null) { |
| 331 // No override. | 339 // No override. |
| 332 if (!declared.isStatic) { | 340 if (!declared.isStatic) { |
| 333 ClassElement superclass = cls.superclass; | 341 ClassElement superclass = cls.superclass; |
| 334 while (superclass != null) { | 342 while (superclass != null) { |
| 335 Member superMember = | 343 Member superMember = |
| 336 superclass.lookupClassMember(declared.name); | 344 superclass.lookupClassMember(declared.name); |
| 337 if (superMember != null && superMember.isStatic) { | 345 if (superMember != null && superMember.isStatic) { |
| 338 reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME, | 346 reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME, |
| 339 () { | 347 () { |
| 340 compiler.reportWarning( | 348 compiler.reportWarning( |
| 341 declared.element, | 349 compiler.createMessage( |
| 342 MessageKind.INSTANCE_STATIC_SAME_NAME, | 350 declared.element, |
| 343 {'memberName': declared.name, | 351 MessageKind.INSTANCE_STATIC_SAME_NAME, |
| 344 'className': superclass.name}); | 352 {'memberName': declared.name, |
| 345 compiler.reportInfo(superMember.element, | 353 'className': superclass.name}), |
| 346 MessageKind.INSTANCE_STATIC_SAME_NAME_CONT); | 354 <DiagnosticMessage>[ |
| 355 compiler.createMessage( |
| 356 superMember.element, |
| 357 MessageKind.INSTANCE_STATIC_SAME_NAME_CONT), |
| 358 ]); |
| 359 |
| 347 }); | 360 }); |
| 348 break; | 361 break; |
| 349 } | 362 } |
| 350 superclass = superclass.superclass; | 363 superclass = superclass.superclass; |
| 351 } | 364 } |
| 352 } | 365 } |
| 353 } else { | 366 } else { |
| 354 assert(declared.name == superMember.name); | 367 assert(declared.name == superMember.name); |
| 355 | 368 |
| 356 if (declared.isStatic) { | 369 if (declared.isStatic) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 379 // An error should already have been reported. | 392 // An error should already have been reported. |
| 380 assert(invariant(declared.element, compiler.compilationFailed, | 393 assert(invariant(declared.element, compiler.compilationFailed, |
| 381 message: "Member $inherited inherited from its " | 394 message: "Member $inherited inherited from its " |
| 382 "declaring class: ${cls}.")); | 395 "declaring class: ${cls}.")); |
| 383 continue; | 396 continue; |
| 384 } | 397 } |
| 385 | 398 |
| 386 void reportError(MessageKind errorKind, MessageKind infoKind) { | 399 void reportError(MessageKind errorKind, MessageKind infoKind) { |
| 387 reportMessage( | 400 reportMessage( |
| 388 inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () { | 401 inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () { |
| 389 compiler.reportError(declared.element, errorKind, | 402 compiler.reportError( |
| 390 {'name': declared.name.text, | 403 compiler.createMessage( |
| 391 'class': cls.thisType, | 404 declared.element, |
| 392 'inheritedClass': inherited.declarer}); | 405 errorKind, |
| 393 compiler.reportInfo(inherited.element, infoKind, | 406 {'name': declared.name.text, |
| 394 {'name': declared.name.text, | 407 'class': cls.thisType, |
| 395 'class': inherited.declarer}); | 408 'inheritedClass': inherited.declarer}), |
| 409 <DiagnosticMessage>[ |
| 410 compiler.createMessage( |
| 411 inherited.element, |
| 412 infoKind, |
| 413 {'name': declared.name.text, |
| 414 'class': inherited.declarer}), |
| 415 ]); |
| 396 }); | 416 }); |
| 397 } | 417 } |
| 398 | 418 |
| 399 if (declared.isDeclaredByField && inherited.isMethod) { | 419 if (declared.isDeclaredByField && inherited.isMethod) { |
| 400 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, | 420 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, |
| 401 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); | 421 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); |
| 402 } else if (declared.isMethod && inherited.isDeclaredByField) { | 422 } else if (declared.isMethod && inherited.isDeclaredByField) { |
| 403 reportError(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, | 423 reportError(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, |
| 404 MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); | 424 MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); |
| 405 } else if (declared.isGetter && inherited.isMethod) { | 425 } else if (declared.isGetter && inherited.isMethod) { |
| 406 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER, | 426 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER, |
| 407 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT); | 427 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT); |
| 408 } else if (declared.isMethod && inherited.isGetter) { | 428 } else if (declared.isMethod && inherited.isGetter) { |
| 409 reportError(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD, | 429 reportError(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD, |
| 410 MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT); | 430 MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT); |
| 411 } else { | 431 } else { |
| 412 DartType inheritedType = inherited.functionType; | 432 DartType inheritedType = inherited.functionType; |
| 413 if (!compiler.types.isSubtype(declaredType, inheritedType)) { | 433 if (!compiler.types.isSubtype(declaredType, inheritedType)) { |
| 414 void reportWarning(var marker, | 434 void reportWarning(var marker, |
| 415 MessageKind warningKind, | 435 MessageKind warningKind, |
| 416 MessageKind infoKind) { | 436 MessageKind infoKind) { |
| 417 reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () { | 437 reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () { |
| 418 compiler.reportWarning(declared.element, warningKind, | 438 compiler.reportWarning( |
| 419 {'declaredType': declared.type, | 439 compiler.createMessage( |
| 420 'name': declared.name.text, | 440 declared.element, |
| 421 'class': cls.thisType, | 441 warningKind, |
| 422 'inheritedType': inherited.type, | 442 {'declaredType': declared.type, |
| 423 'inheritedClass': inherited.declarer}); | 443 'name': declared.name.text, |
| 424 compiler.reportInfo(inherited.element, infoKind, | 444 'class': cls.thisType, |
| 425 {'name': declared.name.text, | 445 'inheritedType': inherited.type, |
| 426 'class': inherited.declarer}); | 446 'inheritedClass': inherited.declarer}), |
| 447 <DiagnosticMessage>[ |
| 448 compiler.createMessage( |
| 449 inherited.element, |
| 450 infoKind, |
| 451 {'name': declared.name.text, |
| 452 'class': inherited.declarer}), |
| 453 ]); |
| 427 }); | 454 }); |
| 428 } | 455 } |
| 429 if (declared.isDeclaredByField) { | 456 if (declared.isDeclaredByField) { |
| 430 if (inherited.isDeclaredByField) { | 457 if (inherited.isDeclaredByField) { |
| 431 reportWarning(inherited.element, | 458 reportWarning(inherited.element, |
| 432 MessageKind.INVALID_OVERRIDE_FIELD, | 459 MessageKind.INVALID_OVERRIDE_FIELD, |
| 433 MessageKind.INVALID_OVERRIDDEN_FIELD); | 460 MessageKind.INVALID_OVERRIDDEN_FIELD); |
| 434 } else if (inherited.isGetter) { | 461 } else if (inherited.isGetter) { |
| 435 reportWarning(inherited, | 462 reportWarning(inherited, |
| 436 MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD, | 463 MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 } | 496 } |
| 470 } | 497 } |
| 471 } | 498 } |
| 472 } | 499 } |
| 473 | 500 |
| 474 void reportErrorWithContext(Element errorneousElement, | 501 void reportErrorWithContext(Element errorneousElement, |
| 475 MessageKind errorMessage, | 502 MessageKind errorMessage, |
| 476 Element contextElement, | 503 Element contextElement, |
| 477 MessageKind contextMessage) { | 504 MessageKind contextMessage) { |
| 478 compiler.reportError( | 505 compiler.reportError( |
| 479 errorneousElement, | 506 compiler.createMessage( |
| 480 errorMessage, | 507 errorneousElement, |
| 481 {'memberName': contextElement.name, | 508 errorMessage, |
| 482 'className': contextElement.enclosingClass.name}); | 509 {'memberName': contextElement.name, |
| 483 compiler.reportInfo(contextElement, contextMessage); | 510 'className': contextElement.enclosingClass.name}), |
| 511 <DiagnosticMessage>[ |
| 512 compiler.createMessage(contextElement, contextMessage), |
| 513 ]); |
| 484 } | 514 } |
| 485 | 515 |
| 486 /// Compute all class and interface names by the [name] in [cls]. | 516 /// Compute all class and interface names by the [name] in [cls]. |
| 487 static void computeClassMembersByName(Compiler compiler, | 517 static void computeClassMembersByName(Compiler compiler, |
| 488 ClassMemberMixin cls, | 518 ClassMemberMixin cls, |
| 489 String name) { | 519 String name) { |
| 490 if (cls.isMemberComputed(name)) return; | 520 if (cls.isMemberComputed(name)) return; |
| 491 LibraryElement library = cls.library; | 521 LibraryElement library = cls.library; |
| 492 _computeClassMember(compiler, cls, name, | 522 _computeClassMember(compiler, cls, name, |
| 493 new Setlet<Name>()..add(new Name(name, library)) | 523 new Setlet<Name>()..add(new Name(name, library)) |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 for (MemberSignature other in inheritedMembers) { | 706 for (MemberSignature other in inheritedMembers) { |
| 677 if (!compiler.types.isSubtype(inherited.functionType, | 707 if (!compiler.types.isSubtype(inherited.functionType, |
| 678 other.functionType)) { | 708 other.functionType)) { |
| 679 continue outer; | 709 continue outer; |
| 680 } | 710 } |
| 681 } | 711 } |
| 682 subtypesOfAllInherited.putIfAbsent(inherited.functionType, | 712 subtypesOfAllInherited.putIfAbsent(inherited.functionType, |
| 683 () => new Setlet<Member>()).add(inherited); | 713 () => new Setlet<Member>()).add(inherited); |
| 684 } | 714 } |
| 685 if (someAreGetters && !allAreGetters) { | 715 if (someAreGetters && !allAreGetters) { |
| 686 compiler.reportWarning(cls, | 716 DiagnosticMessage warning = compiler.createMessage( |
| 687 MessageKind.INHERIT_GETTER_AND_METHOD, | 717 cls, |
| 688 {'class': thisType, 'name': name.text }); | 718 MessageKind.INHERIT_GETTER_AND_METHOD, |
| 719 {'class': thisType, 'name': name.text }); |
| 720 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 689 for (Member inherited in inheritedMembers) { | 721 for (Member inherited in inheritedMembers) { |
| 690 MessageKind kind; | 722 MessageKind kind; |
| 691 if (inherited.isMethod) { | 723 if (inherited.isMethod) { |
| 692 kind = MessageKind.INHERITED_METHOD; | 724 kind = MessageKind.INHERITED_METHOD; |
| 693 } else { | 725 } else { |
| 694 assert(invariant(cls, inherited.isGetter, | 726 assert(invariant(cls, inherited.isGetter, |
| 695 message: 'Conflicting member is neither a method nor a ' | 727 message: 'Conflicting member is neither a method nor a ' |
| 696 'getter.')); | 728 'getter.')); |
| 697 if (inherited.isDeclaredByField) { | 729 if (inherited.isDeclaredByField) { |
| 698 kind = MessageKind.INHERITED_IMPLICIT_GETTER; | 730 kind = MessageKind.INHERITED_IMPLICIT_GETTER; |
| 699 } else { | 731 } else { |
| 700 kind = MessageKind.INHERITED_EXPLICIT_GETTER; | 732 kind = MessageKind.INHERITED_EXPLICIT_GETTER; |
| 701 } | 733 } |
| 702 } | 734 } |
| 703 compiler.reportInfo(inherited.element, kind, | 735 infos.add(compiler.createMessage( |
| 704 {'class': inherited.declarer, 'name': name.text }); | 736 inherited.element, |
| 737 kind, |
| 738 {'class': inherited.declarer, 'name': name.text})); |
| 705 } | 739 } |
| 740 compiler.reportWarning(warning, infos); |
| 706 interfaceMembers[name] = new ErroneousMember(inheritedMembers); | 741 interfaceMembers[name] = new ErroneousMember(inheritedMembers); |
| 707 } else if (subtypesOfAllInherited.length == 1) { | 742 } else if (subtypesOfAllInherited.length == 1) { |
| 708 // All signatures have the same type. | 743 // All signatures have the same type. |
| 709 Setlet<Member> members = subtypesOfAllInherited.values.first; | 744 Setlet<Member> members = subtypesOfAllInherited.values.first; |
| 710 MemberSignature inherited = members.first; | 745 MemberSignature inherited = members.first; |
| 711 if (members.length != 1) { | 746 if (members.length != 1) { |
| 712 // Multiple signatures with the same type => return a | 747 // Multiple signatures with the same type => return a |
| 713 // synthesized signature. | 748 // synthesized signature. |
| 714 inherited = new SyntheticMember( | 749 inherited = new SyntheticMember( |
| 715 members, inherited.type, inherited.functionType); | 750 members, inherited.type, inherited.functionType); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 message: "Members have not been fully computed for $this.")); | 945 message: "Members have not been fully computed for $this.")); |
| 911 if (interfaceMembersAreClassMembers) { | 946 if (interfaceMembersAreClassMembers) { |
| 912 classMembers.forEach((_, member) { | 947 classMembers.forEach((_, member) { |
| 913 if (!member.isStatic) f(member); | 948 if (!member.isStatic) f(member); |
| 914 }); | 949 }); |
| 915 } else { | 950 } else { |
| 916 interfaceMembers.forEach((_, member) => f(member)); | 951 interfaceMembers.forEach((_, member) => f(member)); |
| 917 } | 952 } |
| 918 } | 953 } |
| 919 } | 954 } |
| OLD | NEW |