Skip to content

Commit 0dd20fd

Browse files
authored
Merge pull request swiftlang#73204 from slavapestov/member-operator-check
Sema: Ban uncallable protocol member operators
2 parents f0af3ca + feea84d commit 0dd20fd

File tree

5 files changed

+54
-47
lines changed

5 files changed

+54
-47
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,48 +2034,59 @@ FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
20342034
return op.get();
20352035
}
20362036

2037-
bool swift::isMemberOperator(FuncDecl *decl, Type type) {
2037+
/// This means two things:
2038+
/// - If selfTy is null, 'decl' is assumed to be a member of a nominal type
2039+
/// or extension. We check if its a valid member operator.
2040+
/// - Otherwise, 'decl' is a member or top-level operator. We check if it
2041+
/// is a suitable witness for the given conforming type.
2042+
bool swift::isMemberOperator(FuncDecl *decl, Type selfTy) {
20382043
// Check that member operators reference the type of 'Self'.
20392044
if (decl->isInvalid())
20402045
return true;
20412046

20422047
auto *DC = decl->getDeclContext();
20432048

20442049
auto selfNominal = DC->getSelfNominalTypeDecl();
2050+
assert(selfNominal || selfTy);
20452051

2046-
// Check the parameters for a reference to 'Self'.
2052+
// Is the operator a member of a protocol or protocol extension?
20472053
bool isProtocol = isa_and_nonnull<ProtocolDecl>(selfNominal);
2054+
2055+
// Is the operator a member of a tuple extension?
20482056
bool isTuple = isa_and_nonnull<BuiltinTupleDecl>(selfNominal);
20492057

2058+
// Check the parameters for a reference to 'Self'.
20502059
for (auto param : *decl->getParameters()) {
20512060
// Look through a metatype reference, if there is one.
20522061
auto paramType = param->getInterfaceType()->getMetatypeInstanceType();
20532062

2063+
if (isProtocol || isTuple) {
2064+
// For a member of a protocol or tuple extension, is it the 'Self'
2065+
// type parameter?
2066+
if (paramType->isEqual(DC->getSelfInterfaceType()))
2067+
return true;
2068+
2069+
continue;
2070+
}
2071+
2072+
// We have a member operator of a concrete nominal type, or a global operator.
20542073
auto nominal = paramType->getAnyNominal();
2055-
if (type.isNull()) {
2056-
// Is it the same nominal type?
2057-
if (selfNominal && nominal == selfNominal)
2074+
2075+
if (selfTy.isNull()) {
2076+
// We're validating a member operator.
2077+
2078+
// Does the parameter have the right nominal type?
2079+
if (nominal == selfNominal)
20582080
return true;
20592081
} else {
2060-
// Is it the same nominal type? Or a generic (which may or may not match)?
2061-
if (paramType->is<GenericTypeParamType>() ||
2062-
nominal == type->getAnyNominal())
2063-
return true;
2064-
}
2082+
// We're checking a conformance and this operator is a candidate witness.
20652083

2066-
if (isProtocol) {
2067-
// FIXME: Source compatibility hack for Swift 5. The compiler
2068-
// accepts member operators on protocols with existential
2069-
// type arguments. We should consider banning this in Swift 6.
2070-
if (auto existential = paramType->getAs<ExistentialType>()) {
2071-
if (selfNominal == existential->getConstraintType()->getAnyNominal())
2072-
return true;
2073-
}
2074-
}
2084+
// Does the parameter have the right nominal type for the conformance?
2085+
if (nominal == selfTy->getAnyNominal())
2086+
return true;
20752087

2076-
if (isProtocol || isTuple) {
2077-
// For a protocol or tuple extension, is it the 'Self' type parameter?
2078-
if (paramType->isEqual(DC->getSelfInterfaceType()))
2088+
// Otherwise, we might also have a match if the top-level operator is generic.
2089+
if (paramType->is<GenericTypeParamType>())
20792090
return true;
20802091
}
20812092
}

test/api-digester/Inputs/cake.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public protocol PSub: PSuper {
8585
public let GlobalVar = 1
8686

8787
public extension P1 {
88-
static func +(lhs: P1, rhs: P1) -> P1 { return lhs }
88+
static func +(lhs: Self, rhs: Self) -> Self { return lhs }
8989
}
9090

9191
infix operator ..*..

test/api-digester/Outputs/cake-abi.json

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,23 @@
5454
"children": [
5555
{
5656
"kind": "TypeNominal",
57-
"name": "P1",
58-
"printedName": "any cake.P1",
59-
"usr": "s:4cake2P1P"
57+
"name": "GenericTypeParam",
58+
"printedName": "τ_0_0"
6059
},
6160
{
6261
"kind": "TypeNominal",
63-
"name": "P1",
64-
"printedName": "any cake.P1",
65-
"usr": "s:4cake2P1P"
62+
"name": "GenericTypeParam",
63+
"printedName": "τ_0_0"
6664
},
6765
{
6866
"kind": "TypeNominal",
69-
"name": "P1",
70-
"printedName": "any cake.P1",
71-
"usr": "s:4cake2P1P"
67+
"name": "GenericTypeParam",
68+
"printedName": "τ_0_0"
7269
}
7370
],
7471
"declKind": "Func",
75-
"usr": "s:4cake2P1PAAE1poiyAaB_pAaB_p_AaB_ptFZ",
76-
"mangledName": "$s4cake2P1PAAE1poiyAaB_pAaB_p_AaB_ptFZ",
72+
"usr": "s:4cake2P1PAAE1poiyxx_xtFZ",
73+
"mangledName": "$s4cake2P1PAAE1poiyxx_xtFZ",
7774
"moduleName": "cake",
7875
"genericSig": "<τ_0_0 where τ_0_0 : cake.P1>",
7976
"sugared_genericSig": "<Self where Self : cake.P1>",

test/api-digester/Outputs/cake.json

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,23 @@
5454
"children": [
5555
{
5656
"kind": "TypeNominal",
57-
"name": "P1",
58-
"printedName": "any cake.P1",
59-
"usr": "s:4cake2P1P"
57+
"name": "GenericTypeParam",
58+
"printedName": "Self"
6059
},
6160
{
6261
"kind": "TypeNominal",
63-
"name": "P1",
64-
"printedName": "any cake.P1",
65-
"usr": "s:4cake2P1P"
62+
"name": "GenericTypeParam",
63+
"printedName": "Self"
6664
},
6765
{
6866
"kind": "TypeNominal",
69-
"name": "P1",
70-
"printedName": "any cake.P1",
71-
"usr": "s:4cake2P1P"
67+
"name": "GenericTypeParam",
68+
"printedName": "Self"
7269
}
7370
],
7471
"declKind": "Func",
75-
"usr": "s:4cake2P1PAAE1poiyAaB_pAaB_p_AaB_ptFZ",
76-
"mangledName": "$s4cake2P1PAAE1poiyAaB_pAaB_p_AaB_ptFZ",
72+
"usr": "s:4cake2P1PAAE1poiyxx_xtFZ",
73+
"mangledName": "$s4cake2P1PAAE1poiyxx_xtFZ",
7774
"moduleName": "cake",
7875
"genericSig": "<Self where Self : cake.P1>",
7976
"static": true,

test/decl/func/operator.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,15 @@ extension P2 {
380380
}
381381

382382
protocol P3 {
383-
// Okay: refers to P3
383+
// Not allowed: there's no way to infer 'Self' from this interface type
384384
static func %%%(lhs: P3, rhs: Unrelated) -> Unrelated
385+
// expected-error@-1 {{member operator '%%%' of protocol 'P3' must have at least one argument of type 'Self'}}
385386
}
386387

387388
extension P3 {
388-
// Okay: refers to P3
389+
// Not allowed: there's no way to infer 'Self' from this interface type
389390
static func %%%%(lhs: P3, rhs: Unrelated) -> Unrelated { }
391+
// expected-error@-1 {{member operator '%%%%' of protocol 'P3' must have at least one argument of type 'Self'}}
390392
}
391393

392394
// rdar://problem/27940842 - recovery with a non-static '=='.

0 commit comments

Comments
 (0)