Skip to content

Commit eeb5c95

Browse files
committed
Sema: Ban protocol where clauses that place constraints on 'Self'
These will never work properly because of phase ordering issues with the current declaration checker design. Since we can always express the same thing with the protocol inheritance clause instead, just diagnose this as an error instead of trying to hack around it. Fixes <rdar://problem/38077232>, <https://bugs.swift.org/browse/SR-5581>.
1 parent e3ff63a commit eeb5c95

File tree

7 files changed

+55
-6
lines changed

7 files changed

+55
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,10 @@ WARNING(protocol_composition_with_postfix,none,
18331833
"protocol-constrained type with postfix '%0' is ambiguous "
18341834
"and will be rejected in future version of Swift", (StringRef))
18351835

1836+
ERROR(protocol_where_clause_self_requirement,none,
1837+
"constraint with subject type of 'Self' is not supported; "
1838+
"consider adding requirement to protocol inheritance clause instead", ())
1839+
18361840
ERROR(invalid_protocol_composition_member,none,
18371841
"non-protocol, non-class type %0 cannot be used within a "
18381842
"protocol-constrained type", (Type))

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ void TypeChecker::validateWhereClauses(ProtocolDecl *protocol,
214214
GenericTypeResolver *resolver) {
215215
TypeResolutionOptions options;
216216

217+
options |= TypeResolutionFlags::ProtocolWhereClause;
218+
217219
if (auto whereClause = protocol->getTrailingWhereClause()) {
218220
revertGenericRequirements(whereClause->getRequirements());
219221
validateRequirements(whereClause->getWhereLoc(),

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,31 @@ bool TypeChecker::validateRequirement(SourceLoc whereLoc, RequirementRepr &req,
310310
// Note that we are resolving within a requirement.
311311
options |= TypeResolutionFlags::GenericRequirement;
312312

313+
// Protocol where clauses cannot add conformance and superclass constraints
314+
// to 'Self', because we need to be able to resolve inherited protocols and
315+
// protocol superclasses before computing the protocol requirement signature.
316+
if (options & TypeResolutionFlags::ProtocolWhereClause) {
317+
if (req.getKind() == RequirementReprKind::TypeConstraint ||
318+
req.getKind() == RequirementReprKind::LayoutConstraint) {
319+
if (auto *subjectTyR = req.getSubjectLoc().getTypeRepr()) {
320+
if (auto *componentTyR = dyn_cast<ComponentIdentTypeRepr>(subjectTyR)) {
321+
if (componentTyR->getIdentifier() == Context.Id_Self) {
322+
diagnose(req.getSubjectLoc().getLoc(),
323+
diag::protocol_where_clause_self_requirement);
324+
325+
req.getSubjectLoc().setType(ErrorType::get(Context));
326+
327+
if (req.getKind() == RequirementReprKind::TypeConstraint)
328+
req.getConstraintLoc().setType(ErrorType::get(Context));
329+
330+
req.setInvalid();
331+
return true;
332+
}
333+
}
334+
}
335+
}
336+
}
337+
313338
switch (req.getKind()) {
314339
case RequirementReprKind::TypeConstraint: {
315340
// Validate the types.

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,9 @@ enum class TypeResolutionFlags : unsigned {
552552

553553
/// Whether we are in a requirement of a generic declaration
554554
GenericRequirement = 1 << 26,
555+
556+
/// Whether we are in a protocol's where clause
557+
ProtocolWhereClause = 1 << 27,
555558
};
556559

557560
/// Option set describing how type resolution should work.

test/IDE/print_ast_tc_decls.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,11 +1352,11 @@ extension ProtocolToExtend where Self.Assoc == Int {}
13521352

13531353
// Protocol with where clauses
13541354

1355-
protocol ProtocolWithWhereClause : QuxProtocol where Qux == Int, Self : FooProtocol {}
1356-
// PREFER_TYPE_REPR_PRINTING: protocol ProtocolWithWhereClause : FooProtocol, QuxProtocol where Self.Qux == Int {
1355+
protocol ProtocolWithWhereClause : QuxProtocol where Qux == Int {}
1356+
// PREFER_TYPE_REPR_PRINTING: protocol ProtocolWithWhereClause : QuxProtocol where Self.Qux == Int {
13571357

1358-
protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Qux == Int, Self : FooProtocol {
1359-
// PREFER_TYPE_REPR_PRINTING-DAG: protocol ProtocolWithWhereClauseAndAssoc : FooProtocol, QuxProtocol where Self.Qux == Int {
1358+
protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Qux == Int {
1359+
// PREFER_TYPE_REPR_PRINTING-DAG: protocol ProtocolWithWhereClauseAndAssoc : QuxProtocol where Self.Qux == Int {
13601360
associatedtype A1 : QuxProtocol where A1 : FooProtocol, A1.Qux : QuxProtocol, Int == A1.Qux.Qux
13611361
// PREFER_TYPE_REPR_PRINTING-DAG: {{^}} associatedtype A1 : FooProtocol, QuxProtocol where Self.A1.Qux : QuxProtocol, Self.A1.Qux.Qux == Int{{$}}
13621362

test/Index/roles.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,12 @@ protocol AProtocol {
262262
// CHECK-NEXT: RelChild | protocol/Swift | AProtocol | s:14swift_ide_test9AProtocolP
263263
}
264264

265-
protocol Q where Self: AProtocol {}
266-
// CHECK: [[@LINE-1]]:24 | protocol/Swift | AProtocol | [[AProtocol_USR]] | Ref | rel: 0
265+
protocol QBase {
266+
associatedtype A
267+
}
268+
269+
protocol Q : QBase where Self.A: AProtocol {}
270+
// CHECK: [[@LINE-1]]:34 | protocol/Swift | AProtocol | [[AProtocol_USR]] | Ref | rel: 0
267271

268272
class ASubClass : AClass, AProtocol {
269273
// CHECK: [[@LINE-1]]:7 | class/Swift | ASubClass | s:14swift_ide_test9ASubClassC | Def | rel: 0

test/decl/protocol/req/where_clause.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,14 @@ protocol P3 : P2 {
1616
}
1717

1818
func foo<S>(_: S) where S.SubSequence.Element == C1, S : P3 {}
19+
20+
// Invalid where clauses
21+
protocol InvalidWhereClause1 where Self: AnyObject {}
22+
// expected-error@-1 {{constraint with subject type of 'Self' is not supported; consider adding requirement to protocol inheritance clause instead}}
23+
24+
class AlsoBad {}
25+
26+
protocol InvalidWhereClause2 {
27+
associatedtype T where Self: AlsoBad
28+
// expected-error@-1 {{constraint with subject type of 'Self' is not supported; consider adding requirement to protocol inheritance clause instead}}
29+
}

0 commit comments

Comments
 (0)