Skip to content

Commit dad81fb

Browse files
authored
Merge pull request #81779 from xedin/diagnostic-fixes
[Diagnostics] A collection of diagnostic fixes/improvements
2 parents bb6967b + b12d844 commit dad81fb

File tree

11 files changed

+171
-71
lines changed

11 files changed

+171
-71
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3484,6 +3484,15 @@ class ConstraintSystem {
34843484
return nullptr;
34853485
}
34863486

3487+
Expr *getSemanticsProvidingParentExpr(Expr *expr) {
3488+
while (auto *parent = getParentExpr(expr)) {
3489+
if (parent->getSemanticsProvidingExpr() == parent)
3490+
return parent;
3491+
expr = parent;
3492+
}
3493+
return nullptr;
3494+
}
3495+
34873496
/// Retrieve the depth of the given expression.
34883497
std::optional<unsigned> getExprDepth(Expr *expr) {
34893498
if (auto result = getExprDepthAndParent(expr))

lib/Sema/CSSimplify.cpp

Lines changed: 89 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4282,7 +4282,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
42824282
if (!path.empty()) {
42834283
auto last = path.back();
42844284

4285-
if (last.is<LocatorPathElt::ApplyArgToParam>()) {
4285+
if (last.is<LocatorPathElt::ApplyArgToParam>() ||
4286+
last.is<LocatorPathElt::AutoclosureResult>()) {
42864287
auto proto = protoDecl->getDeclaredInterfaceType();
42874288
// Impact is 2 here because there are two failures
42884289
// 1 - missing conformance and 2 - incorrect argument type.
@@ -4310,6 +4311,15 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
43104311
break;
43114312
}
43124313

4314+
if ((isExpr<ArrayExpr>(anchor) || isExpr<DictionaryExpr>(anchor)) &&
4315+
last.is<LocatorPathElt::TupleElement>()) {
4316+
auto *fix = CollectionElementContextualMismatch::create(
4317+
*this, type1, type2, getConstraintLocator(anchor, path));
4318+
if (recordFix(fix, /*impact=*/2))
4319+
return getTypeMatchFailure(locator);
4320+
break;
4321+
}
4322+
43134323
// TODO(diagnostics): If there are any requirement failures associated
43144324
// with result types which are part of a function type conversion,
43154325
// let's record general conversion mismatch in order for it to capture
@@ -4979,8 +4989,18 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
49794989

49804990
// First, let's check whether it has been determined that
49814991
// it was incorrect to use `?` in this position.
4982-
if (cs.hasFixFor(cs.getConstraintLocator(subExpr), FixKind::RemoveUnwrap))
4992+
if (cs.hasFixFor(cs.getConstraintLocator(subExpr), FixKind::RemoveUnwrap)) {
4993+
if (auto *typeVar =
4994+
fromType->getOptionalObjectType()->getAs<TypeVariableType>()) {
4995+
// If the optional chain is invalid let's unwrap optional and
4996+
// re-introduce the constraint to be solved later once both sides
4997+
// are sufficiently resolved, this would allow to diagnose not only
4998+
// the invalid unwrap but an invalid conversion (if any) as well.
4999+
cs.addConstraint(matchKind, typeVar, toType,
5000+
cs.getConstraintLocator(locator));
5001+
}
49835002
return true;
5003+
}
49845004

49855005
auto type = cs.getType(subExpr);
49865006
// If the type of sub-expression is optional, type of the
@@ -5775,6 +5795,41 @@ bool ConstraintSystem::repairFailures(
57755795
break;
57765796
}
57775797

5798+
// There is no subtyping between object types of inout argument/parameter.
5799+
if (auto argConv = path.back().getAs<LocatorPathElt::ApplyArgToParam>()) {
5800+
// Attempt conversions first.
5801+
if (hasAnyRestriction())
5802+
break;
5803+
5804+
// Unwraps are allowed to preserve l-valueness so we can suggest
5805+
// them here.
5806+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
5807+
conversionsOrFixes, locator))
5808+
return true;
5809+
5810+
auto *loc = getConstraintLocator(locator);
5811+
5812+
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
5813+
TMF_ApplyingFix, locator);
5814+
5815+
ConstraintFix *fix = nullptr;
5816+
if (result.isFailure()) {
5817+
// If this is a "destination" argument to a mutating operator
5818+
// like `+=`, let's consider it contextual and only attempt
5819+
// to fix type mismatch on the "source" right-hand side of
5820+
// such operators.
5821+
if (isOperatorArgument(loc) && argConv->getArgIdx() == 0)
5822+
break;
5823+
5824+
fix = AllowArgumentMismatch::create(*this, lhs, rhs, loc);
5825+
} else {
5826+
fix = AllowInOutConversion::create(*this, lhs, rhs, loc);
5827+
}
5828+
5829+
conversionsOrFixes.push_back(fix);
5830+
break;
5831+
}
5832+
57785833
// If this is a problem with result type of a subscript setter,
57795834
// let's re-attempt to repair without l-value conversion in the
57805835
// locator to fix underlying type mismatch.
@@ -5794,7 +5849,7 @@ bool ConstraintSystem::repairFailures(
57945849
break;
57955850
}
57965851

