Skip to content

Commit 6aadbc3

Browse files
authored
Merge pull request #27390 from xedin/sr-11491
[Diagnostics] Centralize requirement failure impact assessment
2 parents 60c64bf + 694023a commit 6aadbc3

File tree

3 files changed

+83
-26
lines changed

3 files changed

+83
-26
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,56 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1,
12691269
return nullptr;
12701270
}
12711271

1272+
static unsigned
1273+
assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
1274+
ConstraintLocatorBuilder locator) {
1275+
auto *anchor = locator.getAnchor();
1276+
if (!anchor)
1277+
return 1;
1278+
1279+
// If this requirement is associated with an overload choice let's
1280+
// tie impact to how many times this requirement type is mentioned.
1281+
if (auto *ODRE = dyn_cast<OverloadedDeclRefExpr>(anchor)) {
1282+
if (!(requirementType && requirementType->is<TypeVariableType>()))
1283+
return 1;
1284+
1285+
unsigned choiceImpact = 0;
1286+
if (auto *choice = cs.findSelectedOverloadFor(ODRE)) {
1287+
auto *typeVar = requirementType->castTo<TypeVariableType>();
1288+
choice->ImpliedType.visit([&](Type type) {
1289+
if (type->isEqual(typeVar))
1290+
++choiceImpact;
1291+
});
1292+
}
1293+
1294+
return choiceImpact == 0 ? 1 : choiceImpact;
1295+
}
1296+
1297+
// If this requirement is associated with a member reference and it
1298+
// was possible to check it before overload choice is bound, that means
1299+
// types came from the context (most likely Self, or associated type(s))
1300+
// and failing this constraint makes member unrelated/inaccessible, so
1301+
// the impact has to be adjusted accordingly in order for this fix not to
1302+
// interfere with other overload choices.
1303+
//
1304+
// struct S<T> {}
1305+
// extension S where T == AnyObject { func foo() {} }
1306+
//
1307+
// func bar(_ s: S<Int>) { s.foo() }
1308+
//
1309+
// In this case `foo` is only accessible if T == `AnyObject`, which makes
1310+
// fix for same-type requirement higher impact vs. requirement associated
1311+
// with method itself e.g. `func foo<U>() -> U where U : P {}` because
1312+
// `foo` is accessible from any `S` regardless of what `T` is.
1313+
if (isa<UnresolvedDotExpr>(anchor) || isa<UnresolvedMemberExpr>(anchor)) {
1314+
auto *calleeLoc = cs.getCalleeLocator(cs.getConstraintLocator(locator));
1315+
if (!cs.findSelectedOverloadFor(calleeLoc))
1316+
return 10;
1317+
}
1318+
1319+
return 1;
1320+
}
1321+
12721322
/// Attempt to fix missing arguments by introducing type variables
12731323
/// and inferring their types from parameters.
12741324
static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor,
@@ -4235,20 +4285,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
42354285

