From 87cbb7d2d0ecd0df9edca630154576399cd42010 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 11 Sep 2025 18:00:48 -0400 Subject: [PATCH] AST: New way of printing @_opaqueReturnTypeOf when parameter packs are involved This is the ASTPrinter change to go with the Sema change. We now print @_opaqueReturnTypeOf using the new nested syntax when parameter packs are involved. Fixes rdar://problem/151171381. --- lib/AST/ASTPrinter.cpp | 33 ++++- .../variadic-opaque-result-types.swift | 122 ++++++++++++++++++ 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 test/ModuleInterface/variadic-opaque-result-types.swift diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index d23bcd445de..99fce169bc5 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -7515,10 +7515,37 @@ public: Printer << ") __"; if (genericSig) { - printGenericArgs(decl->getASTContext(), - genericSig.getGenericParams(), - T->getSubstitutions().getReplacementTypes()); + auto &ctx = decl->getASTContext(); + auto params = genericSig.getGenericParams(); + auto args = T->getSubstitutions().getReplacementTypes(); + + // Use the new "nested" syntax if there is at least one parameter pack, + // because that case didn't round trip at all before anyway. Otherwise, + // use the old "flat" syntax, even when the owner declaration is in a + // nested generic context, because we want the generated swiftinterface + // to continue to work on old compilers. + if (genericSig->hasParameterPack()) { + bool first = true; + + while (!params.empty()) { + if (!first) { Printer << ".__"; } + first = false; + + unsigned end = 1; + unsigned depth = params.front()->getDepth(); + while (end < params.size() && params[end]->getDepth() == depth) { + ++end; + } + + printGenericArgs(ctx, params.take_front(end), args.take_front(end)); + params = params.slice(end); + args = args.slice(end); + } + } else { + printGenericArgs(ctx, params, args); + } } + return; } case PrintOptions::OpaqueReturnTypePrintingMode::Description: { diff --git a/test/ModuleInterface/variadic-opaque-result-types.swift b/test/ModuleInterface/variadic-opaque-result-types.swift new file mode 100644 index 00000000000..7874a76d9b4 --- /dev/null +++ b/test/ModuleInterface/variadic-opaque-result-types.swift @@ -0,0 +1,122 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-emit-module-interface(%t/VariadicOpaqueResultTypes.swiftinterface) %s -module-name VariadicOpaqueResultTypes -target %target-swift-5.9-abi-triple +// RUN: %target-swift-typecheck-module-from-interface(%t/VariadicOpaqueResultTypes.swiftinterface) -module-name VariadicOpaqueResultTypes +// RUN: %FileCheck %s < %t/VariadicOpaqueResultTypes.swiftinterface + + +/// +/// First, make sure pack expansions can appear in the generic argument list of an opaque return type. +/// + +public struct I1: IteratorProtocol { + public mutating func next() -> (some Any)? { return 3 } +} + +// CHECK: public struct I1 : Swift.IteratorProtocol { +// CHECK: public mutating func next() -> (some Any)? +// CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes2I1V4nextQrSgyF", 0) __ +// CHECK: } + + +public struct S1: Sequence { + public func makeIterator() -> some IteratorProtocol { + return I1() + } +} + +// CHECK: public struct S1 : Swift.Sequence { +// CHECK: public func makeIterator() -> some Swift.IteratorProtocol +// CHECK: public typealias Element = (@_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes2S1V12makeIteratorQryF", 0) __).Element +// CHECK: public typealias Iterator = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes2S1V12makeIteratorQryF", 0) __ +// CHECK: } + + +public struct Scalar { + public struct I2: IteratorProtocol { + public mutating func next() -> (some Any)? { return 3 } + } +} + + +/// +/// Now, test nested types. The next example uses the old "flat" syntax, because parameter packs are not involved. +/// + + +// CHECK: public struct Scalar { +// CHECK: public struct I2 : Swift.IteratorProtocol { +// CHECK: public mutating func next() -> (some Any)? +// CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes6ScalarV2I2V4nextQrSgyF", 0) __ +// CHECK: } +// CHECK: } + + +public struct S2: Sequence { + public func makeIterator() -> Scalar.I2 { + return .init() + } +} + +// CHECK: public struct S2 : Swift.Sequence { +// CHECK: public func makeIterator() -> VariadicOpaqueResultTypes.Scalar.I2 +// CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes6ScalarV2I2V4nextQrSgyF", 0) __ +// CHECK: public typealias Iterator = VariadicOpaqueResultTypes.Scalar.I2 +// CHECK: } + + +/// +/// The remaining examples use the new nested syntax. +/// + +// CHECK: public struct Variadic { +public struct Variadic { + public struct I3: IteratorProtocol { + public mutating func next() -> (some Any)? { return 3 } + } + + // CHECK: public struct I3 : Swift.IteratorProtocol { + // CHECK: public mutating func next() -> (some Any)? + // CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes0A0V2I3V4nextQrSgyF", 0) __.__ + // CHECK: } + + public struct Middle { + public struct Inner { + public struct I4: IteratorProtocol { + public mutating func next() -> (some Any)? { return 3 } + } + } + } + + // CHECK: public struct Middle { + // CHECK: public struct Inner { + // CHECK: public struct I4 : Swift.IteratorProtocol { + // CHECK: public mutating func next() -> (some Any)? + // CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes0A0V6MiddleV5InnerV2I4V4nextQrSgyF", 0) __.__ + // CHECK: } + // CHECK: } + // CHECK: } +} +// CHECK: } + +// CHECK: public struct S3 : Swift.Sequence { +// CHECK: public func makeIterator() -> VariadicOpaqueResultTypes.Variadic.I3 +// CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes0A0V2I3V4nextQrSgyF", 0) __.__ +// CHECK: public typealias Iterator = VariadicOpaqueResultTypes.Variadic.I3 +// CHECK: } +public struct S3: Sequence { + public func makeIterator() -> Variadic.I3 { + return .init() + } +} + +// CHECK: public struct S4 : Swift.Sequence { +// CHECK: public func makeIterator() -> VariadicOpaqueResultTypes.Variadic.Middle.Inner.I4 +// CHECK: public typealias Element = @_opaqueReturnTypeOf("$s25VariadicOpaqueResultTypes0A0V6MiddleV5InnerV2I4V4nextQrSgyF", 0) __.__ +// CHECK: public typealias Iterator = VariadicOpaqueResultTypes.Variadic.Middle.Inner.I4 +// CHECK: } +public struct S4: Sequence { + public func makeIterator() -> Variadic.Middle.Inner.I4 { + return .init() + } +} +