Skip to content

[Sema] Fix crash when retrieving typeContextInfo for a partially bound generic type #37034

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
Apr 27, 2021
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
48 changes: 31 additions & 17 deletions lib/Sema/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
continue;
}

// Does it make sense to substitute types?
ModuleDecl *M = DC->getParentModule();

// If the base type is AnyObject, we might be doing a dynamic
// lookup, so the base type won't match the type of the member's
Expand All @@ -930,16 +930,35 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
(BaseTy->getNominalOrBoundGenericNominal() ||
BaseTy->is<ArchetypeType>()) &&
VD->getDeclContext()->isTypeContext());
ModuleDecl *M = DC->getParentModule();

/// Substitute generic parameters in the signature of a found decl. The
/// returned type can be used to determine if we have already found a
/// conflicting declaration.
auto substGenericArgs = [&](CanType SignatureType, ValueDecl *VD,
Type BaseTy) -> CanType {
if (!SignatureType || !shouldSubst) {
return SignatureType;
}
if (auto GenFuncSignature =
SignatureType->getAs<GenericFunctionType>()) {
GenericEnvironment *GenEnv;
if (auto *GenCtx = VD->getAsGenericContext()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's always going to be a GenericContext if it has a GenericFunctionType

Copy link
Member Author

@ahoppen ahoppen Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually doesn’t. In the following example

protocol FooProtocol {
  var bar: Int { get set }
}

func test(foo: FooProtocol) {
  foo.#^COMPLETE^#
}

foo has a SignatureType of

(generic_function_type escaping
  (input=function_params num_params=1
    (param
      (generic_type_param_type depth=0 index=0)))
  (output=tuple_type num_elements=0)
  ( generic_sig=<τ_0_0 where τ_0_0 : FooProtocol>))

but the value decl VD (which is bar) doesn’t have a generic environment because it’s not generic..

GenEnv = GenCtx->getGenericEnvironment();
} else {
GenEnv = DC->getGenericEnvironmentOfContext();
}
auto subs = BaseTy->getMemberSubstitutionMap(M, VD, GenEnv);
auto CT = GenFuncSignature->substGenericArgs(subs);
if (!CT->hasError()) {
return CT->getCanonicalType();
}
}
return SignatureType;
};

auto FoundSignature = VD->getOverloadSignature();
auto FoundSignatureType = VD->getOverloadSignatureType();
if (FoundSignatureType && shouldSubst) {
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
auto CT = FoundSignatureType.subst(subs);
if (!CT->hasError())
FoundSignatureType = CT->getCanonicalType();
}
auto FoundSignatureType =
substGenericArgs(VD->getOverloadSignatureType(), VD, BaseTy);

bool FoundConflicting = false;
for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end();
Expand All @@ -952,14 +971,9 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
continue;

auto OtherSignature = OtherVD->getOverloadSignature();
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
if (OtherSignatureType && shouldSubst) {
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
auto subs = ActualBaseTy->getMemberSubstitutionMap(M, OtherVD);
auto CT = OtherSignatureType.subst(subs);
if (!CT->hasError())
OtherSignatureType = CT->getCanonicalType();
}
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
auto OtherSignatureType = substGenericArgs(
OtherVD->getOverloadSignatureType(), OtherVD, ActualBaseTy);

