diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 909df265d15..5be5b71aab9 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -8248,6 +8248,39 @@ static void getSyntacticInheritanceClause(const ProtocolDecl *proto, } } +static Type stripParameterizedProtocolArgs(Type type) { + if (!type) + return type; + + // For each ParameterizedProtocolType process each member recursively + if (auto *compositionType = type->getAs()) { + SmallVector processedMembers; + bool hasChanged = false; + for (auto member : compositionType->getMembers()) { + Type processedMember = stripParameterizedProtocolArgs(member); + if (!processedMember) + continue; + processedMembers.push_back(processedMember); + if (processedMember.getPointer() != member.getPointer()) + hasChanged = true; + } + // Rebuild ProtocolCompositionType if at least one member had generic args + if (hasChanged) { + return ProtocolCompositionType::get( + type->getASTContext(), processedMembers, + compositionType->getInverses(), + compositionType->hasExplicitAnyObject()); + } + return type; + } + + // Strip generic arguments of a single ParameterizedProtocolType + if (auto *paramProto = type->getAs()) { + return paramProto->getBaseType(); + } + return type; +} + void swift::getInheritedForPrinting( const Decl *decl, const PrintOptions &options, @@ -8317,7 +8350,16 @@ swift::getInheritedForPrinting( } } - Results.push_back(inherited.getEntry(i)); + auto entry = inherited.getEntry(i); + if (auto type = entry.getType()) { + Type strippedType = stripParameterizedProtocolArgs(type); + if (strippedType.getPointer() != type.getPointer()) { + entry = InheritedEntry(TypeLoc::withoutLoc(strippedType), + entry.getOptions()); + } + } + + Results.push_back(entry); } // Collect synthesized conformances. diff --git a/test/ModuleInterface/parameterized-protocol-type-inheritance.swift b/test/ModuleInterface/parameterized-protocol-type-inheritance.swift new file mode 100644 index 00000000000..e0c352f8271 --- /dev/null +++ b/test/ModuleInterface/parameterized-protocol-type-inheritance.swift @@ -0,0 +1,60 @@ +// RUN: %target-swift-emit-module-interface(%t/Fancy.swiftinterface) %s -module-name Library +// RUN: %target-swift-typecheck-module-from-interface(%t/Fancy.swiftinterface) -module-name Library +// RUN: %FileCheck %s < %t/Fancy.swiftinterface + +public protocol Fancy { + associatedtype Stuff +} + +// CHECK: public struct T : Library.Fancy { +// CHECK: public typealias Stuff = Swift.Float64 +public struct T: Fancy { +} + +public protocol Q { +} + +// CHECK: public struct S : Library.Fancy & Library.Q { +// CHECK: public typealias Stuff = Swift.Int +public struct S: Fancy & Q { +} + +public protocol P { +} + +// CHECK: public struct V : Library.Fancy & Library.P & Library.Q { +// CHECK: public typealias Stuff = Swift.CChar32 +public struct V: ((Fancy & P) & Q) { +} + +public protocol Bar { + associatedtype T +} + +// CHECK: public struct X : Library.Bar & Library.Fancy +// CHECK: public typealias Stuff = Swift.CChar32 +// CHECK: public typealias T = Swift.Int +public struct X: Fancy & Bar { +} + +public class Base { +} + +public protocol B: ~Copyable { + associatedtype A +} + +// CHECK: public class Derived : Library.Base & Library.B { +// CHECK: public typealias A = Swift.Int +public class Derived: Base & B { +} + +public protocol R: ~Copyable & ~Escapable { + associatedtype E +} + +// CHECK: public struct N : Library.B & Library.R & ~Copyable { +// CHECK: public typealias A = Swift.Float64 +// CHECK: public typealias E = Swift.Int +public struct N: R & B & ~Copyable { +}