Skip to content

Commit d0530b9

Browse files
authored
Merge pull request #26798 from xedin/introduces-cs-holes
[ConstraintSystem] Introduce a notion of a "hole"
2 parents e5e48cb + fbb55ce commit d0530b9

File tree

8 files changed

+169
-78
lines changed

8 files changed

+169
-78
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -978,8 +978,33 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
978978
cs.addConstraint(ConstraintKind::Bind, TypeVar, type, locator);
979979

980980
// If this was from a defaultable binding note that.
981-
if (Binding.isDefaultableBinding())
982-
cs.DefaultedConstraints.push_back(Binding.DefaultableBinding);
981+
if (Binding.isDefaultableBinding()) {
982+
auto *locator = Binding.DefaultableBinding;
983+
// If this default binding comes from a "hole"
984+
// in the constraint system, we have to propagate
985+
// this information and mark this type variable
986+
// as well as mark everything adjacent to it as
987+
// a potential "hole".
988+
//
989+
// Consider this example:
990+
//
991+
// func foo<T: BinaryInteger>(_: T) {}
992+
// foo(.bar) <- Since `.bar` can't be inferred due to
993+
// luck of information about its base type,
994+
// it's member type is going to get defaulted
995+
// to `Any` which has to be propaged to type
996+
// variable associated with `T` and vice versa.
997+
if (cs.shouldAttemptFixes() && cs.isHoleAt(locator)) {
998+
auto &CG = cs.getConstraintGraph();
999+
for (auto *constraint : CG.gatherConstraints(
1000+
TypeVar, ConstraintGraph::GatheringKind::EquivalenceClass)) {
1001+
for (auto *typeVar : constraint->getTypeVariables())
1002+
cs.recordHole(typeVar);
1003+
}
1004+
}
1005+
1006+
cs.DefaultedConstraints.push_back(locator);
1007+
}
9831008

