Skip to content

AST: Exclude noncanonical params from GenericSignature::enumeratePairedRequirements. #15960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,17 +345,30 @@ bool GenericSignature::enumeratePairedRequirements(
auto genericParams = getGenericParams();
unsigned curGenericParamIdx = 0, numGenericParams = genericParams.size();

// Figure out which generic parameters are complete.
SmallVector<bool, 4> genericParamsAreConcrete(genericParams.size(), false);
// Figure out which generic parameters are concrete or same-typed to another
// generic parameter.
auto genericParamsAreNonCanonical =
SmallVector<bool, 4>(genericParams.size(), false);
for (auto req : reqs) {
if (req.getKind() != RequirementKind::SameType) continue;
if (req.getSecondType()->isTypeParameter()) continue;

auto gp = req.getFirstType()->getAs<GenericTypeParamType>();
if (!gp) continue;

GenericTypeParamType *gp;
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
// If two generic parameters are same-typed, then the left-hand one
// is canonical.
gp = secondGP;
} else {
// If an associated type is same-typed, it doesn't constrain the generic
// parameter itself.
if (req.getSecondType()->isTypeParameter()) continue;

// Otherwise, the generic parameter is concrete.
gp = req.getFirstType()->getAs<GenericTypeParamType>();
if (!gp) continue;
}

unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
genericParamsAreConcrete[index] = true;
genericParamsAreNonCanonical[index] = true;
}

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

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

bool GenericSignature::isCanonicalTypeInContext(Type type,
GenericSignatureBuilder &builder) {
GenericSignatureBuilder &builder) {
// If the type isn't independently canonical, it's certainly not canonical
// in this context.
if (!type->isCanonical())
Expand Down Expand Up @@ -835,7 +848,7 @@ bool GenericSignature::isCanonicalTypeInContext(Type type,
}

CanType GenericSignature::getCanonicalTypeInContext(Type type,
GenericSignatureBuilder &builder) {
GenericSignatureBuilder &builder) {
type = type->getCanonicalType();

// All the contextual canonicality rules apply to type parameters, so if the
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ swift::_getTypeByMangledName(StringRef typeName,
// Call the associated type access function.
// TODO: can we just request abstract metadata? If so, do we have
// a responsibility to try to finish it later?
return ((const AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
return ((AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
(MetadataState::Complete, base, witnessTable).Value;
});

Expand Down
37 changes: 37 additions & 0 deletions test/IRGen/same_type_constraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,40 @@ where Self : CodingType,

// 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]+]] {
// OSIZE: [[ATTRS]] = {{{.*}}noinline

// Check that same-typing two generic parameters together lowers correctly.

protocol P1 {}
protocol P2 {}
protocol P3 {}
struct ConformsToP1: P1 {}
struct ConformsToP2: P2 {}
struct ConformsToP3: P3 {}

struct SG11<T: P1, U: P2> {}

struct ConformsToP1AndP2 : P1, P2 { }

extension SG11 where U == T {
struct InnerTEqualsU<V: P3> { }
}

extension SG11 where T == ConformsToP1 {
struct InnerTEqualsConformsToP1<V: P3> { }
}

extension SG11 where U == ConformsToP2 {
struct InnerUEqualsConformsToP2<V: P3> { }
}

func inner1() -> Any.Type {
return SG11<ConformsToP1AndP2, ConformsToP1AndP2>.InnerTEqualsU<ConformsToP3>.self
}

func inner2() -> Any.Type {
return SG11<ConformsToP1, ConformsToP2>.InnerTEqualsConformsToP1<ConformsToP3>.self
}

func inner3() -> Any.Type {
return SG11<ConformsToP1, ConformsToP2>.InnerTEqualsConformsToP1<ConformsToP3>.self
}