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)
This commit is contained in:
Kathy Gray
2025-11-10 12:04:47 +00:00
parent 91d1d2e06f
commit fde49b8847
14 changed files with 126 additions and 44 deletions

View File

@@ -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;

View File

@@ -9253,6 +9253,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
req->is<LocatorPathElt::TypeParameterRequirement>()) {
auto *memberLoc = getConstraintLocator(anchor, path.front());
if (hasFixFor(memberLoc))
return SolutionKind::Solved;
auto signature = path[path.size() - 2]
.castTo<LocatorPathElt::OpenedGeneric>()
.getSignature();
@@ -10673,7 +10676,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
candidate,
MemberLookupResult::UR_InvalidStaticMemberOnProtocolMetatype);
}
return;
} else {
if (!hasStaticMembers) {
@@ -11621,8 +11623,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<AnyFunctionType>()) {
@@ -11650,10 +11651,10 @@ 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.
// Increasing the impact for missing member in any argument position
// which may be less likely than other potential mistakes
if (getArgumentLocator(anchorExpr))
impact += 5;
impact += 1;
}
if (recordFix(fix, impact))

View File

@@ -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()

View File

@@ -182,13 +182,13 @@ enum CompassPoint {
}
func isNorth(c : CompassPoint) -> Bool {
// expected-error@+1{{member 'North' expects argument of type 'Int'}}
// FIXME: After improving property lookup fix, this message is not selected. Separate debug to reinstate {{member 'North' expects argument of type 'Int'}}
return c == .North // expected-error {{binary operator '==' cannot be applied to two 'CompassPoint' operands}}
// expected-note@-1 {{binary operator '==' cannot be synthesized for enums with associated values}}
}
func isNorth2(c : CompassPoint) -> Bool {
// expected-error@+1{{member 'North' expects argument of type 'Int'}}
// FIXME: {{member 'North' expects argument of type 'Int'}}
return .North == c // expected-error {{binary operator '==' cannot be applied to two 'CompassPoint' operands}}
// expected-note@-1 {{binary operator '==' cannot be synthesized for enums with associated values}}
}

View File

@@ -177,7 +177,7 @@ test_combo(.genericFn(42)) // expected-error {{global function 'test_combo' requ
extension P { // expected-note 13 {{missing same-type requirement on 'Self'}} {{12-12= where Self == <#Type#>}}
static func generic<T>(_: T) -> T { fatalError() }
static func genericWithReqs<T: Collection, Q>(_: T) -> Q where T.Element == Q { // expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}}
static func genericWithReqs<T: Collection>(_: T) -> Q where T.Element == Q { // expected-note {{required by static method 'genericWithReqs' where 'T' = '()'}}
fatalError()
}
}
@@ -213,10 +213,12 @@ _ = P.generic(S()).other // expected-error {{static member 'generic' cannot be u
_ = P.generic(G<Int>()) // 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([42])
// expected-error@-1 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}}
_ = 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@-1 {{cannot convert value of type 'Int' to expected element type 'any Q'}}
// expected-error@-2 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}}
_ = P.genericWithReqs(())
// expected-error@-1 {{type '()' cannot conform to 'Collection'}}
// expected-error@-2 {{static member 'genericWithReqs' cannot be used on protocol metatype '(any P).Type'}}
// expected-note@-3 {{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 +229,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 +247,38 @@ 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<Int>())) // 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}}
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'}}
test(.genericWithReqs([42]))
// expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
// expected-error@-2 {{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@-3 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
// expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
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: Requires protocol conformance fix for expected two messages below
// expected-error@-1{{type 'Q' has no member 'invalidProp'}}
// {{contextual member reference to static property 'invalidProp' requires 'Self' constraint in the protocol extension}}
// {{value of type 'Int' has no member 'doesntExist'}}
test_combo(.invalidMethod())
// expected-error@-1 {{contextual member reference to static method 'invalidMethod()' requires 'Self' constraint in the protocol extension}}
// expected-error@-1{{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<Int>())) // 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}}
// expected-error@-1{{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}}
test_combo(.generic(S()))
// expected-error@-1{{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}}
test_combo(.generic(G<Int>()))
//expected-error@-1 {{contextual member reference to static method 'generic' requires 'Self' constraint in the protocol extension}}
test_combo(.genericWithReqs([S()]))
// expected-error@-1{{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
test_combo(.genericWithReqs([42])) //FIXME: Requires protocol conformance fix for expected two messages below
// expected-error@-1{{failed to produce diagnostic for expression}}
// {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
// {{cannot convert value of type 'Int' to expected element type 'any Q'}}
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{{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}}
protocol TestWithAssoc {
associatedtype U
@@ -381,4 +393,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}}
// expected-error@-2 {{property 'instanceProp2' requires the types 'Self' and 'S' be equivalent}}

View File

@@ -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'

View File

@@ -0,0 +1,8 @@
// RUN: %target-typecheck-verify-swift
func example(x: Int, regions: [Int]) {
let matchingRegion =
regions.first { region in x + region.bogusProperty }
// expected-error@-1 {{value of type 'Int' has no member 'bogusProperty'}}
}

View File

@@ -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}}
}

