Skip to content

Commit 5ba8ea7

Browse files
committed
[Archetype builder] Cope with typo-corrected nested types slightly better.
Fix two issues that cropped up in rdar://problem/29261689: * We didn't have an ordering between two typo-corrected nested types that were corrected to the same name, triggering an assertion, which we resolve by ordering based on the original (pre-correction) names. * In some cases, typo corrections would not be diagnosed because the type checker wasn't able to map them to specific uses of that type. Introduce a lame fallback case to make sure we get some diagnostic---even though the location information is poor. All of this needs an overhaul, but not today. Fixes rdar://problem/29261689.
1 parent f48644e commit 5ba8ea7

File tree

4 files changed

+87
-10
lines changed

4 files changed

+87
-10
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ class ArchetypeBuilder {
291291
/// be made concrete.
292292
void finalize(SourceLoc loc, bool allowConcreteGenericParams=false);
293293

294+
/// Diagnose any remaining renames.
295+
///
296+
/// \returns \c true if there were any remaining renames to diagnose.
297+
bool diagnoseRemainingRenames(SourceLoc loc);
298+
294299
/// \brief Resolve the given type to the potential archetype it names.
295300
///
296301
/// This routine will synthesize nested types as required to refer to a
@@ -409,8 +414,12 @@ class ArchetypeBuilder::PotentialArchetype {
409414
/// the superclass type.
410415
unsigned RecursiveSuperclassType : 1;
411416

412-
/// Whether we have renamed this (nested) type due to typo correction.
413-
unsigned Renamed : 1;
417+
/// Whether we have diagnosed a rename.
418+
unsigned DiagnosedRename : 1;
419+
420+
/// If we have renamed this (nested) type due to typo correction,
421+
/// the old name.
422+
Identifier OrigName;
414423

415424
/// The equivalence class of this potential archetype.
416425
llvm::TinyPtrVector<PotentialArchetype *> EquivalenceClass;
@@ -421,7 +430,7 @@ class ArchetypeBuilder::PotentialArchetype {
421430
: ParentOrParam(Parent), NameOrAssociatedType(Name), Representative(this),
422431
IsRecursive(false), Invalid(false), SubstitutingConcreteType(false),
423432
RecursiveConcreteType(false), RecursiveSuperclassType(false),
424-
Renamed(false)
433+
DiagnosedRename(false)
425434
{
426435
assert(Parent != nullptr && "Not an associated type?");
427436
EquivalenceClass.push_back(this);
@@ -432,8 +441,8 @@ class ArchetypeBuilder::PotentialArchetype {
432441
: ParentOrParam(Parent), NameOrAssociatedType(AssocType),
433442
Representative(this), IsRecursive(false), Invalid(false),
434443
SubstitutingConcreteType(false), RecursiveConcreteType(false),
435-
RecursiveSuperclassType(false), Renamed(false)
436-
{
444+
RecursiveSuperclassType(false), DiagnosedRename(false)
445+
{
437446
assert(Parent != nullptr && "Not an associated type?");
438447
EquivalenceClass.push_back(this);
439448
}
@@ -443,7 +452,7 @@ class ArchetypeBuilder::PotentialArchetype {
443452
: ParentOrParam(Parent), NameOrAssociatedType(TypeAlias),
444453
Representative(this), IsRecursive(false), Invalid(false),
445454
SubstitutingConcreteType(false), RecursiveConcreteType(false),
446-
RecursiveSuperclassType(false), Renamed(false)
455+
RecursiveSuperclassType(false), DiagnosedRename(false)
447456
{
448457
assert(Parent != nullptr && "Not an associated type?");
449458
EquivalenceClass.push_back(this);
@@ -457,7 +466,7 @@ class ArchetypeBuilder::PotentialArchetype {
457466
NameOrAssociatedType(Name), Representative(this), IsRecursive(false),
458467
Invalid(false), SubstitutingConcreteType(false),
459468
RecursiveConcreteType(false), RecursiveSuperclassType(false),
460-
Renamed(false)
469+
DiagnosedRename(false)
461470
{
462471
EquivalenceClass.push_back(this);
463472
}
@@ -601,15 +610,27 @@ class ArchetypeBuilder::PotentialArchetype {
601610

602611
/// Determine whether this archetype was renamed due to typo
603612
/// correction. If so, \c getName() retrieves the new name.
604-
bool wasRenamed() const { return Renamed; }
613+
bool wasRenamed() const { return !OrigName.empty(); }
605614

606615
/// Note that this potential archetype was renamed (due to typo
607616
/// correction), providing the new name.
608617
void setRenamed(Identifier newName) {
618+
OrigName = getName();
609619
NameOrAssociatedType = newName;
610-
Renamed = true;
611620
}
612621

622+
/// For a renamed potential archetype, retrieve the original name.
623+
Identifier getOriginalName() const {
624+
assert(wasRenamed());
625+
return OrigName;
626+
}
627+
628+
/// Whether we already diagnosed this rename.
629+
bool alreadyDiagnosedRename() const { return DiagnosedRename; }
630+
631+
/// Note that we already diagnosed this rename.
632+
void setAlreadyDiagnosedRename() { DiagnosedRename = true; }
633+
613634
/// Whether this potential archetype makes a better archetype anchor than
614635
/// the given archetype anchor.
615636
bool isBetterArchetypeAnchor(PotentialArchetype *other) const;

lib/AST/ArchetypeBuilder.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ struct ArchetypeBuilder::Implementation {
127127
/// Once all requirements have been added, this will be zero in well-formed
128128
/// code.
129129
unsigned NumUnresolvedNestedTypes = 0;
130+
131+
/// The nested types that have been renamed.
132+
SmallVector<PotentialArchetype *, 4> RenamedNestedTypes;
130133
};
131134

132135
ArchetypeBuilder::PotentialArchetype::~PotentialArchetype() {
@@ -1146,6 +1149,17 @@ static int compareDependentTypes(ArchetypeBuilder::PotentialArchetype * const* p
11461149
if (b->getResolvedAssociatedType())
11471150
return +1;
11481151

1152+
// Along the error path where one or both of the potential archetypes was
1153+
// renamed due to typo correction,
1154+
if (a->wasRenamed() || b->wasRenamed()) {
1155+
if (a->wasRenamed() != b->wasRenamed())
1156+
return a->wasRenamed() ? +1 : -1;
1157+
1158+
if (int compareNames = a->getOriginalName().str().compare(
1159+
b->getOriginalName().str()))
1160+
return compareNames;
1161+
}
1162+
11491163
llvm_unreachable("potential archetype total order failure");
11501164
}
11511165

@@ -1846,6 +1860,7 @@ ArchetypeBuilder::finalize(SourceLoc loc, bool allowConcreteGenericParams) {
18461860

18471861
// Set the typo-corrected name.
18481862
pa->setRenamed(correction);
1863+
Impl->RenamedNestedTypes.push_back(pa);
18491864

18501865
// Resolve the associated type and merge the potential archetypes.
18511866
auto replacement = pa->getParent()->getNestedType(correction, *this);
@@ -1856,6 +1871,20 @@ ArchetypeBuilder::finalize(SourceLoc loc, bool allowConcreteGenericParams) {
18561871
}
18571872
}
18581873

1874+
bool ArchetypeBuilder::diagnoseRemainingRenames(SourceLoc loc) {
1875+
bool invalid = false;
1876+
for (auto pa : Impl->RenamedNestedTypes) {
1877+
if (pa->alreadyDiagnosedRename()) continue;
1878+
1879+
Diags.diagnose(loc, diag::invalid_member_type_suggest,
1880+
pa->getParent()->getDependentType(*this, true),
1881+
pa->getOriginalName(), pa->getName());
1882+
invalid = true;
1883+
}
1884+
1885+
return invalid;
1886+
}
1887+
18591888
template<typename F>
18601889
void ArchetypeBuilder::visitPotentialArchetypes(F f) {
18611890
// Stack containing all of the potential archetypes to visit.

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
191191
baseTy, ref->getIdentifier(), newName)
192192
.fixItReplace(ref->getIdLoc(), newName.str());
193193
ref->overwriteIdentifier(newName);
194-
194+
nestedPA->setAlreadyDiagnosedRename();
195+
195196
// Go get the actual nested type.
196197
nestedPA = basePA->getNestedType(newName, Builder);
197198
assert(!nestedPA->wasRenamed());
@@ -485,6 +486,8 @@ TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
485486
CompleteGenericTypeResolver completeResolver(*this, builder);
486487
if (checkGenericFuncSignature(*this, nullptr, func, completeResolver))
487488
invalid = true;
489+
if (builder.diagnoseRemainingRenames(func->getLoc()))
490+
invalid = true;
488491

489492
// The generic function signature is complete and well-formed. Determine
490493
// the type of the generic function.
@@ -683,6 +686,7 @@ GenericSignature *TypeChecker::validateGenericSignature(
683686
CompleteGenericTypeResolver completeResolver(*this, builder);
684687
checkGenericParamList(nullptr, genericParams, nullptr,
685688
nullptr, &completeResolver);
689+
(void)builder.diagnoseRemainingRenames(genericParams->getSourceRange().Start);
686690

687691
// Record the generic type parameter types and the requirements.
688692
auto sig = builder.getGenericSignature();

test/Generics/associated_type_typo.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func typoAssoc2<T : P1, U : P1>() where T.assoc == U.assoc {}
2424
// CHECK-GENERIC-LABEL: .typoAssoc2
2525
// CHECK-GENERIC: Generic signature: <T, U where T : P1, U : P1, T.Assoc == U.Assoc>
2626

27+
// expected-error@+3{{'U.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}
2728
// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{42-47=Assoc}}
2829
// expected-error@+2{{'U.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{19-24=Assoc}}
2930
func typoAssoc3<T : P2, U : P2>()
@@ -57,3 +58,25 @@ func typoFunc2<T : P1>(x: TypoType, y: T) { // expected-error{{use of undeclared
5758

5859
func typoFunc3<T : P1>(x: TypoType, y: (T.Assoc) -> ()) { // expected-error{{use of undeclared type 'TypoType'}}
5960
}
61+
62+
// rdar://problem/29261689
63+
typealias Element_<S: Sequence> = S.Iterator.Element
64+
65+
public protocol _Indexable1 {
66+
associatedtype Slice
67+
}
68+
public protocol Indexable : _Indexable1 {
69+
associatedtype Slice : _Indexable1
70+
}
71+
72+
protocol Pattern {
73+
associatedtype Element : Equatable
74+
75+
// FIXME: Diagnostics here are very poor
76+
// expected-error@+3{{'C' does not have a member type named 'Iterator'; did you mean 'Slice'?}}
77+
// expected-error@+2{{'C.Slice' does not have a member type named 'Element'; did you mean 'Slice'?}}
78+
// expected-error@+1{{'C.Slice' does not have a member type named 'Iterator'; did you mean 'Slice'?}}
79+
func matched<C: Indexable>(atStartOf c: C)
80+
where Element_<C> == Element
81+
, Element_<C.Slice> == Element
82+
}

0 commit comments

Comments
 (0)