Skip to content

Commit 694023a

Browse files
committed
[Diagnostics] Centralize requirement failure impact assessment
Conformance requirements get their fixes attached directly where other requirements have to use (for now) `repairFailure` mechanism. Regardless of _how_ fixes get recorded there should be a single way to assess impact of a particular requirement failure. The rules are: - If this is a requirement associated with an operator, impact is based on use of the type which failed the requirement; - If this requirement is from conditional extension, it is considered a very high impact because failing such requirement makes referenced member de facto invisible. Resolves: rdar://problem/55593998 Resolves: [SR-11491](https://bugs.swift.org/browse/SR-11491)
1 parent caa5be8 commit 694023a

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
@@ -1164,6 +1164,56 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1,
11641164
return nullptr;
11651165
}
11661166

1167+
static unsigned
1168+
assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
1169+
ConstraintLocatorBuilder locator) {
1170+
auto *anchor = locator.getAnchor();
1171+
if (!anchor)
1172+
return 1;
1173+
1174+
// If this requirement is associated with an overload choice let's
1175+
// tie impact to how many times this requirement type is mentioned.
1176+
if (auto *ODRE = dyn_cast<OverloadedDeclRefExpr>(anchor)) {
1177+
if (!(requirementType && requirementType->is<TypeVariableType>()))
1178+
return 1;
1179+
1180+
unsigned choiceImpact = 0;
1181+
if (auto *choice = cs.findSelectedOverloadFor(ODRE)) {
1182+
auto *typeVar = requirementType->castTo<TypeVariableType>();
1183+
choice->ImpliedType.visit([&](Type type) {
1184+
if (type->isEqual(typeVar))
1185+
++choiceImpact;
1186+
});
1187+
}
1188+
1189+
return choiceImpact == 0 ? 1 : choiceImpact;
1190+
}
1191+
1192+
// If this requirement is associated with a member reference and it
1193+
// was possible to check it before overload choice is bound, that means
1194+
// types came from the context (most likely Self, or associated type(s))
1195+
// and failing this constraint makes member unrelated/inaccessible, so
1196+
// the impact has to be adjusted accordingly in order for this fix not to
1197+
// interfere with other overload choices.
1198+
//
1199+
// struct S<T> {}
1200+
// extension S where T == AnyObject { func foo() {} }
1201+
//
1202+
// func bar(_ s: S<Int>) { s.foo() }
1203+
//
1204+
// In this case `foo` is only accessible if T == `AnyObject`, which makes
1205+
// fix for same-type requirement higher impact vs. requirement associated
1206+
// with method itself e.g. `func foo<U>() -> U where U : P {}` because
1207+
// `foo` is accessible from any `S` regardless of what `T` is.
1208+
if (isa<UnresolvedDotExpr>(anchor) || isa<UnresolvedMemberExpr>(anchor)) {
1209+
auto *calleeLoc = cs.getCalleeLocator(cs.getConstraintLocator(locator));
1210+
if (!cs.findSelectedOverloadFor(calleeLoc))
1211+
return 10;
1212+
}
1213+
1214+
return 1;
1215+
}
1216+
11671217
/// Attempt to fix missing arguments by introducing type variables
11681218
/// and inferring their types from parameters.
11691219
static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor,
@@ -4130,20 +4180,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
41304180

41314181
if (auto *fix =
41324182
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
4133-
unsigned choiceImpact = 0;
4134-
// If this requirement is associated with overload choice let's
4135-
// tie impact to how many times this non-conforming type is mentioned.
4136-
if (auto *ODRE = dyn_cast_or_null<OverloadedDeclRefExpr>(anchor)) {
4137-
auto *choice = findSelectedOverloadFor(ODRE);
4138-
if (typeVar && choice) {
4139-
choice->ImpliedType.visit([&](Type type) {
4140-
if (type->isEqual(typeVar))
4141-
++choiceImpact;
4142-
});
4143-
}
4144-
}
4145-
4146-
if (!recordFix(fix, choiceImpact == 0 ? 1 : choiceImpact)) {
4183+
auto impact = assessRequirementFailureImpact(*this, typeVar, locator);
4184+
if (!recordFix(fix, impact)) {
41474185
// Record this conformance requirement as "fixed".
41484186
recordFixedRequirement(type, RequirementKind::Conformance,
41494187
protocolTy);
@@ -7639,11 +7677,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
76397677

76407678
case FixKind::InsertCall:
76417679
case FixKind::RemoveReturn:
7642-
case FixKind::AddConformance:
76437680
case FixKind::RemoveAddressOf:
76447681
case FixKind::TreatRValueAsLValue:
7645-
case FixKind::SkipSameTypeRequirement:
7646-
case FixKind::SkipSuperclassRequirement:
76477682
case FixKind::AddMissingArguments:
76487683
case FixKind::SkipUnhandledConstructInFunctionBuilder:
76497684
case FixKind::UsePropertyWrapper:
@@ -7654,6 +7689,15 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
76547689
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
76557690
}
76567691

7692+
case FixKind::AddConformance:
7693+
case FixKind::SkipSameTypeRequirement:
7694+
case FixKind::SkipSuperclassRequirement: {
7695+
return recordFix(fix, assessRequirementFailureImpact(*this, type1,
7696+
fix->getLocator()))
7697+
? SolutionKind::Error
7698+
: SolutionKind::Solved;
7699+
}
7700+
76577701
case FixKind::AllowArgumentTypeMismatch: {
76587702
increaseScore(SK_Fix);
76597703
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)