Skip to content

Commit 1860fec

Browse files
authored
Merge pull request #7081 from slavapestov/protocol-typealiases-are-fun
AST: Fix compareDependentTypes() for protocol typealiases
2 parents 0fbb42a + f9789ce commit 1860fec

File tree

4 files changed

+62
-24
lines changed

4 files changed

+62
-24
lines changed

lib/AST/ASTContext.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,6 +2926,8 @@ getGenericFunctionRecursiveProperties(Type Input, Type Result) {
29262926
RecursiveTypeProperties properties;
29272927
if (Result->getRecursiveProperties().hasDynamicSelf())
29282928
properties |= RecursiveTypeProperties::HasDynamicSelf;
2929+
if (Result->getRecursiveProperties().hasError())
2930+
properties |= RecursiveTypeProperties::HasError;
29292931
return properties;
29302932
}
29312933

@@ -3127,17 +3129,23 @@ SILFunctionType::SILFunctionType(GenericSignature *genericSig, ExtInfo ext,
31273129

31283130
for (auto param : getParameters()) {
31293131
(void)param;
3132+
assert(!param.getType()->hasError()
3133+
&& "interface type of parameter should not contain error types");
31303134
assert(!param.getType()->hasArchetype()
3131-
&& "interface type of generic type should not contain context archetypes");
3135+
&& "interface type of parameter should not contain context archetypes");
31323136
}
31333137
for (auto result : getResults()) {
31343138
(void)result;
3139+
assert(!result.getType()->hasError()
3140+
&& "interface type of result should not contain error types");
31353141
assert(!result.getType()->hasArchetype()
3136-
&& "interface type of generic type should not contain context archetypes");
3142+
&& "interface type of result should not contain context archetypes");
31373143
}
31383144
if (hasErrorResult()) {
3145+
assert(!getErrorResult().getType()->hasError()
3146+
&& "interface type of result should not contain error types");
31393147
assert(!getErrorResult().getType()->hasArchetype()
3140-
&& "interface type of generic type should not contain context archetypes");
3148+
&& "interface type of result should not contain context archetypes");
31413149
}
31423150
}
31433151
#endif

lib/AST/ArchetypeBuilder.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,12 @@ static int compareDependentTypes(
373373
if (a->isGenericParam() != b->isGenericParam())
374374
return a->isGenericParam() ? -1 : +1;
375375

376+
// Typealiases must be ordered *after* everything else, to ensure they
377+
// don't become representatives in the case where a typealias is equated
378+
// with an associated type.
379+
if (!!a->getTypeAliasDecl() != !!b->getTypeAliasDecl())
380+
return a->getTypeAliasDecl() ? +1 : -1;
381+
376382
// - Dependent members
377383
auto ppa = a->getParent();
378384
auto ppb = b->getParent();
@@ -411,27 +417,22 @@ static int compareDependentTypes(
411417
// Make sure typealiases are properly ordered, to avoid crashers.
412418
// FIXME: Ideally we would eliminate typealiases earlier.
413419
if (auto *aa = a->getTypeAliasDecl()) {
414-
if (auto *ab = b->getTypeAliasDecl()) {
415-
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
416-
auto protoa =
417-
aa->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
418-
auto protob =
419-
ab->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
420+
auto *ab = b->getTypeAliasDecl();
421+
assert(ab != nullptr && "Should have handled this case above");
420422

421-
if (int compareProtocols
422-
= ProtocolType::compareProtocols(&protoa, &protob))
423-
return compareProtocols;
423+
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
424+
auto protoa =
425+
aa->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
426+
auto protob =
427+
ab->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
424428

425-
// FIXME: Arbitrarily break the result here.
426-
if (aa != ab)
427-
return aa < ab ? -1 : +1;
428-
} else {
429-
// A resolved archetype is always ordered before an unresolved one.
430-
return -1;
431-
}
432-
} else if (b->getTypeAliasDecl()) {
433-
// A resolved archetype is always ordered before an unresolved one.
434-
return +1;
429+
if (int compareProtocols
430+
= ProtocolType::compareProtocols(&protoa, &protob))
431+
return compareProtocols;
432+
433+
// FIXME: Arbitrarily break the result here.
434+
if (aa != ab)
435+
return aa < ab ? -1 : +1;
435436
}
436437

437438
// Along the error path where one or both of the potential archetypes was
@@ -533,8 +534,6 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
533534
continue;
534535

535536
auto type = alias->getDeclaredInterfaceType();
536-
SmallVector<Identifier, 4> identifiers;
537-
538537
if (auto existingPA = builder.resolveArchetype(type)) {
539538
builder.addSameTypeRequirementBetweenArchetypes(pa, existingPA,
540539
redundantSource);

test/SILGen/same_type_abstraction.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,20 @@ extension MyProtocol where Data == (ReadData, ReadData) {
3838
return (readData(), readData())
3939
}
4040
}
41+
42+
// Problem with protocol typealiases, which are modeled as same-type
43+
// constraints
44+
45+
protocol Refined : Associated {
46+
associatedtype Key
47+
typealias Assoc = Key
48+
49+
init()
50+
}
51+
52+
extension Refined {
53+
// CHECK-LABEL: sil hidden @_T021same_type_abstraction7RefinedPAAEx3KeyQz12withElements_tcfC : $@convention(method) <Self where Self : Refined> (@in Self.Key, @thick Self.Type) -> @out Self
54+
init(withElements newElements: Key) {
55+
self.init()
56+
}
57+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-frontend %s -emit-ir
2+
3+
public protocol QHash : Collection, ExpressibleByArrayLiteral {
4+
associatedtype Key
5+
typealias Element = Key
6+
7+
init()
8+
}
9+
10+
extension QHash {
11+
init(withElements newElements: Key...) {
12+
self.init()
13+
}
14+
}

0 commit comments

Comments
 (0)