diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index e23c6abadc378..38618dae2e258 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 455; // Last change: reorder block IDs +const uint16_t SWIFTMODULE_VERSION_MINOR = 456; // Last change: encode depth in generic param XREFs using DeclIDField = BCFixed<31>; @@ -1403,7 +1403,8 @@ namespace decls_block { using XRefGenericParamPathPieceLayout = BCRecordLayout< XREF_GENERIC_PARAM_PATH_PIECE, - BCVBR<5> // index + BCVBR<5>, // depth + BCVBR<5> // index >; using SILGenNameDeclAttrLayout = BCRecordLayout< diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 39a9bab21ebfb..b201980a5eda7 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1622,8 +1622,8 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) { getXRefDeclNameForError()); } - uint32_t paramIndex; - XRefGenericParamPathPieceLayout::readRecord(scratch, paramIndex); + uint32_t depth, paramIndex; + XRefGenericParamPathPieceLayout::readRecord(scratch, depth, paramIndex); pathTrace.addGenericParam(paramIndex); @@ -1645,7 +1645,7 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) { assert(paramList && "Couldn't find constrained extension"); } else { // Simple case: use the nominal type's generic parameters. - paramList = nominal->getGenericParams(); + paramList = nominal->getGenericParamsOfContext(); } } else if (auto alias = dyn_cast(base)) { paramList = alias->getGenericParams(); @@ -1660,6 +1660,18 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) { "cross-reference to generic param for non-generic type", pathTrace, getXRefDeclNameForError()); } + + unsigned currentDepth = paramList->getDepth(); + if (currentDepth < depth) { + return llvm::make_error( + "a containing type has been made non-generic", + pathTrace, getXRefDeclNameForError()); + } + while (currentDepth > depth) { + paramList = paramList->getOuterParameters(); + --currentDepth; + } + if (paramIndex >= paramList->size()) { return llvm::make_error( "generic argument index out of bounds", diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 78b2b8d6c2e4f..44617cd7d2343 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2026,6 +2026,7 @@ void Serializer::writeCrossReference(const Decl *D) { "Cannot cross reference a generic type decl at module scope."); abbrCode = DeclTypeAbbrCodes[XRefGenericParamPathPieceLayout::Code]; XRefGenericParamPathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, + genericParam->getDepth(), genericParam->getIndex()); return; } diff --git a/test/Serialization/Inputs/xref-generic-params-other-extensions-constrained.swift b/test/Serialization/Inputs/xref-generic-params-other-extensions-constrained.swift new file mode 100644 index 0000000000000..2f5b721a85916 --- /dev/null +++ b/test/Serialization/Inputs/xref-generic-params-other-extensions-constrained.swift @@ -0,0 +1,28 @@ +public struct OuterNonGeneric {} +extension OuterNonGeneric { + public struct InnerNonGeneric {} + public struct InnerGeneric {} +} + +public struct OuterGeneric {} +extension OuterGeneric { + public struct InnerNonGeneric {} + public struct InnerGeneric {} +} + + +extension OuterNonGeneric.InnerNonGeneric { + public typealias AliasTy = () +} + +extension OuterNonGeneric.InnerGeneric where Y1: Equatable { + public typealias AliasTy = (Y1, Y2) +} + +extension OuterGeneric.InnerNonGeneric where X1: Equatable { + public typealias AliasTy = (X1, X2) +} + +extension OuterGeneric.InnerGeneric where X1: Equatable, Y1: Equatable { + public typealias AliasTy = (X1, X2, Y1, Y2) +} diff --git a/test/Serialization/Inputs/xref-generic-params-other-extensions-mixed.swift b/test/Serialization/Inputs/xref-generic-params-other-extensions-mixed.swift new file mode 100644 index 0000000000000..5ea29020ed8ba --- /dev/null +++ b/test/Serialization/Inputs/xref-generic-params-other-extensions-mixed.swift @@ -0,0 +1,19 @@ +public struct OuterNonGeneric {} +extension OuterNonGeneric { + public struct InnerNonGeneric { + public typealias AliasTy = () + } + public struct InnerGeneric { + public typealias AliasTy = (Y1, Y2) + } +} + +public struct OuterGeneric {} +extension OuterGeneric { + public struct InnerNonGeneric { + public typealias AliasTy = (X1, X2) + } + public struct InnerGeneric { + public typealias AliasTy = (X1, X2, Y1, Y2) + } +} diff --git a/test/Serialization/Inputs/xref-generic-params-other-extensions.swift b/test/Serialization/Inputs/xref-generic-params-other-extensions.swift new file mode 100644 index 0000000000000..c7ef407e7daa0 --- /dev/null +++ b/test/Serialization/Inputs/xref-generic-params-other-extensions.swift @@ -0,0 +1,28 @@ +public struct OuterNonGeneric {} +extension OuterNonGeneric { + public struct InnerNonGeneric {} + public struct InnerGeneric {} +} + +public struct OuterGeneric {} +extension OuterGeneric { + public struct InnerNonGeneric {} + public struct InnerGeneric {} +} + + +extension OuterNonGeneric.InnerNonGeneric { + public typealias AliasTy = () +} + +extension OuterNonGeneric.InnerGeneric { + public typealias AliasTy = (Y1, Y2) +} + +extension OuterGeneric.InnerNonGeneric { + public typealias AliasTy = (X1, X2) +} + +extension OuterGeneric.InnerGeneric { + public typealias AliasTy = (X1, X2, Y1, Y2) +} diff --git a/test/Serialization/Inputs/xref-generic-params-other.swift b/test/Serialization/Inputs/xref-generic-params-other.swift new file mode 100644 index 0000000000000..1f9e334f366ca --- /dev/null +++ b/test/Serialization/Inputs/xref-generic-params-other.swift @@ -0,0 +1,17 @@ +public struct OuterNonGeneric { + public struct InnerNonGeneric { + public typealias AliasTy = () + } + public struct InnerGeneric { + public typealias AliasTy = (Y1, Y2) + } +} + +public struct OuterGeneric { + public struct InnerNonGeneric { + public typealias AliasTy = (X1, X2) + } + public struct InnerGeneric { + public typealias AliasTy = (X1, X2, Y1, Y2) + } +} diff --git a/test/Serialization/xref-extensions.swift b/test/Serialization/xref-extensions-counters.swift similarity index 100% rename from test/Serialization/xref-extensions.swift rename to test/Serialization/xref-extensions-counters.swift diff --git a/test/Serialization/xref-generic-params.swift b/test/Serialization/xref-generic-params.swift new file mode 100644 index 0000000000000..6e7ab1ad67360 --- /dev/null +++ b/test/Serialization/xref-generic-params.swift @@ -0,0 +1,40 @@ +// RUN: %empty-directory(%t) + +// Run the same test several times, providing the nested types a different way +// each time. + +// RUN: %target-swift-frontend -emit-module -o %t/a.swiftmodule -primary-file %s %S/Inputs/xref-generic-params-other.swift -module-name main +// RUN: %target-swift-frontend -emit-module -o %t/b.swiftmodule %s -primary-file %S/Inputs/xref-generic-params-other.swift -module-name main +// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/main.swiftmodule %t/a.swiftmodule %t/b.swiftmodule -module-name main +// RUN: %target-swift-ide-test -print-module -module-to-print=main -I %t -source-filename=x | %FileCheck %s + +// RUN: %target-swift-frontend -emit-module -o %t/a-extensions.swiftmodule -primary-file %s %S/Inputs/xref-generic-params-other-extensions.swift -module-name extensions +// RUN: %target-swift-frontend -emit-module -o %t/b-extensions.swiftmodule %s -primary-file %S/Inputs/xref-generic-params-other-extensions.swift -module-name extensions +// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/extensions.swiftmodule %t/a-extensions.swiftmodule %t/b-extensions.swiftmodule -module-name extensions +// RUN: %target-swift-ide-test -print-module -module-to-print=extensions -I %t -source-filename=x | %FileCheck %s + +// RUN: %target-swift-frontend -emit-module -o %t/a-extensions_mixed.swiftmodule -primary-file %s %S/Inputs/xref-generic-params-other-extensions-mixed.swift -module-name extensions_mixed +// RUN: %target-swift-frontend -emit-module -o %t/b-extensions_mixed.swiftmodule %s -primary-file %S/Inputs/xref-generic-params-other-extensions-mixed.swift -module-name extensions_mixed +// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/extensions_mixed.swiftmodule %t/a-extensions_mixed.swiftmodule %t/b-extensions_mixed.swiftmodule -module-name extensions_mixed +// RUN: %target-swift-ide-test -print-module -module-to-print=extensions_mixed -I %t -source-filename=x | %FileCheck %s + +// RUN: %target-swift-frontend -emit-module -o %t/a-extensions_constrained.swiftmodule -primary-file %s %S/Inputs/xref-generic-params-other-extensions-constrained.swift -module-name extensions_constrained +// RUN: %target-swift-frontend -emit-module -o %t/b-extensions_constrained.swiftmodule %s -primary-file %S/Inputs/xref-generic-params-other-extensions-constrained.swift -module-name extensions_constrained +// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/extensions_constrained.swiftmodule %t/a-extensions_constrained.swiftmodule %t/b-extensions_constrained.swiftmodule -module-name extensions_constrained +// RUN: %target-swift-ide-test -print-module -module-to-print=extensions_constrained -I %t -source-filename=x | %FileCheck %s + +public struct A: Equatable {} +public struct B: Equatable {} +public struct C: Equatable {} +public struct D: Equatable {} + +// CHECK-LABEL: func test( +public func test( +// CHECK-SAME: _: OuterNonGeneric.InnerNonGeneric.AliasTy + _: OuterNonGeneric.InnerNonGeneric.AliasTy, +// CHECK-SAME: _: OuterNonGeneric.InnerGeneric.AliasTy + _: OuterNonGeneric.InnerGeneric.AliasTy, +// CHECK-SAME: _: OuterGeneric.InnerNonGeneric.AliasTy + _: OuterGeneric.InnerNonGeneric.AliasTy, +// CHECK-SAME: _: OuterGeneric.InnerGeneric.AliasTy + _: OuterGeneric.InnerGeneric.AliasTy) {}