Skip to content

Commit fe7ba8b

Browse files
committed
[GSB] Pull typo correction for nested types into delayed reqs handling.
Rather than performing typo correction at the very end of finalize(), do it as part of delayed requirement handling when we cannot otherwise make progress. This is a cleaner way to cope with typo correction that gives us a better chance of getting to a sane result. Fixes rdar://problem/31048352 by eliminating the need for tracking the number of unresolved potential archetypes altogether. Fixes rdar://problem/32077627.
1 parent 4860607 commit fe7ba8b

File tree

3 files changed

+98
-96
lines changed

3 files changed

+98
-96
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ class GenericSignatureBuilder {
299299
const RequirementSource *Source);
300300

301301
/// Try to resolve the given unresolved potential archetype.
302-
ConstraintResult resolveUnresolvedType(PotentialArchetype *pa);
302+
ConstraintResult resolveUnresolvedType(PotentialArchetype *pa,
303+
bool allowTypoCorrection);
303304

304305
public:
305306
/// \brief Add a new same-type requirement between two fully resolved types

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 95 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ struct GenericSignatureBuilder::Implementation {
8585
/// The potential archetypes for the generic parameters in \c GenericParams.
8686
SmallVector<PotentialArchetype *, 4> PotentialArchetypes;
8787

88-
/// The number of nested types that haven't yet been resolved to archetypes.
89-
/// Once all requirements have been added, this will be zero in well-formed
90-
/// code.
91-
unsigned NumUnresolvedNestedTypes = 0;
92-
9388
/// The nested types that have been renamed.
9489
SmallVector<PotentialArchetype *, 4> RenamedNestedTypes;
9590

@@ -1099,9 +1094,6 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
10991094
isUnresolvedNestedType = false;
11001095
identifier.assocTypeOrConcrete = assocType;
11011096
assert(assocType->getName() == getNestedName());
1102-
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
1103-
"Mismatch in number of unresolved nested types");
1104-
--builder.Impl->NumUnresolvedNestedTypes;
11051097
}
11061098

11071099
void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType(
@@ -1111,9 +1103,6 @@ void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType(
11111103
isUnresolvedNestedType = false;
11121104
identifier.assocTypeOrConcrete = concreteDecl;
11131105
assert(concreteDecl->getName() == getNestedName());
1114-
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
1115-
"Mismatch in number of unresolved nested types");
1116-
--builder.Impl->NumUnresolvedNestedTypes;
11171106
}
11181107

