Skip to content

[CodeCompletion] Fix a crash when completing the call pattern of a function that takes a parameter pack #72570

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 Mar 25, 2024

The issue here was that we inferred the contextual type of the Mixer call to be the following, inferred from the result type of the partial call to the initializer of Mixer

(bound_generic_struct_type decl="swift_ide_test.(file).Mixer@/Users/alex/src/swift/test/IDE/complete_parameter_pack_as_call_argument.swift:3:8"
  (pack_type num_elements=1
    (pack_expansion_type
      (pattern=unresolved_type)
      (count=unresolved_type))))

Technically, the contextual type that we should have here should be Any (from print) but getting that information out of the constraint system turns out to be quite hard. #72568 makes some improvements in this area but in general the constraint system does not contain enough information to figure out the contextual type of an arbitrary expression.

The important thing right now is that the unresolved type in here trips the constraint system over when comparing types of code completion results with the contextual type. To prevent the crash for now, reset the expected call type if the computed type contains an unresolved type.

rdar://124166587

@ahoppen ahoppen force-pushed the ahoppen/parameter-pack-pattern-crash branch from 4e5dd2e to c4247bc Compare March 25, 2024 21:03
if (!isSynthesizedArg && isForCodeCompletion() &&
containsIDEInspectionTarget(arg) && !lhs->isVoid() &&
!lhs->isUninhabited())
fixBehavior = FixBehavior::Suppress;
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if this returns true like before instead of trying to suppress the diagnostic which wouldn't be emitted anyway in the code completion mode?

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason I want to record the fix is so I can inspect it while producing code completion results here: https://github.com/apple/swift/pull/72568/files#diff-1e522eaf116c0d9062c2ba193e9a4cd86687f87ebd6d3afbd705917a2f5746dbR178-R192.

That’s basically the content of #72568 which this PR depends on.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, containsIDEInspectionTarget is overly broad then... If there is a mismatch between result type of a call where code completion token is used and some contextual type, I think presence of completion token shouldn't affect that.

Is the following example covered by this check as well:

func other(_: Int) {}
func test(_: String) {}
func compute(_: Int) -> String {}

other(test(compute(#^COMPLETE^#)))

for (auto Fix : S.Fixes) {
if (auto CM = dyn_cast<AllowArgumentMismatch>(Fix)) {
if (simplifyLocatorToAnchor(CM->getLocator()) == ASTNode(ParentCall)) {
ExpectedCallType = CM->getToType();
Copy link
Contributor

@Mayank-84 Mayank-84 Mar 26, 2024

Choose a reason for hiding this comment

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

nit: Can we merge two if conditions into one using && operator. This might improve readability

Copy link
Member Author

Choose a reason for hiding this comment

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

I don’t think so because one of them is binding a variable (auto CM) and the other one is a boolean check.

Copy link
Contributor

Choose a reason for hiding this comment

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

Technically we could now do (as of C++17) if (auto CM = dyn_cast<AllowArgumentMismatch>(Fix); simplifyLocatorToAnchor(CM->getLocator()) == ASTNode(ParentCall)). But we don't use this pattern anywhere else in the compiler and IMO we probably want to agree in general that it's a pattern we want to use first.

Copy link
Member Author

Choose a reason for hiding this comment

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

The part of the condition after ; still gets evaluated even if CM is nullptr. Which means that it would need to be if (auto CM = dyn_cast<AllowArgumentMismatch>(Fix); CM && simplifyLocatorToAnchor(CM->getLocator()) == ASTNode(ParentCall)) which I find sufficiently ugly to not use.

// func bar() -> String {}
// foo(bar(#^COMPLETE^#))
for (auto Fix : S.Fixes) {
if (auto CM = dyn_cast<AllowArgumentMismatch>(Fix)) {
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 regardless of presence of fix we should dig up the "contextual" type from the solution instead of taking result of the call because conversions are allowed here i.e. bar() could produce String but foo might expect String? as a parameter.

@ahoppen ahoppen force-pushed the ahoppen/parameter-pack-pattern-crash branch from c4247bc to 992587a Compare April 12, 2024 20:22
…nction that takes a parameter pack

The issue here was that we inferred the contextual type of the `Mixer` call to be the following, inferred from the result type of the partial call to the initializer of `Mixer`

```
(bound_generic_struct_type decl="swift_ide_test.(file).Mixer@/Users/alex/src/swift/test/IDE/complete_parameter_pack_as_call_argument.swift:3:8"
  (pack_type num_elements=1
    (pack_expansion_type
      (pattern=unresolved_type)
      (count=unresolved_type))))
```

Technically, the contextual type that we should have here should be `Any` (from `print`) but getting that information out of the constraint system turns out to be quite hard. swiftlang#72568 makes some improvements in this area but in general the constraint system does not contain enough information to figure out the contextual type of an arbitrary expression.

The important thing right now is that the unresolved type in here trips the constraint system over when comparing types of code completion results with the contextual type. To prevent the crash for now, reset the expected call type if the computed type contains an unresolved type.

rdar://124166587

Co-authored-by: Pavel Yaskevich <[email protected]>
@ahoppen ahoppen force-pushed the ahoppen/parameter-pack-pattern-crash branch from 992587a to 078e1ea Compare April 12, 2024 21:04
@ahoppen ahoppen changed the title [CodeCompletion] Fix a crash when completing the call pattern of a function that takes a parameter pack 🚥 #72568 [CodeCompletion] Fix a crash when completing the call pattern of a function that takes a parameter pack Apr 12, 2024
@ahoppen
Copy link
Member Author

ahoppen commented Apr 15, 2024

@swift-ci Please smoke test

@ahoppen ahoppen merged commit 70757ff into swiftlang:main Apr 16, 2024
@ahoppen ahoppen deleted the ahoppen/parameter-pack-pattern-crash branch April 16, 2024 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants