Skip to content

Commit

Permalink
ModulePrinting: Teach synthesized extension analyzer to handle bounde…
Browse files Browse the repository at this point in the history
…d generic types appearing in requirements.
  • Loading branch information
nkcsgexi committed Mar 7, 2016
1 parent fb00e16 commit 7e3e42c
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 39 deletions.
66 changes: 66 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,68 @@ struct SynthesizedExtensionAnalyzer::Implementation {
pTransform(new ArchetypeSelfTransformer(Target)),
Results(collectSynthesizedExtensionInfo()) {}

Type checkElementType(StringRef Text) {
assert(Text.find('<') == StringRef::npos && "Not element type.");
assert(Text.find(',') == StringRef::npos && "Not element type.");
if (auto Result = pTransform->checkMemberTypeInternal(Text)) {
return Result;
}
return lookUpTypeInContext(DC, Text);
}

Type parseComplexTypeString(StringRef Text) {
Text = Text.trim();
auto ParamStart = Text.find_first_of('<');
auto ParamEnd = Text.find_last_of('>');
if(StringRef::npos == ParamStart) {
return checkElementType(Text);
}
Type GenericType = checkElementType(StringRef(Text.data(), ParamStart));
if (!GenericType)
return Type();
NominalTypeDecl *NTD = GenericType->getAnyNominal();
if (!NTD || NTD->getInnermostGenericParamTypes().empty())
return GenericType;
StringRef Param = StringRef(Text.data() + ParamStart + 1,
ParamEnd - ParamStart - 1);
std::vector<char> Brackets;
std::vector<Type> Arguments;
unsigned CurrentStart = 0;
for (unsigned I = 0; I < Param.size(); ++ I) {
char C = Param[I];
if (C == '<')
Brackets.push_back(C);
else if (C == '>')
Brackets.pop_back();
else if (C == ',' && Brackets.empty()) {
StringRef ArgString(Param.data() + CurrentStart, I - CurrentStart);
Type Arg = parseComplexTypeString(ArgString);
if (Arg.isNull())
return GenericType;
Arguments.push_back(Arg);
CurrentStart = I + 1;
}
}

// Add the last argument, or the only argument.
StringRef ArgString(Param.data() + CurrentStart,
Param.size() - CurrentStart);
Type Arg = parseComplexTypeString(ArgString);
if (Arg.isNull())
return GenericType;
Arguments.push_back(Arg);

auto GenericParams = NTD->getInnermostGenericParamTypes();
assert(Arguments.size() == GenericParams.size());
TypeSubstitutionMap Map;
for (auto It = GenericParams.begin(); It != GenericParams.end(); ++ It) {
auto Index = std::distance(GenericParams.begin(), It);
Map[(*It)->getCanonicalType()->castTo<SubstitutableType>()] =
Arguments[Index];
}
return NTD->getDeclaredTypeInContext().subst(DC->getParentModule(), Map, None);
}

SynthesizedExtensionInfo isApplicable(ExtensionDecl *Ext) {
assert(Ext->getGenericParams() && "Have no generic params.");
SynthesizedExtensionInfo Result;
Expand All @@ -232,6 +294,10 @@ struct SynthesizedExtensionAnalyzer::Implementation {
RequirementReprKind Kind = std::get<2>(TupleOp.getValue());
Type First = pTransform->checkMemberTypeInternal(FirstType);
Type Second = lookUpTypeInContext(DC, SecondType);
if (!First)
First = parseComplexTypeString(FirstType);
if (!Second)
Second = parseComplexTypeString(SecondType);
if (First && Second) {
First = First->getDesugaredType();
Second = Second->getDesugaredType();
Expand Down
119 changes: 80 additions & 39 deletions test/IDE/print_synthesized_extensions.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
// RUN: rm -rf %t && mkdir %t
// RUN: %target-swift-frontend -emit-module-path %t/print_synthesized_extensions.swiftmodule %s
// RUN: %target-swift-ide-test -print-module -annotate-print -synthesize-extension -print-interface -module-to-print=print_synthesized_extensions -I %t -source-filename=%s > %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN1 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN2 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN3 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN4 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN5 < %t.syn.txt
// RUN: FileCheck %s -check-prefix=CHECK-SYN6 < %t.syn.txt
// RUN: FileCheck %s < %t.syn.txt

public protocol P1{
associatedtype T1
Expand Down Expand Up @@ -111,39 +106,85 @@ public struct S7 {
}
}

// CHECK-SYN1: <synthesized>/// Synthesized extension from P1
// CHECK-SYN1: extension <ref:Struct>S1</ref> where T : P2 {
// CHECK-SYN1: <decl:Func>public func <loc>ef1(<decl:Param>t: T</decl>)</loc></decl>
// CHECK-SYN1: <decl:Func>public func <loc>ef2(<decl:Param>t: <ref:Struct>S2</ref></decl>)</loc></decl>
// CHECK-SYN1: }</synthesized>

// CHECK-SYN2: <synthesized>/// Synthesized extension from P2
// CHECK-SYN2: extension <ref:Struct>S1</ref> where T : P2 {
// CHECK-SYN2: <decl:Func>public func <loc>p2member()</loc></decl>
// CHECK-SYN2: }</synthesized>

// No applicable extensions for S2
// CHECK-SYN1-NOT: extension S2 where

// No applicable extensions for S3
// CHECK-SYN1-NOT: extension S3 where

// CHECK-SYN3: <synthesized>/// Synthesized extension from P1
// CHECK-SYN3: extension <ref:Struct>S4</ref> {
// CHECK-SYN3: <decl:Func>public func <loc>p1IntFunc(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-SYN3: }</synthesized>
public extension P1 where T1 == S9<Int> {
public func S9IntFunc() {}
}

// CHECK-SYN4: <synthesized>/// Synthesized extension from P1
// CHECK-SYN4: extension <ref:Struct>S6</ref> {
// CHECK-SYN4: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-SYN4: }</synthesized>
public struct S9<T> : P3 {}

// CHECK-SYN5: <synthesized>/// Synthesized extension from P1
// CHECK-SYN5: extension <ref:module>print_synthesized_extensions</ref>.<ref:Struct>S7</ref>.<ref:Struct>S8</ref> {
// CHECK-SYN5: <decl:Func>public func <loc>ef5(<decl:Param>t: <ref:Struct>S5</ref></decl>)</loc></decl>
// CHECK-SYN5: }</synthesized>
public struct S10 : P1 {
public typealias T1 = S9<Int>
public typealias T2 = S9<Int>
public func f1(t : T1) -> T1 {
return t
}
public func f2(t : T2) -> T2 {
return t
}
}

// CHECK-SYN6: <synthesized>/// Synthesized extension from P1
// CHECK-SYN6: extension <ref:module>print_synthesized_extensions</ref>.<ref:Struct>S7</ref>.<ref:Struct>S8</ref> {
// CHECK-SYN6: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-SYN6: }</synthesized>
// CHECK: <synthesized>/// Synthesized extension from P2
// CHECK-NEXT: extension <ref:Struct>S1</ref> where T : P2 {
// CHECK-NEXT: <decl:Func>public func <loc>p2member()</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S1</ref> where T == Int {
// CHECK-NEXT: <decl:Func>public func <loc>p1IntFunc(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S1</ref> where T : P3 {
// CHECK-NEXT: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S1</ref> where T : P2 {
// CHECK-NEXT: <decl:Func>public func <loc>ef1(<decl:Param>t: T</decl>)</loc></decl>
// CHECK-NEXT: <decl:Func>public func <loc>ef2(<decl:Param>t: <ref:Struct>S2</ref></decl>)</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S1</ref> where T == S9<Int> {
// CHECK-NEXT: <decl:Func>public func <loc>S9IntFunc()</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S10</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S10</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>ef5(<decl:Param>t: <ref:Struct>S9</ref><<ref:Struct>Int</ref>></decl>)</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S10</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>S9IntFunc()</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S4</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>p1IntFunc(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S6</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:Struct>S6</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>ef5(<decl:Param>t: <ref:Struct>S5</ref></decl>)</loc></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:module>print_synthesized_extensions</ref>.<ref:Struct>S7</ref>.<ref:Struct>S8</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>p3Func(<decl:Param>i: <ref:Struct>Int</ref></decl>)</loc> -> <ref:Struct>Int</ref></decl>
// CHECK-NEXT: }</synthesized>

// CHECK: <synthesized>/// Synthesized extension from P1
// CHECK-NEXT: extension <ref:module>print_synthesized_extensions</ref>.<ref:Struct>S7</ref>.<ref:Struct>S8</ref> {
// CHECK-NEXT: <decl:Func>public func <loc>ef5(<decl:Param>t: <ref:Struct>S5</ref></decl>)</loc></decl>
// CHECK-NEXT: }</synthesized>

0 comments on commit 7e3e42c

Please sign in to comment.