11191108
Optional<ConcreteConstraint>
@@ -1214,8 +1203,6 @@ void EquivalenceClass::dump() const {
12141203

12151204
void GenericSignatureBuilder::recordUnresolvedType(
12161205
PotentialArchetype *unresolvedPA) {
1217-
++Impl->NumUnresolvedNestedTypes;
1218-
12191206
Impl->DelayedRequirements.push_back(
12201207
{DelayedRequirement::Unresolved, unresolvedPA, RequirementRHS(),
12211208
FloatingRequirementSource::forAbstract()});
@@ -2806,8 +2793,59 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
28062793
return ConstraintResult::Resolved;
28072794
}
28082795

2796+
/// Perform typo correction on the given nested type, producing the
2797+
/// corrected name (if successful).
2798+
static Identifier typoCorrectNestedType(
2799+
GenericSignatureBuilder::PotentialArchetype *pa) {
2800+
StringRef name = pa->getNestedName().str();
2801+
2802+
// Look through all of the associated types of all of the protocols
2803+
// to which the parent conforms.
2804+
llvm::SmallVector<Identifier, 2> bestMatches;
2805+
unsigned bestEditDistance = 0;
2806+
unsigned maxScore = (name.size() + 1) / 3;
2807+
for (auto proto : pa->getParent()->getConformsTo()) {
2808+
for (auto member : getProtocolMembers(proto)) {
2809+
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
2810+
if (!assocType)
2811+
continue;
2812+
2813+
unsigned dist = name.edit_distance(assocType->getName().str(),
2814+
/*AllowReplacements=*/true,
2815+
maxScore);
2816+
assert(dist > 0 && "nested type should have matched associated type");
2817+
if (bestEditDistance == 0 || dist == bestEditDistance) {
2818+
bestEditDistance = dist;
2819+
maxScore = bestEditDistance;
2820+
bestMatches.push_back(assocType->getName());
2821+
} else if (dist < bestEditDistance) {
2822+
bestEditDistance = dist;
2823+
maxScore = bestEditDistance;
2824+
bestMatches.clear();
2825+
bestMatches.push_back(assocType->getName());
2826+
}
2827+
}
2828+
}
2829+
2830+
// FIXME: Look through the superclass.
2831+
2832+
// If we didn't find any matches at all, fail.
2833+
if (bestMatches.empty())
2834+
return Identifier();
2835+
2836+
// Make sure that we didn't find more than one match at the best
2837+
// edit distance.
2838+
for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) {
2839+
if (other != bestMatches.front())
2840+
return Identifier();
2841+
}
2842+
2843+
return bestMatches.front();
2844+
}
2845+
28092846
ConstraintResult GenericSignatureBuilder::resolveUnresolvedType(
2810-
PotentialArchetype *pa) {
2847+
PotentialArchetype *pa,
2848+
bool allowTypoCorrection) {
28112849
// If something else resolved this type, we're done.
28122850
if (!pa->isUnresolved())
28132851
return ConstraintResult::Resolved;
@@ -2828,8 +2866,31 @@ ConstraintResult GenericSignatureBuilder::resolveUnresolvedType(
28282866
return ConstraintResult::Resolved;
28292867
}
28302868

2831-
// We are unable to resolve this constraint.
2832-
return ConstraintResult::Unresolved;
2869+
// If we aren't allowed to perform typo correction, we can't resolve the
2870+
// constraint.
2871+
if (!allowTypoCorrection)
2872+
return ConstraintResult::Unresolved;
2873+
2874+
// Try to typo correct to a nested type name.
2875+
Identifier correction = typoCorrectNestedType(pa);
2876+
if (correction.empty()) {
2877+
pa->setInvalid();
2878+
return ConstraintResult::Conflicting;
2879+
}
2880+
2881+
// Note that this is being renamed.
2882+
pa->saveNameForRenaming();
2883+
Impl->RenamedNestedTypes.push_back(pa);
2884+
2885+
// Resolve the associated type and merge the potential archetypes.
2886+
auto replacement = pa->getParent()->getNestedType(correction, *this);
2887+
pa->resolveAssociatedType(replacement->getResolvedAssociatedType(),
2888+
*this);
2889+
addSameTypeRequirement(pa, replacement,
2890+
RequirementSource::forNestedTypeNameMatch(pa),
2891+
UnresolvedHandlingKind::GenerateConstraints);
2892+
2893+
return ConstraintResult::Resolved;
28332894
}
28342895

28352896
ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
@@ -3749,56 +3810,6 @@ void GenericSignatureBuilder::inferRequirements(
37493810
}
37503811
}
37513812

