Skip to content

Commit 454e5cf

Browse files
authored
Merge pull request #72825 from slavapestov/two-minor-fixes-and-tests
RequirementMachine: Fix two minor crash on invalid bugs
2 parents 4677d14 + ae73cd4 commit 454e5cf

File tree

6 files changed

+140
-47
lines changed

6 files changed

+140
-47
lines changed

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -971,30 +971,28 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
971971
// DependentMemberType X, and the right hand side is the
972972
// underlying type of the typealias.
973973
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(decl)) {
974-
if (!typeAliasDecl->isGeneric()) {
975-
// Ignore the typealias if we have an associated type with the same name
976-
// in the same protocol. This is invalid anyway, but it's just here to
977-
// ensure that we produce the same requirement signature on some tests
978-
// with -requirement-machine-protocol-signatures=verify.
979-
if (assocTypes.contains(typeAliasDecl->getName()))
980-
continue;
974+
if (typeAliasDecl->isGeneric())
975+
continue;
981976

982-
// The structural type of a typealias will always be a TypeAliasType,
983-
// so unwrap it to avoid a requirement that prints as 'Self.T == Self.T'
984-
// in diagnostics.
985-
auto underlyingType = typeAliasDecl->getStructuralType();
986-
if (auto *aliasType = dyn_cast<TypeAliasType>(underlyingType.getPointer()))
987-
underlyingType = aliasType->getSinglyDesugaredType();
977+
// Ignore the typealias if we have an associated type with the same name
978+
// in the same protocol. This is invalid anyway, but it's just here to
979+
// ensure that we produce the same requirement signature on some tests
980+
// with -requirement-machine-protocol-signatures=verify.
981+
if (assocTypes.contains(typeAliasDecl->getName()))
982+
continue;
988983

989-
if (underlyingType->is<UnboundGenericType>())
990-
continue;
984+
// The structural type of a typealias will always be a TypeAliasType,
985+
// so unwrap it to avoid a requirement that prints as 'Self.T == Self.T'
986+
// in diagnostics.
987+
auto underlyingType = typeAliasDecl->getStructuralType();
988+
if (underlyingType->is<UnboundGenericType>())
989+
continue;
991990

992-
auto subjectType = DependentMemberType::get(
993-
selfTy, typeAliasDecl->getName());
994-
Requirement req(RequirementKind::SameType, subjectType,
995-
underlyingType);
996-
result.push_back({req, typeAliasDecl->getLoc()});
997-
}
991+
auto subjectType = DependentMemberType::get(
992+
selfTy, typeAliasDecl->getName());
993+
Requirement req(RequirementKind::SameType, subjectType,
994+
underlyingType);
995+
result.push_back({req, typeAliasDecl->getLoc()});
998996
}
999997
}
1000998

@@ -1053,21 +1051,28 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
10531051
return typeDecl->getDeclaredInterfaceType();
10541052
};
10551053

