Skip to content

Commit c07aa4b

Browse files
authored
Merge pull request #6766 from DougGregor/archetype-representative-cleanup
2 parents 0d0dc79 + 8199ba9 commit c07aa4b

File tree

4 files changed

+100
-109
lines changed

4 files changed

+100
-109
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ class ArchetypeBuilder::PotentialArchetype {
448448
return getGenericParam();
449449
}
450450

451+
/// \brief Retrieve the representative for this archetype, performing
452+
/// path compression on the way.
453+
PotentialArchetype *getRepresentative();
454+
455+
friend class ArchetypeBuilder;
456+
friend class GenericSignature;
457+
451458
public:
452459
~PotentialArchetype();
453460

@@ -548,10 +555,6 @@ class ArchetypeBuilder::PotentialArchetype {
548555
/// the number of associated type references.
549556
unsigned getNestingDepth() const;
550557

551-
/// \brief Retrieve the representative for this archetype, performing
552-
/// path compression on the way.
553-
PotentialArchetype *getRepresentative();
554-
555558
/// Retrieve the equivalence class containing this potential archetype.
556559
ArrayRef<PotentialArchetype *> getEquivalenceClass() {
557560
return getRepresentative()->EquivalenceClass;

lib/AST/ArchetypeBuilder.cpp

Lines changed: 86 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,89 @@ bool ArchetypeBuilder::PotentialArchetype::hasConcreteTypeInPath() const {
363363
return false;
364364
}
365365

366+
/// Canonical ordering for dependent types in generic signatures.
367+
static int compareDependentTypes(
368+
ArchetypeBuilder::PotentialArchetype * const* pa,
369+
ArchetypeBuilder::PotentialArchetype * const* pb) {
370+
auto a = *pa, b = *pb;
371+
372+
// Fast-path check for equality.
373+
if (a == b)
374+
return 0;
375+
376+
// Ordering is as follows:
377+
// - Generic params
378+
if (a->isGenericParam() && b->isGenericParam())
379+
return a->getGenericParamKey() < b->getGenericParamKey() ? -1 : +1;
380+
381+
// A generic parameter is always ordered before a nested type.
382+
if (a->isGenericParam() != b->isGenericParam())
383+
return a->isGenericParam() ? -1 : +1;
384+
385+
// - Dependent members
386+
auto ppa = a->getParent();
387+
auto ppb = b->getParent();
388+
389+
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
390+
if (int compareBases = compareDependentTypes(&ppa, &ppb))
391+
return compareBases;
392+
393+
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
394+
if (int compareNames = a->getName().str().compare(b->getName().str()))
395+
return compareNames;
396+
397+
if (auto *aa = a->getResolvedAssociatedType()) {
398+
if (auto *ab = b->getResolvedAssociatedType()) {
399+
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
400+
auto protoa = aa->getProtocol();
401+
auto protob = ab->getProtocol();
402+
if (int compareProtocols
403+
= ProtocolType::compareProtocols(&protoa, &protob))
404+
return compareProtocols;
405+
} else {
406+
// A resolved archetype is always ordered before an unresolved one.
407+
return -1;
408+
}
409+
}
410+
411+
// A resolved archetype is always ordered before an unresolved one.
412+
if (b->getResolvedAssociatedType())
413+
return +1;
414+
415+
// Make sure typealiases are properly ordered, to avoid crashers.
416+
// FIXME: Ideally we would eliminate typealiases earlier.
417+
if (auto *aa = a->getTypeAliasDecl()) {
418+
if (auto *ab = b->getTypeAliasDecl()) {
419+
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
420+
auto protoa = aa->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
421+
auto protob = ab->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
422+
if (int compareProtocols
423+
= ProtocolType::compareProtocols(&protoa, &protob))
424+
return compareProtocols;
425+
}
426+
427+
// A resolved archetype is always ordered before an unresolved one.
428+
return -1;
429+
}
430+
431+
// A resolved archetype is always ordered before an unresolved one.
432+
if (b->getTypeAliasDecl())
433+
return +1;
434+
435+
// Along the error path where one or both of the potential archetypes was
436+
// renamed due to typo correction,
437+
if (a->wasRenamed() || b->wasRenamed()) {
438+
if (a->wasRenamed() != b->wasRenamed())
439+
return a->wasRenamed() ? +1 : -1;
440+
441+
if (int compareNames = a->getOriginalName().str().compare(
442+
b->getOriginalName().str()))
443+
return compareNames;
444+
}
445+
446+
llvm_unreachable("potential archetype total order failure");
447+
}
448+
366449
bool ArchetypeBuilder::PotentialArchetype::isBetterArchetypeAnchor(
367450
PotentialArchetype *other) const {
368451
auto concrete = hasConcreteTypeInPath();
@@ -1065,88 +1148,6 @@ bool ArchetypeBuilder::addSuperclassRequirement(PotentialArchetype *T,
10651148
return false;
10661149
}
10671150

1068-
/// Canonical ordering for dependent types in generic signatures.
1069-
static int compareDependentTypes(ArchetypeBuilder::PotentialArchetype * const* pa,
1070-
ArchetypeBuilder::PotentialArchetype * const* pb) {
1071-
auto a = *pa, b = *pb;
1072-
1073-
// Fast-path check for equality.
1074-
if (a == b)
1075-
return 0;
1076-
1077-
// Ordering is as follows:
1078-
// - Generic params
1079-
if (a->isGenericParam() && b->isGenericParam())
1080-
return a->getGenericParamKey() < b->getGenericParamKey() ? -1 : +1;
1081-
1082-
// A generic parameter is always ordered before a nested type.
1083-
if (a->isGenericParam() != b->isGenericParam())
1084-
return a->isGenericParam() ? -1 : +1;
1085-
1086-
// - Dependent members
1087-
auto ppa = a->getParent();
1088-
auto ppb = b->getParent();
1089-
1090-
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
1091-
if (int compareBases = compareDependentTypes(&ppa, &ppb))
1092-
return compareBases;
1093-
1094-
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
1095-
if (int compareNames = a->getName().str().compare(b->getName().str()))
1096-
return compareNames;
1097-
1098-
if (auto *aa = a->getResolvedAssociatedType()) {
1099-
if (auto *ab = b->getResolvedAssociatedType()) {
1100-
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
1101-
auto protoa = aa->getProtocol();
1102-
auto protob = ab->getProtocol();
1103-
if (int compareProtocols
1104-
= ProtocolType::compareProtocols(&protoa, &protob))
1105-
return compareProtocols;
1106-
} else {
1107-
// A resolved archetype is always ordered before an unresolved one.
1108-
return -1;
1109-
}
1110-
}
1111-
1112-
// A resolved archetype is always ordered before an unresolved one.
1113-
if (b->getResolvedAssociatedType())
1114-
return +1;
1115-
1116-
// Make sure typealiases are properly ordered, to avoid crashers.
1117-
// FIXME: Ideally we would eliminate typealiases earlier.
1118-
if (auto *aa = a->getTypeAliasDecl()) {
1119-
if (auto *ab = b->getTypeAliasDecl()) {
1120-
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
1121-
auto protoa = aa->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
1122-
auto protob = ab->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
1123-
if (int compareProtocols
1124-
= ProtocolType::compareProtocols(&protoa, &protob))
1125-
return compareProtocols;
1126-
}
1127-
1128-
// A resolved archetype is always ordered before an unresolved one.
1129-
return -1;
1130-
}
1131-
1132-
// A resolved archetype is always ordered before an unresolved one.
1133-
if (b->getTypeAliasDecl())
1134-
return +1;
1135-
1136-
// Along the error path where one or both of the potential archetypes was
1137-
// renamed due to typo correction,
1138-
if (a->wasRenamed() || b->wasRenamed()) {
1139-
if (a->wasRenamed() != b->wasRenamed())
1140-
return a->wasRenamed() ? +1 : -1;
1141-
1142-
if (int compareNames = a->getOriginalName().str().compare(
1143-
b->getOriginalName().str()))
1144-
return compareNames;
1145-
}
1146-
1147-
llvm_unreachable("potential archetype total order failure");
1148-
}
1149-
11501151
bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes(
11511152
PotentialArchetype *T1,
11521153
PotentialArchetype *T2,
@@ -1161,23 +1162,9 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes(
11611162
return false;
11621163

11631164
// Decide which potential archetype is to be considered the representative.
1164-
// We necessarily prefer potential archetypes rooted at parameters that come
1165-
// from outer generic parameter lists, since those generic parameters will
1166-
// have archetypes bound in the outer context.
1167-
//
1168-
// FIXME: The above comment is mostly obsolete, so why can't we just use
1169-
// compareDependentTypes() here?
1170-
auto T1Param = T1->getRootGenericParamKey();
1171-
auto T2Param = T2->getRootGenericParamKey();
1172-
unsigned T1Depth = T1->getNestingDepth();
1173-
unsigned T2Depth = T2->getNestingDepth();
1174-
auto T1Key = std::make_tuple(T1->wasRenamed(), +T1Param.Depth,
1175-
+T1Param.Index, T1Depth);
1176-
auto T2Key = std::make_tuple(T2->wasRenamed(), +T2Param.Depth,
1177-
+T2Param.Index, T2Depth);
1178-
if (T2Key < T1Key ||
1179-
(T2Key == T1Key &&
1180-
compareDependentTypes(&T2, &T1) < 0))
1165+
// It doesn't specifically matter which we use, but it's a minor optimization
1166+
// to prefer the canonical type.
1167+
if (compareDependentTypes(&T2, &T1) < 0)
11811168
std::swap(T1, T2);
11821169

11831170
// Merge any concrete constraints.

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Type DependentGenericTypeResolver::resolveDependentMemberType(
4444
auto archetype = Builder.resolveArchetype(baseTy);
4545
assert(archetype && "Bad generic context nesting?");
4646

47-
return archetype->getRepresentative()
47+
return archetype
4848
->getNestedType(ref->getIdentifier(), Builder)
4949
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true);
5050
}
@@ -54,7 +54,7 @@ Type DependentGenericTypeResolver::resolveSelfAssociatedType(
5454
auto archetype = Builder.resolveArchetype(selfTy);
5555
assert(archetype && "Bad generic context nesting?");
5656

57-
return archetype->getRepresentative()
57+
return archetype
5858
->getNestedType(assocType->getName(), Builder)
5959
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true);
6060
}
@@ -152,7 +152,6 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
152152
// Resolve the base to a potential archetype.
153153
auto basePA = Builder.resolveArchetype(baseTy);
154154
assert(basePA && "Missing potential archetype for base");
155-
basePA = basePA->getRepresentative();
156155

157156
// Retrieve the potential archetype for the nested type.
158157
auto nestedPA = basePA->getNestedType(ref->getIdentifier(), Builder);
@@ -214,7 +213,7 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
214213

215214
Type CompleteGenericTypeResolver::resolveSelfAssociatedType(
216215
Type selfTy, AssociatedTypeDecl *assocType) {
217-
return Builder.resolveArchetype(selfTy)->getRepresentative()
216+
return Builder.resolveArchetype(selfTy)
218217
->getNestedType(assocType->getName(), Builder)
219218
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/false);
220219
}

test/Generics/associated_type_typo.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
3939
// CHECK-GENERIC-LABEL: .typoAssoc4@
4040
// CHECK-GENERIC-NEXT: Requirements:
4141
// CHECK-GENERIC-NEXT: T : P2 [explicit
42-
// CHECK-GENERIC-NEXT: T[.P2].AssocP2 : P1 [protocol
4342
// CHECK-GENERIC-NEXT: T[.P2].AssocP2 == T[.P2].AssocP2 [redundant]
44-
// CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc : P3 [explicit
43+
// CHECK-GENERIC-NEXT: T[.P2].AssocP2 : P1 [protocol
4544
// CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc == T[.P2].AssocP2[.P1].Assoc [redundant
45+
// CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc : P3 [explicit
46+
// CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc == T[.P2].AssocP2[.P1].Assoc [redundant]
4647
// CHECK-GENERIC-NEXT: Generic signature
4748

4849
// <rdar://problem/19620340>
@@ -72,6 +73,7 @@ protocol Pattern {
7273
associatedtype Element : Equatable
7374

7475
// FIXME: Diagnostics here are very poor
76+
// expected-error@+4{{'C.Slice' does not have a member type named 'Iterator'; did you mean 'Slice'?}}
7577
// expected-error@+3{{'C' does not have a member type named 'Iterator'; did you mean 'Slice'?}}
7678
// expected-error@+2{{'C.Slice' does not have a member type named 'Element'; did you mean 'Slice'?}}
7779
// expected-error@+1{{'C.Slice' does not have a member type named 'Iterator'; did you mean 'Slice'?}}

0 commit comments

Comments
 (0)