-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[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
[Sema] Fix crash when retrieving typeContextInfo for a partially bound generic type #37034
Conversation
@swift-ci Please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some minor nitpicks you can skip or roll over into another PR if you want. The logic looks fine otherwise.
lib/Sema/LookupVisibleDecls.cpp
Outdated
@@ -930,16 +932,35 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { | |||
(BaseTy->getNominalOrBoundGenericNominal() || | |||
BaseTy->is<ArchetypeType>()) && | |||
VD->getDeclContext()->isTypeContext()); | |||
ModuleDecl *M = DC->getParentModule(); | |||
|
|||
/// Substitue generic parameters in the signature of a found decl. The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: "Substitute"
if (auto GenFuncSignature = | ||
SignatureType->getAs<GenericFunctionType>()) { | ||
GenericEnvironment *GenEnv; | ||
if (auto *GenCtx = VD->getAsGenericContext()) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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..
lib/Sema/LookupVisibleDecls.cpp
Outdated
/// Substitue 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 normalizeSignatureType = [&](CanType SignatureType, ValueDecl *VD, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename this to "substGenericArgs" since that's more descriptive than "normalize" which could mean anything
…d generic type In the following test case, we are crashing while building the generic signature of `someGenericFunc`, potentially invoked on `model` in line 11. ```swift 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) } } ``` Because we know that `model` has type `MyBinding<TextFieldInner>`, we substitute the `BindingOuter` generic parameter by `TextFieldInner`. Thus, `someGenericFunc` has the signature `<TextFieldInner /* substitutes BindingOuter */, BindingInner>`. `TextFieldInner` and `BindingOuter` both have `depth = 1`, `index = 0`. Thus the verification in `GenericSignatureBuilder` is failing. After discussion with Slava, the root issue appears to be that we shouldn’t be calling `subst` on a `GenericFunctionType` at all. Instead we should be using `substGenericArgs` which doesn’t attempt to rebuild a generic signature, but instead builds a non-generic function type. -------------------------------------------------------------------------------- We slightly regress in code completion results by showing two `collidingGeneric` twice in the following case. ```swift protocol P1 { func collidingGeneric<T>(x: T) } protocol P2 { func collidingGeneric<T>(x: T) } class C : P1, P2 { #^COMPLETE^# } ``` Previously, we were representing the type of `collidingGeneric` by a generic function type with generic param `T` that doesn’t have any restrictions. Since we are now using `substGenericArgs` instead of `subst`, we receive a non-generic function type that represents `T` as an archetype. And since that archetype is different for the two function signatures, we show the result twice in code completion. One could also argue that showing the result twice is intended (or at least acceptable) behaviour since, the two protocol may name their generic params differently. E.g. in ```swift protocol P1 { func collidingGeneric<S>(x: S) } protocol P2 { func collidingGeneric<T>(x: T) } class C : P1, P2 { #^COMPLETE^# } ``` we might be expected to show the following two results ``` func collidingGeneric<S>(x: S) func collidingGeneric<T>(x: T) ``` Resolves rdar://76711477 [SR-14495]
70311cc
to
b70e91f
Compare
@swift-ci Please test |
In the following test case, we are crashing while building the generic signature of
someGenericFunc
, potentially invoked onmodel
in line 11.Because we know that
model
has typeMyBinding<TextFieldInner>
, we substitute theBindingOuter
generic parameter byTextFieldInner
. Thus,someGenericFunc
has the signature<TextFieldInner /* substitutes BindingOuter */, BindingInner>
.TextFieldInner
andBindingOuter
both havedepth = 1
,index = 0
. Thus the verification inGenericSignatureBuilder
is failing.After discussion with @slavapestov, the root issue appears to be that we shouldn’t be calling
subst
on aGenericFunctionType
at all. Instead we should be usingsubstGenericArgs
which doesn’t attempt to rebuild a generic signature, but instead builds a non-generic function type.We slightly regress in code completion results by showing two
collidingGeneric
twice in the following case.Previously, we were representing the type of
collidingGeneric
by a generic function type with generic paramT
that doesn’t have any restrictions. Since we are now usingsubstGenericArgs
instead ofsubst
, we receive a non-generic function type that representsT
as an archetype. And since that archetype is different for the two function signatures, we show the result twice in code completion.One could also argue that showing the result twice is intended (or at least acceptable) behaviour since, the two protocol may name their generic params differently. E.g. in
we might be expected to show the following two results
Resolves rdar://76711477 [SR-14495]