[ASTPrinter] Fix issue printing Self resolved to a generic type

When printing a type in type through `ASTPrinter::printTransformedTypeWithOptions`, we are removing any contextual types by mapping the type out of context. However, when substituting `Self` (or any other type member) with their concrete type from `CurrentType`, we might re-introduce contextual types.

To fix this, make sure that `CurrentType` is always an interface type that has all contextual types removed.

Fixes rdar://76021569
This commit is contained in:
Alex Hoppen
2021-04-09 13:58:09 +02:00
parent 5cf19e4570
commit 9ba892c5af
4 changed files with 51 additions and 10 deletions

View File

@@ -535,6 +535,13 @@ class PrintAST : public ASTVisitor<PrintAST> {
Decl *Current = nullptr;
Type CurrentType;
void setCurrentType(Type NewCurrentType) {
CurrentType = NewCurrentType;
assert(CurrentType.isNull() ||
!CurrentType->hasArchetype() &&
"CurrentType should be an interface type");
}
friend DeclVisitor<PrintAST>;
/// RAII object that increases the indentation level.
@@ -913,8 +920,13 @@ private:
public:
PrintAST(ASTPrinter &Printer, const PrintOptions &Options)
: Printer(Printer), Options(Options) {
if (Options.TransformContext)
CurrentType = Options.TransformContext->getBaseType();
if (Options.TransformContext) {
Type CurrentType = Options.TransformContext->getBaseType();
if (CurrentType && CurrentType->hasArchetype()) {
CurrentType = CurrentType->mapTypeOutOfContext();
}
setCurrentType(CurrentType);
}
}
using ASTVisitor::visit;
@@ -941,11 +953,11 @@ public:
if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
auto Subs = CurrentType->getContextSubstitutionMap(
Options.CurrentModule, NTD->getDeclContext());
CurrentType = NTD->getDeclaredInterfaceType().subst(Subs);
setCurrentType(NTD->getDeclaredInterfaceType().subst(Subs));
}
}
SWIFT_DEFER { CurrentType = OldType; };
SWIFT_DEFER { setCurrentType(OldType); };
if (Synthesize) {
Printer.setSynthesizedTarget(Options.TransformContext->getDecl());

View File

@@ -0,0 +1,29 @@
// RUN: %empty-directory(%t.mod)
// RUN: %swift -emit-module -o %t.mod/test.swiftmodule %s -parse-as-library -emit-module-doc-path %t.mod/test.swiftdoc
// RUN: %sourcekitd-test -req=doc-info -module test -- -I %t.mod | %FileCheck %s
public protocol Proto {}
public struct AttributesSlice1<T> : Proto {}
public struct ListFormatStyle<Style, Base: Proto> {
public enum Width {
case standard
case short
case narrow
}
}
public extension Proto {
// The tricky part about this test case is that when synthesizing this
// extension for `AttributesSlice1`, we replace `Self` by
// `AttributesSlice1<T>` but `S` remains an generic parameter. We thus
// have a type that contains both an archetype (namely `T` as the generic
// paramter of `AttributedSlice1<T>`) and an unbound generic paramters.
// This used to cause issues when printing the type.
func formatted<S>(width: ListFormatStyle<S, Self>.Width) -> String {
// CHECK: func formatted<S>(width width: ListFormatStyle<S, AttributesSlice1<T>>.Width) -> String
fatalError()
}
}

View File

@@ -1643,7 +1643,7 @@ func shouldPrintAnyAsKeyword(x x: Any)
{
key.kind: source.lang.swift.ref.generic_type_param,
key.name: "Wrapped",
key.usr: "s:4cake2S3VA2A2P6RzrlE7Wrappedxmfp",
key.usr: "s:4cake2S3V7Wrappedxmfp",
key.offset: 2041,
key.length: 7
},
@@ -2744,7 +2744,7 @@ func shouldPrintAnyAsKeyword(x x: Any)
key.original_usr: "s:4cake2P6PAAE4null7ElementQzSgvp",
key.offset: 2031,
key.length: 34,
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>null</decl.name>: <decl.var.type><ref.generic_type_param usr=\"s:4cake2S3VA2A2P6RzrlE7Wrappedxmfp\">Wrapped</ref.generic_type_param>.<ref.associatedtype usr=\"s:4cake2P5P7ElementQa\">Element</ref.associatedtype>?</decl.var.type> { <syntaxtype.keyword>get</syntaxtype.keyword> }</decl.var.instance>"
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>null</decl.name>: <decl.var.type><ref.generic_type_param usr=\"s:4cake2S3V7Wrappedxmfp\">Wrapped</ref.generic_type_param>.<ref.associatedtype usr=\"s:4cake2P5P7ElementQa\">Element</ref.associatedtype>?</decl.var.type> { <syntaxtype.keyword>get</syntaxtype.keyword> }</decl.var.instance>"
}
]
},

