mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ConstraintSystem] Diagnose conformance failure with base of a static member lookup
Produce a tailored diagnostic when it has been established that base type of a static member reference on protocol metatype doesn't conform to a required protocol.
This commit is contained in:
@@ -5787,20 +5787,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
|
|||||||
return SolutionKind::Solved;
|
return SolutionKind::Solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we hit a type variable without a fixed type, we can't
|
auto formUnsolved = [&](bool activate = false) {
|
||||||
// solve this yet.
|
|
||||||
if (type->isTypeVariableOrMember()) {
|
|
||||||
// If we're supposed to generate constraints, do so.
|
// If we're supposed to generate constraints, do so.
|
||||||
if (flags.contains(TMF_GenerateConstraints)) {
|
if (flags.contains(TMF_GenerateConstraints)) {
|
||||||
addUnsolvedConstraint(
|
auto *conformance = Constraint::create(
|
||||||
Constraint::create(*this, kind, type,
|
*this, kind, type, protocol->getDeclaredInterfaceType(),
|
||||||
protocol->getDeclaredInterfaceType(),
|
getConstraintLocator(locator));
|
||||||
getConstraintLocator(locator)));
|
|
||||||
|
addUnsolvedConstraint(conformance);
|
||||||
|
if (activate)
|
||||||
|
activateConstraint(conformance);
|
||||||
|
|
||||||
return SolutionKind::Solved;
|
return SolutionKind::Solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SolutionKind::Unsolved;
|
return SolutionKind::Unsolved;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// If we hit a type variable without a fixed type, we can't
|
||||||
|
// solve this yet.
|
||||||
|
if (type->isTypeVariableOrMember())
|
||||||
|
return formUnsolved();
|
||||||
|
|
||||||
auto *loc = getConstraintLocator(locator);
|
auto *loc = getConstraintLocator(locator);
|
||||||
|
|
||||||
@@ -5922,7 +5929,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
|
|||||||
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
|
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.back().is<LocatorPathElt::AnyRequirement>()) {
|
if (auto req = path.back().getAs<LocatorPathElt::AnyRequirement>()) {
|
||||||
// If this is a requirement associated with `Self` which is bound
|
// If this is a requirement associated with `Self` which is bound
|
||||||
// to `Any`, let's consider this "too incorrect" to continue.
|
// to `Any`, let's consider this "too incorrect" to continue.
|
||||||
//
|
//
|
||||||
@@ -5941,6 +5948,39 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto anchor = locator.getAnchor();
|
||||||
|
|
||||||
|
if ((isExpr<UnresolvedDotExpr>(anchor) ||
|
||||||
|
isExpr<UnresolvedMemberExpr>(anchor)) &&
|
||||||
|
req->is<LocatorPathElt::TypeParameterRequirement>()) {
|
||||||
|
auto signature = path[path.size() - 2]
|
||||||
|
.castTo<LocatorPathElt::OpenedGeneric>()
|
||||||
|
.getSignature();
|
||||||
|
auto requirement = signature->getRequirements()[req->getIndex()];
|
||||||
|
|
||||||
|
auto *memberLoc = getConstraintLocator(anchor, path.front());
|
||||||
|
auto *memberRef = findResolvedMemberRef(memberLoc);
|
||||||
|
|
||||||
|
// To figure out what is going on here we need to wait until
|
||||||
|
// member overload is set in the constraint system.
|
||||||
|
if (!memberRef)
|
||||||
|
return formUnsolved(/*activate=*/true);
|
||||||
|
|
||||||
|
// If this is a `Self` conformance requirement from a static member
|
||||||
|
// reference on a protocol metatype, let's produce a tailored diagnostic.
|
||||||
|
if (memberRef->isStatic()) {
|
||||||
|
if (auto *protocolDecl =
|
||||||
|
memberRef->getDeclContext()->getSelfProtocolDecl()) {
|
||||||
|
auto selfTy = protocolDecl->getProtocolSelfType();
|
||||||
|
if (selfTy->isEqual(requirement.getFirstType())) {
|
||||||
|
auto *fix = AllowInvalidStaticMemberRefOnProtocolMetatype::create(
|
||||||
|
*this, memberLoc);
|
||||||
|
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (auto *fix =
|
if (auto *fix =
|
||||||
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
|
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
|
||||||
auto impact = assessRequirementFailureImpact(*this, rawType, locator);
|
auto impact = assessRequirementFailureImpact(*this, rawType, locator);
|
||||||
@@ -5953,27 +5993,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.back().is<LocatorPathElt::MemberRefBase>()) {
|
|
||||||
path.pop_back();
|
|
||||||
|
|
||||||
auto *memberLoc = getConstraintLocator(anchor, path);
|
|
||||||
if (auto overload = findSelectedOverloadFor(memberLoc)) {
|
|
||||||
const auto &choice = overload->choice;
|
|
||||||
assert(choice.isDecl());
|
|
||||||
|
|
||||||
auto *decl = choice.getDecl();
|
|
||||||
auto nameRef = choice.getFunctionRefKind() == FunctionRefKind::Compound
|
|
||||||
? decl->createNameRef()
|
|
||||||
: DeclNameRef(decl->getBaseName());
|
|
||||||
|
|
||||||
auto *fix = AllowTypeOrInstanceMember::create(
|
|
||||||
*this, MetatypeType::get(protocolTy, getASTContext()), decl,
|
|
||||||
nameRef, memberLoc);
|
|
||||||
|
|
||||||
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an implicit Hashable conformance check generated for each
|
// If this is an implicit Hashable conformance check generated for each
|
||||||
// index argument of the keypath subscript component, we could just treat
|
// index argument of the keypath subscript component, we could just treat
|
||||||
// it as though it conforms.
|
// it as though it conforms.
|
||||||
@@ -6833,8 +6852,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
|
|||||||
// referred from.
|
// referred from.
|
||||||
assert(hasStaticMembers);
|
assert(hasStaticMembers);
|
||||||
|
|
||||||
Type resultTy;
|
|
||||||
|
|
||||||
// Cannot instantiate a protocol or reference a member on
|
// Cannot instantiate a protocol or reference a member on
|
||||||
// protocol composition type.
|
// protocol composition type.
|
||||||
if (isa<ConstructorDecl>(decl) ||
|
if (isa<ConstructorDecl>(decl) ||
|
||||||
@@ -6844,6 +6861,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type resultTy;
|
||||||
|
|
||||||
if (isa<AbstractFunctionDecl>(decl)) {
|
if (isa<AbstractFunctionDecl>(decl)) {
|
||||||
auto refTy =
|
auto refTy =
|
||||||
decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
|
decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
|
||||||
@@ -8017,10 +8036,11 @@ ConstraintSystem::simplifyUnresolvedMemberChainBaseConstraint(
|
|||||||
auto *memberLoc =
|
auto *memberLoc =
|
||||||
getConstraintLocator(baseExpr, ConstraintLocator::UnresolvedMember);
|
getConstraintLocator(baseExpr, ConstraintLocator::UnresolvedMember);
|
||||||
|
|
||||||
auto *memberRef = findResolvedMemberRef(memberLoc);
|
if (shouldAttemptFixes() && hasFixFor(memberLoc))
|
||||||
assert(memberRef);
|
return SolutionKind::Solved;
|
||||||
|
|
||||||
if (memberRef->isStatic()) {
|
auto *memberRef = findResolvedMemberRef(memberLoc);
|
||||||
|
if (memberRef && memberRef->isStatic()) {
|
||||||
return simplifyConformsToConstraint(
|
return simplifyConformsToConstraint(
|
||||||
resultTy, baseTy, ConstraintKind::ConformsTo,
|
resultTy, baseTy, ConstraintKind::ConformsTo,
|
||||||
getConstraintLocator(memberLoc, ConstraintLocator::MemberRefBase),
|
getConstraintLocator(memberLoc, ConstraintLocator::MemberRefBase),
|
||||||
|
|||||||
@@ -1577,6 +1577,11 @@ ConstraintSystem::getTypeOfMemberReference(
|
|||||||
Type baseOpenedTy = baseObjTy;
|
Type baseOpenedTy = baseObjTy;
|
||||||
|
|
||||||
if (isStaticMemberRefOnProtocol) {
|
if (isStaticMemberRefOnProtocol) {
|
||||||
|
// In diagnostic mode, let's not try to replace base type
|
||||||
|
// if there is already a known issue associated with this
|
||||||
|
// reference e.g. it might be incorrect initializer call
|
||||||
|
// or result type is invalid.
|
||||||
|
if (!(shouldAttemptFixes() && hasFixFor(getConstraintLocator(locator)))) {
|
||||||
// Member type with Self applied.
|
// Member type with Self applied.
|
||||||
auto refTy = openedType->castTo<FunctionType>()->getResult();
|
auto refTy = openedType->castTo<FunctionType>()->getResult();
|
||||||
// If member is a function type, let's use its result type
|
// If member is a function type, let's use its result type
|
||||||
@@ -1586,6 +1591,7 @@ ConstraintSystem::getTypeOfMemberReference(
|
|||||||
baseOpenedTy = funcTy->getResult();
|
baseOpenedTy = funcTy->getResult();
|
||||||
else
|
else
|
||||||
baseOpenedTy = refTy;
|
baseOpenedTy = refTy;
|
||||||
|
}
|
||||||
} else if (baseObjTy->isExistentialType()) {
|
} else if (baseObjTy->isExistentialType()) {
|
||||||
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
|
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
|
||||||
OpenedExistentialTypes.push_back(
|
OpenedExistentialTypes.push_back(
|
||||||
|
|||||||
Reference in New Issue
Block a user