View File

@@ -14,8 +14,8 @@ extension EnvironmentValues {
var myHorizontalAlignment: AlignmentID? {
get { fatalError() }
set { self[\.MyHorizontalAlignmentEnvironmentKey.self] = newValue }
// expected-error@-1 {{subscript 'subscript(_:)' requires that 'any AlignmentID' be a class type}}
// expected-error@-2 {{cannot infer key path type from context; consider explicitly specifying a root type}}
// expected-error@-1 {{value of type 'EnvironmentValues' has no member 'MyHorizontalAlignmentEnvironmentKey'}}
// expected-error@-2 {{missing argument label 'keyPath:' in subscript}}
}
}

View File

@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -target %target-cpu-apple-macosx10.15 -swift-version 5
// REQUIRES: objc_interop
// REQUIRES: OS=macosx
@@ -22,17 +22,20 @@ struct ContentView: View {
var body: some View {
ScrollView {
VStack {
VStack {
Picker(selection: $selection) {
ForEach(["a", "b", "c"], id: \.self) {
Text($0) // expected-error {{reasonable time}}
.foregroundStyl(.red) // Typo is here
}
} label: {
Picker(selection: $selection) {
ForEach(["a", "b", "c"], id: \.self) {
Text($0) // expected-error {{ reasonable time}}
.foregroundStyl(.red) // Typo is here
}
.pickerStyle(.segmented)
} label: {
}
.pickerStyle(.segmented)
}
.padding(.horizontal)
.padding(.vertical)
}
.padding(.horizontal)
}
.onChange(of: a) { oldValue, newValue in
}

View File

@@ -0,0 +1,38 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unrelated -target %target-cpu-apple-macosx10.15 -swift-version 5
// REQUIRES: objc_interop
// REQUIRES: OS=macosx
// https://forums.swift.org/t/roadmap-for-improving-the-type-checker/82952/9
//
// This test formerly ran out of time. Now we catch the typo error
//
import SwiftUI
struct ContentView: View {
@State var selection = ""
@State var a: Int?
@State var b: Int?
@State var c: Int?
var body: some View {
ScrollView {
Picker(selection: $selection) {
ForEach(["a", "b", "c"], id: \.self) {
Text($0) // Formerly ran out of time
.foregroundStyl(.red) // expected-error {{value of type 'Text' has no member 'foregroundStyl'; did you mean 'foregroundStyle'}}
// expected-error@-1 {{cannot infer contextual base in reference to member 'red'}}
}
} label: {
}
.pickerStyle(.segmented)
}
.onChange(of: a) { oldValue, newValue in
}
.onChange(of: b) { oldValue, newValue in
}
.onChange(of: c) { oldValue, newValue in
}
}
}

View File

@@ -1,3 +0,0 @@
// {"kind":"typecheck","signature":"swift::constraints::SubscriptMisuseFailure::diagnoseAsError()","signatureAssert":"Assertion failed: (isa<To>(Val) && \"cast<Ty>() argument of incompatible type!\"), function cast"}
// RUN: not --crash %target-swift-frontend -typecheck %s
"" [.subscript

View File

@@ -0,0 +1,2 @@
// RUN: not %target-swift-frontend -typecheck %s
"" [.subscript

View File

@@ -1,5 +1,5 @@
// {"kind":"typecheck","original":"5b785ef0","signature":"swift::ASTWalker::PreWalkResult<swift::Expr*> (anonymous namespace)::Verifier::dispatchVisitPreExpr<swift::OpenExistentialExpr*>(swift::OpenExistentialExpr*)","signatureAssert":"Assertion failed: (isa<To>(Val) && \"cast<Ty>() argument of incompatible type!\"), function cast"}
// RUN: not --crash %target-swift-frontend -typecheck %s
// RUN: not %target-swift-frontend -typecheck %s
extension Dictionary {
a(b: Sequence)
{