Skip to content

Commit 61dbaf8

Browse files
committed
RequirementMachine: Fix crash with protocol typealias having unbound generic type
Make sure we don't try to introduce an implicit same-type requirement in this case. Fixes rdar://problem/63731199.
1 parent 31114f2 commit 61dbaf8

File tree

2 files changed

+76
-45
lines changed

2 files changed

+76
-45
lines changed

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -955,30 +955,28 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
955955
// DependentMemberType X, and the right hand side is the
956956
// underlying type of the typealias.
957957
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(decl)) {
958-
if (!typeAliasDecl->isGeneric()) {
959-
// Ignore the typealias if we have an associated type with the same name
960-
// in the same protocol. This is invalid anyway, but it's just here to
961-
// ensure that we produce the same requirement signature on some tests
962-
// with -requirement-machine-protocol-signatures=verify.
963-
if (assocTypes.contains(typeAliasDecl->getName()))
964-
continue;
958+
if (typeAliasDecl->isGeneric())
959+
continue;
965960

966-
// The structural type of a typealias will always be a TypeAliasType,
967-
// so unwrap it to avoid a requirement that prints as 'Self.T == Self.T'
968-
// in diagnostics.
969-
auto underlyingType = typeAliasDecl->getStructuralType();
970-
if (auto *aliasType = dyn_cast<TypeAliasType>(underlyingType.getPointer()))
971-
underlyingType = aliasType->getSinglyDesugaredType();
961+
// Ignore the typealias if we have an associated type with the same name
962+
// in the same protocol. This is invalid anyway, but it's just here to
963+
// ensure that we produce the same requirement signature on some tests
964+
// with -requirement-machine-protocol-signatures=verify.
965+
if (assocTypes.contains(typeAliasDecl->getName()))
966+
continue;
972967

973-
if (underlyingType->is<UnboundGenericType>())
974-
continue;
968+
// The structural type of a typealias will always be a TypeAliasType,
969+
// so unwrap it to avoid a requirement that prints as 'Self.T == Self.T'
970+
// in diagnostics.
971+
auto underlyingType = typeAliasDecl->getStructuralType();
972+
if (underlyingType->is<UnboundGenericType>())
973+
continue;
975974

976-
auto subjectType = DependentMemberType::get(
977-
selfTy, typeAliasDecl->getName());
978-
Requirement req(RequirementKind::SameType, subjectType,
979-
underlyingType);
980-
result.push_back({req, typeAliasDecl->getLoc()});
981-
}
975+
auto subjectType = DependentMemberType::get(
976+
selfTy, typeAliasDecl->getName());
977+
Requirement req(RequirementKind::SameType, subjectType,
978+
underlyingType);
979+
result.push_back({req, typeAliasDecl->getLoc()});
982980
}
983981
}
984982

@@ -1037,21 +1035,28 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
10371035
return typeDecl->getDeclaredInterfaceType();
10381036
};
10391037

