Skip to content

[SourceKit] Workaround a bug that parameterized protocols without 'any' cannot be mangled #60765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/IDE/CodeCompletionResultType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
return USRBasedType::null(Arena);
}

// ParameterizedProtocolType should always be wrapped in ExistentialType and
// cannot be mangled on its own.
// But ParameterizedProtocolType can currently occur in 'typealias'
// declarations. rdar://99176683
// To avoid crashing in USR generation, simply return a null type until the
// underlying issue has been fixed.
if (Ty->is<ParameterizedProtocolType>()) {
return USRBasedType::null(Arena);
}

SmallString<32> USR;
llvm::raw_svector_ostream OS(USR);
printTypeUSR(Ty, OS);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %empty-directory(%t/split)
// RUN: %empty-directory(%t/build)
// RUN: %{python} %utils/split_file.py -o %t/split %s

// RUN: %target-swift-frontend -emit-module -o %t/build %t/split/pck.swift

// RUN: %target-swift-ide-test -code-completion -source-filename %t/split/test.swift -I %t/build -code-completion-token=COMPLETE | %FileCheck %s

// BEGIN pck.swift

public protocol Foo<Bar> {
associatedtype Bar
}

public typealias Problem = Foo<String>

public protocol EmptyProto {}
public typealias ConstrainedBar<T: EmptyProto> = Foo<T>

// BEGIN test.swift

import pck

#^COMPLETE^#

// CHECK: Begin completions
// CHECK-DAG: Decl[Protocol]/OtherModule[pck]/Flair[RareType]: Foo[#Foo#];
// CHECK-DAG: Decl[TypeAlias]/OtherModule[pck]: Problem[#Foo<String>#];
// CHECK-DAG: Decl[TypeAlias]/OtherModule[pck]: ConstrainedBar[#Foo<T>#];
// CHECK: End completions
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Testing that these requests don't crash

public protocol Foo<Bar> {
associatedtype Bar
}
// RUN: %sourcekitd-test -req=cursor -pos=%(line+1):11 %s -- %s
typealias Problem = Foo<String>

protocol EmptyProto {}
// RUN: %sourcekitd-test -req=cursor -pos=%(line+1):11 %s -- %s
typealias ConstrainedBar<T: EmptyProto> = Foo<T>
// RUN: %sourcekitd-test -req=cursor -pos=%(line+1):11 %s -- %s
typealias ConstrainedBarMetatype<T: P> = Foo<T>.Type
16 changes: 16 additions & 0 deletions tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,22 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
}
Symbol.TypeName = copyAndClearString(Allocator, Buffer);

// ParameterizedProtocolType should always be wrapped in ExistentialType and
// cannot be mangled on its own.
// But ParameterizedProtocolType can currently occur in 'typealias'
// declarations. rdar://99176683
// To avoid crashing in USR generation, return an error for now.
if (auto Ty = DInfo.VD->getInterfaceType()) {
while (auto MetaTy = Ty->getAs<MetatypeType>()) {
Ty = MetaTy->getInstanceType();
}
if (Ty && Ty->getCanonicalType()->is<ParameterizedProtocolType>()) {
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Cannot mangle USR for ParameterizedProtocolType without 'any'.");
}
}

SwiftLangSupport::printDeclTypeUSR(DInfo.VD, OS);
Symbol.TypeUSR = copyAndClearString(Allocator, Buffer);

Expand Down