Skip to content

Commit 6737721

Browse files
committed
[Diagnostics] Result Builders: Improve diagnostic for uninitialized variable declarations
Resolves: rdar://81532339
1 parent b651278 commit 6737721

File tree

3 files changed

+45
-2
lines changed

3 files changed

+45
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5882,6 +5882,9 @@ NOTE(result_builder_missing_build_array, none,
58825882
NOTE(result_builder_missing_build_limited_availability, none,
58835883
"add 'buildLimitedAvailability(_:)' to the result "
58845884
"builder %0 to erase type information for less-available types", (Type))
5885+
ERROR(result_builder_requires_explicit_var_initialization,none,
5886+
"local variable%select{| '%1'}0 requires explicit initializer to be used with "
5887+
"result builder %2", (bool, StringRef, DeclName))
58855888

58865889
//------------------------------------------------------------------------------
58875890
// MARK: Tuple Shuffle Diagnostics

lib/Sema/CSDiagnostics.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5872,6 +5872,38 @@ static bool hasMissingElseInChain(IfStmt *ifStmt) {
58725872

58735873
void SkipUnhandledConstructInResultBuilderFailure::diagnosePrimary(
58745874
bool asNote) {
5875+
5876+
if (auto *decl = unhandled.dyn_cast<Decl *>()) {
5877+
if (auto *PB = dyn_cast<PatternBindingDecl>(decl)) {
5878+
// Diagnose all of the patterns without explicit initializers.
5879+
bool diagnosed = false;
5880+
for (unsigned i : range(PB->getNumPatternEntries())) {
5881+
if (PB->isExplicitlyInitialized(i))
5882+
continue;
5883+
5884+
auto *pattern = PB->getPattern(i);
5885+
5886+
StringRef name;
5887+
5888+
if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
5889+
if (auto *NP = dyn_cast<NamedPattern>(TP->getSubPattern()))
5890+
name = NP->getNameStr();
5891+
}
5892+
5893+
emitDiagnosticAt(
5894+
pattern->getLoc(),
5895+
diag::result_builder_requires_explicit_var_initialization,
5896+
!name.empty(), name, builder->getName())
5897+
.fixItInsertAfter(pattern->getEndLoc(), " = <#value#>");
5898+
5899+
diagnosed = true;
5900+
}
5901+
5902+
if (diagnosed)
5903+
return;
5904+
}
5905+
}
5906+
58755907
if (auto stmt = unhandled.dyn_cast<Stmt *>()) {
58765908
emitDiagnostic(asNote ? diag::note_result_builder_control_flow
58775909
: diag::result_builder_control_flow,

test/Constraints/result_builder_diags.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ enum Either<T,U> {
66
}
77

88
@resultBuilder
9-
struct TupleBuilder { // expected-note 2 {{struct 'TupleBuilder' declared here}}
9+
struct TupleBuilder { // expected-note 3 {{struct 'TupleBuilder' declared here}}
1010
static func buildBlock() -> () { }
1111

1212
static func buildBlock<T1>(_ t1: T1) -> T1 {
@@ -99,10 +99,18 @@ func testDiags() {
9999
tuplify(true) { _ in
100100
17
101101
let x = 17
102-
let y: Int // expected-error{{closure containing a declaration cannot be used with result builder 'TupleBuilder'}}
102+
let y: Int // expected-error{{local variable 'y' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{15-15= = <#value#>}}
103103
x + 25
104104
}
105105

106+
tuplify(true) { _ in
107+
17
108+
let y: Int, z: String
109+
// expected-error@-1 {{local variable 'y' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{15-15= = <#value#>}}
110+
// expected-error@-2 {{local variable 'z' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{26-26= = <#value#>}}
111+
y + 25
112+
}
113+
106114
// Statements unsupported by the particular builder.
107115
tuplifyWithoutIf(true) {
108116
if $0 { // expected-error{{closure containing control flow statement cannot be used with result builder 'TupleBuilderWithoutIf'}}

0 commit comments

Comments
 (0)