Skip to content

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

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

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Apr 27, 2021

Cherry-picks #37034.


In the following test case, we are crashing while building the generic signature of someGenericFunc, potentially invoked on model in line 11.

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.

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

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)

…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]
@ahoppen ahoppen requested a review from akyrtzi April 27, 2021 15:23
@ahoppen
Copy link
Member Author

ahoppen commented Apr 27, 2021

@swift-ci Please test

@ahoppen ahoppen added the r5.5 label Apr 27, 2021
@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 80fa362

@ahoppen
Copy link
Member Author

ahoppen commented Apr 27, 2021

@swift-ci Please test Linux

@ahoppen ahoppen merged commit 1fe90db into swiftlang:release/5.5 Apr 28, 2021
@ahoppen ahoppen deleted the pr-5.5/subst-generic-params-mismatch branch April 28, 2021 09:43
@AnthonyLatsis AnthonyLatsis added 🍒 release cherry pick Flag: Release branch cherry picks swift 5.5 labels Jan 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍒 release cherry pick Flag: Release branch cherry picks swift 5.5
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants