From 325e0158a1d7e1b40013d5e30aea7dc4970a1e11 Mon Sep 17 00:00:00 2001 From: Kathy Gray Date: Mon, 10 Nov 2025 12:04:47 +0000 Subject: [PATCH] Diagnostics : Increase possibility for missed property diagnostic Impact for an unknown property access was frequently higher than other options on ambiguous selections, by 3 to 5 points, causing fix selections that were farther away and frequently noted to be in accurate. This commit lowers the impact to be in a similar range to other fixes and this causes property accesses to be selected more proprotionaly. In the existing test suite, this changed the diagnostic only in the case of protocol composition, which was also discovered to be a flawed binding lookup. Tests added for the property lookup, tests updated for protocol composition (Including correcting a likely error in a test specification) --- lib/Sema/CSRanking.cpp | 3 +- lib/Sema/CSSimplify.cpp | 13 ++-- .../async_overload_filtering.swift | 2 +- ...mbers_on_protocol_in_generic_context.swift | 61 +++++++++++++------ test/IDE/complete_closure_ambiguity.swift | 2 +- .../SwiftUI/foreach_with_typo_property.swift | 20 ++++++ 6 files changed, 75 insertions(+), 26 deletions(-) create mode 100644 validation-test/Sema/SwiftUI/foreach_with_typo_property.swift diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 3e506750bd296..add34b15be1d3 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -174,7 +174,8 @@ bool ConstraintSystem::worseThanBestSolution() const { if (isDebugMode()) { llvm::errs().indent(solverState->getCurrentIndent()) - << "(solution is worse than the best solution)\n"; + << "(solution " << CurrentScore << " is worse than the best solution " + << solverState->BestScore <<")\n"; } return true; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index bd18655a96a9b..17e8cd96050ea 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -11616,8 +11616,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( alreadyDiagnosed, locator); auto instanceTy = baseObjTy->getMetatypeInstanceType(); - - auto impact = 4; + auto impact = 2; // Impact is higher if the base type is any function type // because function types can't have any members other than self if (instanceTy->is()) { @@ -11646,9 +11645,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( } // Increasing the impact for missing member in any argument position so - // it doesn't affect situations where there are another fixes involved. + // it doesn't significantly pull away from situations with options. if (getArgumentLocator(anchorExpr)) - impact += 5; + impact += 1; } if (recordFix(fix, impact)) @@ -15650,6 +15649,12 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact, if (auto impactScoreKind = fix->impact()) increaseScore(*impactScoreKind, fix->getLocator(), impact); + if (isDebugMode()) { + auto &log = llvm::errs(); + log.indent(solverState ? solverState->getCurrentIndent() : 0) + << "(fix has score " << impact << ")\n"; + } + // If we've made the current solution worse than the best solution we've seen // already, stop now. if (worseThanBestSolution()) diff --git a/test/Concurrency/async_overload_filtering.swift b/test/Concurrency/async_overload_filtering.swift index 67276216f5435..57bf57f6b8a68 100644 --- a/test/Concurrency/async_overload_filtering.swift +++ b/test/Concurrency/async_overload_filtering.swift @@ -22,7 +22,7 @@ var a: String? = nil // CHECK: overload set choice binding $T0 := {{.*}} // CHECK-NEXT: (considering: ({{.*}}) -> {{.*}} applicable fn {{.*}} // CHECK: increasing 'sync-in-asynchronous' score by 1 -// CHECK: solution is worse than the best solution +// CHECK: solution {{.*}} is worse than the best solution {{.*}} filter_async { Obj() diff --git a/test/Constraints/static_members_on_protocol_in_generic_context.swift b/test/Constraints/static_members_on_protocol_in_generic_context.swift index 6e1a7206121af..d97b4e6f5d449 100644 --- a/test/Constraints/static_members_on_protocol_in_generic_context.swift +++ b/test/Constraints/static_members_on_protocol_in_generic_context.swift @@ -175,14 +175,14 @@ test_combo(.genericFn(42)) // expected-error {{global function 'test_combo' requ /* Invalid result types */ -extension P { // expected-note 13 {{missing same-type requirement on 'Self'}} {{12-12= where Self == <#Type#>}} +extension P { // expected-note 8 {{missing same-type requirement on 'Self'}} {{12-12= where Self == <#Type#>}} static func generic(_: T) -> T { fatalError() } - static func genericWithReqs(_: T) -> Q where T.Element == Q { // expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}} + static func genericWithReqs(_: T) -> Q where T.Element == Q { // expected-note 4 {{required by static method 'genericWithReqs' where 'T' = '()'}} expected-note 5 {{where 'T' = '[any Q]'}} fatalError() } } -extension P { // expected-note 6 {{missing same-type requirement on 'Self'}} +extension P { // expected-note 5 {{missing same-type requirement on 'Self'}} static var invalidProp: Int { 42 } static var selfProp: Self { fatalError() } static func invalidMethod() -> Int { 42 } @@ -211,12 +211,16 @@ _ = P.generic(42).other _ = P.generic(S()) // expected-error {{static member 'generic' cannot be used on protocol metatype '(any P).Type'}} _ = P.generic(S()).other // expected-error {{static member 'generic' cannot be used on protocol metatype '(any P).Type'}} _ = P.generic(G()) // expected-error {{static member 'generic' cannot be used on protocol metatype '(any P).Type'}} -_ = P.genericWithReqs([S()]) // expected-error {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}} +_ = P.genericWithReqs([S()]) // expected-error {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}} expected-error {{static method 'genericWithReqs' requires that '[any Q]' conform to 'Q'}} _ = P.genericWithReqs([42]) // expected-error@-1 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}} +// expected-error@-2 {{cannot convert value of type 'Int' to expected element type 'any Q'}} +// expected-error@-3 {{static method 'genericWithReqs' requires that '[any Q]' conform to 'Q'}} _ = P.genericWithReqs(()) -// expected-error@-1 {{type '()' cannot conform to 'Collection'}} expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}} -// expected-error@-2 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}} +// expected-error@-1 {{type '()' cannot conform to 'Collection'}} +// expected-error@-2 {{type '()' cannot conform to 'Q'}} +// expected-error@-3 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}} +// expected-note@-4 2 {{only concrete types such as structs, enums and classes can conform to protocols}} _ = P[q: ""] // expected-error@-1 {{static member 'subscript' cannot be used on protocol metatype '(any P).Type'}} _ = P[q: ""].other @@ -227,6 +231,8 @@ test(.doesntExist) // expected-error {{type 'P' has no member 'doesntExist'}} test(.doesnt.exist()) // expected-error {{type 'P' has no member 'doesnt'}} test(.invalidProp) // expected-error@-1 {{contextual member reference to static property 'invalidProp' requires 'Self' constraint in the protocol extension}} +test(.property.doesntExist) +// expected-error@-1 {{value of type 'S' has no member 'doesntExist'}} test(.invalidProp.other) // expected-error@-1 {{contextual member reference to static property 'invalidProp' requires 'Self' constraint in the protocol extension}} // expected-error@-2 {{value of type 'Int' has no member 'other'}} @@ -243,30 +249,47 @@ test(.generic(42).other) test(.generic(S())) // expected-error {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} test(.generic(G())) // expected-error {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} test(.genericWithReqs([S()])) // expected-error {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{static method 'genericWithReqs' requires that '[any Q]' conform to 'Q'}} +test(.genericWithReqs([S()]).doesntExist) // expected-error {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{value of type 'any Q' has no member 'doesntExist'}} +// expected-error@-2 {{static method 'genericWithReqs' requires that '[any Q]' conform to 'Q'}} test(.genericWithReqs([42])) // expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-2 {{static method 'genericWithReqs' requires that '[any Q]' conform to 'Q'}} +// expected-error@-3 {{cannot convert value of type 'Int' to expected element type 'any Q'}} test(.genericWithReqs(())) // expected-error@-1 {{type '()' cannot conform to 'Collection'}} -// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}} +// expected-error@-2 {{type '()' cannot conform to 'Q'}} // expected-error@-3 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-note@-4 2 {{only concrete types such as structs, enums and classes can conform to protocols}} test_combo(.doesntExist) // expected-error {{reference to member 'doesntExist' cannot be resolved without a contextual type}} test_combo(.doesnt.exist()) // expected-error {{reference to member 'doesnt' cannot be resolved without a contextual type}} test_combo(.invalidProp) // expected-error@-1 {{contextual member reference to static property 'invalidProp' requires 'Self' constraint in the protocol extension}} +test_combo(.invalidProp.doesntExist) //FIXME Should be reporting that Int has no doesntExist if P&Q lookup fixed +// expected-error@-1{{type 'Q' has no member 'invalidProp'}} test_combo(.invalidMethod()) -// expected-error@-1 {{contextual member reference to static method 'invalidMethod()' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{failed to produce diagnostic for expression}} +// {{contextual member reference to static method 'invalidMethod()' requires 'Self' constraint in the protocol extension}} test_combo(.generic(42)) -// expected-error@-1 {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} -test_combo(.generic(S())) // expected-error {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} -test_combo(.generic(G())) // expected-error {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} -test_combo(.genericWithReqs([S()])) // expected-error {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} -test_combo(.genericWithReqs([42])) -// expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} -test_combo(.genericWithReqs(())) -// expected-error@-1 {{type '()' cannot conform to 'Collection'}} -// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}} -// expected-error@-3 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{failed to produce diagnostic for expression}} +// {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} +test_combo(.generic(S())) // expected-error {{failed to produce diagnostic for expression}} +// {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} +test_combo(.generic(G())) // expected-error {{failed to produce diagnostic for expression}} +// {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}} +test_combo(.genericWithReqs([S()])) //FIXME error on Q membership an error on P&Q lookup, contextual error should occur +// {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-2 {{type 'Q' has no member 'genericWithReqs'}} +test_combo(.genericWithReqs([42])) //FIXME error on Q membership an error on P&Q lookup, contextual error should occur +// {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-2 {{type 'Q' has no member 'genericWithReqs'}} +test_combo(.genericWithReqs(())) //FIXME error on Q membership an error on P&Q lookup, other errors should occur +// expected-error@-1{{type 'Q' has no member 'genericWithReqs'}} +// {{type '()' cannot conform to 'Collection'}} +// {{only concrete types such as structs, enums and classes can conform to protocols}} +// {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} protocol TestWithAssoc { associatedtype U @@ -381,4 +404,4 @@ test(.instanceProp) // expected-error@-1 {{instance member 'instanceProp' cannot be used on type 'P'}} test(.instanceProp2) // expected-error@-1 {{instance member 'instanceProp2' cannot be used on type 'P'}} -// expected-error@-2 {{property 'instanceProp2' requires the types 'Self' and 'S' be equivalent}} \ No newline at end of file +// expected-error@-2 {{property 'instanceProp2' requires the types 'Self' and 'S' be equivalent}} diff --git a/test/IDE/complete_closure_ambiguity.swift b/test/IDE/complete_closure_ambiguity.swift index a1daa7be26079..d48c8541ca5df 100644 --- a/test/IDE/complete_closure_ambiguity.swift +++ b/test/IDE/complete_closure_ambiguity.swift @@ -26,6 +26,6 @@ foo { // CONSTRAINTS: attempting disjunction choice {{.*}}:12:6 // CONSTRAINTS: increasing 'disfavored overload' score -// CONSTRAINTS: solution is worse than the best solution +// CONSTRAINTS: solution {{.*}} is worse than the best solution {{.*}} // CONSTRAINTS-NOT-NOT: increasing 'hole' diff --git a/validation-test/Sema/SwiftUI/foreach_with_typo_property.swift b/validation-test/Sema/SwiftUI/foreach_with_typo_property.swift new file mode 100644 index 0000000000000..3f62294ef7601 --- /dev/null +++ b/validation-test/Sema/SwiftUI/foreach_with_typo_property.swift @@ -0,0 +1,20 @@ +// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5 +// REQUIRES: objc_interop +// REQUIRES: OS=macosx +// + +import SwiftUI + struct ContentView: View { + var foos: [F] + + var body: some View { + ForEach(foos) { foo in + let name = foo.bat //expected-error{{value of type 'F' has no member 'bat'}} + } + } + } + + struct F: Identifiable, Hashable { + var id: String { bar } + var bar: String // expected-note {{'bar' declared here}} + }