9841009
return !cs.failedConstraint && !cs.simplify();
9851010
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,18 +2863,6 @@ bool MissingMemberFailure::diagnoseAsError() {
28632863
if (!anchor || !baseExpr)
28642864
return false;
28652865

2866-
if (auto *typeVar = getBaseType()->getAs<TypeVariableType>()) {
2867-
auto &CS = getConstraintSystem();
2868-
auto *memberLoc = typeVar->getImpl().getLocator();
2869-
// Don't try to diagnose anything besides first missing
2870-
// member in the chain. e.g. `x.foo().bar()` let's make
2871-
// sure to diagnose only `foo()` as missing because we
2872-
// don't really know much about what `bar()` is supposed
2873-
// to be.
2874-
if (CS.MissingMembers.count(memberLoc))
2875-
return false;
2876-
}
2877-
28782866
auto baseType = resolveType(getBaseType())->getWithoutSpecifierType();
28792867

28802868
DeclNameLoc nameLoc(anchor->getStartLoc());
@@ -2940,6 +2928,27 @@ bool MissingMemberFailure::diagnoseAsError() {
29402928
diagnostic.highlight(baseExpr->getSourceRange())
29412929
.highlight(nameLoc.getSourceRange());
29422930
correction->addFixits(diagnostic);
2931+
} else if (instanceTy->getAnyNominal() &&
2932+
getName().getBaseName() == DeclBaseName::createConstructor()) {
2933+
auto &cs = getConstraintSystem();
2934+
2935+
auto memberName = getName().getBaseName();
2936+
auto result = cs.performMemberLookup(
2937+
ConstraintKind::ValueMember, memberName, metatypeTy,
2938+
FunctionRefKind::DoubleApply, getLocator(),
2939+
/*includeInaccessibleMembers=*/true);
2940+
2941+
// If there are no `init` members at all produce a tailored
2942+
// diagnostic for that, otherwise fallback to generic
2943+
// "no such member" one.
2944+
if (result.ViableCandidates.empty() &&
2945+
result.UnviableCandidates.empty()) {
2946+
emitDiagnostic(anchor->getLoc(), diag::no_accessible_initializers,
2947+
instanceTy)
2948+
.highlight(baseExpr->getSourceRange());
2949+
} else {
2950+
emitBasicError(baseType);
2951+
}
29432952
} else {
29442953
emitBasicError(baseType);
29452954
}

lib/Sema/CSSimplify.cpp

Lines changed: 95 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,9 @@ static ConstraintFix *fixPropertyWrapperFailure(
22052205
if (!decl->hasValidSignature() || !type)
22062206
return nullptr;
22072207

2208+
if (baseTy->isEqual(type))
2209+
return nullptr;
2210+
22082211
if (!attemptFix(resolvedOverload, decl, type))
22092212
return nullptr;
22102213

@@ -3765,6 +3768,23 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
37653768
ConstraintKind kind,
37663769
ConstraintLocatorBuilder locator,
37673770
TypeMatchOptions flags) {
3771+
if (shouldAttemptFixes()) {
3772+
auto *typeVar = type->getAs<TypeVariableType>();
3773+
// If type variable, associated with this conformance check,
3774+
// has been determined to be a "hole" in constraint system,
3775+
// let's consider this check a success without recording
3776+
// a fix, because it's just a consequence of other failure
3777+
// e.g.
3778+
//
3779+
// func foo<T: BinaryInteger>(_: T) {}
3780+
// foo(Foo.bar) <- if `Foo` doesn't have `bar` there is
3781+
// no reason to complain about missing conformance.
3782+
if (typeVar && isHole(typeVar)) {
3783+
increaseScore(SK_Fix);
3784+
return SolutionKind::Solved;
3785+
}
3786+
}
3787+
37683788
// Dig out the fixed type to which this type refers.
37693789
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
37703790

@@ -5176,12 +5196,33 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
51765196
// If the lookup found no hits at all (either viable or unviable), diagnose it
51775197
// as such and try to recover in various ways.
51785198
if (shouldAttemptFixes()) {
5179-
// Let's record missing member in constraint system, this helps to prevent
5180-
// stacking up fixes for the same member, because e.g. if its base was of
5181-
// optional type, we'd re-introduce member constraint with optional stripped
5182-
// off to see if the problem is related to base not being explicitly unwrapped.
5183-
if (!MissingMembers.insert(locator))
5184-
return SolutionKind::Error;
5199+
auto fixMissingMember = [&](Type baseTy, Type memberTy,
5200+
ConstraintLocator *locator) -> SolutionKind {
5201+
// Let's check whether there are any generic parameters
5202+
// associated with base type, we'd have to default them
5203+
// to `Any` and record as potential holes if so.
5204+
baseTy.transform([&](Type type) -> Type {
5205+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
5206+
if (typeVar->getImpl().hasRepresentativeOrFixed())
5207+
return type;
5208+
recordHole(typeVar);
5209+
}
5210+
return type;
5211+
});
5212+
5213+
auto *fix =
5214+
DefineMemberBasedOnUse::create(*this, baseTy, member, locator);
5215+
if (recordFix(fix))
5216+
return SolutionKind::Error;
5217+
5218+
// Allow member type to default to `Any` to make it possible to form
5219+
// solutions when contextual type of the result cannot be deduced e.g.
5220+
// `let _ = x.foo`.
5221+
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
5222+
recordHole(memberTypeVar);
5223+
5224+
return SolutionKind::Solved;
5225+
};
51855226

51865227
if (baseObjTy->getOptionalObjectType()) {
51875228
// If the base type was an optional, look through it.
@@ -5203,6 +5244,18 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
52035244
}
52045245
}
52055246

5247+
// Let's check whether the problem is related to optionality of base
5248+
// type, or there is no member with a given name.
5249+
result =
5250+
performMemberLookup(kind, member, baseObjTy->getOptionalObjectType(),
5251+
functionRefKind, locator,
5252+
/*includeInaccessibleMembers*/ true);
5253+
5254+
// If uwrapped type still couldn't find anything for a given name,
5255+
// let's fallback to a "not such member" fix.
5256+
if (result.ViableCandidates.empty() && result.UnviableCandidates.empty())
5257+
return fixMissingMember(origBaseTy, memberTy, locator);
5258+
52065259
// The result of the member access can either be the expected member type
52075260
// (for '!' or optional members with '?'), or the original member type
52085261
// with one extra level of optionality ('?' with non-optional members).
@@ -5230,26 +5283,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
52305283
return SolutionKind::Solved;
52315284
}
52325285

