Skip to content

[Diagnostics] Strip off unrelated optionals from generic parameter di… #31982

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
May 25, 2020

Conversation

xedin
Copy link
Contributor

@xedin xedin commented May 22, 2020

…agnostics

In situations where left-hand side requires value-to-optional
promotion which ends up in type mismatch let's not mention
optionals in the diagnostic because they are unrelated e.g.

func test(_: UnsafePointer<Int>??) {}

var value: Float = 0
test(&value)

In this example value gets implicitly wrapped into a double optional
before UnsafePointer<Float> could be matched against UnsafePointer<Int>
associated with the parameter.

Diagnostic is about generic argument mismatch Float vs. Int
and shouldn't mention any optionals.

…agnostics

In situations where left-hand side requires value-to-optional
promotion which ends up in type mismatch let's not mention
optionals in the diagnostic because they are unrelated e.g.

```swift
func test(_: UnsafePointer<Int>??) {}

var value: Float = 0
test(&value)
```

In this example `value` gets implicitly wrapped into a double optional
before `UnsafePointer<Float>` could be matched against `UnsafePointer<Int>`
associated with the parameter.

Diagnostic is about generic argument mismatch `Float` vs. `Int`
and shouldn't mention any optionals.
@xedin xedin requested a review from hborla May 22, 2020 22:20
@xedin
Copy link
Contributor Author

xedin commented May 22, 2020

@swift-ci please smoke test

@@ -1447,7 +1447,7 @@ func assignGenericMismatch() {
let value: [Int] = []
func gericArgToParamOptional(_ param: [String]?) {}

gericArgToParamOptional(value) // expected-error {{convert value of type '[Int]' to expected argument type '[String]?'}}
gericArgToParamOptional(value) // expected-error {{convert value of type '[Int]' to expected argument type '[String]'}}
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I'm not sure how I feel about these diagnostics changes. I understand that Optional is not part of the mismatch, but it is important in identifying where that type is in the source code. This error message seems wrong because the argument type is [String]?, not [String].

Could we instead add a note similar to the one we emit for same-type generic requirements?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of the diagnostics here were wrong because they mentioned optional only on one side and produced a note which mentioned either Element or Pointee which is confusing. So this is at least an improvement on status quo.

Because it's allowed to implicitly load value into an optional, the problem is that either we produce a diagnostic where everything is optional - e.g. [Int]? and [String]? and a note which would have to say that Wrapped is a problem (which is incorrect), or we ignore optionals and produce diagnostic about actual mismatch which is better.

Copy link
Contributor

Choose a reason for hiding this comment

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

This error message seems wrong because the argument type is [String]?, not [String].

I thought the same when added this in #30814, because that is the argument type as the user declared :)
So to me, it seemed like the type in the message was not right in some way

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems like before doing anything else we need to figure out diagnostic format that allows to mention complete types as well as their portions e.g. tuple mismatches which have to mention whole tuple as well as narrowed down message(s) about mismatched bits.

Copy link
Member

Choose a reason for hiding this comment

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

I think it's fine that the diagnostic only has optional on one side - I think that's how users think about value-to-optional conversions anyway. I was suggesting adding a new note about the Element types expected to be the same (in this case), not Wrapped

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@hborla What do you mean by new note? There is a note about Element already associated with that error.

Copy link
Member

Choose a reason for hiding this comment

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

Oh whoops, you're right, I didn't even notice the note because it wasn't part of the change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think if we wanted to start mentioning types as written we'd end up with diagnostics like this:

func takesConstPointer(_ x: UnsafePointer<Int>??) -> Character { return "x" }

var ff: [Float] = [0, 1, 2]
takesConstPointer(ff)
error:  cannot convert value of type '[Float]' to expected argument type 'UnsafePointer<Int>??'

note: arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal
takesConstPointer(ff)
                  ^

Which is not very informative, but maybe okay?

Copy link
Member

Choose a reason for hiding this comment

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

I think that case in particular might benefit from a tailored argument-to-parameter error message that somehow mentions the array-to-pointer conversion so that Pointee in the note makes more sense... I do think the note is very informative because it tells you exactly which part of the type that's wrong (Float vs Int)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We currently produce a diagnostic which mentions UnsafePointer<Float> instead of [Float] and doesn't have optional on the right-hand side, that's why it makes sense to have Pointee in the note.

If we wanted to start diagnosing chains like [Float] -> [Float]? -> [Float]?? -> UnsafePointer<Float>?? which then matched vs. UnsafePointer<Int>?? we'd probably need to get some kind of "nested" error representation first...

Copy link
Member

@hborla hborla left a comment

Choose a reason for hiding this comment

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

Pavel and I discussed this offline and we decided to take this change for now

@LucianoPAlmeida
Copy link
Contributor

I think if we wanted to start mentioning types as written we'd end up with diagnostics like this:

func takesConstPointer(_ x: UnsafePointer<Int>??) -> Character { return "x" }

var ff: [Float] = [0, 1, 2]
takesConstPointer(ff)
error:  cannot convert value of type '[Float]' to expected argument type 'UnsafePointer<Int>??'

note: arguments to generic parameter 'Pointee' ('Float' and 'Int') are expected to be equal
takesConstPointer(ff)
                  ^

@xedin @hborla I wonder if cases like this ☝️ you mentioned already exists on the suit?
If not, maybe it is worth adding? :)

@xedin
Copy link
Contributor Author

xedin commented May 23, 2020

Yeah, that’s the test case from the suite :)

@xedin
Copy link
Contributor Author

xedin commented May 25, 2020

@swift-ci please smoke test macOS platform

@xedin xedin merged commit 9eb22c0 into swiftlang:master May 25, 2020
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.

3 participants