[DiagnosticsQoI] SR-6272 Tailored diagnostics with fixits for numerical conversions#13272
[DiagnosticsQoI] SR-6272 Tailored diagnostics with fixits for numerical conversions#13272xedin merged 8 commits intoswiftlang:masterfrom
Conversation
|
So sorry this got left by the wayside |
| @@ -4,7 +4,7 @@ protocol P { | |||
| associatedtype SomeType | |||
There was a problem hiding this comment.
All the little whitespace changes in this file should be reverted.
test/Constraints/diagnostics.swift
Outdated
| enum Foo: Int { | ||
| case bar | ||
| } | ||
| // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'Float'}} {{22-28=}} {{29-30=}} |
There was a problem hiding this comment.
This technically changed a whole lot more tests than just this one. I'm not sure if it's worth it to go through and update them all, but it would be nice to pull some non-integral/floating types into this test just to make sure we don't accidentally try to, say, cast a string to a Float or something.
There was a problem hiding this comment.
Makes sense! Will do!
CodaFi
left a comment
There was a problem hiding this comment.
It's a great first start. Comments inline.
This reverts commit b2059c6.
|
@CodaFi Addressed your comments. Thanks! |
| } | ||
| // expected-error@+2 {{binary operator '*' cannot be applied to operands of type 'Int' and 'Float'}} {{22-28=}} {{29-30=}} | ||
| // expected-note@+1 {{overloads for '*' exist with these partially matching parameter lists: (Float, Float), (Int, Int)}} | ||
| Foo.bar.rawValue * Float(0) |
There was a problem hiding this comment.
How does this fare with a contextual type?
let x: Float = Foo.bar.rawValue * Float(0)There was a problem hiding this comment.
Good point..
It suggests to fix Float(0) to 0 so far..
Will fix it.
There was a problem hiding this comment.
tryIntegerCastFixIts treats the toType as a contextual type, always. You may want to try calling it on the LHS and RHS expressions of the binary operation and pass along their respective types and the contextual type. tryIntegerCastFixIts tells you if it succeeds in diagnosing part of the expression or not.
|
@swift-ci please smoke test |
lib/Sema/CSDiag.cpp
Outdated
| .highlight(rhsExpr->getSourceRange()); | ||
|
|
||
| auto contextualType = CS.getContextualType(); | ||
| if (contextualType && contextualType->isEqual(rhsType)) { |
There was a problem hiding this comment.
Thanks for the patch, @chuganzy! Unfortunately it's not always correct to use contextual type this way because it applies to the whole expression, while the problem could be local to sub-expression that might have some other type different from (or equal to) contextual type e.g.
struct A: ExpressibleByIntegerLiteral {
typealias IntegerLiteralType = Int
init(integerLiteral: Int) {}
static func +(lhs: A, rhs: Int) -> Float { return 42.0 }
}
let x: Float = 1.0
let _: Float = A(integerLiteral: 42) + x
let _: Float = A(integerLiteral: 42) + 42.0
let _: Float = A(integerLiteral: 42) + x + 1.0Most of the cases here are going to get suggestion to wrap x into A but there is no overload like that, or in case of first example is going to suggest wrapping A into Float which also might be incorrect because it's going to call a different overload all together.
Even without contextual type, I think we shouldn't try to suggest fix-its like that without taking into account more information e.g. what overloads are available for sub-expression and if suggestion is going to result in different overload choice or not.
There was a problem hiding this comment.
Hmm, makes sense.
lib/Sema/CSDiag.cpp
Outdated
| .highlight(rhsExpr->getSourceRange()); | ||
|
|
||
| for (auto &candidate : calleeInfo.candidates) { | ||
| auto tupleType = dyn_cast<TupleType>(candidate.getArgumentType().getPointer()); |
There was a problem hiding this comment.
It would be better to use:
if (auto *fnType = candidate.getUncurriedFunctionType()) {
auto params = fnType->getParams();
}here since we are trying to move away from using parameter types directly.
There was a problem hiding this comment.
The problem though is that even though we could diagnose one of the candidates with cast fix-it it doesn't necessarily mean that we should do that... E.g. if I had +(A, Int) -> Float and +(A, Double) -> Float and I have A() + x where x: Float expression like in my previous example, the question is which fix-it should I suggest, Int or Double? IMHO none, because it's ambiguous what the user wanted to do here...
There was a problem hiding this comment.
So what is supposed to do in following case?
let x: Int = 0
let y: Float = 0
x * yWe have 2 candidates to suggest "fix-it" - x * Int(y) or Float(x) * y.
You think we should not suggest in this case?
There was a problem hiding this comment.
Yes, that's right, I don't think it makes sense to suggest fix-it in this case because it's unclear what is intended.
|
@chuganzy I haven't forgotten about this, will take a look soon! |
|
@swift-ci please smoke test |
|
Thank you, @chuganzy! |
If there's an explicit numeric conversion that could make the system type-check, suggest "fix it".
Resolves https://bugs.swift.org/browse/SR-6272