Skip to content

[Diagnostics] Extend use of argument mismatch fix to autoclosure pa… #27608

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
Oct 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3007,13 +3007,38 @@ bool ConstraintSystem::repairFailures(
if (repairByInsertingExplicitCall(lhs, rhs))
return true;

auto result = matchTypes(lhs, rhs, ConstraintKind::ArgumentConversion,
TypeMatchFlags::TMF_ApplyingFix,
locator.withPathElement(ConstraintLocator::FunctionArgument));
auto isPointerType = [](Type type) -> bool {
return bool(
type->lookThroughAllOptionalTypes()->getAnyPointerElementType());
};

if (result.isSuccess())
conversionsOrFixes.push_back(AllowAutoClosurePointerConversion::create(
*this, lhs, rhs, getConstraintLocator(locator)));
// Let's see whether this is an implicit conversion to a pointer type
// which is invalid in @autoclosure context e.g. from `inout`, Array
// or String.
if (!isPointerType(lhs) && isPointerType(rhs)) {
auto result = matchTypes(
lhs, rhs, ConstraintKind::ArgumentConversion,
TypeMatchFlags::TMF_ApplyingFix,
locator.withPathElement(ConstraintLocator::FunctionArgument));

if (result.isSuccess())
conversionsOrFixes.push_back(AllowAutoClosurePointerConversion::create(
*this, lhs, rhs, getConstraintLocator(locator)));
}

// In situations like this:
//
// struct S<T> {}
// func foo(_: @autoclosure () -> S<Int>) {}
// foo(S<String>())
//
// Generic type conversion mismatch is a better fix which is going to
// point to the generic arguments that did not align properly.
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality))
break;

conversionsOrFixes.push_back(AllowArgumentMismatch::create(
*this, lhs, rhs, getConstraintLocator(locator)));
break;
}

Expand Down
3 changes: 2 additions & 1 deletion test/Constraints/bridging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ func rdar19836341(_ ns: NSString?, vns: NSString?) {

// <rdar://problem/20029786> Swift compiler sometimes suggests changing "as!" to "as?!"
func rdar20029786(_ ns: NSString?) {
var s: String = ns ?? "str" as String as String // expected-error{{cannot convert value of type 'NSString?' to expected argument type 'String?'}}{{21-21= as String?}}
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}}
// expected-error@-1 {{cannot convert value of type 'String' to expected argument type 'NSString'}} {{50-50= as NSString}}
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}}

let s3: NSString? = "str" as String? // expected-error {{cannot convert value of type 'String?' to specified type 'NSString?'}}{{39-39= as NSString?}}
Expand Down
7 changes: 7 additions & 0 deletions test/attr/attr_autoclosure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,10 @@ func autoclosure_param_returning_func_type() {
func biz_5(_ fn: @escaping () -> (() -> Int)) { fiz(fn) } // Can't forward in Swift >= 5 mode
// expected-error@-1 {{add () to forward @autoclosure parameter}} {{57-57=()}}
}

func test_autoclosure_with_generic_argument_mismatch() {
struct S<T> {} // expected-note {{arguments to generic parameter 'T' ('String' and 'Int') are expected to be equal}}
func foo(_: @autoclosure () -> S<Int>) {}

foo(S<String>()) // expected-error {{cannot convert value of type 'S<String>' to expected argument type 'S<Int>'}}
}
3 changes: 1 addition & 2 deletions test/decl/func/dynamic_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,7 @@ class Factory : FactoryPattern {

convenience init(string: String) {
self.init(factory: Factory(_string: string))
// expected-error@-1 {{incorrect argument label in call (have 'factory:', expected '_string:')}}
// FIXME: Bogus diagnostic
// expected-error@-1 {{cannot convert value of type 'Factory' to expected argument type 'Self'}}
}
}

Expand Down
4 changes: 3 additions & 1 deletion test/expr/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -774,14 +774,16 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange<Int>?) {
// ?? should have higher precedence than logical operators like || and comparisons.
if cond || (a ?? 42 > 0) {} // Ok.
if (cond || a) ?? 42 > 0 {} // expected-error {{cannot be used as a boolean}} {{15-15=(}} {{16-16= != nil)}}
// expected-error@-1:12 {{cannot convert value of type 'Bool' to expected argument type 'Int?'}}
if (cond || a) ?? (42 > 0) {} // expected-error {{cannot be used as a boolean}} {{15-15=(}} {{16-16= != nil)}}

if cond || a ?? 42 > 0 {} // Parses as the first one, not the others.


// ?? should have lower precedence than range and arithmetic operators.
let r1 = r ?? (0...42) // ok
let r2 = (r ?? 0)...42 // not ok: expected-error {{cannot convert value of type 'Int' to expected argument type 'ClosedRange<Int>'}}
let r2 = (r ?? 0)...42 // not ok: expected-error 2 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange<Int>'}}
// expected-error@-1 {{argument type 'ClosedRange<Int>' does not conform to expected type 'Comparable'}}
let r3 = r ?? 0...42 // parses as the first one, not the second.


Expand Down