Skip to content

Commit 1ee66cd

Browse files
authored
Merge pull request #23500 from theblixguy/fix/SR-9267
[CSDiag] Improving the fix-it for defining computed variables
2 parents cc568d2 + 56b0c55 commit 1ee66cd

File tree

7 files changed

+107
-6
lines changed

7 files changed

+107
-6
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: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,16 +2315,21 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
23152315
exprType->isEqual(contextualType)) {
23162316
return false;
23172317
}
2318-
2318+
23192319
// If we're trying to convert something of type "() -> T" to T, then we
23202320
// probably meant to call the value.
23212321
if (auto srcFT = exprType->getAs<AnyFunctionType>()) {
23222322
if (srcFT->getParams().empty() &&
23232323
!isUnresolvedOrTypeVarType(srcFT->getResult()) &&
23242324
CS.TC.isConvertibleTo(srcFT->getResult(), contextualType, CS.DC)) {
2325-
diagnose(expr->getLoc(), diag::missing_nullary_call, srcFT->getResult())
2326-
.highlight(expr->getSourceRange())
2327-
.fixItInsertAfter(expr->getEndLoc(), "()");
2325+
2326+
auto locator =
2327+
CS.getConstraintLocator(expr, ConstraintLocator::ContextualType);
2328+
ContextualFailure failure =
2329+
ContextualFailure(nullptr, CS, srcFT, contextualType, locator);
2330+
auto diagnosed = failure.diagnoseAsError();
2331+
assert(diagnosed && "Failed to produce contextual failure diagnostic");
2332+
(void)diagnosed;
23282333
return true;
23292334
}
23302335
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Decl.h"
2323
#include "swift/AST/Expr.h"
2424
#include "swift/AST/GenericSignature.h"
25+
#include "swift/AST/Initializer.h"
2526
#include "swift/AST/ParameterList.h"
2627
#include "swift/AST/Pattern.h"
2728
#include "swift/AST/ProtocolConformance.h"
@@ -1348,6 +1349,9 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const {
13481349
srcFT->getResult())
13491350
.highlight(anchor->getSourceRange())
13501351
.fixItInsertAfter(anchor->getEndLoc(), "()");
1352+
1353+
tryComputedPropertyFixIts(anchor);
1354+
13511355
return true;
13521356
}
13531357

@@ -1378,6 +1382,53 @@ bool ContextualFailure::trySequenceSubsequenceFixIts(InFlightDiagnostic &diag,
13781382
return false;
13791383
}
13801384

1385+
void ContextualFailure::tryComputedPropertyFixIts(Expr *expr) const {
1386+
if (!isa<ClosureExpr>(expr))
1387+
return;
1388+
1389+
// It is possible that we're looking at a stored property being
1390+
// initialized with a closure. Something like:
1391+
//
1392+
// var foo: Int = { return 0 }
1393+
//
1394+
// Let's offer another fix-it to remove the '=' to turn the stored
1395+
// property into a computed property. If the variable is immutable, then
1396+
// replace the 'let' with a 'var'.
1397+
1398+
PatternBindingDecl *PBD = nullptr;
1399+
1400+
if (auto TLCD = dyn_cast<TopLevelCodeDecl>(getDC())) {
1401+
if (TLCD->getBody()->isImplicit()) {
1402+
if (auto decl = TLCD->getBody()->getElement(0).dyn_cast<Decl *>()) {
1403+
if (auto binding = dyn_cast<PatternBindingDecl>(decl)) {
1404+
PBD = binding;
1405+
}
1406+
}
1407+
}
1408+
} else if (auto PBI = dyn_cast<PatternBindingInitializer>(getDC())) {
1409+
PBD = PBI->getBinding();
1410+
}
1411+
1412+
if (PBD) {
1413+
if (auto VD = PBD->getSingleVar()) {
1414+
auto entry = PBD->getPatternEntryForVarDecl(VD);
1415+
1416+
if (!VD->isStatic() &&
1417+
!VD->getAttrs().getAttribute<DynamicReplacementAttr>() &&
1418+
entry.getInit() && isa<ClosureExpr>(entry.getInit())) {
1419+
auto diag = emitDiagnostic(expr->getLoc(),
1420+
diag::extension_stored_property_fixit,
1421+
VD->getName());
1422+
diag.fixItRemove(entry.getEqualLoc());
1423+
1424+
if (VD->isLet()) {
1425+
diag.fixItReplace(PBD->getStartLoc(), getTokenText(tok::kw_var));
1426+
}
1427+
}
1428+
}
1429+
}
1430+
}
1431+
13811432
bool AutoClosureForwardingFailure::diagnoseAsError() {
13821433
auto path = getLocator()->getPath();
13831434
assert(!path.empty());

lib/Sema/CSDiagnostics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,10 @@ class ContextualFailure final : public FailureDiagnostic {
681681
}
682682
return type;
683683
}
684+
685+
/// Try to add a fix-it to convert a stored property into a computed
686+
/// property
687+
void tryComputedPropertyFixIts(Expr *expr) const;
684688
};
685689

686690
/// Diagnose situations when @autoclosure argument is passed to @autoclosure

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,17 @@ repairFailures(ConstraintSystem &cs, Type lhs, Type rhs,
19891989
break;
19901990
}
19911991

1992+
case ConstraintLocator::ContextualType: {
1993+
if (lhs->is<FunctionType>() && !rhs->is<AnyFunctionType>() &&
1994+
isa<ClosureExpr>(anchor)) {
1995+
auto *fix = ContextualMismatch::create(cs, lhs, rhs,
1996+
cs.getConstraintLocator(locator));
1997+
conversionsOrFixes.push_back(fix);
1998+
}
1999+
2000+
break;
2001+
}
2002+
19922003
default:
19932004
return;
19942005
}

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+
}

test/expr/closure/closures.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ var closure5 : (Double) -> Int = {
2020

2121
var closure6 = $0 // expected-error {{anonymous closure argument not contained in a closure}}
2222

23-
var closure7 : Int =
24-
{ 4 } // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{9-9=()}}
23+
var closure7 : Int = { 4 } // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{27-27=()}} // expected-note {{Remove '=' to make 'closure7' a computed property}}{{20-22=}}
2524

2625
var capturedVariable = 1
2726
var closure8 = { [capturedVariable] in

0 commit comments

Comments
 (0)