Skip to content

Commit cad60ba

Browse files
committed
[csdiag] offer a fix-it to turn a stored property into a computed property if needed
1 parent de65d30 commit cad60ba

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,8 @@ ERROR(extension_specialization,none,
15221522
"type %0 with constraints specified by a 'where' clause", (Identifier))
15231523
ERROR(extension_stored_property,none,
15241524
"extensions must not contain stored properties", ())
1525+
NOTE(extension_stored_property_fixit,none,
1526+
"Remove '=' to make %0 a computed property", (Identifier))
15251527
ERROR(extension_nongeneric_trailing_where,none,
15261528
"trailing 'where' clause for extension of non-generic type %0",
15271529
(DeclName))

lib/Sema/CSDiag.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,51 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
23252325
diagnose(expr->getLoc(), diag::missing_nullary_call, srcFT->getResult())
23262326
.highlight(expr->getSourceRange())
23272327
.fixItInsertAfter(expr->getEndLoc(), "()");
2328+
2329+
// It is possible that we're looking at a stored property being
2330+
// initialized with a closure. Something like:
2331+
//
2332+
// var foo: Int = { return 0 }
2333+
//
2334+
// Let's offer another fix-it to remove the '=' to turn the stored
2335+
// property into a computed property. If the variable is immutable, then
2336+
// replace the 'let' with a 'var'
2337+
2338+
// First, check if the variable is declared top level or not. If it is
2339+
// not, then it means we're inside a decl like a class or an extension.
2340+
PatternBindingDecl *PBD = nullptr;
2341+
2342+
if (auto TLCD = dyn_cast<TopLevelCodeDecl>(CS.DC)) {
2343+
if (TLCD->getBody()->isImplicit()) {
2344+
if (auto decl = TLCD->getBody()->getElement(0).dyn_cast<Decl *>()) {
2345+
if (auto binding = dyn_cast<PatternBindingDecl>(decl)) {
2346+
PBD = binding;
2347+
}
2348+
}
2349+
}
2350+
} else if (auto PBI = dyn_cast<PatternBindingInitializer>(CS.DC)) {
2351+
PBD = PBI->getBinding();
2352+
}
2353+
2354+
if (PBD) {
2355+
if (auto VD = PBD->getSingleVar()) {
2356+
auto entry = PBD->getPatternEntryForVarDecl(VD);
2357+
2358+
if (!VD->isStatic() &&
2359+
!VD->getAttrs().getAttribute<DynamicReplacementAttr>() &&
2360+
entry.getInit() && isa<ClosureExpr>(entry.getInit())) {
2361+
auto diag = CS.TC.diagnose(expr->getLoc(),
2362+
diag::extension_stored_property_fixit,
2363+
VD->getName());
2364+
diag.fixItRemove(entry.getEqualLoc());
2365+
2366+
if (VD->isLet()) {
2367+
diag.fixItReplace(PBD->getStartLoc(), getTokenText(tok::kw_var));
2368+
}
2369+
}
2370+
}
2371+
}
2372+
23282373
return true;
23292374
}
23302375
}

test/decl/var/properties.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,3 +1277,32 @@ let sr8811b: Never = fatalError() // Ok
12771277
let sr8811c = (16, fatalError()) // expected-warning {{constant 'sr8811c' inferred to have type '(Int, Never)', which contains an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}
12781278

12791279
let sr8811d: (Int, Never) = (16, fatalError()) // Ok
1280+
1281+
// SR-9267
1282+
1283+
class SR_9267 {}
1284+
extension SR_9267 {
1285+
var foo: String = { // expected-error {{extensions must not contain stored properties}} // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'foo' a computed property}}{{19-21=}}
1286+
return "Hello"
1287+
}
1288+
}
1289+
1290+
enum SR_9267_E {
1291+
var SR_9267_prop: String = { // expected-error {{enums must not contain stored properties}} // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop' a computed property}}{{28-30=}}
1292+
return "Hello"
1293+
}
1294+
}
1295+
1296+
var SR_9267_prop_1: Int = { // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_1' a computed property}}{{25-27=}}
1297+
return 0
1298+
}
1299+
1300+
class SR_9267_C {
1301+
var SR_9267_prop_2: String = { // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_2' a computed property}}{{30-32=}}
1302+
return "Hello"
1303+
}
1304+
}
1305+
1306+
class SR_9267_C2 {
1307+
let SR_9267_prop_3: Int = { return 0 } // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_3' a computed property}}{{3-6=var}}{{27-29=}}
1308+
}

0 commit comments

Comments
 (0)