42364286
if (auto *fix =
42374287
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
4238-
unsigned choiceImpact = 0;
4239-
// If this requirement is associated with overload choice let's
4240-
// tie impact to how many times this non-conforming type is mentioned.
4241-
if (auto *ODRE = dyn_cast_or_null<OverloadedDeclRefExpr>(anchor)) {
4242-
auto *choice = findSelectedOverloadFor(ODRE);
4243-
if (typeVar && choice) {
4244-
choice->ImpliedType.visit([&](Type type) {
4245-
if (type->isEqual(typeVar))
4246-
++choiceImpact;
4247-
});
4248-
}
4249-
}
4250-
4251-
if (!recordFix(fix, choiceImpact == 0 ? 1 : choiceImpact)) {
4288+
auto impact = assessRequirementFailureImpact(*this, typeVar, locator);
4289+
if (!recordFix(fix, impact)) {
42524290
// Record this conformance requirement as "fixed".
42534291
recordFixedRequirement(type, RequirementKind::Conformance,
42544292
protocolTy);
@@ -7744,11 +7782,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
77447782

77457783
case FixKind::InsertCall:
77467784
case FixKind::RemoveReturn:
7747-
case FixKind::AddConformance:
77487785
case FixKind::RemoveAddressOf:
77497786
case FixKind::TreatRValueAsLValue:
7750-
case FixKind::SkipSameTypeRequirement:
7751-
case FixKind::SkipSuperclassRequirement:
77527787
case FixKind::AddMissingArguments:
77537788
case FixKind::SkipUnhandledConstructInFunctionBuilder:
77547789
case FixKind::UsePropertyWrapper:
@@ -7759,6 +7794,15 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
77597794
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
77607795
}
77617796

7797+
case FixKind::AddConformance:
7798+
case FixKind::SkipSameTypeRequirement:
7799+
case FixKind::SkipSuperclassRequirement: {
7800+
return recordFix(fix, assessRequirementFailureImpact(*this, type1,
7801+
fix->getLocator()))
7802+
? SolutionKind::Error
7803+
: SolutionKind::Solved;
7804+
}
7805+
77627806
case FixKind::AllowArgumentTypeMismatch: {
77637807
increaseScore(SK_Fix);
77647808
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;

test/Constraints/generics.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,9 @@ func test_identification_of_key_path_component_callees() {
830830
_ = \SR11435<Int>.foo // expected-error {{property 'foo' requires that 'Int' conform to 'P'}}
831831
_ = \SR11435<Int>.[x: 5] // expected-error {{subscript 'subscript(x:)' requires that 'Int' conform to 'P'}}
832832
}
833+
834+
func sr_11491(_ value: [String]) {
835+
var arr: Set<String> = []
836+
arr.insert(value)
837+
// expected-error@-1 {{cannot convert value of type '[String]' to expected argument type 'String'}}
838+
}

test/stdlib/KeyPathAppending.swift

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,31 +50,38 @@ func mismatchedAppends<T, U, V>(readOnlyLeft: KeyPath<T, U>,
5050
writableRight: WritableKeyPath<U, V>,
5151
referenceRight: ReferenceWritableKeyPath<U, V>){
5252
_ = readOnlyRight.appending(path: readOnlyLeft)
53-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'KeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
53+
// expected-error@-1 {{cannot convert value of type 'KeyPath<T, U>' to expected argument type 'KeyPath<V, U>'}}
54+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
5455

5556
_ = readOnlyRight.appending(path: writableLeft)
56-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'KeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
57+
// expected-error@-1 {{cannot convert value of type 'KeyPath<T, U>' to expected argument type 'KeyPath<V, U>'}}
58+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
5759

5860
_ = readOnlyRight.appending(path: referenceLeft)
59-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'KeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
61+
// expected-error@-1 {{cannot convert value of type 'ReferenceWritableKeyPath<T, U>' to expected argument type 'ReferenceWritableKeyPath<V, U>'}}
62+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
6063

6164
_ = writableRight.appending(path: readOnlyLeft)
62-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'WritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
65+
// expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath<U, V>' inherit from 'KeyPath<U, T>'}}
6366

6467
_ = writableRight.appending(path: writableLeft)
65-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'WritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
68+
// expected-error@-1 {{cannot convert value of type 'WritableKeyPath<T, U>' to expected argument type 'WritableKeyPath<V, U>'}}
69+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
6670

6771
_ = writableRight.appending(path: referenceLeft)
68-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'WritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
72+
// expected-error@-1 {{cannot convert value of type 'ReferenceWritableKeyPath<T, U>' to expected argument type 'ReferenceWritableKeyPath<V, U>'}}
73+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
6974

7075
_ = referenceRight.appending(path: readOnlyLeft)
71-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'ReferenceWritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
76+
// expected-error@-1 {{instance method 'appending(path:)' requires that 'KeyPath<U, V>' inherit from 'KeyPath<U, T>'}}
7277

7378
_ = referenceRight.appending(path: writableLeft)
74-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'ReferenceWritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
79+
// expected-error@-1 {{cannot convert value of type 'WritableKeyPath<T, U>' to expected argument type 'WritableKeyPath<V, U>'}}
80+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
7581

7682
_ = referenceRight.appending(path: referenceLeft)
77-
// expected-error@-1 {{referencing instance method 'appending(path:)' on '_AppendKeyPath' requires the types 'ReferenceWritableKeyPath<U, V>' and 'AnyKeyPath' be equivalent}}
83+
// expected-error@-1 {{cannot convert value of type 'WritableKeyPath<T, U>' to expected argument type 'WritableKeyPath<V, U>'}}
84+
// expected-note@-2 {{arguments to generic parameter 'Root' ('T' and 'V') are expected to be equal}}
7885
}
7986

8087
func partialAppends<T, U, V>(partial: PartialKeyPath<T>,

0 commit comments

Comments
 (0)