Skip to content

Commit 5c7f211

Browse files
authored
Merge pull request #15960 from jckarter/enumerate-only-canonical-paired-requirements
AST: Exclude noncanonical params from `GenericSignature::enumeratePairedRequirements`.
2 parents 89ede1c + b842686 commit 5c7f211

File tree

3 files changed

+62
-12
lines changed

3 files changed

+62
-12
lines changed

lib/AST/GenericSignature.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -345,17 +345,30 @@ bool GenericSignature::enumeratePairedRequirements(
345345
auto genericParams = getGenericParams();
346346
unsigned curGenericParamIdx = 0, numGenericParams = genericParams.size();
347347

348-
// Figure out which generic parameters are complete.
349-
SmallVector<bool, 4> genericParamsAreConcrete(genericParams.size(), false);
348+
// Figure out which generic parameters are concrete or same-typed to another
349+
// generic parameter.
350+
auto genericParamsAreNonCanonical =
351+
SmallVector<bool, 4>(genericParams.size(), false);
350352
for (auto req : reqs) {
351353
if (req.getKind() != RequirementKind::SameType) continue;
352-
if (req.getSecondType()->isTypeParameter()) continue;
353-
354-
auto gp = req.getFirstType()->getAs<GenericTypeParamType>();
355-
if (!gp) continue;
354+
355+
GenericTypeParamType *gp;
356+
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
357+
// If two generic parameters are same-typed, then the left-hand one
358+
// is canonical.
359+
gp = secondGP;
360+
} else {
361+
// If an associated type is same-typed, it doesn't constrain the generic
362+
// parameter itself.
363+
if (req.getSecondType()->isTypeParameter()) continue;
364+
365+
// Otherwise, the generic parameter is concrete.
366+
gp = req.getFirstType()->getAs<GenericTypeParamType>();
367+
if (!gp) continue;
368+
}
356369

357370
unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
358-
genericParamsAreConcrete[index] = true;
371+
genericParamsAreNonCanonical[index] = true;
359372
}
360373

361374
/// Local function to 'catch up' to the next dependent type we're going to
@@ -382,7 +395,7 @@ bool GenericSignature::enumeratePairedRequirements(
382395
if (curGenericParam->getDepth() < stopDepth ||
383396
(curGenericParam->getDepth() == stopDepth &&
384397
curGenericParam->getIndex() < stopIndex)) {
385-
if (!genericParamsAreConcrete[curGenericParamIdx] &&
398+
if (!genericParamsAreNonCanonical[curGenericParamIdx] &&
386399
fn(curGenericParam, { }))
387400
return true;
388401

@@ -441,7 +454,7 @@ bool GenericSignature::enumeratePairedRequirements(
441454
// parameter we can't skip, invoke the callback.
442455
if ((startIdx != endIdx ||
443456
(isa<GenericTypeParamType>(depTy) &&
444-
!genericParamsAreConcrete[
457+
!genericParamsAreNonCanonical[
445458
GenericParamKey(cast<GenericTypeParamType>(depTy))
446459
.findIndexIn(genericParams)])) &&
447460
fn(depTy, reqs.slice(startIdx, endIdx-startIdx)))
@@ -807,7 +820,7 @@ bool GenericSignature::isCanonicalTypeInContext(Type type) {
807820
}
808821

809822
bool GenericSignature::isCanonicalTypeInContext(Type type,
810-
GenericSignatureBuilder &builder) {
823+
GenericSignatureBuilder &builder) {
811824
// If the type isn't independently canonical, it's certainly not canonical
812825
// in this context.
813826
if (!type->isCanonical())
@@ -835,7 +848,7 @@ bool GenericSignature::isCanonicalTypeInContext(Type type,
835848
}
836849

837850
CanType GenericSignature::getCanonicalTypeInContext(Type type,
838-
GenericSignatureBuilder &builder) {
851+
GenericSignatureBuilder &builder) {
839852
type = type->getCanonicalType();
840853

841854
// All the contextual canonicality rules apply to type parameters, so if the

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ swift::_getTypeByMangledName(StringRef typeName,
10311031
// Call the associated type access function.
10321032
// TODO: can we just request abstract metadata? If so, do we have
10331033
// a responsibility to try to finish it later?
1034-
return ((const AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
1034+
return ((AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
10351035
(MetadataState::Complete, base, witnessTable).Value;
10361036
});
10371037

test/IRGen/same_type_constraints.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,40 @@ where Self : CodingType,
6262

6363
// OSIZE: define internal swiftcc i8** @"$S21same_type_constraints12GenericKlazzCyxq_GAA1EAA4Data_AA0F4TypePWT"(%swift.type* %"GenericKlazz<T, R>.Data", %swift.type* nocapture readonly %"GenericKlazz<T, R>", i8** nocapture readnone %"GenericKlazz<T, R>.E") [[ATTRS:#[0-9]+]] {
6464
// OSIZE: [[ATTRS]] = {{{.*}}noinline
65+
66+
// Check that same-typing two generic parameters together lowers correctly.
67+
68+
protocol P1 {}
69+
protocol P2 {}
70+
protocol P3 {}
71+
struct ConformsToP1: P1 {}
72+
struct ConformsToP2: P2 {}
73+
struct ConformsToP3: P3 {}
74+
75+
struct SG11<T: P1, U: P2> {}
76+
77+
struct ConformsToP1AndP2 : P1, P2 { }
78+
79+
extension SG11 where U == T {
80+
struct InnerTEqualsU<V: P3> { }
81+
}
82+
83+
extension SG11 where T == ConformsToP1 {
84+
struct InnerTEqualsConformsToP1<V: P3> { }
85+
}
86+
87+
extension SG11 where U == ConformsToP2 {
88+
struct InnerUEqualsConformsToP2<V: P3> { }
89+
}
90+
91+
func inner1() -> Any.Type {
92+
return SG11<ConformsToP1AndP2, ConformsToP1AndP2>.InnerTEqualsU<ConformsToP3>.self
93+
}
94+
95+
func inner2() -> Any.Type {
96+
return SG11<ConformsToP1, ConformsToP2>.InnerTEqualsConformsToP1<ConformsToP3>.self
97+
}
98+
99+
func inner3() -> Any.Type {
100+
return SG11<ConformsToP1, ConformsToP2>.InnerTEqualsConformsToP1<ConformsToP3>.self
101+
}

0 commit comments

Comments
 (0)