if (conflicting(M->getASTContext(), FoundSignature, FoundSignatureType,
OtherSignature, OtherSignatureType,
Expand Down
29 changes: 20 additions & 9 deletions test/IDE/complete_override_access_control_protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,21 @@ public class TestPublicDE : ProtocolDPrivate, ProtocolEPublic {
#^TEST_PUBLIC_DE^#
}

// TEST_PRIVATE_DE: Begin completions, 2 items
// FIXME: We should only be suggesting `collidingGeneric` once in all the test cases below.

// TEST_PRIVATE_DE: Begin completions, 3 items
// TEST_PRIVATE_DE-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}
// TEST_PRIVATE_DE-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PRIVATE_DE-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

// TEST_INTERNAL_DE: Begin completions, 2 items
// TEST_INTERNAL_DE: Begin completions, 3 items
// TEST_INTERNAL_DE-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}
// TEST_INTERNAL_DE-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_INTERNAL_DE-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

// TEST_PUBLIC_DE: Begin completions, 2 items
// TEST_PUBLIC_DE: Begin completions, 3 items
// TEST_PUBLIC_DE-DAG: Decl[InstanceMethod]/Super: public func colliding() {|}{{; name=.+$}}
// TEST_PUBLIC_DE-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PUBLIC_DE-DAG: Decl[InstanceMethod]/Super: public func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

private class TestPrivateED : ProtocolEPublic, ProtocolDPrivate {
Expand All @@ -203,16 +208,19 @@ public class TestPublicED : ProtocolEPublic, ProtocolDPrivate {
#^TEST_PUBLIC_ED^#
}

// TEST_PRIVATE_ED: Begin completions, 2 items
// TEST_PRIVATE_ED: Begin completions, 3 items
// TEST_PRIVATE_ED-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}
// TEST_PRIVATE_ED-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PRIVATE_ED-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

// TEST_INTERNAL_ED: Begin completions, 2 items
// TEST_INTERNAL_ED: Begin completions, 3 items
// TEST_INTERNAL_ED-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_INTERNAL_ED-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_INTERNAL_ED-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}

// TEST_PUBLIC_ED: Begin completions, 2 items
// TEST_PUBLIC_ED: Begin completions, 3 items
// TEST_PUBLIC_ED-DAG: Decl[InstanceMethod]/Super: public func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PUBLIC_ED-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PUBLIC_ED-DAG: Decl[InstanceMethod]/Super: public func colliding() {|}{{; name=.+$}}

private class TestPrivateEF : ProtocolEPublic, ProtocolFPublic {
Expand All @@ -229,14 +237,17 @@ public class TestPublicEF : ProtocolEPublic, ProtocolFPublic {
#^TEST_PUBLIC_EF^#
}

// TEST_PRIVATE_EF: Begin completions, 2 items
// TEST_PRIVATE_EF: Begin completions, 3 items
// TEST_PRIVATE_EF-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}
// TEST_PRIVATE_EF-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PRIVATE_EF-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

// TEST_INTERNAL_EF: Begin completions, 2 items
// TEST_INTERNAL_EF: Begin completions, 3 items
// TEST_INTERNAL_EF-DAG: Decl[InstanceMethod]/Super: func colliding() {|}{{; name=.+$}}
// TEST_INTERNAL_EF-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_INTERNAL_EF-DAG: Decl[InstanceMethod]/Super: func collidingGeneric<T>(x: T) {|}{{; name=.+$}}

// TEST_PUBLIC_EF: Begin completions, 2 items
// TEST_PUBLIC_EF: Begin completions, 3 items
// TEST_PUBLIC_EF-DAG: Decl[InstanceMethod]/Super: public func colliding() {|}{{; name=.+$}}
// TEST_PUBLIC_EF-DAG: Decl[InstanceMethod]/Super: public func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
// TEST_PUBLIC_EF-DAG: Decl[InstanceMethod]/Super: public func collidingGeneric<T>(x: T) {|}{{; name=.+$}}
17 changes: 17 additions & 0 deletions test/SourceKit/TypeContextInfo/typecontext_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ struct S<T> {
static var instance: Self = S<T>()
}

struct MyBinding<BindingOuter> {
func someGenericFunc<BindingInner>(x: BindingInner) {}
}

struct MyTextField<TextFieldOuter> {
init<TextFieldInner>(text: MyBinding<TextFieldInner>) {}
}

struct EncodedView {
func foo(model: MyBinding<String>) {
let _ = MyTextField<String>(text: model)
}
}

// RUN: %sourcekitd-test -req=typecontextinfo -pos=7:12 %s -- %s > %t.response.1
// RUN: %diff -u %s.response.1 %t.response.1
// RUN: %sourcekitd-test -req=typecontextinfo -pos=8:12 %s -- %s > %t.response.2
Expand All @@ -32,3 +46,6 @@ struct S<T> {
// RUN: %diff -u %s.response.5 %t.response.5
// RUN: %sourcekitd-test -req=typecontextinfo -pos=16:18 %s -- %s > %t.response.6
// RUN: %diff -u %s.response.6 %t.response.6

// RUN: %sourcekitd-test -req=typecontextinfo -pos=32:43 %s -- %s > %t.response.7
// RUN: %diff -u %s.response.7 %t.response.7
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
key.results: [
{
key.typename: "MyBinding<TextFieldInner>",
key.typeusr: "$s20typecontext_generics9MyBindingVyqd__GD",
key.implicitmembers: [
]
}
]
}