Skip to content

Commit 92db547

Browse files
authored
Merge pull request #4138 from rudkx/fix-27536066-swift-3.0
[SE-0091] Require member operators to refer to the enclosing nominal …
2 parents c5e63fe + 2e97364 commit 92db547

File tree

4 files changed

+153
-9
lines changed

4 files changed

+153
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,9 @@ ERROR(nonstatic_operator_in_type,none,
638638
ERROR(nonfinal_operator_in_class,none,
639639
"operator %0 declared in non-final class %1 must be 'final'",
640640
(Identifier, Type))
641+
ERROR(operator_in_unrelated_type,none,
642+
"member operator %2%select{| of protocol %0}1 must have at least one "
643+
"argument of type %select{%0|'Self'}1", (Type, bool, DeclName))
641644

642645
// Precedence groups
643646
ERROR(ambiguous_precedence_groups,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4592,6 +4592,48 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
45924592
return type->getAs<AnyFunctionType>();
45934593
}
45944594

4595+
void checkMemberOperator(FuncDecl *FD) {
4596+
// Check that member operators reference the type of 'Self'.
4597+
if (FD->getNumParameterLists() != 2 || FD->isInvalid()) return;
4598+
4599+
auto selfNominal =
4600+
FD->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
4601+
if (!selfNominal) return;
4602+
4603+
// Check the parameters for a reference to 'Self'.
4604+
bool isProtocol = isa<ProtocolDecl>(selfNominal);
4605+
for (auto param : *FD->getParameterList(1)) {
4606+
auto paramType = param->getInterfaceType();
4607+
if (!paramType) break;
4608+
4609+
// Look through 'inout'.
4610+
paramType = paramType->getInOutObjectType();
4611+
4612+
// Look through a metatype reference, if there is one.
4613+
if (auto metatypeType = paramType->getAs<AnyMetatypeType>())
4614+
paramType = metatypeType->getInstanceType();
4615+
4616+
// Is it the same nominal type?
4617+
if (paramType->getAnyNominal() == selfNominal) return;
4618+
4619+
if (isProtocol) {
4620+
// For a protocol, is it the 'Self' type parameter?
4621+
if (auto genericParam = paramType->getAs<GenericTypeParamType>())
4622+
if (genericParam->getDepth() == 0 && genericParam->getIndex() == 0)
4623+
return;
4624+
4625+
// ... or the 'Self' archetype?
4626+
if (auto archetype = paramType->getAs<ArchetypeType>())
4627+
if (archetype->getSelfProtocol() == selfNominal) return;
4628+
}
4629+
}
4630+
4631+
// We did not find 'Self'. Complain.
4632+
TC.diagnose(FD, diag::operator_in_unrelated_type,
4633+
FD->getDeclContext()->getDeclaredTypeInContext(),
4634+
isProtocol, FD->getFullName());
4635+
}
4636+
45954637
void visitFuncDecl(FuncDecl *FD) {
45964638
if (!IsFirstPass) {
45974639
if (FD->hasBody()) {
@@ -4740,6 +4782,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
47404782
}
47414783
}
47424784

4785+
if (FD->isOperator())
4786+
checkMemberOperator(FD);
4787+
47434788
Optional<ObjCReason> isObjC = shouldMarkAsObjC(TC, FD);
47444789

47454790
ProtocolDecl *protocolContext = dyn_cast<ProtocolDecl>(

test/IDE/print_ast_tc_decls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,10 +1092,10 @@ postfix operator <*>
10921092
// PASS_2500-LABEL: {{^}}postfix operator <*>{{$}}
10931093

10941094
protocol d2600_ProtocolWithOperator1 {
1095-
static postfix func <*>(_: Int)
1095+
static postfix func <*>(_: Self)
10961096
}
10971097
// PASS_2500: {{^}}protocol d2600_ProtocolWithOperator1 {{{$}}
1098-
// PASS_2500-NEXT: {{^}} postfix static func <*>(_: Int){{$}}
1098+
// PASS_2500-NEXT: {{^}} postfix static func <*>(_: Self){{$}}
10991099
// PASS_2500-NEXT: {{^}}}{{$}}
11001100

11011101
struct d2601_TestAssignment {}

test/decl/func/operator.swift

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,29 +214,125 @@ extension S0 {
214214
}
215215

216216
struct S1 {
217-
func %%%(lhs: S0, rhs: S0) -> S0 { return lhs } // expected-error{{operator '%%%' declared in type 'S1' must be 'static'}}{{3-3=static }}
217+
func %%%(lhs: S1, rhs: S1) -> S1 { return lhs } // expected-error{{operator '%%%' declared in type 'S1' must be 'static'}}{{3-3=static }}
218218
}
219219

220220
extension S1 {
221-
func %%%%(lhs: S0, rhs: S0) -> S0 { return lhs } // expected-error{{operator '%%%%' declared in type 'S1' must be 'static'}}{{3-3=static }}
221+
func %%%%(lhs: S1, rhs: S1) -> S1 { return lhs } // expected-error{{operator '%%%%' declared in type 'S1' must be 'static'}}{{3-3=static }}
222222
}
223223

224224
class C0 {
225-
static func %%%(lhs: S0, rhs: S0) -> S0 { return lhs }
225+
static func %%%(lhs: C0, rhs: C0) -> C0 { return lhs }
226226
}
227227

228228
class C1 {
229-
final func %%%(lhs: S0, rhs: S0) -> S0 { return lhs }
229+
final func %%%(lhs: C1, rhs: C1) -> C1 { return lhs }
230230
}
231231

232232
final class C2 {
233-
class func %%%(lhs: S0, rhs: S0) -> S0 { return lhs }
233+
class func %%%(lhs: C2, rhs: C2) -> C2 { return lhs }
234234
}
235235

236236
class C3 {
237-
class func %%%(lhs: S0, rhs: S0) -> S0 { return lhs } // expected-error{{operator '%%%' declared in non-final class 'C3' must be 'final'}}{{3-3=final }}
237+
class func %%%(lhs: C3, rhs: C3) -> C3 { return lhs } // expected-error{{operator '%%%' declared in non-final class 'C3' must be 'final'}}{{3-3=final }}
238238
}
239239

240240
class C4 {
241-
func %%%(lhs: S0, rhs: S0) -> S0 { return lhs } // expected-error{{operator '%%%' declared in type 'C4' must be 'static'}}{{3-3=static }}
241+
func %%%(lhs: C4, rhs: C4) -> C4 { return lhs } // expected-error{{operator '%%%' declared in type 'C4' must be 'static'}}{{3-3=static }}
242+
}
243+
244+
struct Unrelated { }
245+
246+
struct S2 {
247+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> Unrelated { }
248+
// expected-error@-1{{member operator '%%%' must have at least one argument of type 'S2'}}
249+
250+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> S2 { }
251+
// expected-error@-1{{member operator '%%%' must have at least one argument of type 'S2'}}
252+
253+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> S2.Type { }
254+
// expected-error@-1{{member operator '%%%' must have at least one argument of type 'S2'}}
255+
256+
// Okay: refers to S2
257+
static func %%%(lhs: S2, rhs: Unrelated) -> Unrelated { }
258+
static func %%%(lhs: inout S2, rhs: Unrelated) -> Unrelated { }
259+
static func %%%(lhs: S2.Type, rhs: Unrelated) -> Unrelated { }
260+
static func %%%(lhs: inout S2.Type, rhs: Unrelated) -> Unrelated { }
261+
static func %%%(lhs: Unrelated, rhs: S2) -> Unrelated { }
262+
static func %%%(lhs: Unrelated, rhs: inout S2) -> Unrelated { }
263+
static func %%%(lhs: Unrelated, rhs: S2.Type) -> Unrelated { }
264+
static func %%%(lhs: Unrelated, rhs: inout S2.Type) -> Unrelated { }
265+
}
266+
267+
extension S2 {
268+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> Unrelated { }
269+
// expected-error@-1{{member operator '%%%%' must have at least one argument of type 'S2'}}
270+
271+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> S2 { }
272+
// expected-error@-1{{member operator '%%%%' must have at least one argument of type 'S2'}}
273+
274+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> S2.Type { }
275+
// expected-error@-1{{member operator '%%%%' must have at least one argument of type 'S2'}}
276+
277+
// Okay: refers to S2
278+
static func %%%%(lhs: S2, rhs: Unrelated) -> Unrelated { }
279+
static func %%%%(lhs: inout S2, rhs: Unrelated) -> Unrelated { }
280+
static func %%%%(lhs: S2.Type, rhs: Unrelated) -> Unrelated { }
281+
static func %%%%(lhs: inout S2.Type, rhs: Unrelated) -> Unrelated { }
282+
static func %%%%(lhs: Unrelated, rhs: S2) -> Unrelated { }
283+
static func %%%%(lhs: Unrelated, rhs: inout S2) -> Unrelated { }
284+
static func %%%%(lhs: Unrelated, rhs: S2.Type) -> Unrelated { }
285+
static func %%%%(lhs: Unrelated, rhs: inout S2.Type) -> Unrelated { }
286+
}
287+
288+
protocol P2 {
289+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> Unrelated
290+
// expected-error@-1{{member operator '%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
291+
292+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> Self
293+
// expected-error@-1{{member operator '%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
294+
295+
static func %%%(lhs: Unrelated, rhs: Unrelated) -> Self.Type
296+
// expected-error@-1{{member operator '%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
297+
298+
// Okay: refers to Self
299+
static func %%%(lhs: Self, rhs: Unrelated) -> Unrelated
300+
static func %%%(lhs: inout Self, rhs: Unrelated) -> Unrelated
301+
static func %%%(lhs: Self.Type, rhs: Unrelated) -> Unrelated
302+
static func %%%(lhs: inout Self.Type, rhs: Unrelated) -> Unrelated
303+
static func %%%(lhs: Unrelated, rhs: Self) -> Unrelated
304+
static func %%%(lhs: Unrelated, rhs: inout Self) -> Unrelated
305+
static func %%%(lhs: Unrelated, rhs: Self.Type) -> Unrelated
306+
static func %%%(lhs: Unrelated, rhs: inout Self.Type) -> Unrelated
307+
}
308+
309+
extension P2 {
310+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> Unrelated { }
311+
// expected-error@-1{{member operator '%%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
312+
313+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> Self { }
314+
// expected-error@-1{{member operator '%%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
315+
316+
static func %%%%(lhs: Unrelated, rhs: Unrelated) -> Self.Type { }
317+
// expected-error@-1{{member operator '%%%%' of protocol 'P2' must have at least one argument of type 'Self'}}
318+
319+
// Okay: refers to Self
320+
static func %%%%(lhs: Self, rhs: Unrelated) -> Unrelated { }
321+
static func %%%%(lhs: inout Self, rhs: Unrelated) -> Unrelated { }
322+
static func %%%%(lhs: Self.Type, rhs: Unrelated) -> Unrelated { }
323+
static func %%%%(lhs: inout Self.Type, rhs: Unrelated) -> Unrelated { }
324+
static func %%%%(lhs: Unrelated, rhs: Self) -> Unrelated { }
325+
static func %%%%(lhs: Unrelated, rhs: inout Self) -> Unrelated { }
326+
static func %%%%(lhs: Unrelated, rhs: Self.Type) -> Unrelated { }
327+
static func %%%%(lhs: Unrelated, rhs: inout Self.Type) -> Unrelated { }
328+
}
329+
330+
protocol P3 {
331+
// Okay: refers to P3
332+
static func %%%(lhs: P3, rhs: Unrelated) -> Unrelated
333+
}
334+
335+
extension P3 {
336+
// Okay: refers to P3
337+
static func %%%%(lhs: P3, rhs: Unrelated) -> Unrelated { }
242338
}

0 commit comments

Comments
 (0)