Skip to content

[Sema] Improves diagnostic when passing an argument as property of an optional class instance (#57437) #68264

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Rajveer100
Copy link
Contributor

@Rajveer100 Rajveer100 commented Sep 1, 2023

Resolves #57437

As described in the issue, “Type of expression is ambiguous” error is thrown when passing an argument as property of an optional class instance, which further broken down into an argument or contextual type.

@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Sep 1, 2023

A small query, although I have understood certain pattern to calling the getConstraintLocator 's constructors, mainly being a (anchor, path) and (locator), could you differentiate among the different calls for specific cases?

@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch from de00dc6 to 3ad2fc6 Compare September 1, 2023 13:03
@xedin
Copy link
Contributor

xedin commented Sep 1, 2023

The changes need clang-format but I'm going to run tests to see if anything is broken.

@xedin
Copy link
Contributor

xedin commented Sep 1, 2023

@swift-ci please test

@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch 2 times, most recently from 71f1a65 to 99ac378 Compare September 1, 2023 17:21
@xedin
Copy link
Contributor

xedin commented Sep 1, 2023

@swift-ci please test

@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Sep 1, 2023

I haven't updated tests for new error diagnostics, will do.

@xedin
Copy link
Contributor

xedin commented Sep 1, 2023

I think some of them are regressions because they loose optionality and there is one test-case in parameterized_existentials.swift where instead of reporting any P<Int> and any P<String> the diagnostic is only about Int and String, which could be okay but it has to be reworded to not speak about return expression directly.

@xedin
Copy link
Contributor

xedin commented Sep 1, 2023

Maybe it's just a matter of moving new code after if (flags.contains(TMF_MatchingGenericArguments)) check.

@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch from 99ac378 to 89ab678 Compare September 2, 2023 05:28
@Rajveer100
Copy link
Contributor Author

Maybe it's just a matter of moving new code after if (flags.contains(TMF_MatchingGenericArguments)) check.

Let's try this.

@AnthonyLatsis
Copy link
Collaborator

@Rajveer100 Have you tried running that test locally to see if this change counters the regression?

@Rajveer100
Copy link
Contributor Author

Just to confirm, we are interested in the following file:

  • ./test/Constraints/parameterized_existentials.swift

@AnthonyLatsis
Copy link
Collaborator

Yes, that should be the one.

@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Sep 3, 2023

Well, the tweak doesn't seem to work:

/test/Constraints/parameterized_existentials.swift:39:32: error: incorrect message found
  return x // expected-error {{cannot convert return expression of type '(any P)?' to return type '(any P<Int>)?'}}
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               cannot convert return expression of type 'any P' to return type 'any P<Int>'
/test/Constraints/parameterized_existentials.swift:47:32: error: incorrect message found
  return x // expected-error {{cannot convert return expression of type '(any P<Int>)?' to return type '(any P<String>)?'}}
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                               cannot convert return expression of type 'String' to return type 'Int'

@Rajveer100
Copy link
Contributor Author

What do you recommend, change it to the desired diagnostic message?

@xedin
Copy link
Contributor

xedin commented Sep 4, 2023

I think it should be good to strip the optionals but preserve complete types:

cannot convert return expression of type 'any P<Int>' to return type 'any P<String>'

and produce a note like other cases do:

arguments to generic parameter 'T' ('any P<Int>' and 'any P<String>') are expected to be equal

@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Sep 4, 2023

The notes are already implemented for the generic struct, did you mean any other addition?

struct G<T> {}
// expected-note@-1 {{arguments to generic parameter 'T' ('any P<Int>' and 'any P') are expected to be equal}}
// expected-note@-2 {{arguments to generic parameter 'T' ('any P' and 'any P<Int>') are expected to be equal}}
// expected-note@-3 {{arguments to generic parameter 'T' ('any P<Int>' and 'any P<String>') are expected to be equal}}

@xedin
Copy link
Contributor

xedin commented Sep 5, 2023

We need to make sure that they are actually emitted for this error, these notes might be attached to the declaration of the struct but they should be emitted as part of the conversion diagnostic.

@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Sep 10, 2023

What do you suggest in terms of rewording the second case in the test file as here?
Wouldn't rewording affect diagnostics and tests for other cases?

I have stripped the optionals as discussed, also did you mean to add notes just for this case or also including the reworded case to be done?

@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch from 89ab678 to a5e35fa Compare September 11, 2023 08:02
@xedin
Copy link
Contributor

xedin commented Sep 11, 2023

For this case the most important thing is to drop the optionals because first of all they match and secondly they are not the problem, the actual problem is that Int is not a String and that's why I'm emphasizing that we need notes and that diagnostics should mention a full type minus the optional bit.

@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch 2 times, most recently from b5a7cec to bf123ea Compare October 12, 2023 08:26
@Rajveer100 Rajveer100 force-pushed the branch-for-issue-57437 branch from bf123ea to 37831ac Compare November 7, 2023 11:35
@Rajveer100
Copy link
Contributor Author

Rajveer100 commented Nov 14, 2023

@xedin
How do we convert the basic types to full types, i.e, String to any P<String> and Int to any P<Int>. I have added notes (only in test file, yet to add in codebase) and also reworded the diagnostic, let me know the further changes to be made about the rewording of message.

@@ -330,7 +330,7 @@ ERROR(cannot_convert_initializer_value_nil,none,
"'nil' cannot initialize specified type %0", (Type))

ERROR(cannot_convert_to_return_type,none,
"cannot convert return expression of type %0 to return type %1",
"return expressions for types %0 and %1 are not interconvertible",
Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC the feedback from @xedin, the discussion about rewording was not about only re-phrasing but add more info about the types involved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, notes are to be added, as I said above, I have only added in the test file at the moment. Will add it in the code as well to reflect the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@LucianoPAlmeida
For this particular case:

struct S {
  var str: String
}

func test(s: S?) {
  let _: Int? = s?.str

  func f(_: Int?) {}
  f(s?.str)
}

I don't get the expected error, it still gives an ambiguous diagnostic message:

error: type of expression is ambiguous without a type annotation

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like fixes are being correctly added in repairFailures but something is happening in the middle resulting in not a solution formed with those fixes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, in diagnoseFailureFor, it's falling through this call:

DE.diagnose(expr->getLoc(), diag::type_of_expression_is_ambiguous)
        .highlight(expr->getSourceRange());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I added breakpoints in repairFailures , it actually never goes through path.back().is<LocatorPathElt::ContextualType>() as a successful check. Hence, it does through the ambiguous diagnosis.

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.

[SR-15111] “Type of expression is ambiguous” error when initializing a class
4 participants