mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ConstraintSystem] Deplay opening generic requirements until after contextual self has been applied
While computing a type of member via `getTypeOfMemberReference`
let's delay opening generic requirements associated with function
type until after self constraint has been created, that would give
a chance for contextual types to get propagated and make mismatch
originated in generic requirements much easier to diagnose.
Consider following example:
```swift
struct S<T> {}
extension S where T == Int {
func foo() {}
}
func test(_ s: S<String>) {
s.foo()
}
```
`foo` would get opened as `(S<$T>) -> () -> Void` and contextual `self`
type is going to be `S<String>`, so applying that before generic requirement
`$T == Int` would make sure that `$T` gets bound to a contextual
type of `String` and later fails requirement constraint `$T == Int`.
This is much easier to diagnose comparing to `$T` being bound to
`Int` right away due to same-type generic requirement and then
failing an attempt to convert `S<String>` to `S<Int>` while simplifying
self constraint.
Resolves: rdar://problem/46427500
Resolves: rdar://problem/34770265
This commit is contained in:
@@ -644,7 +644,8 @@ Type ConstraintSystem::openFunctionType(
|
||||
OpenedTypeMap &replacements,
|
||||
DeclContext *innerDC,
|
||||
DeclContext *outerDC,
|
||||
bool skipProtocolSelfConstraint) {
|
||||
bool skipProtocolSelfConstraint,
|
||||
bool skipGenericRequirements) {
|
||||
Type type;
|
||||
|
||||
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
|
||||
@@ -654,7 +655,8 @@ Type ConstraintSystem::openFunctionType(
|
||||
genericFn->getGenericSignature(),
|
||||
skipProtocolSelfConstraint,
|
||||
locator,
|
||||
replacements);
|
||||
replacements,
|
||||
skipGenericRequirements);
|
||||
|
||||
// Transform the parameters and output type.
|
||||
llvm::SmallVector<AnyFunctionType::Param, 4> openedParams;
|
||||
@@ -1110,7 +1112,8 @@ void ConstraintSystem::openGeneric(
|
||||
GenericSignature *sig,
|
||||
bool skipProtocolSelfConstraint,
|
||||
ConstraintLocatorBuilder locator,
|
||||
OpenedTypeMap &replacements) {
|
||||
OpenedTypeMap &replacements,
|
||||
bool skipGenericRequirements) {
|
||||
if (sig == nullptr)
|
||||
return;
|
||||
|
||||
@@ -1137,6 +1140,9 @@ void ConstraintSystem::openGeneric(
|
||||
|
||||
bindArchetypesFromContext(*this, outerDC, locatorPtr, replacements);
|
||||
|
||||
if (skipGenericRequirements)
|
||||
return;
|
||||
|
||||
// Add the requirements as constraints.
|
||||
openGenericRequirements(
|
||||
outerDC, sig, skipProtocolSelfConstraint, locator,
|
||||
@@ -1327,9 +1333,12 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
}
|
||||
}
|
||||
|
||||
// While opening member function type, let's delay opening requirements
|
||||
// to allow contextual types to affect the situation.
|
||||
openedType = openFunctionType(funcType, numRemovedArgumentLabels,
|
||||
locator, replacements, innerDC, outerDC,
|
||||
/*skipProtocolSelfConstraint=*/true);
|
||||
/*skipProtocolSelfConstraint=*/true,
|
||||
/*skipGenericRequirements=*/true);
|
||||
|
||||
if (!outerDC->getSelfProtocolDecl()) {
|
||||
// Class methods returning Self as well as constructors get the
|
||||
@@ -1373,6 +1382,19 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
addSelfConstraint(*this, baseOpenedTy, selfObjTy, locator);
|
||||
}
|
||||
|
||||
// Open generic requirements after self constraint has been
|
||||
// applied and contextual types have been propagated. This
|
||||
// helps diagnostics because instead of self type conversion
|
||||
// failing we'll get a generic requirement constraint failure
|
||||
// if mismatch is related to generic parameters which is much
|
||||
// easier to diagnose.
|
||||
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
|
||||
openGenericRequirements(
|
||||
outerDC, genericFn->getGenericSignature(),
|
||||
/*skipProtocolSelfConstraint=*/true, locator,
|
||||
[&](Type type) { return openType(type, replacements); });
|
||||
}
|
||||
|
||||
// Compute the type of the reference.
|
||||
Type type;
|
||||
if (!value->isInstanceMember() || isInstance) {
|
||||
|
||||
Reference in New Issue
Block a user