[ConstraintSystem] Record unable to infer base only if hole originated from affected reference

If base type of a unresolved member reference couldn't be determined
(represented as a hole type), before recording a fix about lack of
contextual information, let's make sure that hole originated in either
base or result type of this reference, otherwise the problem is
contextual e.g. generic parameter, which supposed to act as contextual
type for a reference, couldn't be inferred.
This commit is contained in:
Pavel Yaskevich
2020-09-07 11:24:39 -07:00
parent 923d6ed66b
commit 79a2ab0c8c
3 changed files with 77 additions and 37 deletions

View File

@@ -6966,40 +6966,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
auto locator = getConstraintLocator(locatorB);
// If the base type of this member lookup is a "hole" there is no
// reason to perform a lookup because it wouldn't return any results.
if (shouldAttemptFixes()) {
auto markMemberTypeAsPotentialHole = [&](Type memberTy) {
if (auto *typeVar = memberTy->getAs<TypeVariableType>())
recordPotentialHole(typeVar);
};
// If this is an unresolved member ref e.g. `.foo` and its contextual base
// type has been determined to be a "hole", let's mark the resulting member
// type as a potential hole and continue solving.
if (kind == ConstraintKind::UnresolvedValueMember &&
baseObjTy->getMetatypeInstanceType()->isHole()) {
auto *fix =
SpecifyBaseTypeForContextualMember::create(*this, member, locator);
if (recordFix(fix))
return SolutionKind::Error;
markMemberTypeAsPotentialHole(memberTy);
return SolutionKind::Solved;
} else if ((kind == ConstraintKind::ValueMember ||
kind == ConstraintKind::ValueWitness) &&
baseObjTy->getMetatypeInstanceType()->isHole()) {
// If base type is a "hole" there is no reason to record any
// more "member not found" fixes for chained member references.
markMemberTypeAsPotentialHole(memberTy);
return SolutionKind::Solved;
}
}
MemberLookupResult result =
performMemberLookup(kind, member, baseTy, functionRefKind, locator,
/*includeInaccessibleMembers*/ shouldAttemptFixes());
auto formUnsolved = [&](bool activate = false) {
// If requested, generate a constraint.
if (flags.contains(TMF_GenerateConstraints)) {
@@ -7018,6 +6984,82 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
return SolutionKind::Unsolved;
};
// If the base type of this member lookup is a "hole" there is no
// reason to perform a lookup because it wouldn't return any results.
if (shouldAttemptFixes()) {
auto markMemberTypeAsPotentialHole = [&](Type memberTy) {
if (auto *typeVar = memberTy->getAs<TypeVariableType>())
recordPotentialHole(typeVar);
};
// If this is an unresolved member ref e.g. `.foo` and its contextual base
// type has been determined to be a "hole", let's mark the resulting member
// type as a potential hole and continue solving.
if (kind == ConstraintKind::UnresolvedValueMember) {
// Let's look through all metatypes to find "underlying" type
// of this lookup.
Type underlyingType = baseObjTy;
while (auto *MT = underlyingType->getAs<AnyMetatypeType>()) {
underlyingType = MT->getInstanceType();
}
// Let's delay solving this constraint in diagnostic
// mode until it's certain that there is no way to
// find out what the base type is.
if (underlyingType->isTypeVariableOrMember())
return formUnsolved();
// Let's record a fix only if the hole originates either
// at the result of the chain (that could happen since solving
// of this constraint is delayed until base could be resolved),
// or it is certain that base type can't be bound to any other
// type but a hole.
auto shouldRecordFixForHole = [&](HoleType *baseType) {
auto *originator =
baseType->getOriginatorType().dyn_cast<TypeVariableType *>();
if (!originator)
return false;
auto *originatorLoc = originator->getImpl().getLocator();
// It could either be a hole associated directly with the base
// or a hole which came from result type of the chain.
if (originatorLoc->isLastElement<
LocatorPathElt::UnresolvedMemberChainResult>()) {
auto *UMCR = castToExpr<UnresolvedMemberChainResultExpr>(
originatorLoc->getAnchor());
return UMCR->getChainBase() == getAsExpr(locator->getAnchor());
}
return originatorLoc == locator;
};
if (auto *hole = underlyingType->getAs<HoleType>()) {
if (shouldRecordFixForHole(hole)) {
auto *fix = SpecifyBaseTypeForContextualMember::create(*this, member,
locator);
if (recordFix(fix))
return SolutionKind::Error;
}
markMemberTypeAsPotentialHole(memberTy);
return SolutionKind::Solved;
}
} else if ((kind == ConstraintKind::ValueMember ||
kind == ConstraintKind::ValueWitness) &&
baseObjTy->getMetatypeInstanceType()->isHole()) {
// If base type is a "hole" there is no reason to record any
// more "member not found" fixes for chained member references.
markMemberTypeAsPotentialHole(memberTy);
return SolutionKind::Solved;
}
}
MemberLookupResult result =
performMemberLookup(kind, member, baseTy, functionRefKind, locator,
/*includeInaccessibleMembers*/ shouldAttemptFixes());
switch (result.OverallResult) {
case MemberLookupResult::Unsolved:
return formUnsolved();

View File

@@ -45,5 +45,4 @@ SR12382(&i) // expected-error {{cannot convert value of type 'UnsafeMutablePoint
//problem/68254165 - Bad diagnostic when using String init(decodingCString:) with an incorrect pointer type
func rdar68254165(ptr: UnsafeMutablePointer<Int8>) {
_ = String(decodingCString: ptr, as: .utf8) // expected-error {{generic parameter 'Encoding' could not be inferred}}
// expected-error@-1 {{type '_.Type' has no member 'utf8'}}
}

View File

@@ -100,8 +100,7 @@ func test3a(_ a: ZeroOneTwoThree) {
var h = ZeroOneTwoThree(1)
var i = 0 > 3 ? .none : .some(3) // expected-error {{cannot infer contextual base in reference to member 'none'}}
// expected-error@-1 {{cannot infer contextual base in reference to member 'some'}}
test3a; // expected-error {{unused function}}
.Zero // expected-error {{reference to member 'Zero' cannot be resolved without a contextual type}}
test3a // expected-error {{unused function}}