Skip to content

Commit a22b360

Browse files
authored
Merge pull request #16903 from xedin/fix-constrainted-expr-typealias
[CSSolver] Make sure generic requirements are checked for typealiases
2 parents f692b15 + 4ad9b48 commit a22b360

File tree

4 files changed

+104
-18
lines changed

4 files changed

+104
-18
lines changed

include/swift/AST/Types.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,15 +1616,14 @@ class NameAliasType final
16161616
return Bits.NameAliasType.HasSubstitutionMap ? 1 : 0;
16171617
}
16181618

1619+
public:
16191620
/// Retrieve the generic signature used for substitutions.
16201621
GenericSignature *getGenericSignature() const {
16211622
return getSubstitutionMap().getGenericSignature();
16221623
}
16231624

1624-
public:
16251625
static NameAliasType *get(TypeAliasDecl *typealias, Type parent,
1626-
SubstitutionMap substitutions,
1627-
Type underlying);
1626+
SubstitutionMap substitutions, Type underlying);
16281627

16291628
/// \brief Returns the declaration that declares this type.
16301629
TypeAliasDecl *getDecl() const {

lib/Sema/ConstraintSystem.cpp

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,32 @@ Type ConstraintSystem::openUnboundGenericType(
486486
ConstraintLocatorBuilder locator) {
487487
assert(!type->hasTypeParameter());
488488

489+
// If this is a generic typealias defined inside of constrainted extension,
490+
// let's add all of the generic requirements to the constraint system to
491+
// make sure that it's something we can use.
492+
if (auto *NAT = dyn_cast<NameAliasType>(type.getPointer())) {
493+
auto *decl = NAT->getDecl();
494+
auto *extension = dyn_cast<ExtensionDecl>(decl->getDeclContext());
495+
auto parentTy = NAT->getParent();
496+
497+
if (parentTy && extension && extension->isConstrainedExtension()) {
498+
auto subMap = NAT->getSubstitutionMap();
499+
auto contextSubMap = parentTy->getContextSubstitutionMap(
500+
extension->getParentModule(),
501+
extension->getAsNominalTypeOrNominalTypeExtensionContext());
502+
503+
if (auto *signature = NAT->getGenericSignature()) {
504+
openGenericRequirements(
505+
extension, signature, /*skipProtocolSelfConstraint*/ true, locator,
506+
[&](Type type) {
507+
return type.subst(QuerySubstitutionMap{contextSubMap},
508+
LookUpConformanceInSubstitutionMap(subMap),
509+
SubstFlags::UseErrorType);
510+
});
511+
}
512+
}
513+
}
514+
489515
if (!type->hasUnboundGenericType())
490516
return type;
491517

@@ -1133,41 +1159,48 @@ void ConstraintSystem::openGeneric(
11331159
bindArchetypesFromContext(*this, outerDC, locatorPtr, replacements);
11341160

11351161
// Add the requirements as constraints.
1136-
auto requirements = sig->getRequirements();
1162+
openGenericRequirements(
1163+
outerDC, sig, skipProtocolSelfConstraint, locator,
1164+
[&](Type type) { return openType(type, replacements); });
1165+
}
1166+
1167+
void ConstraintSystem::openGenericRequirements(
1168+
DeclContext *outerDC, GenericSignature *signature,
1169+
bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator,
1170+
llvm::function_ref<Type(Type)> substFn) {
1171+
auto requirements = signature->getRequirements();
11371172
for (unsigned pos = 0, n = requirements.size(); pos != n; ++pos) {
11381173
const auto &req = requirements[pos];
11391174

1140-
Optional<Requirement> openedReq;
1141-
auto openedFirst = openType(req.getFirstType(), replacements);
1175+
auto firstType = substFn(req.getFirstType());
11421176

11431177
auto kind = req.getKind();
1178+
auto requirementLoc =
1179+
locator.withPathElement(ConstraintLocator::OpenedGeneric)
1180+
.withPathElement(LocatorPathElt::getTypeRequirementComponent(pos));
1181+
11441182
switch (kind) {
11451183
case RequirementKind::Conformance: {
11461184
auto proto = req.getSecondType()->castTo<ProtocolType>();
11471185
auto protoDecl = proto->getDecl();
11481186
// Determine whether this is the protocol 'Self' constraint we should
11491187
// skip.
1150-
if (skipProtocolSelfConstraint &&
1151-
protoDecl == outerDC &&
1188+
if (skipProtocolSelfConstraint && protoDecl == outerDC &&
11521189
protoDecl->getSelfInterfaceType()->isEqual(req.getFirstType()))
11531190
continue;
1154-
openedReq = Requirement(kind, openedFirst, proto);
1191+
addConstraint(Requirement(kind, firstType, proto), requirementLoc);
11551192
break;
11561193
}
11571194
case RequirementKind::Superclass:
11581195
case RequirementKind::SameType:
1159-
openedReq = Requirement(kind, openedFirst,
1160-
openType(req.getSecondType(), replacements));
1196+
addConstraint(Requirement(kind, firstType, substFn(req.getSecondType())),
1197+
requirementLoc);
11611198
break;
11621199
case RequirementKind::Layout:
1163-
openedReq = Requirement(kind, openedFirst, req.getLayoutConstraint());
1200+
addConstraint(Requirement(kind, firstType, req.getLayoutConstraint()),
1201+
requirementLoc);
11641202
break;
11651203
}
1166-
1167-
addConstraint(
1168-
*openedReq,
1169-
locator.withPathElement(ConstraintLocator::OpenedGeneric)
1170-
.withPathElement(LocatorPathElt::getTypeRequirementComponent(pos)));
11711204
}
11721205
}
11731206

@@ -1246,7 +1279,6 @@ ConstraintSystem::getTypeOfMemberReference(
12461279

12471280
auto memberTy = TC.substMemberTypeWithBase(DC->getParentModule(),
12481281
typeDecl, baseObjTy);
1249-
12501282
// Open the type if it was a reference to a generic type.
12511283
memberTy = openUnboundGenericType(memberTy, locator);
12521284

lib/Sema/ConstraintSystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,15 @@ class ConstraintSystem {
21752175
ConstraintLocatorBuilder locator,
21762176
OpenedTypeMap &replacements);
21772177

2178+
/// Given generic signature open its generic requirements,
2179+
/// using substitution function, and record them in the
2180+
/// constraint system for further processing.
2181+
void openGenericRequirements(DeclContext *outerDC,
2182+
GenericSignature *signature,
2183+
bool skipProtocolSelfConstraint,
2184+
ConstraintLocatorBuilder locator,
2185+
llvm::function_ref<Type(Type)> subst);
2186+
21782187
/// Record the set of opened types for the given locator.
21792188
void recordOpenedTypes(
21802189
ConstraintLocatorBuilder locator,

test/Constraints/rdar39931339.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P {}
4+
5+
struct S<T> {}
6+
7+
class C : P {}
8+
9+
extension S where T : P {
10+
typealias A = Int
11+
typealias B<U> = S<U>
12+
}
13+
14+
extension S where T == Float {
15+
typealias C = Int
16+
}
17+
18+
class A<T, U> {}
19+
20+
extension A where T == [U], U: P {
21+
typealias S1 = Int
22+
}
23+
24+
extension A where T == [U], U == Int {
25+
typealias S2 = Int
26+
}
27+
28+
class B<U> : A<[U], U> {}
29+
30+
_ = B<C>.S1() // Ok
31+
_ = B<Int>.S2() // Ok
32+
_ = B<Float>.S1() // expected-error {{type 'Float' does not conform to protocol 'P'}}
33+
_ = B<String>.S2() // expected-error {{'B<String>.S2.Type' (aka 'Int.Type') requires the types '[String]' and '[Int]' be equivalent}}
34+
35+
_ = S<C>.A() // Ok
36+
_ = S<Int>.A() // expected-error {{type 'Int' does not conform to protocol 'P'}}
37+
_ = S<String>.B<Int>() // expected-error {{type 'String' does not conform to protocol 'P'}}
38+
_ = S<Int>.C() // expected-error {{'S<Int>.C.Type' (aka 'Int.Type') requires the types 'Int' and 'Float' be equivalent}}
39+
40+
func foo<T>(_ s: S<T>.Type) {
41+
_ = s.A() // expected-error {{type 'T' does not conform to protocol 'P'}}
42+
}
43+
44+
func bar<T: P>(_ s: S<T>.Type) {
45+
_ = s.A() // Ok
46+
}

0 commit comments

Comments
 (0)