5797-
LLVM_FALLTHROUGH;
5852+
break;
57985853
}
57995854

58005855
case ConstraintLocator::ApplyArgToParam: {
@@ -5874,52 +5929,6 @@ bool ConstraintSystem::repairFailures(
58745929
if (repairByTreatingRValueAsLValue(lhs, rhs))
58755930
break;
58765931

5877-
// If the problem is related to missing unwrap, there is a special
5878-
// fix for that.
5879-
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
5880-
// If this is an attempt to check whether optional conforms to a
5881-
// particular protocol, let's do that before attempting to force
5882-
// unwrap the optional.
5883-
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
5884-
break;
5885-
5886-
auto result = matchTypes(lhs->getOptionalObjectType(), rhs, matchKind,
5887-
TMF_ApplyingFix, locator);
5888-
5889-
if (result.isSuccess()) {
5890-
conversionsOrFixes.push_back(
5891-
ForceOptional::create(*this, lhs, rhs, loc));
5892-
break;
5893-
}
5894-
}
5895-
5896-
// There is no subtyping between object types of inout argument/parameter.
5897-
if (elt.getKind() == ConstraintLocator::LValueConversion) {
5898-
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
5899-
TMF_ApplyingFix, locator);
5900-
5901-
ConstraintFix *fix = nullptr;
5902-
if (result.isFailure()) {
5903-
// If this is a "destination" argument to a mutating operator
5904-
// like `+=`, let's consider it contextual and only attempt
5905-
// to fix type mismatch on the "source" right-hand side of
5906-
// such operators.
5907-
if (isOperatorArgument(loc) &&
5908-
loc->findLast<LocatorPathElt::ApplyArgToParam>()->getArgIdx() == 0)
5909-
break;
5910-
5911-
fix = AllowArgumentMismatch::create(*this, lhs, rhs, loc);
5912-
} else {
5913-
fix = AllowInOutConversion::create(*this, lhs, rhs, loc);
5914-
}
5915-
5916-
conversionsOrFixes.push_back(fix);
5917-
break;
5918-
}
5919-
5920-
if (elt.getKind() != ConstraintLocator::ApplyArgToParam)
5921-
break;
5922-
59235932
// If argument in l-value type and parameter is `inout` or a pointer,
59245933
// let's see if it's generic parameter matches and suggest adding explicit
59255934
// `&`.
@@ -6046,7 +6055,7 @@ bool ConstraintSystem::repairFailures(
60466055

60476056
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
60486057
locator))
6049-
break;
6058+
return true;
60506059