1038+
auto isSuitableType = [&](TypeDecl *req) -> bool {
1039+
// Ignore generic types.
1040+
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
1041+
if (genReq->isGeneric())
1042+
return false;
1043+
1044+
// Ignore typealiases with UnboundGenericType, since they
1045+
// are like generic typealiases.
1046+
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(req))
1047+
if (getStructuralType(typeAlias)->is<UnboundGenericType>())
1048+
return false;
1049+
1050+
return true;
1051+
};
1052+
10401053
// Collect all typealiases from inherited protocols recursively.
10411054
llvm::MapVector<Identifier, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
10421055
for (auto *inheritedProto : ctx.getRewriteContext().getInheritedProtocols(proto)) {
10431056
for (auto req : inheritedProto->getMembers()) {
10441057
if (auto *typeReq = dyn_cast<TypeDecl>(req)) {
1045-
// Ignore generic types.
1046-
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
1047-
if (genReq->getGenericParams())
1048-
continue;
1049-
1050-
// Ignore typealiases with UnboundGenericType, since they
1051-
// are like generic typealiases.
1052-
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(req))
1053-
if (getStructuralType(typeAlias)->is<UnboundGenericType>())
1054-
continue;
1058+
if (!isSuitableType(typeReq))
1059+
continue;
10551060

10561061
inheritedTypeDecls[typeReq->getName()].push_back(typeReq);
10571062
}
@@ -1061,10 +1066,13 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
10611066
// An inferred same-type requirement between the two type declarations
10621067
// within this protocol or a protocol it inherits.
10631068
auto recordInheritedTypeRequirement = [&](TypeDecl *first, TypeDecl *second) {
1064-
desugarRequirement(Requirement(RequirementKind::SameType,
1065-
getStructuralType(first),
1066-
getStructuralType(second)),
1067-
SourceLoc(), result, ignoredInverses, errors);
1069+
auto firstType = getStructuralType(first);
1070+
auto secondType = getStructuralType(second);
1071+
assert(!firstType->is<UnboundGenericType>());
1072+
assert(!secondType->is<UnboundGenericType>());
1073+
1074+
desugarRequirement(Requirement(RequirementKind::SameType, firstType, secondType),
1075+
SourceLoc(), result, ignoredInverses, errors);
10681076
};
10691077

10701078
// Local function to find the insertion point for the protocol's "where"
@@ -1190,25 +1198,31 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
11901198
const auto name = inherited.first;
11911199
for (auto found : proto->lookupDirect(name)) {
11921200
// We only want concrete type declarations.
1193-
auto type = dyn_cast<TypeDecl>(found);
1194-
if (!type || isa<AssociatedTypeDecl>(type)) continue;
1201+
auto typeReq = dyn_cast<TypeDecl>(found);
1202+
if (!typeReq || isa<AssociatedTypeDecl>(typeReq)) continue;
11951203

11961204
// Ignore nominal types. They're always invalid declarations.
1197-
if (isa<NominalTypeDecl>(type))
1205+
if (isa<NominalTypeDecl>(typeReq))
1206+
continue;
1207+
1208+
// Ignore generic type aliases.
1209+
if (!isSuitableType(typeReq))
11981210
continue;
11991211

12001212
// ... from the same module as the protocol.
1201-
if (type->getModuleContext() != proto->getModuleContext()) continue;
1213+
if (typeReq->getModuleContext() != proto->getModuleContext()) continue;
12021214

12031215
// Ignore types defined in constrained extensions; their equivalence
12041216
// to the associated type would have to be conditional, which we cannot
12051217
// model.
1206-
if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
1218+
if (auto ext = dyn_cast<ExtensionDecl>(typeReq->getDeclContext())) {
12071219
// FIXME: isConstrainedExtension() can cause request cycles because it
12081220
// computes a generic signature. getTrailingWhereClause() should be good
12091221
// enough for protocol extensions, which cannot specify constraints in
12101222
// any other way right now (eg, via requirement inference or by
12111223
// extending a bound generic type).
1224+
//
1225+
// FIXME: Protocol extensions with noncopyable generics can!
12121226
if (ext->getTrailingWhereClause()) continue;
12131227
}
12141228

@@ -1221,19 +1235,19 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
12211235
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
12221236
// Infer a same-type requirement between the typealias' underlying
12231237
// type and the inherited associated type.
1224-
recordInheritedTypeRequirement(inheritedAssocTypeDecl, type);
1238+
recordInheritedTypeRequirement(inheritedAssocTypeDecl, typeReq);
12251239

12261240
// Warn that one should use where clauses for this.
12271241
if (shouldWarnAboutRedeclaration) {
12281242
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
12291243
auto fixItWhere = getProtocolWhereLoc();
1230-
ctx.Diags.diagnose(type,
1244+
ctx.Diags.diagnose(typeReq,
12311245
diag::typealias_override_associated_type,
12321246
name,
12331247
inheritedFromProto->getDeclaredInterfaceType())
12341248
.fixItInsertAfter(fixItWhere.Loc,
1235-
getConcreteTypeReq(type, fixItWhere.Item))
1236-
.fixItRemove(type->getSourceRange());
1249+
getConcreteTypeReq(typeReq, fixItWhere.Item))
1250+
.fixItRemove(typeReq->getSourceRange());
12371251
ctx.Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
12381252
inheritedAssocTypeDecl);
12391253

@@ -1244,7 +1258,7 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
12441258
}
12451259

12461260
// Two typealiases that should be the same.
1247-
recordInheritedTypeRequirement(inheritedType, type);
1261+
recordInheritedTypeRequirement(inheritedType, typeReq);
12481262
}
12491263

12501264
// We can remove this entry.

test/Generics/rdar63731199.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol PerturberProtocol {
4+
associatedtype CP: Perturbation
5+
}
6+
7+
protocol Perturbation {
8+
associatedtype Perturber: PerturberProtocol where Self == Perturber.CP
9+
}
10+
11+
protocol IDCMemberFunctionAddition: Perturbation {
12+
// This type alias should not cause a crash.
13+
typealias Perturber = MemberAdder
14+
}
15+
16+
class MemberAdder<CP: IDCMemberFunctionAddition>: PerturberProtocol {
17+
}

0 commit comments

Comments
 (0)