Skip to content

Commit 5758ae2

Browse files
committed
[ConstraintSystem] Filtering for static member lookup on protocol metatypes
Detect and filter some of the overload choices which can't possibly match because their result type cannot conform to the expected protocol.
1 parent df76400 commit 5758ae2

File tree

3 files changed

+74
-64
lines changed

3 files changed

+74
-64
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,24 +1189,10 @@ namespace {
11891189
// Here `P.foo` would be replaced with `S.foo`
11901190
if (!isExistentialMetatype && baseTy->is<ProtocolType>() &&
11911191
member->isStatic()) {
1192-
auto refKind = choice.getFunctionRefKind();
1193-
Type baseTy;
1194-
1195-
bool isMethod = isa<AbstractFunctionDecl>(member);
1196-
switch (refKind) {
1197-
case FunctionRefKind::Compound:
1198-
case FunctionRefKind::Unapplied:
1199-
case FunctionRefKind::SingleApply: {
1200-
baseTy = isMethod ? openedType->castTo<FunctionType>()->getResult()
1201-
: openedType;
1202-
break;
1203-
}
1204-
1205-
case FunctionRefKind::DoubleApply: {
1206-
llvm_unreachable("not implemented yet");
1207-
}
1208-
}
1209-
1192+
Type baseTy =
1193+
simplifyType(openedType->is<FunctionType>()
1194+
? openedType->castTo<FunctionType>()->getResult()
1195+
: openedType);
12101196
base = TypeExpr::createImplicitHack(base->getLoc(), baseTy, context);
12111197
cs.cacheType(base);
12121198
}

lib/Sema/CSSimplify.cpp

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5511,19 +5511,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
55115511
}
55125512
}
55135513
}
5514-
5515-
if (elt->is<LocatorPathElt::UnresolvedMemberChainResult>()) {
5516-
if (type1->is<ProtocolType>() && !type2->isTypeVariableOrMember()) {
5517-
auto result = simplifyConformsToConstraint(
5518-
type2, type1, ConstraintKind::ConformsTo,
5519-
locator.withPathElement(LocatorPathElt::TypeParameterRequirement(
5520-
0, RequirementKind::Conformance)),
5521-
subflags);
5522-
5523-
return result == SolutionKind::Error ? getTypeMatchFailure(locator)
5524-
: getTypeMatchSuccess();
5525-
}
5526-
}
55275514
}
55285515