1054+
auto isSuitableType = [&](TypeDecl *req) -> bool {
1055+
// Ignore generic types.
1056+
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
1057+
if (genReq->isGeneric())
1058+
return false;
1059+
1060+
// Ignore typealiases with UnboundGenericType, since they
1061+
// are like generic typealiases.
1062+
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(req))
1063+
if (getStructuralType(typeAlias)->is<UnboundGenericType>())
1064+
return false;
1065+
1066+
return true;
1067+
};
1068+
10561069
// Collect all typealiases from inherited protocols recursively.
10571070
llvm::MapVector<Identifier, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
10581071
for (auto *inheritedProto : ctx.getRewriteContext().getInheritedProtocols(proto)) {
10591072
for (auto req : inheritedProto->getMembers()) {
10601073
if (auto *typeReq = dyn_cast<TypeDecl>(req)) {
1061-
// Ignore generic types.
1062-
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
1063-
if (genReq->getGenericParams())
1064-
continue;
1065-
1066-
// Ignore typealiases with UnboundGenericType, since they
1067-
// are like generic typealiases.
1068-
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(req))
1069-
if (getStructuralType(typeAlias)->is<UnboundGenericType>())
1070-
continue;
1074+
if (!isSuitableType(typeReq))
1075+
continue;
10711076

10721077
inheritedTypeDecls[typeReq->getName()].push_back(typeReq);
10731078
}
@@ -1077,10 +1082,13 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
10771082
// An inferred same-type requirement between the two type declarations
10781083
// within this protocol or a protocol it inherits.
10791084
auto recordInheritedTypeRequirement = [&](TypeDecl *first, TypeDecl *second) {
1080-
desugarRequirement(Requirement(RequirementKind::SameType,
1081-
getStructuralType(first),
1082-
getStructuralType(second)),
1083-
SourceLoc(), result, ignoredInverses, errors);
1085+
auto firstType = getStructuralType(first);
1086+
auto secondType = getStructuralType(second);
1087+
assert(!firstType->is<UnboundGenericType>());
1088+
assert(!secondType->is<UnboundGenericType>());
1089+
1090+
desugarRequirement(Requirement(RequirementKind::SameType, firstType, secondType),
1091+
SourceLoc(), result, ignoredInverses, errors);
10841092
};
10851093

10861094
// Local function to find the insertion point for the protocol's "where"
@@ -1206,25 +1214,31 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
12061214
const auto name = inherited.first;
12071215
for (auto found : proto->lookupDirect(name)) {
12081216
// We only want concrete type declarations.
1209-
auto type = dyn_cast<TypeDecl>(found);
1210-
if (!type || isa<AssociatedTypeDecl>(type)) continue;
1217+
auto typeReq = dyn_cast<TypeDecl>(found);
1218+
if (!typeReq || isa<AssociatedTypeDecl>(typeReq)) continue;
12111219

12121220
// Ignore nominal types. They're always invalid declarations.
1213-
if (isa<NominalTypeDecl>(type))
1221+
if (isa<NominalTypeDecl>(typeReq))
1222+
continue;
1223+
1224+
// Ignore generic type aliases.
1225+
if (!isSuitableType(typeReq))
12141226
continue;
12151227

12161228
// ... from the same module as the protocol.
1217-
if (type->getModuleContext() != proto->getModuleContext()) continue;
1229+
if (typeReq->getModuleContext() != proto->getModuleContext()) continue;
12181230

12191231
// Ignore types defined in constrained extensions; their equivalence
12201232
// to the associated type would have to be conditional, which we cannot
12211233
// model.
1222-
if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
1234+
if (auto ext = dyn_cast<ExtensionDecl>(typeReq->getDeclContext())) {
12231235
// FIXME: isConstrainedExtension() can cause request cycles because it
12241236
// computes a generic signature. getTrailingWhereClause() should be good
12251237
// enough for protocol extensions, which cannot specify constraints in
12261238
// any other way right now (eg, via requirement inference or by
12271239
// extending a bound generic type).
1240+
//
1241+
// FIXME: Protocol extensions with noncopyable generics can!
12281242
if (ext->getTrailingWhereClause()) continue;
12291243
}
12301244

@@ -1237,19 +1251,19 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
12371251
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
12381252
// Infer a same-type requirement between the typealias' underlying
12391253
// type and the inherited associated type.
1240-
recordInheritedTypeRequirement(inheritedAssocTypeDecl, type);
1254+
recordInheritedTypeRequirement(inheritedAssocTypeDecl, typeReq);
12411255

12421256
// Warn that one should use where clauses for this.
12431257
if (shouldWarnAboutRedeclaration) {
12441258
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
12451259
auto fixItWhere = getProtocolWhereLoc();
1246-
ctx.Diags.diagnose(type,
1260+
ctx.Diags.diagnose(typeReq,
12471261
diag::typealias_override_associated_type,
12481262
name,
12491263
inheritedFromProto->getDeclaredInterfaceType())
12501264
.fixItInsertAfter(fixItWhere.Loc,
1251-
getConcreteTypeReq(type, fixItWhere.Item))
1252-
.fixItRemove(type->getSourceRange());
1265+
getConcreteTypeReq(typeReq, fixItWhere.Item))
1266+
.fixItRemove(typeReq->getSourceRange());
12531267
ctx.Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
12541268
inheritedAssocTypeDecl);
12551269

@@ -1260,7 +1274,7 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
12601274
}
12611275

12621276
// Two typealiases that should be the same.
1263-
recordInheritedTypeRequirement(inheritedType, type);
1277+
recordInheritedTypeRequirement(inheritedType, typeReq);
12641278
}
12651279

12661280
// We can remove this entry.

lib/AST/RequirementMachine/TypeDifference.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,16 +332,18 @@ swift::rewriting::buildTypeDifference(
332332
return nextSubstitution(substitution);
333333
}
334334

335-
assert(!t->is<DependentMemberType>());
335+
// DependentMemberType with ErrorType base is OK.
336+
assert(!t->isTypeParameter());
336337
return std::nullopt;
337338
});
338339
}
339340
}
340341

341-
assert(!t->is<DependentMemberType>());
342342
return nextSubstitution(substitutions[index]);
343343
}
344344

345+
// DependentMemberType with ErrorType base is OK.
346+
assert(!t->isTypeParameter());
345347
return std::nullopt;
346348
});
347349

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+
}

test/Generics/rdar94848868.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// This is too circular to work, but it shouldn't crash.
4+
5+
protocol MyCollectionProtocol: Collection where Iterator == MyCollectionIterator<Self> {}
6+
// expected-error@-1 {{circular reference}}
7+
8+
struct MyCollectionIterator<MyCollection: MyCollectionProtocol>: IteratorProtocol {
9+
// expected-note@-1 3{{through reference here}}
10+
mutating func next() -> MyCollection.Element? {
11+
// expected-note@-1 2{{through reference here}}
12+
return nil
13+
}
14+
}
15+
16+
struct MyCollection: MyCollectionProtocol {
17+
struct Element {}
18+
19+
var startIndex: Int { fatalError() }
20+
var endIndex: Int { fatalError() }
21+
22+
func index(after i: Int) -> Int { fatalError() }
23+
subscript(position: Int) -> Element { fatalError() }
24+
25+
public func makeIterator() -> MyCollectionIterator<Self> { fatalError() }
26+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: not %target-swift-frontend -emit-ir %s
2+
3+
protocol P1 {}
4+
protocol Q1 {
5+
associatedtype A
6+
associatedtype B
7+
}
8+
9+
protocol Q2: Q1 where B == S<Self>, B.C == Self {}
10+
11+
protocol P2: P1 {
12+
associatedtype C: Q2 where C.A == Void
13+
}
14+
15+
struct S<C: Q2>: P2 {
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: not %target-swift-frontend -typecheck %s
2+
3+
protocol Box<Content> {
4+
associatedtype Content
5+
var value: Content {get set}
6+
}
7+
extension Box where Self == _Box {
8+
init(_ v: Content) {
9+
self.init(value: v)
10+
}
11+
}
12+
13+
struct _Box<Content> {
14+
var value: Content
15+
init(value: Content) {
16+
self.value = value
17+
}
18+
}

0 commit comments

Comments
 (0)