View File

@@ -897,7 +897,7 @@ protocol Other1 {
{
key.kind: source.lang.swift.ref.generic_type_param,
key.name: "T",
key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp",
key.usr: "s:16UnderscoredProto1DV1Txmfp",
key.offset: 1472,
key.length: 1
},
@@ -945,7 +945,7 @@ protocol Other1 {
{
key.kind: source.lang.swift.ref.generic_type_param,
key.name: "T",
key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp",
key.usr: "s:16UnderscoredProto1DV1Txmfp",
key.offset: 1585,
key.length: 1
},
@@ -1570,7 +1570,7 @@ protocol Other1 {
],
key.offset: 1454,
key.length: 135,
key.fully_annotated_decl: "<syntaxtype.keyword>extension</syntaxtype.keyword> <ref.struct usr=\"s:16UnderscoredProto1DV\">D</ref.struct> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:16UnderscoredProto1DVAASQRzrlE1Txmfp\">T</ref.generic_type_param> : <ref.protocol usr=\"s:16UnderscoredProto6Other1P\">Other1</ref.protocol></decl.generic_type_requirement>, <decl.generic_type_requirement><ref.generic_type_param usr=\"s:16UnderscoredProto1DVAASQRzrlE1Txmfp\">T</ref.generic_type_param> : <ref.protocol usr=\"s:SQ\">Equatable</ref.protocol></decl.generic_type_requirement>",
key.fully_annotated_decl: "<syntaxtype.keyword>extension</syntaxtype.keyword> <ref.struct usr=\"s:16UnderscoredProto1DV\">D</ref.struct> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:16UnderscoredProto1DV1Txmfp\">T</ref.generic_type_param> : <ref.protocol usr=\"s:16UnderscoredProto6Other1P\">Other1</ref.protocol></decl.generic_type_requirement>, <decl.generic_type_requirement><ref.generic_type_param usr=\"s:16UnderscoredProto1DVAASQRzrlE1Txmfp\">T</ref.generic_type_param> : <ref.protocol usr=\"s:SQ\">Equatable</ref.protocol></decl.generic_type_requirement>",
key.extends: {
key.kind: source.lang.swift.ref.struct,
key.name: "D",
@@ -1584,7 +1584,7 @@ protocol Other1 {
key.original_usr: "s:16UnderscoredProto05_SomeB0PA2A6Other14ItemRpzrlE04fromcB24ExtensionSplitConditions05takese2IfD0yAF_tF",
key.offset: 1505,
key.length: 82,
key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>fromSomeProtoExtensionSplitConditions</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>takesItemIfOther1</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.generic_type_param usr=\"s:16UnderscoredProto1DVAASQRzrlE1Txmfp\">T</ref.generic_type_param></decl.var.parameter.type></decl.var.parameter>)</decl.function.method.instance>",
key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>fromSomeProtoExtensionSplitConditions</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>takesItemIfOther1</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.generic_type_param usr=\"s:16UnderscoredProto1DV1Txmfp\">T</ref.generic_type_param></decl.var.parameter.type></decl.var.parameter>)</decl.function.method.instance>",
key.entities: [
{
key.kind: source.lang.swift.decl.var.local,