Skip to content

[CSClosure] Fix handling of property wrapped pattern bindings #59300

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

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 3 additions & 0 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8892,6 +8892,9 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
} else if (auto patternBinding = target.getAsPatternBinding()) {
ConstraintSystem &cs = solution.getConstraintSystem();
for (unsigned index : range(patternBinding->getNumPatternEntries())) {
if (patternBinding->isInitializerChecked(index))
continue;

// Find the solution application target for this.
auto knownTarget = *cs.getSolutionApplicationTarget(
{patternBinding, index});
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/CSClosure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,9 @@ class SyntacticElementConstraintGenerator
locator, LocatorPathElt::SyntacticElement(patternBinding));

for (unsigned index : range(patternBinding->getNumPatternEntries())) {
if (patternBinding->isInitializerChecked(index))
continue;

auto *pattern = TypeChecker::resolvePattern(
patternBinding->getPattern(index), patternBinding->getDeclContext(),
/*isStmtCondition=*/true);
Expand Down Expand Up @@ -502,6 +505,9 @@ class SyntacticElementConstraintGenerator
locator->castLastElementTo<LocatorPathElt::PatternBindingElement>()
.getIndex();

if (patternBinding->isInitializerChecked(index))
return;

auto contextualPattern =
ContextualPattern::forPatternBindingDecl(patternBinding, index);
Type patternType = TypeChecker::typeCheckPattern(contextualPattern);
Expand Down
12 changes: 6 additions & 6 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4711,15 +4711,15 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {
// overloads, depth, *reverse* of the index). N.B. - cannot be used for the
// reversing: the score version of index == 0 should be > than that of 1, but
// -0 == 0 < UINT_MAX == -1, whereas ~0 == UINT_MAX > UINT_MAX - 1 == ~1.
auto score = [](unsigned distinctOverloads, unsigned depth, unsigned index) {
return std::make_tuple(distinctOverloads, depth, ~index);
auto score = [](unsigned depth, unsigned index, unsigned distinctOverloads) {
return std::make_tuple(depth, ~index, distinctOverloads);
};
auto bestScore = score(0, 0, std::numeric_limits<unsigned>::max());
auto bestScore = score(0, std::numeric_limits<unsigned>::max(), 0);

// Get a map of expressions to their depths and post-order traversal indices.
// Heuristically, all other things being equal, we should complain about the
// ambiguous expression that (1) has the most overloads, (2) is deepest, or
// (3) comes earliest in the expression.
// ambiguous expression that (1) is deepest, (2) comes earliest in the
// expression, or (3) has the most overloads.
llvm::DenseMap<Expr *, unsigned> indexMap;
for (auto expr : InputExprs) {
extendPreorderIndexMap(expr, indexMap);
Expand Down Expand Up @@ -4780,7 +4780,7 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {

// If we have more distinct overload choices for this locator than for
// prior locators, just keep this locator.
auto thisScore = score(distinctOverloads, depth, index);
auto thisScore = score(depth, index, distinctOverloads);
if (thisScore > bestScore) {
bestScore = thisScore;
bestOverload = i;
Expand Down
21 changes: 21 additions & 0 deletions test/Constraints/diag_ambiguities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,24 @@ func %% (_ lhs: Float, _ rhs: Float) -> Float {
func SR15053<T : Numeric>(_ a: T, _ b: T) {
(a + b) %% 2 // expected-error {{cannot convert value of type 'T' to expected argument type 'Int'}}
}

// rdar://94360230 - diagnosing 'filter' instead of ambiguity in its body
func test_diagnose_deepest_ambiguity() {
struct S {
func ambiguous(_: Int = 0) -> Bool { true } // expected-note 2 {{found this candidate}}
func ambiguous(_: String = "") -> Bool { true } // expected-note 2 {{found this candidate}}
}

func test_single(arr: [S]) {
arr.filter { $0.ambiguous() } // expected-error {{ambiguous use of 'ambiguous'}}
}

func test_multi(arr: [S]) {
arr.filter {
if true {
print($0.ambiguous()) // expected-error {{ambiguous use of 'ambiguous'}}
}
return true
}
}
}
10 changes: 5 additions & 5 deletions test/expr/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ struct SpecialPi {} // Type with no implicit construction.

var pi_s: SpecialPi

func getPi() -> Float {}
func getPi() -> Double {}
func getPi() -> Float {} // expected-note 3 {{found this candidate}}
func getPi() -> Double {} // expected-note 3 {{found this candidate}}
func getPi() -> SpecialPi {}

enum Empty { }
Expand All @@ -585,12 +585,12 @@ func conversionTest(_ a: inout Double, b: inout Int) {
var pi_d1 = Double(pi_d)
var pi_s1 = SpecialPi(pi_s) // expected-error {{argument passed to call that takes no arguments}}

var pi_f2 = Float(getPi()) // expected-error {{ambiguous use of 'init(_:)'}}
var pi_d2 = Double(getPi()) // expected-error {{ambiguous use of 'init(_:)'}}
var pi_f2 = Float(getPi()) // expected-error {{ambiguous use of 'getPi()'}}
var pi_d2 = Double(getPi()) // expected-error {{ambiguous use of 'getPi()'}}
var pi_s2: SpecialPi = getPi() // no-warning

var float = Float.self
var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'init(_:)'}}
var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'getPi()'}}
var pi_f4 = float.init(pi_f)

var e = Empty(f) // expected-warning {{variable 'e' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{8-8=: Empty}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %target-typecheck-verify-swift

// https://github.com/apple/swift/issues/59294

@propertyWrapper
struct WrapperValue<Value> {
var value: Value
init(wrappedValue: Value) {
self.value = wrappedValue
}

var projectedValue: Self {
return self
}

var wrappedValue: Value {
get {
self.value
}
set {
self.value = newValue
}
}

func printValue() {
print(value)
}
}


class Test {
static func test() {
return [0, 1, 2].compactMap { _ in // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}}
@WrapperValue var value: Bool? = false
if value != nil {
return false
}

return value ?? false
}
}
}