[ConstraintSystem] Implement new rule for static member lookup in generic contexts

Instead of requiring result type of the member to conform to declaring protocol,
as originally proposed by SE-0299, let's instead require `Self` to be bound to
some concrete type in extension that declares a static member.

This would make sure that:

1. Members are only visible on a particular type;
2. There is no ambiguity regarding what base of the member chain is going to be.
This commit is contained in:
Pavel Yaskevich
2021-02-04 15:47:07 -08:00
parent 55cd99bce8
commit c44a92ae0b
4 changed files with 50 additions and 57 deletions

View File

@@ -1589,19 +1589,12 @@ ConstraintSystem::getTypeOfMemberReference(
// reference e.g. it might be incorrect initializer call
// or result type is invalid.
if (!(shouldAttemptFixes() && hasFixFor(getConstraintLocator(locator)))) {
// Member type with Self applied.
auto refTy = openedType->castTo<FunctionType>()->getResult();
// If member is a function type, let's use its result type
// since it could be either a static method or a property
// which returns a function type.
if (auto *funcTy = refTy->getAs<FunctionType>())
baseOpenedTy = funcTy->getResult();
else
baseOpenedTy = refTy;
// It should be possible to form optional chains which start
// from a protocol metatype.
baseOpenedTy = baseOpenedTy->lookThroughAllOptionalTypes();
if (auto concreteSelf =
getConcreteReplacementForProtocolSelfType(value)) {
// Concrete type replacing `Self` could be generic, so we need
// to make sure that it's opened before use.
baseOpenedTy = openType(concreteSelf, replacements);
}
}
} else if (baseObjTy->isExistentialType()) {
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
@@ -4540,6 +4533,23 @@ bool constraints::hasExplicitResult(ClosureExpr *closure) {
ClosureHasExplicitResultRequest{closure}, false);
}
Type constraints::getConcreteReplacementForProtocolSelfType(ValueDecl *member) {
auto *DC = member->getDeclContext();
if (!DC->getSelfProtocolDecl())
return Type();
GenericSignature signature;
if (auto *genericContext = member->getAsGenericContext()) {
signature = genericContext->getGenericSignature();
} else {
signature = DC->getGenericSignatureOfContext();
}
auto selfTy = DC->getProtocolSelfType();
return signature->getConcreteType(selfTy);
}
static bool isOperator(Expr *expr, StringRef expectedName) {
auto name = getOperatorName(expr);
return name ? name->is(expectedName) : false;