Skip to content

Commit ff7cf59

Browse files
authored
Merge pull request swiftlang#36051 from DougGregor/marker-protocols-cleanup
2 parents e4ac7ae + 66cd7d8 commit ff7cf59

File tree

6 files changed

+42
-27
lines changed

6 files changed

+42
-27
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5622,8 +5622,8 @@ ERROR(marker_protocol_requirement, none,
56225622
ERROR(marker_protocol_inherit_nonmarker, none,
56235623
"marker protocol %0 cannot inherit non-marker protocol %1",
56245624
(DeclName, DeclName))
5625-
ERROR(marker_protocol_value,none,
5626-
"marker protocol %0 can only be used in generic constraints", (DeclName))
5625+
ERROR(marker_protocol_cast,none,
5626+
"marker protocol %0 cannot be used in a conditional cast", (DeclName))
56275627

56285628
//------------------------------------------------------------------------------
56295629
// MARK: differentiable programming diagnostics

lib/AST/Module.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,8 +918,8 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
918918

919919
// Due to an IRGen limitation, witness tables cannot be passed from an
920920
// existential to an archetype parameter, so for now we restrict this to
921-
// @objc protocols.
922-
if (!layout.isObjC()) {
921+
// @objc protocols and marker protocols.
922+
if (!layout.isObjC() && !protocol->isMarkerProtocol()) {
923923
// There's a specific exception for protocols with self-conforming
924924
// witness tables, but the existential has to be *exactly* that type.
925925
// TODO: synthesize witness tables on-demand for protocol compositions

lib/Sema/MiscDiagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "TypeCheckConcurrency.h"
2020
#include "TypeChecker.h"
2121
#include "swift/AST/ASTWalker.h"
22+
#include "swift/AST/ExistentialLayout.h"
2223
#include "swift/AST/NameLookup.h"
2324
#include "swift/AST/NameLookupRequests.h"
2425
#include "swift/AST/Pattern.h"
@@ -65,6 +66,7 @@ static Expr *isImplicitPromotionToOptional(Expr *E) {
6566
/// - Warn about promotions to optional in specific syntactic forms.
6667
/// - Error about collection literals that default to Any collections in
6768
/// invalid positions.
69+
/// - Marker protocols cannot occur as the type of an as? or is expression.
6870
///
6971
static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
7072
bool isExprStmt) {
@@ -311,9 +313,31 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
311313
}
312314
}
313315

316+
// Diagnose checked casts that involve marker protocols.
317+
if (auto cast = dyn_cast<CheckedCastExpr>(E)) {
318+
checkCheckedCastExpr(cast);
319+
}
320+
314321
return { true, E };
315322
}
316323

324+
void checkCheckedCastExpr(CheckedCastExpr *cast) {
325+
if (!isa<ConditionalCheckedCastExpr>(cast) && !isa<IsExpr>(cast))
326+
return;
327+
328+
Type castType = cast->getCastType();
329+
if (!castType || !castType->isExistentialType())
330+
return;
331+
332+
auto layout = castType->getExistentialLayout();
333+
for (auto proto : layout.getProtocols()) {
334+
if (proto->getDecl()->isMarkerProtocol()) {
335+
Ctx.Diags.diagnose(cast->getLoc(), diag::marker_protocol_cast,
336+
proto->getDecl()->getName());
337+
}
338+
}
339+
}
340+
317341
/// Visit the argument/s represented by either a ParenExpr or TupleExpr,
318342
/// unshuffling if needed. If any other kind of expression, will pass it
319343
/// straight back.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,12 @@ ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator,
643643
bool
644644
ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator,
645645
ProtocolDecl *decl) const {
646-
// If it's not @objc, it conforms to itself only if it has a self-conformance
647-
// witness table.
646+
// Marker protocols always self-conform.
647+
if (decl->isMarkerProtocol())
648+
return true;
649+
650+
// Otherwise, if it's not @objc, it conforms to itself only if it has a
651+
// self-conformance witness table.
648652
if (!decl->isObjC())
649653
return decl->requiresSelfConformanceWitnessTable();
650654

lib/Sema/TypeCheckType.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3906,12 +3906,6 @@ class UnsupportedProtocolVisitor
39063906
proto->getName());
39073907
T->setInvalid();
39083908
}
3909-
if (proto->isMarkerProtocol()) {
3910-
Ctx.Diags.diagnose(comp->getNameLoc(),
3911-
diag::marker_protocol_value,
3912-
proto->getName());
3913-
T->setInvalid();
3914-
}
39153909
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
39163910
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
39173911
type.findIf([&](Type type) -> bool {
@@ -3921,15 +3915,6 @@ class UnsupportedProtocolVisitor
39213915
auto layout = type->getExistentialLayout();
39223916
for (auto *proto : layout.getProtocols()) {
39233917
auto *protoDecl = proto->getDecl();
3924-
3925-
if (protoDecl->isMarkerProtocol()) {
3926-
Ctx.Diags.diagnose(comp->getNameLoc(),
3927-
diag::marker_protocol_value,
3928-
protoDecl->getName());
3929-
T->setInvalid();
3930-
continue;
3931-
}
3932-
39333918
if (protoDecl->existentialTypeSupported())
39343919
continue;
39353920

test/attr/attr_marker_protocol.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,24 @@ protocol P6: P3 { } // okay
3030

3131
func genericOk<T: P3>(_: T) { }
3232

33-
func testGenericOk(i: Int, arr: [Int], nope: [Double]) {
33+
func testGenericOk(i: Int, arr: [Int], nope: [Double], p3: P3, p3array: [P3]) {
3434
genericOk(i)
3535
genericOk(arr)
3636
genericOk(nope) // expected-error{{global function 'genericOk' requires that 'Double' conform to 'P3'}}
37+
genericOk(p3)
38+
genericOk(p3array)
3739
}
3840

3941
// Incorrect uses of marker protocols in types.
4042
func testNotOkay(a: Any) {
41-
var mp1: P3 = 17 // expected-error{{marker protocol 'P3' can only be used in generic constraints}}
43+
var mp1: P3 = 17
4244
_ = mp1
4345
mp1 = 17
4446

45-
if let mp2 = a as? P3 { _ = mp2 } // expected-error{{marker protocol 'P3' can only be used in generic constraints}}
46-
if let mp3 = a as? AnyObject & P3 { _ = mp3 } // expected-error{{marker protocol 'P3' can only be used in generic constraints}}
47-
if a is AnyObject & P3 { } // expected-error{{marker protocol 'P3' can only be used in generic constraints}}
47+
if let mp2 = a as? P3 { _ = mp2 } // expected-error{{marker protocol 'P3' cannot be used in a conditional cast}}
48+
if let mp3 = a as? AnyObject & P3 { _ = mp3 } // expected-error{{marker protocol 'P3' cannot be used in a conditional cast}}
49+
if a is AnyObject & P3 { } // expected-error{{marker protocol 'P3' cannot be used in a conditional cast}}
4850

49-
func inner(p3: P3) { } // expected-error{{marker protocol 'P3' can only be used in generic constraints}}
51+
func inner(p3: P3) { }
5052
}
5153

0 commit comments

Comments
 (0)