Skip to content

Commit cfb8d1b

Browse files
authored
Merge pull request swiftlang#25053 from xedin/diag-conditional-req-in-self
[ConstraintSystem] Deplay opening generic requirements until after co…
2 parents a870baa + 91dbcfd commit cfb8d1b

File tree

7 files changed

+76
-15
lines changed

7 files changed

+76
-15
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,8 @@ Type ConstraintSystem::openFunctionType(
644644
OpenedTypeMap &replacements,
645645
DeclContext *innerDC,
646646
DeclContext *outerDC,
647-
bool skipProtocolSelfConstraint) {
647+
bool skipProtocolSelfConstraint,
648+
bool skipGenericRequirements) {
648649
Type type;
649650

650651
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
@@ -654,7 +655,8 @@ Type ConstraintSystem::openFunctionType(
654655
genericFn->getGenericSignature(),
655656
skipProtocolSelfConstraint,
656657
locator,
657-
replacements);
658+
replacements,
659+
skipGenericRequirements);
658660

659661
// Transform the parameters and output type.
660662
llvm::SmallVector<AnyFunctionType::Param, 4> openedParams;
@@ -1110,7 +1112,8 @@ void ConstraintSystem::openGeneric(
11101112
GenericSignature *sig,
11111113
bool skipProtocolSelfConstraint,
11121114
ConstraintLocatorBuilder locator,
1113-
OpenedTypeMap &replacements) {
1115+
OpenedTypeMap &replacements,
1116+
bool skipGenericRequirements) {
11141117
if (sig == nullptr)
11151118
return;
11161119

@@ -1137,6 +1140,9 @@ void ConstraintSystem::openGeneric(
11371140

11381141
bindArchetypesFromContext(*this, outerDC, locatorPtr, replacements);
11391142

1143+
if (skipGenericRequirements)
1144+
return;
1145+
11401146
// Add the requirements as constraints.
11411147
openGenericRequirements(
11421148
outerDC, sig, skipProtocolSelfConstraint, locator,
@@ -1327,9 +1333,12 @@ ConstraintSystem::getTypeOfMemberReference(
13271333
}
13281334
}
13291335

1336+
// While opening member function type, let's delay opening requirements
1337+
// to allow contextual types to affect the situation.
13301338
openedType = openFunctionType(funcType, numRemovedArgumentLabels,
13311339
locator, replacements, innerDC, outerDC,
1332-
/*skipProtocolSelfConstraint=*/true);
1340+
/*skipProtocolSelfConstraint=*/true,
1341+
/*skipGenericRequirements=*/true);
13331342

13341343
if (!outerDC->getSelfProtocolDecl()) {
13351344
// Class methods returning Self as well as constructors get the
@@ -1373,6 +1382,19 @@ ConstraintSystem::getTypeOfMemberReference(
13731382
addSelfConstraint(*this, baseOpenedTy, selfObjTy, locator);
13741383
}
13751384

1385+
// Open generic requirements after self constraint has been
1386+
// applied and contextual types have been propagated. This
1387+
// helps diagnostics because instead of self type conversion
1388+
// failing we'll get a generic requirement constraint failure
1389+
// if mismatch is related to generic parameters which is much
1390+
// easier to diagnose.
1391+
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
1392+
openGenericRequirements(
1393+
outerDC, genericFn->getGenericSignature(),
1394+
/*skipProtocolSelfConstraint=*/true, locator,
1395+
[&](Type type) { return openType(type, replacements); });
1396+
}
1397+
13761398
// Compute the type of the reference.
13771399
Type type;
13781400
if (!value->isInstanceMember() || isInstance) {

lib/Sema/ConstraintSystem.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,9 @@ class ConstraintSystem {
23762376
/// \param skipProtocolSelfConstraint Whether to skip the constraint on a
23772377
/// protocol's 'Self' type.
23782378
///
2379+
/// \param skipGenericRequirements Whether to skip opening generic
2380+
/// requirements asscoiated with given function type.
2381+
///
23792382
/// \returns The opened type, or \c type if there are no archetypes in it.
23802383
Type openFunctionType(
23812384
AnyFunctionType *funcType,
@@ -2384,16 +2387,18 @@ class ConstraintSystem {
23842387
OpenedTypeMap &replacements,
23852388
DeclContext *innerDC,
23862389
DeclContext *outerDC,
2387-
bool skipProtocolSelfConstraint);
2390+
bool skipProtocolSelfConstraint,
2391+
bool skipGenericRequirements = false);
23882392

2389-
/// Open the generic parameter list and its requirements, creating
2390-
/// type variables for each of the type parameters.
2393+
/// Open the generic parameter list and (if requested) its requirements,
2394+
/// creating type variables for each of the type parameters.
23912395
void openGeneric(DeclContext *innerDC,
23922396
DeclContext *outerDC,
23932397
GenericSignature *signature,
23942398
bool skipProtocolSelfConstraint,
23952399
ConstraintLocatorBuilder locator,
2396-
OpenedTypeMap &replacements);
2400+
OpenedTypeMap &replacements,
2401+
bool skipGenericRequirements = false);
23972402

23982403
/// Given generic signature open its generic requirements,
23992404
/// using substitution function, and record them in the

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,14 @@ static Optional<RequirementMatch> findMissingGenericRequirementForSolutionFix(
751751
Type selfTy = proto->getSelfInterfaceType().subst(reqSubMap);
752752
if (type->isEqual(selfTy)) {
753753
type = conformance->getType();
754+
755+
// e.g. `extension P where Self == C { func foo() { ... } }`
756+
// and `C` doesn't actually conform to `P`.
757+
if (type->isEqual(missingType)) {
758+
requirementKind = RequirementKind::Conformance;
759+
missingType = proto->getDeclaredType();
760+
}
761+
754762
if (auto agt = type->getAs<AnyGenericType>())
755763
type = agt->getDecl()->getDeclaredInterfaceType();
756764
return missingRequirementMatch(type);

test/Constraints/members.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,30 @@ func rdar_50467583_and_50909555() {
627627
s[1] // expected-error {{static member 'subscript' cannot be used on instance of type 'S'}} {{5-6=S}}
628628
}
629629
}
630+
631+
// SR-9396 (rdar://problem/46427500) - Nonsensical error message related to constrained extensions
632+
struct SR_9396<A, B> {}
633+
634+
extension SR_9396 where A == Bool { // expected-note {{where 'A' = 'Int'}}
635+
func foo() {}
636+
}
637+
638+
func test_sr_9396(_ s: SR_9396<Int, Double>) {
639+
s.foo() // expected-error {{referencing instance method 'foo()' on 'SR_9396' requires the types 'Int' and 'Bool' be equivalent}}
640+
}
641+
642+
// rdar://problem/34770265 - Better diagnostic needed for constrained extension method call
643+
extension Dictionary where Key == String { // expected-note {{where 'Key' = 'Int'}}
644+
func rdar_34770265_key() {}
645+
}
646+
647+
extension Dictionary where Value == String { // expected-note {{where 'Value' = 'Int'}}
648+
func rdar_34770265_val() {}
649+
}
650+
651+
func test_34770265(_ dict: [Int: Int]) {
652+
dict.rdar_34770265_key()
653+
// expected-error@-1 {{referencing instance method 'rdar_34770265_key()' on 'Dictionary' requires the types 'Int' and 'String' be equivalent}}
654+
dict.rdar_34770265_val()
655+
// expected-error@-1 {{referencing instance method 'rdar_34770265_val()' on 'Dictionary' requires the types 'Int' and 'String' be equivalent}}
656+
}

test/Serialization/extension-of-typealias.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func test(x: Int) {
4141
x.addedMember()
4242
[x].addedMember()
4343
[x].addedMemberInt()
44-
([] as [Bool]).addedMemberInt() // expected-error {{'[Bool]' is not convertible to 'Array<Int>'}}
44+
([] as [Bool]).addedMemberInt() // expected-error {{referencing instance method 'addedMemberInt()' on 'Array' requires the types 'Bool' and 'Int' be equivalent}}
4545
}
4646

4747
#endif

test/decl/nested/type_in_type.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,8 @@ protocol ExpressibleByDogLiteral {}
377377
struct Kitten : ExpressibleByCatLiteral {}
378378
struct Puppy : ExpressibleByDogLiteral {}
379379

380-
struct Claws<A: ExpressibleByCatLiteral> { // expected-note {{'A' declared as parameter to type 'Claws'}}
381-
struct Fangs<B: ExpressibleByDogLiteral> { }
380+
struct Claws<A: ExpressibleByCatLiteral> {
381+
struct Fangs<B: ExpressibleByDogLiteral> { } // expected-note {{where 'B' = 'NotADog'}}
382382
}
383383

384384
struct NotADog {}
@@ -401,9 +401,8 @@ func test() {
401401
// expected-error@-1 {{cannot convert value of type 'Claws<_>.Fangs<_>' to specified type 'Claws.Fangs<Puppy>'}}
402402
let _: Claws.Fangs<NotADog> = something()
403403
// expected-error@-1 {{generic parameter 'T' could not be inferred}} // FIXME: bad diagnostic
404-
_ = Claws.Fangs<NotADog>()
405-
// expected-error@-1 {{generic parameter 'A' could not be inferred}}
406-
// expected-note@-2 {{explicitly specify the generic arguments to fix this issue}}
404+
_ = Claws.Fangs<NotADog>() // TODO(diagnostics): There should be two errors here - "cannot infer A" and "NotADog conformance to ExpressibleByDogLiteral"
405+
// expected-error@-1 {{referencing initializer 'init()' on 'Claws.Fangs' requires that 'NotADog' conform to 'ExpressibleByDogLiteral'}}
407406
}
408407

409408
// https://bugs.swift.org/browse/SR-4379

test/decl/protocol/conforms/self.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protocol HasDefault {
5050

5151
extension HasDefault where Self == SillyClass {
5252
func foo() {}
53-
// expected-note@-1 {{candidate has non-matching type '<Self> () -> ()'}}
53+
// expected-note@-1 {{candidate would match if 'SillyClass' conformed to 'HasDefault'}}
5454
}
5555

5656
extension SillyClass : HasDefault {}

0 commit comments

Comments
 (0)