mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ConstraintSystem] Adjust recording of "fixed" requirements to avoid conflicts
Currently it's possible to have a type conflict between different requirements deduced as the same type which leads to incorrect diagnostics. To mitigate that let's adjust how "fixed" requirements are stored - instead of using resolved type for the left-hand side, let's use originating generic parameter type.
This commit is contained in:
@@ -4810,3 +4810,103 @@ SourceLoc constraints::getLoc(ASTNode anchor) {
|
||||
SourceRange constraints::getSourceRange(ASTNode anchor) {
|
||||
return anchor.getSourceRange();
|
||||
}
|
||||
|
||||
static Optional<Requirement> getRequirement(ConstraintSystem &cs,
|
||||
ConstraintLocator *reqLocator) {
|
||||
auto reqLoc = reqLocator->getLastElementAs<LocatorPathElt::AnyRequirement>();
|
||||
if (!reqLoc)
|
||||
return None;
|
||||
|
||||
if (reqLoc->isConditionalRequirement()) {
|
||||
auto path = reqLocator->getPath();
|
||||
auto *typeReqLoc =
|
||||
cs.getConstraintLocator(reqLocator->getAnchor(), path.drop_back());
|
||||
|
||||
auto conformances = cs.getCheckedConformances();
|
||||
auto result = llvm::find_if(
|
||||
conformances,
|
||||
[&typeReqLoc](
|
||||
const std::pair<ConstraintLocator *, ProtocolConformanceRef>
|
||||
&conformance) { return conformance.first == typeReqLoc; });
|
||||
assert(result != conformances.end());
|
||||
|
||||
auto conformance = result->second;
|
||||
assert(conformance.isConcrete());
|
||||
|
||||
return conformance.getConditionalRequirements()[reqLoc->getIndex()];
|
||||
}
|
||||
|
||||
if (auto openedGeneric =
|
||||
reqLocator->findLast<LocatorPathElt::OpenedGeneric>()) {
|
||||
auto signature = openedGeneric->getSignature();
|
||||
return signature->getRequirements()[reqLoc->getIndex()];
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
static Optional<std::pair<GenericTypeParamType *, RequirementKind>>
|
||||
getRequirementInfo(ConstraintSystem &cs, ConstraintLocator *reqLocator) {
|
||||
auto requirement = getRequirement(cs, reqLocator);
|
||||
if (!requirement)
|
||||
return None;
|
||||
|
||||
auto *GP = requirement->getFirstType()->getAs<GenericTypeParamType>();
|
||||
if (!GP)
|
||||
return None;
|
||||
|
||||
auto path = reqLocator->getPath();
|
||||
auto iter = path.rbegin();
|
||||
auto openedGeneric =
|
||||
reqLocator->findLast<LocatorPathElt::OpenedGeneric>(iter);
|
||||
assert(openedGeneric);
|
||||
|
||||
auto newPath = path.drop_back(iter - path.rbegin() + 1);
|
||||
auto *baseLoc = cs.getConstraintLocator(reqLocator->getAnchor(), newPath);
|
||||
|
||||
auto openedTypes = cs.getOpenedTypes();
|
||||
auto substitutions = llvm::find_if(
|
||||
openedTypes,
|
||||
[&baseLoc](
|
||||
const std::pair<ConstraintLocator *, ArrayRef<OpenedType>> &entry) {
|
||||
return entry.first == baseLoc;
|
||||
});
|
||||
|
||||
if (substitutions == openedTypes.end())
|
||||
return None;
|
||||
|
||||
auto replacement =
|
||||
llvm::find_if(substitutions->second, [&GP](const OpenedType &entry) {
|
||||
auto *typeVar = entry.second;
|
||||
return typeVar->getImpl().getGenericParameter() == GP;
|
||||
});
|
||||
|
||||
if (replacement == substitutions->second.end())
|
||||
return None;
|
||||
|
||||
auto *repr = cs.getRepresentative(replacement->second);
|
||||
return std::make_pair(repr->getImpl().getGenericParameter(),
|
||||
requirement->getKind());
|
||||
}
|
||||
|
||||
bool ConstraintSystem::isFixedRequirement(ConstraintLocator *reqLocator,
|
||||
Type requirementTy) {
|
||||
if (auto reqInfo = getRequirementInfo(*this, reqLocator)) {
|
||||
auto *GP = reqInfo->first;
|
||||
auto reqKind = static_cast<unsigned>(reqInfo->second);
|
||||
return FixedRequirements.count(
|
||||
std::make_tuple(GP, reqKind, requirementTy.getPointer()));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConstraintSystem::recordFixedRequirement(ConstraintLocator *reqLocator,
|
||||
Type requirementTy) {
|
||||
if (auto reqInfo = getRequirementInfo(*this, reqLocator)) {
|
||||
auto *GP = reqInfo->first;
|
||||
auto reqKind = static_cast<unsigned>(reqInfo->second);
|
||||
FixedRequirements.insert(
|
||||
std::make_tuple(GP, reqKind, requirementTy.getPointer()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user