60516060
{
60526061
auto *calleeLocator = getCalleeLocator(loc);
@@ -6856,9 +6865,28 @@ bool ConstraintSystem::repairFailures(
68566865
if (!path.empty() && path.back().is<LocatorPathElt::PackElement>())
68576866
path.pop_back();
68586867

6859-
if (!path.empty() && path.back().is<LocatorPathElt::AnyRequirement>()) {
6860-
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
6861-
getConstraintLocator(anchor, path));
6868+
if (!path.empty()) {
6869+
if (path.back().is<LocatorPathElt::AnyRequirement>()) {
6870+
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
6871+
getConstraintLocator(anchor, path));
6872+
}
6873+
6874+
if (auto argConv = path.back().getAs<LocatorPathElt::ApplyArgToParam>()) {
6875+
auto argIdx = argConv->getArgIdx();
6876+
auto paramIdx = argConv->getParamIdx();
6877+
6878+
auto *argLoc = getConstraintLocator(anchor, path);
6879+
if (auto overload = findSelectedOverloadFor(getCalleeLocator(argLoc))) {
6880+
auto *overloadTy =
6881+
simplifyType(overload->boundType)->castTo<FunctionType>();
6882+
auto *argList = getArgumentList(argLoc);
6883+
ASSERT(argList);
6884+
conversionsOrFixes.push_back(AllowArgumentMismatch::create(
6885+
*this, getType(argList->getExpr(argIdx)),
6886+
overloadTy->getParams()[paramIdx].getPlainType(), argLoc));
6887+
return true;
6888+
}
6889+
}
68626890
}
68636891

68646892
// When the solver sets `TMF_MatchingGenericArguments` it means
@@ -11410,6 +11438,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1141011438
// `key path` constraint can't be retired until all components
1141111439
// are simplified.
1141211440
addTypeVariableConstraintsToWorkList(memberTypeVar);
11441+
} else if (locator->getAnchor().is<Expr *>() &&
11442+
!getSemanticsProvidingParentExpr(
11443+
getAsExpr(locator->getAnchor()))) {
11444+
// If there are no contextual expressions that could provide
11445+
// a type for the member type variable, let's default it to
11446+
// a placeholder eagerly so it could be propagated to the
11447+
// pattern if necessary.
11448+
recordTypeVariablesAsHoles(memberTypeVar);
1141311449
} else if (locator->isLastElement<LocatorPathElt::PatternMatch>()) {
1141411450
// Let's handle member patterns specifically because they use
1141511451
// equality instead of argument application constraint, so allowing

test/Constraints/bridging.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,9 @@ func rdar19836341(_ ns: NSString?, vns: NSString?) {
296296

297297
// <rdar://problem/20029786> Swift compiler sometimes suggests changing "as!" to "as?!"
298298
func rdar20029786(_ ns: NSString?) {
299-
var s: String = ns ?? "str" as String as String // expected-error{{'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?}} {{19-19=(}} {{50-50=) as String}}
300-
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'NSString'}} {{50-50= as NSString}}
301-
var s2 = ns ?? "str" as String as String // expected-error {{cannot convert value of type 'String' to expected argument type 'NSString'}}{{43-43= as NSString}}
299+
var s: String = ns ?? "str" as String as String
300+
// expected-error@-1 {{cannot convert value of type 'NSString?' to expected argument type 'String?'}} {{21-21= as String?}}
301+
var s2 = ns ?? "str" as String as String // expected-error {{binary operator '??' cannot be applied to operands of type 'NSString?' and 'String'}}
302302

303303
let s3: NSString? = "str" as String? // expected-error {{cannot convert value of type 'String?' to specified type 'NSString?'}}{{39-39= as NSString?}}
304304

test/Constraints/closures.swift

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,6 @@ overloaded { print("hi"); print("bye") } // multiple expression closure without
803803
// expected-error@-1 {{ambiguous use of 'overloaded'}}
804804

805805
func not_overloaded(_ handler: () -> Int) {}
806-
// expected-note@-1 {{'not_overloaded' declared here}}
807806

808807
not_overloaded { } // empty body
809808
// expected-error@-1 {{cannot convert value of type '()' to closure result type 'Int'}}
@@ -1156,7 +1155,7 @@ struct R_76250381<Result, Failure: Error> {
11561155
func rdar77022842(argA: Bool? = nil, argB: Bool? = nil) {
11571156
if let a = argA ?? false, if let b = argB ?? {
11581157
// expected-error@-1 {{initializer for conditional binding must have Optional type, not 'Bool'}}
1159-
// expected-error@-2 {{closure passed to parameter of type 'Bool?' that does not accept a closure}}
1158+
// expected-error@-2 {{cannot convert value of type 'Bool?' to expected argument type '(() -> ())?'}}
11601159
// expected-error@-3 {{cannot convert value of type 'Void' to expected condition type 'Bool'}}
11611160
// expected-error@-4 {{'if' may only be used as expression in return, throw, or as the source of an assignment}}
11621161
// expected-error@-5 {{'if' must have an unconditional 'else' to be used as expression}}
@@ -1337,3 +1336,33 @@ func rdar143338891() {
13371336
}
13381337
}
13391338
}
1339+
1340+
do {
1341+
struct V {
1342+
init(value: @autoclosure @escaping () -> any Hashable) { }
1343+
init(other: @autoclosure @escaping () -> String) { }
1344+
}
1345+
1346+
let _ = V(value: { [Int]() }) // expected-error {{add () to forward '@autoclosure' parameter}} {{31-31=()}}
1347+
let _ = V(other: { [Int]() }) // expected-error {{cannot convert value of type '[Int]' to closure result type 'String'}}
1348+
}
1349+
1350+
// https://github.com/swiftlang/swift/issues/81770
1351+
do {
1352+
func test(_: Int) {}
1353+
func test(_: Int = 42, _: (Int) -> Void) {}
1354+
1355+
test {
1356+
if let _ = $0.missing { // expected-error {{value of type 'Int' has no member 'missing'}}
1357+
}
1358+
}
1359+
1360+
test {
1361+
if let _ = (($0.missing)) { // expected-error {{value of type 'Int' has no member 'missing'}}
1362+
}
1363+
}
1364+
1365+
test { // expected-error {{invalid conversion from throwing function of type '(Int) throws -> Void' to non-throwing function type '(Int) -> Void'}}
1366+
try $0.missing // expected-error {{value of type 'Int' has no member 'missing'}}
1367+
}
1368+
}

test/Constraints/if_expr.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ func builderInClosure() {
705705
func testInvalidOptionalChainingInIfContext() {
706706
let v63796 = 1
707707
if v63796? {} // expected-error{{cannot use optional chaining on non-optional value of type 'Int'}}
708+
// expected-error@-1 {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}}
708709
}
709710

710711
// https://github.com/swiftlang/swift/issues/79395

test/Constraints/optional.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func test_force_unwrap_not_being_too_eager() {
435435
// rdar://problem/57097401
436436
func invalidOptionalChaining(a: Any) {
437437
a == "="? // expected-error {{cannot use optional chaining on non-optional value of type 'String'}}
438-
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Any' and 'String?'}}
438+
// expected-error@-1 {{cannot convert value of type 'Any' to expected argument type 'String'}}
439439
}
440440

441441
/// https://github.com/apple/swift/issues/54739
@@ -595,3 +595,26 @@ do {
595595
test(x!) // expected-error {{no exact matches in call to local function 'test'}}
596596
// expected-error@-1 {{cannot force unwrap value of non-optional type 'Double'}}
597597
}
598+
599+
func testExtraQuestionMark(action: () -> Void, v: Int) {
600+
struct Test {
601+
init(action: () -> Void) {}
602+
}
603+
604+
Test(action: action?)
605+
// expected-error@-1 {{cannot use optional chaining on non-optional value of type '() -> Void'}}
606+
Test(action: v?)
607+
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type '() -> Void'}}
608+
// expected-error@-2 {{cannot use optional chaining on non-optional value of type 'Int'}}
609+
}
610+
611+
func testPassingOptionalChainAsWrongArgument() {
612+
class Test {
613+
func fn(_ asdType: String?) {
614+
}
615+
}
616+
617+
func test(test: Test, arr: [Int]?) {
618+
test.fn(arr?.first) // expected-error {{cannot convert value of type 'Int?' to expected argument type 'String?'}}
619+
}
620+
}

test/Constraints/protocols.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,11 @@ do {
577577

578578
isFooableError(overloaded()) // Ok
579579
}
580+
581+
do {
582+
func takesFooables(_: [any Fooable]) {}
583+
584+
func test(v: String) {
585+
takesFooables([v]) // expected-error {{cannot convert value of type 'String' to expected element type 'any Fooable'}}
586+
}
587+
}

test/Constraints/rdar44770297.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,3 @@ func foo<T: P>(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Neve
1010

1111
let _ = foo() {fatalError()} & nil
1212
// expected-error@-1 {{global function 'foo' requires that 'Never' conform to 'P'}}
13-
// expected-error@-2 {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}}
14-
// expected-note@-3 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
15-
// expected-note@-4 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}

test/decl/func/typed_throws.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ enum G_E<T> {
192192

193193
func testArrMap(arr: [String]) {
194194
_ = mapArray(arr, body: G_E<Int>.tuple)
195-
// expected-error@-1{{cannot convert value of type '((x: Int, y: Int)) -> G_E<Int>' to expected argument type '(String) -> G_E<Int>'}}
195+
// expected-error@-1{{conflicting arguments to generic parameter 'T' ('String' vs. '(x: Int, y: Int)')}}
196196
}
197197

198198
// Shadowing of typed-throws Result.get() addresses a source compatibility

test/expr/expressions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange<Int>?) {
794794

795795
// ?? should have lower precedence than range and arithmetic operators.
796796
let r1 = r ?? (0...42) // ok
797-
let r2 = (r ?? 0)...42 // not ok: expected-error {{binary operator '??' cannot be applied to operands of type 'ClosedRange<Int>?' and 'Int'}}
797+
let r2 = (r ?? 0)...42 // not ok: expected-error {{cannot convert value of type 'ClosedRange<Int>?' to expected argument type 'Int?'}}
798798
let r3 = r ?? 0...42 // parses as the first one, not the second.
799799

800800

test/stdlib/UnsafePointerDiagnostics.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,14 @@ func unsafePointerConversionAvailability(
7878

7979
_ = UnsafeMutablePointer<Int>(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
8080
_ = UnsafeMutablePointer<Int>(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
81-
// Two candidates here: OpaquePointer? and UnsafeMutablePointer<Int>?
81+
// This is ambiguous because we have failable and non-failable initializers that accept the same argument type.
8282
_ = UnsafeMutablePointer<Int>(orp) // expected-error {{no exact matches in call to initializer}}
83-
// Two candidates here: OpaquePointer? and UnsafeMutablePointer<Int>?
84-
_ = UnsafeMutablePointer<Int>(omrp) // expected-error {{no exact matches in call to initializer}}
83+
_ = UnsafeMutablePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
8584

8685
_ = UnsafePointer<Int>(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int>'}}
8786
_ = UnsafePointer<Int>(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafePointer<Int>'}}
88-
// Two candidates here: OpaquePointer? and UnsafeMutablePointer<Int>?
89-
_ = UnsafePointer<Int>(orp) // expected-error {{no exact matches in call to initializer}}
90-
// Two candidates here: OpaquePointer? and UnsafeMutablePointer<Int>?
91-
_ = UnsafePointer<Int>(omrp) // expected-error {{no exact matches in call to initializer}}
87+
_ = UnsafePointer<Int>(orp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int>'}}
88+
_ = UnsafePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafePointer<Int>'}}
9289

9390
_ = UnsafePointer<Int>(ups) // expected-error {{cannot convert value of type 'UnsafePointer<String>' to expected argument type 'UnsafePointer<Int>'}}
9491
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('String' and 'Int') are expected to be equal}}

0 commit comments

Comments
 (0)