55295516
if (kind == ConstraintKind::BindParam) {
@@ -6839,7 +6826,50 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
68396826
->hasTypeParameter()) {
68406827

68416828
/* We're OK */
6829+
} else if (baseObjTy->is<MetatypeType>() &&
6830+
instanceTy->isExistentialType()) {
6831+
// Static member lookup on protocol metatype requires that result type
6832+
// of a selected member to conform to protocol this method is being
6833+
// referred from.
6834+
assert(hasStaticMembers);
6835+
6836+
Type resultTy;
6837+
6838+
// Cannot instantiate a protocol or reference a member on
6839+
// protocol composition type.
6840+
if (isa<ConstructorDecl>(decl) ||
6841+
instanceTy->is<ProtocolCompositionType>()) {
6842+
result.addUnviable(candidate,
6843+
MemberLookupResult::UR_TypeMemberOnInstance);
6844+
return;
6845+
}
6846+
6847+
if (isa<AbstractFunctionDecl>(decl)) {
6848+
auto refTy =
6849+
decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
6850+
resultTy = refTy->castTo<FunctionType>()->getResult();
6851+
} else if (isa<SubscriptDecl>(decl)) {
6852+
resultTy =
6853+
decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
6854+
} else {
6855+
resultTy = decl->getInterfaceType();
6856+
}
68426857

6858+
if (auto *fnType = resultTy->getAs<FunctionType>())
6859+
resultTy = fnType->getResult();
6860+
6861+
// If result is not a concrete type which could conform to the
6862+
// expected protocol, this method is only viable for diagnostics.
6863+
if (!(resultTy->is<NominalType>() || resultTy->is<BoundGenericType>()) ||
6864+
resultTy->isExistentialType()) {
6865+
result.addUnviable(
6866+
candidate,
6867+
MemberLookupResult::UR_InvalidStaticMemberOnProtocolMetatype);
6868+
return;
6869+
}
6870+
6871+
result.addViable(candidate);
6872+
return;
68436873
} else {
68446874
if (!hasStaticMembers) {
68456875
result.addUnviable(candidate,
@@ -7980,6 +8010,24 @@ ConstraintSystem::simplifyUnresolvedMemberChainBaseConstraint(
79808010
return SolutionKind::Unsolved;
79818011
}
79828012

8013+
if (baseTy->is<ProtocolType>()) {
8014+
auto *baseExpr =
8015+
castToExpr<UnresolvedMemberChainResultExpr>(locator.getAnchor())
8016+
->getChainBase();
8017+
auto *memberLoc =
8018+
getConstraintLocator(baseExpr, ConstraintLocator::UnresolvedMember);
8019+
8020+
auto *memberRef = findResolvedMemberRef(memberLoc);
8021+
assert(memberRef);
8022+
8023+
if (memberRef->isStatic()) {
8024+
return simplifyConformsToConstraint(
8025+
resultTy, baseTy, ConstraintKind::ConformsTo,
8026+
getConstraintLocator(memberLoc, ConstraintLocator::MemberRefBase),
8027+
flags);
8028+
}
8029+
}
8030+
79838031
return matchTypes(baseTy, resultTy, ConstraintKind::Equal, flags, locator);
79848032
}
79858033

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,22 +1577,15 @@ ConstraintSystem::getTypeOfMemberReference(
15771577
Type baseOpenedTy = baseObjTy;
15781578

15791579
if (isStaticMemberRefOnProtocol) {
1580-
auto refTy = openedType->castTo<FunctionType>();
1581-
switch (functionRefKind) {
1582-
// Either variable or use of method as a value
1583-
case FunctionRefKind::Unapplied:
1584-
case FunctionRefKind::SingleApply:
1585-
case FunctionRefKind::Compound: {
1586-
baseOpenedTy =
1587-
isa<AbstractFunctionDecl>(value)
1588-
? refTy->getResult()->castTo<FunctionType>()->getResult()
1589-
: refTy->getResult();
1590-
break;
1591-
}
1592-
1593-
case FunctionRefKind::DoubleApply:
1594-
llvm_unreachable("not implemented yet");
1595-
}
1580+
// Member type with Self applied.
1581+
auto refTy = openedType->castTo<FunctionType>()->getResult();
1582+
// If member is a function type, let's use its result type
1583+
// since it could be either a static method or a property
1584+
// which returns a function type.
1585+
if (auto *funcTy = refTy->getAs<FunctionType>())
1586+
baseOpenedTy = funcTy->getResult();
1587+
else
1588+
baseOpenedTy = refTy;
15961589
} else if (baseObjTy->isExistentialType()) {
15971590
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
15981591
OpenedExistentialTypes.push_back(
@@ -1611,23 +1604,6 @@ ConstraintSystem::getTypeOfMemberReference(
16111604
// if it didn't conform.
16121605
addConstraint(ConstraintKind::Bind, baseOpenedTy, selfObjTy,
16131606
getConstraintLocator(locator));
1614-
1615-
if (isStaticMemberRefOnProtocol) {
1616-
// Since base is a protocol metatype we could use to make sure that
1617-
// self type inferred from result of the member does indeed conform
1618-
// to the expected protocol.
1619-
//
1620-
// Delay solving this constraint until after member choice has
1621-
// been completely resolved by the constraint system, so that
1622-
// conformance failure has access to a referenced declaration.
1623-
auto *constraint = Constraint::create(
1624-
*this, ConstraintKind::ConformsTo, selfObjTy, baseObjTy,
1625-
getConstraintLocator(
1626-
locator.withPathElement(ConstraintLocator::MemberRefBase)));
1627-
1628-
addUnsolvedConstraint(constraint);
1629-
activateConstraint(constraint);
1630-
}
16311607
} else if (!isDynamicResult) {
16321608
addSelfConstraint(*this, baseOpenedTy, selfObjTy, locator);
16331609
}

0 commit comments

Comments
 (0)