[ConstraintSystem] With the new approach for holes, hole propagation happens

automatically.

This commit also renames `ConstraintSystem::recordHole/isHole` to
`recordPotentialHole` and `isPotentialHole` to make it clear that
we don't know for sure whether a type variable is a hole until it's
bound to unresolved.
This commit is contained in:
Holly Borla
2019-10-11 14:22:38 -07:00
parent e63f259f4f
commit 4fd1377c81
10 changed files with 53 additions and 98 deletions

View File

@@ -869,10 +869,7 @@ public:
CS.createTypeVariable(argLoc, TVO_CanBindToInOut | TVO_CanBindToLValue |
TVO_CanBindToNoEscape);
CS.recordHole(argType);
CS.addUnsolvedConstraint(
Constraint::create(CS, ConstraintKind::Defaultable, argType,
CS.getASTContext().TheAnyType, argLoc));
CS.recordPotentialHole(argType);
Arguments.push_back(param.withType(argType));
++NumSynthesizedArgs;
@@ -969,7 +966,7 @@ public:
auto argType = Arguments[argIdx].getPlainType();
argType.visit([&](Type type) {
if (auto *typeVar = type->getAs<TypeVariableType>())
CS.recordHole(typeVar);
CS.recordPotentialHole(typeVar);
});
const auto &param = Parameters[paramIdx];
@@ -1497,19 +1494,12 @@ static bool fixExtraneousArguments(ConstraintSystem &cs,
ArrayRef<AnyFunctionType::Param> args,
int numExtraneous,
ConstraintLocatorBuilder locator) {
auto AnyType = cs.getASTContext().TheAnyType;
SmallVector<std::pair<unsigned, AnyFunctionType::Param>, 4> extraneous;
auto argumentLocator =
locator.withPathElement(ConstraintLocator::FunctionArgument);
for (unsigned i = args.size() - numExtraneous, n = args.size(); i != n; ++i) {
extraneous.push_back({i, args[i]});
if (auto *typeVar = args[i].getPlainType()->getAs<TypeVariableType>()) {
cs.recordHole(typeVar);
cs.addConstraint(
ConstraintKind::Defaultable, typeVar, AnyType,
argumentLocator.withPathElement(LocatorPathElt::TupleElement(i)));
cs.recordPotentialHole(typeVar);
}
}
@@ -2065,15 +2055,14 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
if (!type1->satisfiesClassConstraint()) {
if (shouldAttemptFixes()) {
if (auto last = locator.last()) {
// If solver is in diagnostic mode and this is a
// superclass requirement, let's consider conformance
// to `AnyObject` as solved since actual superclass
// requirement is going to fail too (because type can't
// satisfy it), and it's more interesting from diagnostics
// perspective.
// If solver is in diagnostic mode and type1 is a hole, or if this
// is a superclass requirement, let's consider `AnyObject`
// conformance solved. The actual superclass requirement
// will also fail (because type can't satisfy it), and it's
// more interesting for diagnostics.
auto req = last->getAs<LocatorPathElt::AnyRequirement>();
if (req &&
req->getRequirementKind() == RequirementKind::Superclass)
if (type1->isHole() || (req &&
req->getRequirementKind() == RequirementKind::Superclass))
return getTypeMatchSuccess();
auto *fix = fixRequirementFailure(*this, type1, type2, locator);
@@ -3450,7 +3439,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
if (last->is<LocatorPathElt::SequenceElementType>() &&
desugar1->is<DependentMemberType>() &&
!desugar1->hasTypeVariable()) {
recordHole(typeVar2);
recordPotentialHole(typeVar2);
return getTypeMatchSuccess();
}
}
@@ -4361,25 +4350,21 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
ConstraintLocatorBuilder locator,
TypeMatchOptions flags) {
auto *typeVar = type->getAs<TypeVariableType>();
if (shouldAttemptFixes()) {
// If type variable, associated with this conformance check,
// has been determined to be a "hole" in constraint system,
// let's consider this check a success without recording
// a fix, because it's just a consequence of other failure
// e.g.
// Dig out the fixed type to which this type refers.
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
if (shouldAttemptFixes() && type->isHole()) {
// If the type associated with this conformance check is a "hole" in the
// constraint system, let's consider this check a success without recording
// a fix, because it's just a consequence of the other failure, e.g.
//
// func foo<T: BinaryInteger>(_: T) {}
// foo(Foo.bar) <- if `Foo` doesn't have `bar` there is
// no reason to complain about missing conformance.
if (typeVar && isHole(typeVar)) {
increaseScore(SK_Fix);
return SolutionKind::Solved;
}
increaseScore(SK_Fix);
return SolutionKind::Solved;
}
// Dig out the fixed type to which this type refers.
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
// If we hit a type variable without a fixed type, we can't
// solve this yet.
if (type->isTypeVariableOrMember()) {
@@ -5804,14 +5789,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
if (shouldAttemptFixes()) {
auto fixMissingMember = [&](Type baseTy, Type memberTy,
ConstraintLocator *locator) -> SolutionKind {
// Let's check whether there are any generic parameters
// associated with base type, we'd have to default them
// to `Any` and record as potential holes if so.
baseTy.transform([&](Type type) -> Type {
// Let's check whether there are any generic parameters associated with
// base type, and record potential holes if so.
simplifyType(baseTy).transform([&](Type type) -> Type {
if (auto *typeVar = type->getAs<TypeVariableType>()) {
if (typeVar->getImpl().hasRepresentativeOrFixed())
return type;
recordHole(typeVar);
recordPotentialHole(typeVar);
}
return type;
});
@@ -5830,7 +5814,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
// solutions when contextual type of the result cannot be deduced e.g.
// `let _ = x.foo`.
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
recordHole(memberTypeVar);
recordPotentialHole(memberTypeVar);
return SolutionKind::Solved;
};
@@ -5983,15 +5967,11 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
// If base type is a "hole" there is no reason to record any
// more "member not found" fixes for chained member references.
if (auto *baseType = origBaseTy->getMetatypeInstanceType()
->getRValueType()
->getAs<TypeVariableType>()) {
if (isHole(baseType)) {
increaseScore(SK_Fix);
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
recordHole(memberTypeVar);
return SolutionKind::Solved;
}
if (baseTy->isHole()) {
increaseScore(SK_Fix);
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
recordPotentialHole(memberTypeVar);
return SolutionKind::Solved;
}
return fixMissingMember(origBaseTy, memberTy, locator);
@@ -6560,7 +6540,7 @@ ConstraintSystem::simplifyKeyPathConstraint(
//
// This helps to, for example, diagnose problems with missing
// members used as part of a key path.
if (isHoleAt(componentLoc)) {
if (isPotentialHoleAt(componentLoc)) {
anyComponentsUnresolved = true;
capability = ReadOnly;
continue;
@@ -6961,7 +6941,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
// Let's check if this member couldn't be found and is fixed
// to exist based on its usage.
if (auto *memberTy = type2->getAs<TypeVariableType>()) {
if (isHole(memberTy)) {
if (isPotentialHole(memberTy)) {
auto *funcTy = type1->castTo<FunctionType>();
auto *locator = memberTy->getImpl().getLocator();
// Bind type variable associated with member to a type of argument
@@ -6969,11 +6949,10 @@ ConstraintSystem::simplifyApplicableFnConstraint(
// types of the parameters matching argument types exactly.
addConstraint(ConstraintKind::Bind, memberTy, funcTy, locator);
// There might be no contextual type for result of the application,
// in cases like `let _ = x.foo()`, so let's default result to `Any`
// to make expressions like that type-check.
// in cases like `let _ = x.foo()`, so let's record a potential hole.
auto resultTy = funcTy->getResult();
if (auto *typeVar = resultTy->getAs<TypeVariableType>())
recordHole(typeVar);
recordPotentialHole(typeVar);
return SolutionKind::Solved;
}
}
@@ -7187,7 +7166,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
// they have to be marked as "holes".
type1.visit([&](Type subType) {
if (auto *typeVar = subType->getAs<TypeVariableType>())
recordHole(typeVar);
recordPotentialHole(typeVar);
});
auto *fix = RemoveInvalidCall::create(*this, getConstraintLocator(locator));
@@ -7971,7 +7950,7 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) {
return false;
}
void ConstraintSystem::recordHole(TypeVariableType *typeVar) {
void ConstraintSystem::recordPotentialHole(TypeVariableType *typeVar) {
assert(typeVar);
Holes.insert(typeVar->getImpl().getLocator());
}
@@ -8067,7 +8046,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
newTupleTypes.push_back(smallerElt);
} else {
if (largerElt.getType()->isTypeVariableOrMember())
recordHole(largerElt.getType()->getAs<TypeVariableType>());
recordPotentialHole(largerElt.getType()->getAs<TypeVariableType>());
}
}
auto matchingType =