5233-
auto solveWithNewBaseOrName = [&](Type baseType, DeclName memberName,
5234-
bool allowFixes = true) -> SolutionKind {
5235-
// Let's re-enable fixes for this member, because
5236-
// the base or member name has been changed.
5237-
if (allowFixes)
5238-
MissingMembers.remove(locator);
5286+
auto solveWithNewBaseOrName = [&](Type baseType,
5287+
DeclName memberName) -> SolutionKind {
52395288
return simplifyMemberConstraint(kind, baseType, memberName, memberTy,
52405289
useDC, functionRefKind, outerAlternatives,
5241-
flags, locatorB);
5290+
flags | TMF_ApplyingFix, locatorB);
52425291
};
52435292

5293+
// If this member reference is a result of a previous fix, let's not allow
5294+
// any more fixes expect when base is optional, because it could also be
5295+
// an IUO which requires a separate fix.
5296+
if (flags.contains(TMF_ApplyingFix))
5297+
return SolutionKind::Error;
5298+
52445299
// Check if any property wrappers on the base of the member lookup have
52455300
// matching members that we can fall back to, or if the type wraps any
52465301
// properties that have matching members.
52475302
if (auto *fix = fixPropertyWrapperFailure(
52485303
*this, baseTy, locator,
52495304
[&](ResolvedOverloadSetListItem *overload, VarDecl *decl,
52505305
Type newBase) {
5251-
return solveWithNewBaseOrName(newBase, member,
5252-
/*allowFixes=*/false) ==
5306+
return solveWithNewBaseOrName(newBase, member) ==
52535307
SolutionKind::Solved;
52545308
})) {
52555309
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
@@ -5316,29 +5370,20 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
53165370
// fake its presence based on use, that makes it possible to diagnose
53175371
// problems related to member lookup more precisely.
53185372

5319-
origBaseTy.transform([&](Type type) -> Type {
5320-
if (auto *typeVar = type->getAs<TypeVariableType>()) {
5321-
if (typeVar->getImpl().hasRepresentativeOrFixed())
5322-
return type;
5323-
// Default all of the generic parameters found in base to `Any`.
5324-
addConstraint(ConstraintKind::Defaultable, typeVar,
5325-
getASTContext().TheAnyType,
5326-
typeVar->getImpl().getLocator());
5373+
// If base type is a "hole" there is no reason to record any
5374+
// more "member not found" fixes for chained member references.
5375+
if (auto *baseType = origBaseTy->getMetatypeInstanceType()
5376+
->getRValueType()
5377+
->getAs<TypeVariableType>()) {
5378+
if (isHole(baseType)) {
5379+
increaseScore(SK_Fix);
5380+
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
5381+
recordHole(memberTypeVar);
5382+
return SolutionKind::Solved;
53275383
}
5328-
return type;
5329-
});
5330-
5331-
auto *fix =
5332-
DefineMemberBasedOnUse::create(*this, origBaseTy, member, locator);
5333-
if (recordFix(fix))
5334-
return SolutionKind::Error;
5384+
}
53355385

5336-
// Allow member type to default to `Any` to make it possible to form
5337-
// solutions when contextual type of the result cannot be deduced e.g.
5338-
// `let _ = x.foo`.
5339-
addConstraint(ConstraintKind::Defaultable, memberTy,
5340-
getASTContext().TheAnyType, locator);
5341-
return SolutionKind::Solved;
5386+
return fixMissingMember(origBaseTy, memberTy, locator);
53425387
}
53435388
return SolutionKind::Error;
53445389
}
@@ -6285,18 +6330,19 @@ ConstraintSystem::simplifyApplicableFnConstraint(
62856330
// Let's check if this member couldn't be found and is fixed
62866331
// to exist based on its usage.
62876332
if (auto *memberTy = type2->getAs<TypeVariableType>()) {
6288-
auto *locator = memberTy->getImpl().getLocator();
6289-
if (MissingMembers.count(locator)) {
6333+
if (isHole(memberTy)) {
62906334
auto *funcTy = type1->castTo<FunctionType>();
6335+
auto *locator = memberTy->getImpl().getLocator();
62916336
// Bind type variable associated with member to a type of argument
62926337
// application, which makes it seem like member exists with the
62936338
// types of the parameters matching argument types exactly.
62946339
addConstraint(ConstraintKind::Bind, memberTy, funcTy, locator);
62956340
// There might be no contextual type for result of the application,
62966341
// in cases like `let _ = x.foo()`, so let's default result to `Any`
62976342
// to make expressions like that type-check.
6298-
addConstraint(ConstraintKind::Defaultable, funcTy->getResult(),
6299-
getASTContext().TheAnyType, locator);
6343+
auto resultTy = funcTy->getResult();
6344+
if (auto *typeVar = resultTy->getAs<TypeVariableType>())
6345+
recordHole(typeVar);
63006346
return SolutionKind::Solved;
63016347
}
63026348
}
@@ -7241,6 +7287,15 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix) {
72417287
return false;
72427288
}
72437289

7290+
void ConstraintSystem::recordHole(TypeVariableType *typeVar) {
7291+
assert(typeVar);
7292+
auto *locator = typeVar->getImpl().getLocator();
7293+
if (Holes.insert(locator)) {
7294+
addConstraint(ConstraintKind::Defaultable, typeVar,
7295+
getASTContext().TheAnyType, locator);
7296+
}
7297+
}
7298+
72447299
ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
72457300
ConstraintFix *fix, Type type1, Type type2, ConstraintKind matchKind,
72467301
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {

lib/Sema/CSSolver.cpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,6 @@ Solution ConstraintSystem::finalize() {
125125
}
126126
solution.Fixes.append(Fixes.begin() + firstFixIndex, Fixes.end());
127127

128-
// Remember all of the missing member references encountered,
129-
// that helps diagnostics to avoid emitting error for each
130-
// member in the chain.
131-
for (auto *member : MissingMembers)
132-
solution.MissingMembers.push_back(member);
133-
134128
// Remember all the disjunction choices we made.
135129
for (auto &choice : DisjunctionChoices) {
136130
// We shouldn't ever register disjunction choices multiple times,
@@ -267,10 +261,6 @@ void ConstraintSystem::applySolution(const Solution &solution) {
267261

268262
// Register any fixes produced along this path.
269263
Fixes.append(solution.Fixes.begin(), solution.Fixes.end());
270-
271-
// Register any missing members encountered along this path.
272-
MissingMembers.insert(solution.MissingMembers.begin(),
273-
solution.MissingMembers.end());
274264
}
275265

276266
/// Restore the type variable bindings to what they were before
@@ -452,14 +442,14 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
452442
numSavedBindings = cs.solverState->savedBindings.size();
453443
numConstraintRestrictions = cs.ConstraintRestrictions.size();
454444
numFixes = cs.Fixes.size();
445+
numHoles = cs.Holes.size();
455446
numFixedRequirements = cs.FixedRequirements.size();
456447
numDisjunctionChoices = cs.DisjunctionChoices.size();
457448
numOpenedTypes = cs.OpenedTypes.size();
458449
numOpenedExistentialTypes = cs.OpenedExistentialTypes.size();
459450
numDefaultedConstraints = cs.DefaultedConstraints.size();
460451
numAddedNodeTypes = cs.addedNodeTypes.size();
461452
numCheckedConformances = cs.CheckedConformances.size();
462-
numMissingMembers = cs.MissingMembers.size();
463453
numDisabledConstraints = cs.solverState->getNumDisabledConstraints();
464454
numFavoredConstraints = cs.solverState->getNumFavoredConstraints();
465455
numBuilderTransformedClosures = cs.builderTransformedClosures.size();
@@ -500,6 +490,9 @@ ConstraintSystem::SolverScope::~SolverScope() {
500490
// Remove any fixes.
501491
truncate(cs.Fixes, numFixes);
502492

493+
// Remove any holes encountered along the current path.
494+
truncate(cs.Holes, numHoles);
495+
503496
// Remove any disjunction choices.
504497
truncate(cs.DisjunctionChoices, numDisjunctionChoices);
505498

@@ -525,9 +518,6 @@ ConstraintSystem::SolverScope::~SolverScope() {
525518
// Remove any conformances checked along the current path.
526519
truncate(cs.CheckedConformances, numCheckedConformances);
527520

528-
// Remove any missing members found along the current path.
529-
truncate(cs.MissingMembers, numMissingMembers);
530-
531521
/// Remove any builder transformed closures.
532522
truncate(cs.builderTransformedClosures, numBuilderTransformedClosures);
533523

0 commit comments

Comments
 (0)