3752-
/// Perform typo correction on the given nested type, producing the
3753-
/// corrected name (if successful).
3754-
static Identifier typoCorrectNestedType(
3755-
GenericSignatureBuilder::PotentialArchetype *pa) {
3756-
StringRef name = pa->getNestedName().str();
3757-
3758-
// Look through all of the associated types of all of the protocols
3759-
// to which the parent conforms.
3760-
llvm::SmallVector<Identifier, 2> bestMatches;
3761-
unsigned bestEditDistance = 0;
3762-
unsigned maxScore = (name.size() + 1) / 3;
3763-
for (auto proto : pa->getParent()->getConformsTo()) {
3764-
for (auto member : getProtocolMembers(proto)) {
3765-
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
3766-
if (!assocType)
3767-
continue;
3768-
3769-
unsigned dist = name.edit_distance(assocType->getName().str(),
3770-
/*AllowReplacements=*/true,
3771-
maxScore);
3772-
assert(dist > 0 && "nested type should have matched associated type");
3773-
if (bestEditDistance == 0 || dist == bestEditDistance) {
3774-
bestEditDistance = dist;
3775-
maxScore = bestEditDistance;
3776-
bestMatches.push_back(assocType->getName());
3777-
} else if (dist < bestEditDistance) {
3778-
bestEditDistance = dist;
3779-
maxScore = bestEditDistance;
3780-
bestMatches.clear();
3781-
bestMatches.push_back(assocType->getName());
3782-
}
3783-
}
3784-
}
3785-
3786-
// FIXME: Look through the superclass.
3787-
3788-
// If we didn't find any matches at all, fail.
3789-
if (bestMatches.empty())
3790-
return Identifier();
3791-
3792-
// Make sure that we didn't find more than one match at the best
3793-
// edit distance.
3794-
for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) {
3795-
if (other != bestMatches.front())
3796-
return Identifier();
3797-
}
3798-
3799-
return bestMatches.front();
3800-
}
3801-
38023813
namespace swift {
38033814
template<typename T>
38043815
bool operator<(const Constraint<T> &lhs, const Constraint<T> &rhs) {
@@ -4104,33 +4115,6 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
41044115
}
41054116
}
41064117
}
4107-
4108-
// If any nested types remain unresolved, produce diagnostics.
4109-
if (Impl->NumUnresolvedNestedTypes > 0) {
4110-
visitPotentialArchetypes([&](PotentialArchetype *pa) {
4111-
// We only care about nested types that haven't been resolved.
4112-
if (!pa->isUnresolved()) return;
4113-
4114-
// Try to typo correct to a nested type name.
4115-
Identifier correction = typoCorrectNestedType(pa);
4116-
if (correction.empty()) {
4117-
pa->setInvalid();
4118-
return;
4119-
}
4120-
4121-
// Note that this is being renamed.
4122-
pa->saveNameForRenaming();
4123-
Impl->RenamedNestedTypes.push_back(pa);
4124-
4125-
// Resolve the associated type and merge the potential archetypes.
4126-
auto replacement = pa->getParent()->getNestedType(correction, *this);
4127-
pa->resolveAssociatedType(replacement->getResolvedAssociatedType(),
4128-
*this);
4129-
addSameTypeRequirement(pa, replacement,
4130-
RequirementSource::forNestedTypeNameMatch(pa),
4131-
UnresolvedHandlingKind::GenerateConstraints);
4132-
});
4133-
}
41344118
}
41354119

41364120
bool GenericSignatureBuilder::diagnoseRemainingRenames(
@@ -4162,12 +4146,17 @@ static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
41624146

41634147
void GenericSignatureBuilder::processDelayedRequirements() {
41644148
bool anySolved = !Impl->DelayedRequirements.empty();
4149+
bool allowTypoCorrection = false;
41654150
while (anySolved) {
41664151
// Steal the delayed requirements so we can reprocess them.
41674152
anySolved = false;
41684153
auto delayed = std::move(Impl->DelayedRequirements);
41694154
Impl->DelayedRequirements.clear();
41704155

4156+
// Whether we saw any unresolve type constraints that we couldn't
4157+
// resolve.
4158+
bool hasUnresolvedUnresolvedTypes = false;
4159+
41714160
// Process delayed requirements.
41724161
for (const auto &req : delayed) {
41734162
// Reprocess the delayed requirement.
@@ -4192,7 +4181,9 @@ void GenericSignatureBuilder::processDelayedRequirements() {
41924181
break;
41934182

41944183
case DelayedRequirement::Unresolved:
4195-
reqResult = resolveUnresolvedType(req.lhs.get<PotentialArchetype *>());
4184+
reqResult = resolveUnresolvedType(
4185+
req.lhs.get<PotentialArchetype *>(),
4186+
allowTypoCorrection);
41964187
break;
41974188
}
41984189

@@ -4210,9 +4201,19 @@ void GenericSignatureBuilder::processDelayedRequirements() {
42104201
case ConstraintResult::Unresolved:
42114202
// Add the requirement back.
42124203
Impl->DelayedRequirements.push_back(req);
4204+
4205+
if (req.kind == DelayedRequirement::Unresolved)
4206+
hasUnresolvedUnresolvedTypes = true;
42134207
break;
42144208
}
42154209
}
4210+
4211+
// If we didn't solve anything, but we did see some unresolved types,
4212+
// try again with typo correction enabled.
4213+
if (!anySolved && hasUnresolvedUnresolvedTypes && !allowTypoCorrection) {
4214+
allowTypoCorrection = true;
4215+
anySolved = true;
4216+
}
42164217
}
42174218
}
42184219

Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
// RUN: not --crash %target-swift-frontend -typecheck -primary-file %s
1+
// RUN: not %target-swift-frontend -typecheck -primary-file %s
22

33
func hexEncodeBytes<T: Collection>(_ bytes: T) where T.Generator.Element == UInt8 { }

0 commit comments

Comments
 (0)