Skip to content

Commit ad29110

Browse files
committed
[SR-10979] Add fix-it for missing operator
1 parent b0f30c8 commit ad29110

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3641,8 +3641,37 @@ void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
36413641
}
36423642

36433643
if (!op) {
3644-
// FIXME: Add Fix-It introducing an operator declaration?
3645-
TC.diagnose(FD, diag::declared_operator_without_operator_decl);
3644+
SourceLoc insertionLoc;
3645+
if (dyn_cast<SourceFile>(FD->getParent())) {
3646+
// Parent context is SourceFile, insertion location is start of func declaration
3647+
// or unary operator
3648+
insertionLoc = FD->isUnaryOperator() ? FD->getAttrs().getStartLoc() : FD->getStartLoc();
3649+
} else {
3650+
// Finding top-level decl context before SourceFile and inserting before it
3651+
for (DeclContext *CurContext = FD->getLocalContext();
3652+
CurContext;
3653+
CurContext = CurContext->getParent()) {
3654+
insertionLoc = CurContext->getAsDecl()->getStartLoc();
3655+
if (dyn_cast<SourceFile>(CurContext->getParent()))
3656+
break;
3657+
}
3658+
}
3659+
3660+
SmallString<128> insertion;
3661+
auto numOfParams = FD->getParameters()->size();
3662+
if (numOfParams == 1) {
3663+
if (FD->getAttrs().hasAttribute<PrefixAttr>())
3664+
insertion += "prefix operator ";
3665+
else
3666+
insertion += "postfix operator ";
3667+
} else if (numOfParams == 2) {
3668+
insertion += "infix operator ";
3669+
}
3670+
3671+
insertion += operatorName.str();
3672+
insertion += " : <# Precedence Group #>\n";
3673+
TC.diagnose(FD, diag::declared_operator_without_operator_decl)
3674+
.fixItInsert(insertionLoc, insertion);
36463675
return;
36473676
}
36483677

test/decl/func/operator.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,27 @@ struct Y {}
1111

1212
func +(lhs: X, rhs: X) -> X {} // okay
1313

14-
func +++(lhs: X, rhs: X) -> X {} // expected-error {{operator implementation without matching operator declaration}}
14+
func <=>(lhs: X, rhs: X) -> X {} // expected-error {{operator implementation without matching operator declaration}}{{1-1=infix operator <=> : <# Precedence Group #>\n}}
15+
16+
extension X {
17+
static func <=>(lhs: X, rhs: X) -> X {} // expected-error {{operator implementation without matching operator declaration}}{{1-1=infix operator <=> : <# Precedence Group #>\n}}
18+
}
19+
20+
extension X {
21+
struct Z {
22+
static func <=> (lhs: Z, rhs: Z) -> Z {} // expected-error {{operator implementation without matching operator declaration}}{{1-1=infix operator <=> : <# Precedence Group #>\n}}
23+
}
24+
}
25+
26+
extension X {
27+
static prefix func <=>(lhs: X) -> X {} // expected-error {{operator implementation without matching operator declaration}}{{1-1=prefix operator <=> : <# Precedence Group #>\n}}
28+
}
29+
30+
extension X {
31+
struct ZZ {
32+
static prefix func <=>(lhs: ZZ) -> ZZ {} // expected-error {{operator implementation without matching operator declaration}}{{1-1=prefix operator <=> : <# Precedence Group #>\n}}
33+
}
34+
}
1535

1636
infix operator ++++ : ReallyHighPrecedence
1737
precedencegroup ReallyHighPrecedence {

0 commit comments

Comments
 (0)