From 74edd073e0fb2ab3affdc0690c1be9b3cfefb31b Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Wed, 22 Jul 2020 12:45:28 -0700 Subject: [PATCH] AST: consider extension and extended type are from the same module if valid alternative module names are equal Framework authors may move a type along with its extensions from a high-level framework to a low-level one. We should compare alternative module names for them to check if they should be considered from the same module to preserve ABI stability. rdar://65889766 --- lib/AST/Decl.cpp | 26 ++++++++++---- test/TBD/move_to_extension_comove.swift | 48 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 test/TBD/move_to_extension_comove.swift diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 31f9bb20c088f..a8ba3eca40072 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1295,14 +1295,28 @@ bool ExtensionDecl::isConstrainedExtension() const { bool ExtensionDecl::isEquivalentToExtendedContext() const { auto decl = getExtendedNominal(); bool extendDeclFromSameModule = false; - if (!decl->getAlternateModuleName().empty()) { - // if the extended type was defined in the same module with the extension, - // we should consider them as the same module to preserve ABI stability. - extendDeclFromSameModule = decl->getAlternateModuleName() == - getParentModule()->getNameStr(); + auto extensionAlterName = getAlternateModuleName(); + auto typeAlterName = decl->getAlternateModuleName(); + + if (!extensionAlterName.empty()) { + if (!typeAlterName.empty()) { + // Case I: type and extension are both moved from somewhere else + extendDeclFromSameModule = typeAlterName == extensionAlterName; + } else { + // Case II: extension alone was moved from somewhere else + extendDeclFromSameModule = extensionAlterName == + decl->getParentModule()->getNameStr(); + } } else { - extendDeclFromSameModule = decl->getParentModule() == getParentModule(); + if (!typeAlterName.empty()) { + // Case III: extended type alone was moved from somewhere else + extendDeclFromSameModule = typeAlterName == getParentModule()->getNameStr(); + } else { + // Case IV: neither of type and extension was moved from somewhere else + extendDeclFromSameModule = getParentModule() == decl->getParentModule(); + } } + return extendDeclFromSameModule && !isConstrainedExtension() && !getDeclaredInterfaceType()->isExistentialType(); diff --git a/test/TBD/move_to_extension_comove.swift b/test/TBD/move_to_extension_comove.swift new file mode 100644 index 0000000000000..8cc2b07e1fab6 --- /dev/null +++ b/test/TBD/move_to_extension_comove.swift @@ -0,0 +1,48 @@ +// REQUIRES: OS=macosx +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -typecheck %s -emit-tbd -emit-tbd-path %t/before_move.tbd -D BEFORE_MOVE -module-name Foo -enable-library-evolution -emit-sil -o %t/before_move.sil +// RUN: %FileCheck %s --check-prefix=CHECK-TBD < %t/before_move.tbd +// RUN: %FileCheck %s --check-prefix=CHECK-SIL < %t/before_move.sil + +// RUN: %target-swift-frontend %s -emit-module -emit-module-path %t/FooCore.swiftmodule -D AFTER_MOVE_FOO_CORE -module-name FooCore -enable-library-evolution -emit-tbd -emit-tbd-path %t/after_move.tbd -emit-sil -o %t/after_move.sil + +// RUN: %FileCheck %s --check-prefix=CHECK-TBD < %t/after_move.tbd +// RUN: %FileCheck %s --check-prefix=CHECK-SIL < %t/after_move.sil + +// CHECK-TBD: '_$s3Foo4DateC03SubB0V4yearAESi_tcfC' +// CHECK-TBD: '_$s3Foo4DateC03SubB0VMn' + +// CHECK-SIL: sil [available 10.7] @$s3Foo4DateC03SubB0V4yearAESi_tcfC : $@convention(method) (Int, @thin Date.SubDate.Type) -> @out Date.SubDate + +#if BEFORE_MOVE + +@available(OSX 10.7, *) +public class Date { + public static func getCurrentYear() -> Int { return 2020 } +} + +@available(OSX 10.7, *) +extension Date { + public struct SubDate { + public init(year: Int) {} + } +} + +#endif + +#if AFTER_MOVE_FOO_CORE + +@available(OSX 10.7, *) +@_originallyDefinedIn(module: "Foo", OSX 10.9) +public class Date {} + +@available(OSX 10.7, *) +@_originallyDefinedIn(module: "Foo", OSX 10.9) +extension Date { + public struct SubDate { + public init(year: Int) {} + } +} + +#endif