Skip to content

Commit e2728f6

Browse files
committed
[CodeCompletion] Fix completion for 'catch' pattern bound values
Previously code completion for 'catch' pattern bound values didn't work correctly because code completion type checker fails to type check the value decl in the pattern. That was because the body of the 'do' statement is not type checked, so the thrown error is not determined, then falled backed to the default 'Never', which doesn't matches any patterns. To resolve this, always type check the body when typechecking 'catch' patterns. Also, pretends 'do {}' throws 'any Error' even without any throwing expressions in the body. rdar://126699879 (cherry picked from commit 0e12254)
1 parent 41308c1 commit e2728f6

File tree

6 files changed

+63
-96
lines changed

6 files changed

+63
-96
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2746,9 +2746,15 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const {
27462746
// We have some other parent stmt. Type check it completely.
27472747
if (auto CS = dyn_cast<CaseStmt>(parentStmt))
27482748
parentStmt = CS->getParentStmt();
2749+
2750+
bool LeaveBodyUnchecked = true;
2751+
// type-checking 'catch' patterns depends on the type checked body.
2752+
if (isa<DoCatchStmt>(parentStmt))
2753+
LeaveBodyUnchecked = false;
2754+
27492755
ASTNode node(parentStmt);
27502756
TypeChecker::typeCheckASTNode(node, VD->getDeclContext(),
2751-
/*LeaveBodyUnchecked=*/true);
2757+
LeaveBodyUnchecked);
27522758
}
27532759
namingPattern = VD->getCanonicalVarDecl()->NamingPattern;
27542760
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,14 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
16691669
bool limitExhaustivityChecks = true;
16701670

16711671
Type caughtErrorType = TypeChecker::catchErrorType(DC, S);
1672+
1673+
// If there was no throwing expression in the body, let's pretend it can
1674+
// throw 'any Error' just for type checking the pattern. That avoids
1675+
// superfluous diagnostics. Note that we still diagnose unreachable 'catch'
1676+
// separately in TypeCheckEffects.
1677+
if (caughtErrorType->isNever())
1678+
caughtErrorType = Ctx.getErrorExistentialType();
1679+
16721680
auto catches = S->getCatches();
16731681
checkSiblingCaseStmts(catches.begin(), catches.end(),
16741682
CaseParentKind::DoCatch, limitExhaustivityChecks,

test/IDE/complete_exception.swift

Lines changed: 46 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,5 @@
1-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH1 | %FileCheck %s -check-prefix=CATCH1
2-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW1 > %t.throw1
3-
// RUN: %FileCheck %s -check-prefix=THROW1 < %t.throw1
4-
// RUN: %FileCheck %s -check-prefix=THROW1-LOCAL < %t.throw1
5-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH2 | %FileCheck %s -check-prefix=CATCH2
6-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW2 | %FileCheck %s -check-prefix=THROW2
7-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CATCH3 | %FileCheck %s -check-prefix=CATCH3
8-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=THROW3 | %FileCheck %s -check-prefix=THROW3
9-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH1 | %FileCheck %s -check-prefix=CATCH1
10-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW1 | %FileCheck %s -check-prefix=THROW1
11-
12-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_CATCH2 | %FileCheck %s -check-prefix=CATCH2
13-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW2 | %FileCheck %s -check-prefix=THROW2
14-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_THROW3 | %FileCheck %s -check-prefix=THROW3
15-
16-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH1 > %t.inside_catch1
17-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch1
18-
// RUN: %FileCheck %s -check-prefix=IMPLICIT_ERROR < %t.inside_catch1
19-
20-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH2 > %t.inside_catch2
21-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch2
22-
// RUN: %FileCheck %s -check-prefix=EXPLICIT_ERROR_E < %t.inside_catch2
23-
24-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH3 > %t.inside_catch3
25-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch3
26-
// RUN: %FileCheck %s -check-prefix=EXPLICIT_NSERROR_E < %t.inside_catch3
27-
28-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH4 > %t.inside_catch4
29-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch4
30-
// RUN: %FileCheck %s -check-prefix=EXPLICIT_ERROR_PAYLOAD_I < %t.inside_catch4
31-
32-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH5 > %t.inside_catch5
33-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch5
34-
// RUN: %FileCheck %s -check-prefix=EXPLICIT_ERROR_E < %t.inside_catch5
35-
// RUN: %FileCheck %s -check-prefix=NO_ERROR_AND_A < %t.inside_catch5
36-
37-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH6 > %t.inside_catch6
38-
// RUN: %FileCheck %s -check-prefix=STMT < %t.inside_catch6
39-
// RUN: %FileCheck %s -check-prefix=NO_E < %t.inside_catch6
40-
// RUN: %FileCheck %s -check-prefix=NO_ERROR_AND_A < %t.inside_catch6
41-
42-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT1 | %FileCheck %s -check-prefix=ERROR_DOT
43-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT2 | %FileCheck %s -check-prefix=ERROR_DOT
44-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT3 | %FileCheck %s -check-prefix=NSERROR_DOT
45-
// RUNFIXME: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT4 | %FileCheck %s -check-prefix=INT_DOT
46-
47-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_INSIDE_CATCH1 > %t.top_level_inside_catch1
48-
// RUN: %FileCheck %s -check-prefix=STMT < %t.top_level_inside_catch1
49-
// RUN: %FileCheck %s -check-prefix=IMPLICIT_ERROR < %t.top_level_inside_catch1
50-
51-
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_INSIDE_CATCH_ERR_DOT1 | %FileCheck %s -check-prefix=ERROR_DOT
1+
// RUN: %empty-directory(%t/batch-code-completion)
2+
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t/batch-code-completion
523

534
// REQUIRES: objc_interop
545

@@ -71,10 +22,10 @@ func getNSError() -> NSError { return NSError(domain: "", code: 1, userInfo: [:]
7122
func test001() {
7223
do {} catch #^CATCH1^#
7324

74-
// CATCH1-DAG: Decl[Enum]/CurrModule: Error4[#Error4#]; name=Error4{{$}}
75-
// CATCH1-DAG: Decl[Class]/CurrModule: Error3[#Error3#]; name=Error3{{$}}
76-
// CATCH1-DAG: Decl[Class]/CurrModule: Error2[#Error2#]; name=Error2{{$}}
77-
// CATCH1-DAG: Decl[Class]/CurrModule: Error1[#Error1#]; name=Error1{{$}}
25+
// CATCH1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}}
26+
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}}
27+
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error2[#Error2#]; name=Error2{{$}}
28+
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error1[#Error1#]; name=Error1{{$}}
7829
// CATCH1-DAG: Keyword[let]/None: let{{; name=.+$}}
7930
// CATCH1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}}
8031
// CATCH1-DAG: Decl[Class]/OtherModule[Foundation]/IsSystem: NSError[#NSError#]{{; name=.+$}}
@@ -84,7 +35,7 @@ func test002() {
8435
let text = "NonError"
8536
let e1 = Error1()
8637
let e2 = Error2()
87-
throw #^THROW1^#
38+
throw #^THROW1?check=THROW1,THROW1-LOCAL^#
8839

8940
// THROW1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}}
9041
// THROW1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}}
@@ -93,45 +44,42 @@ func test002() {
9344
// THROW1-DAG: Decl[Protocol]/CurrModule/Flair[RareType]/TypeRelation[Convertible]: ErrorPro1[#ErrorPro1#]; name=ErrorPro1{{$}}
9445
// THROW1-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Convertible]: getError1()[#Error1#]{{; name=.+$}}
9546
// THROW1-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Convertible]: getNSError()[#NSError#]{{; name=.+$}}
47+
// THROW1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}}
9648

97-
// If we could prove that there is no way to get to an Error value by
98-
// starting from these, we could remove them. But that may be infeasible in
99-
// the presence of overloaded operators.
100-
// THROW1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}}
10149
// THROW1-LOCAL-DAG: Decl[LocalVar]/Local: text[#String#]; name=text{{$}}
10250
// THROW1-LOCAL-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: e1[#Error1#]; name=e1{{$}}
10351
// THROW1-LOCAL-DAG: Decl[LocalVar]/Local/TypeRelation[Convertible]: e2[#Error2#]; name=e2{{$}}
10452
}
10553

10654
func test003() {
10755
do {} catch Error4.#^CATCH2^#
108-
// CATCH2: Decl[EnumElement]/CurrNominal: E1[#Error4#]{{; name=.+$}}
109-
// CATCH2: Decl[EnumElement]/CurrNominal: E2({#Int32#})[#Error4#]{{; name=.+$}}
56+
// CATCH2-DAG: Decl[EnumElement]/CurrNominal: E1[#Error4#]{{; name=.+$}}
57+
// CATCH2-DAG: Decl[EnumElement]/CurrNominal: E2({#Int32#})[#Error4#]{{; name=.+$}}
11058
}
11159

11260
func test004() {
11361
throw Error4.#^THROW2^#
114-
// THROW2: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E1[#Error4#]{{; name=.+$}}
115-
// THROW2: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E2({#Int32#})[#Error4#]{{; name=.+$}}
62+
// THROW2-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E1[#Error4#]{{; name=.+$}}
63+
// THROW2-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E2({#Int32#})[#Error4#]{{; name=.+$}}
11664
}
11765

11866
func test005() {
11967
do {} catch Error4.E2#^CATCH3^#
120-
// CATCH3: Pattern/CurrModule/Flair[ArgLabels]: ({#Int32#})[#Error4#]{{; name=.+$}}
68+
// CATCH3-DAG: Pattern/CurrModule/Flair[ArgLabels]: ({#Int32#})[#Error4#]{{; name=.+$}}
12169
}
12270

12371
func testInvalid() {
12472
try throw Error4.#^THROW3^#
125-
// THROW3: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E1[#Error4#]{{; name=.+$}}
126-
// THROW3: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E2({#Int32#})[#Error4#]{{; name=.+$}}
73+
// THROW3-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E1[#Error4#]{{; name=.+$}}
74+
// THROW3-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: E2({#Int32#})[#Error4#]{{; name=.+$}}
12775
}
12876

12977
//===--- Top-level throw/catch
130-
do {} catch #^TOP_LEVEL_CATCH1^# {}
131-
throw #^TOP_LEVEL_THROW1^#
132-
do {} catch Error4.#^TOP_LEVEL_CATCH2^# {}
133-
throw Error4.#^TOP_LEVEL_THROW2^#
134-
try throw Error4.#^TOP_LEVEL_THROW3^#
78+
do {} catch #^TOP_LEVEL_CATCH1?check=CATCH1^# {}
79+
throw #^TOP_LEVEL_THROW1?check=THROW1^#
80+
do {} catch Error4.#^TOP_LEVEL_CATCH2?check=CATCH2^# {}
81+
throw Error4.#^TOP_LEVEL_THROW2?check=THROW2^#
82+
try throw Error4.#^TOP_LEVEL_THROW3?check=THROW3^#
13583

13684
//===--- Inside catch body
13785

@@ -145,38 +93,37 @@ try throw Error4.#^TOP_LEVEL_THROW3^#
14593
func test006() {
14694
do {
14795
} catch {
148-
#^INSIDE_CATCH1^#
96+
#^INSIDE_CATCH1?check=STMT,IMPLICIT_ERROR^#
14997
}
150-
// IMPLICIT_ERROR: Decl[LocalVar]/Local: error[#any Error#]; name=error
98+
// IMPLICIT_ERROR-DAG: Decl[LocalVar]/Local: error[#any Error#]; name=error
15199
}
152100
func test007() {
153101
do {
154102
} catch let e {
155-
#^INSIDE_CATCH2^#
103+
#^INSIDE_CATCH2?check=STMT,EXPLICIT_ERROR_E^#
156104
}
157-
// EXPLICIT_ERROR_E: Decl[LocalVar]/Local: e[#any Error#]; name=e
105+
// EXPLICIT_ERROR_E-DAG: Decl[LocalVar]/Local: e[#any Error#]; name=e
158106
}
159107
func test008() {
160108
do {
161109
} catch let e as NSError {
162-
#^INSIDE_CATCH3^#
110+
#^INSIDE_CATCH3?check=STMT,EXPLICIT_NSERROR_E^#
163111
}
164-
// EXPLICIT_NSERROR_E: Decl[LocalVar]/Local: e[#NSError#]; name=e
112+
// EXPLICIT_NSERROR_E-DAG: Decl[LocalVar]/Local: e[#NSError#]; name=e
165113
}
166114
func test009() {
167115
do {
168116
} catch Error4.E2(let i) {
169-
#^INSIDE_CATCH4^#
117+
#^INSIDE_CATCH4?check=STMT,EXPLICIT_ERROR_PAYLOAD_I^#
170118
}
171-
172119
// FIXME: we're getting parentheses around the type when it's unnamed...
173-
// EXPLICIT_ERROR_PAYLOAD_I: Decl[LocalVar]/Local: i[#<<error type>>#]; name=i
120+
// EXPLICIT_ERROR_PAYLOAD_I-DAG: Decl[LocalVar]/Local: i[#(Int32)#]; name=i
174121
}
175122
func test010() {
176123
do {
177124
} catch let awesomeError {
178125
} catch let e {
179-
#^INSIDE_CATCH5^#
126+
#^INSIDE_CATCH5?check=STMT,EXPLICIT_ERROR_E;check=NO_ERROR_AND_A^#
180127
} catch {}
181128
// NO_ERROR_AND_A-NOT: awesomeError
182129
// NO_ERROR_AND_A-NOT: Decl[LocalVar]/Local: error
@@ -186,26 +133,26 @@ func test011() {
186133
} catch let awesomeError {
187134
} catch let excellentError {
188135
} catch {}
189-
#^INSIDE_CATCH6^#
136+
#^INSIDE_CATCH6?check=STMT;check=NO_ERROR_AND_A,NO_E^#
190137
// NO_E-NOT: excellentError
191138
}
192139
func test012() {
193140
do {
194141
} catch {
195-
error.#^INSIDE_CATCH_ERR_DOT1^#
142+
error.#^INSIDE_CATCH_ERR_DOT1?check=ERROR_DOT^#
196143
}
197144
}
198-
// ERROR_DOT: Keyword[self]/CurrNominal: self[#any Error#]; name=self
145+
// ERROR_DOT-DAG: Keyword[self]/CurrNominal: self[#any Error#]; name=self
199146
func test013() {
200147
do {
201148
} catch let e {
202-
e.#^INSIDE_CATCH_ERR_DOT2^#
149+
e.#^INSIDE_CATCH_ERR_DOT2?check=ERROR_DOT^#
203150
}
204151
}
205152
func test014() {
206153
do {
207154
} catch let e as NSError {
208-
e.#^INSIDE_CATCH_ERR_DOT3^#
155+
e.#^INSIDE_CATCH_ERR_DOT3?check=NSERROR_DOT^#
209156
}
210157
// NSERROR_DOT-DAG: Decl[InstanceVar]/CurrNominal/IsSystem: domain[#String#]; name=domain
211158
// NSERROR_DOT-DAG: Decl[InstanceVar]/CurrNominal/IsSystem: code[#Int#]; name=code
@@ -218,7 +165,7 @@ func test014() {
218165
func test015() {
219166
do {
220167
} catch Error4.E2(let i) where i == 2 {
221-
i.#^INSIDE_CATCH_ERR_DOT4^#
168+
i.#^INSIDE_CATCH_ERR_DOT4?check=INT_DOT^#
222169
}
223170
}
224171
// Check that we can complete on the bound value; Not exhaustive..
@@ -228,9 +175,18 @@ func test015() {
228175
//===--- Inside catch body top-level
229176
do {
230177
} catch {
231-
#^TOP_LEVEL_INSIDE_CATCH1^#
178+
#^TOP_LEVEL_INSIDE_CATCH1?check=STMT,IMPLICIT_ERROR^#
232179
}
233180
do {
234181
} catch {
235-
error.#^TOP_LEVEL_INSIDE_CATCH_ERR_DOT1^#
182+
error.#^TOP_LEVEL_INSIDE_CATCH_ERR_DOT1?check=ERROR_DOT^#
183+
}
184+
185+
func canThrowError4() throws(Error4) {}
186+
func test016() {
187+
do {
188+
try canThrowError4()
189+
} catch .E2(let i) {
190+
i.#^INSIDE_CATCH_TYPEDERR_DOT?check=INT_DOT^#
191+
}
236192
}

test/Sema/redeclaration-checking.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ func stmtTest() {
8787
// expected-note@-1 {{'x' previously declared here}}
8888
// expected-error@-2 {{invalid redeclaration of 'x'}}
8989
// expected-warning@-3 {{unreachable}}
90-
// expected-error@-4{{pattern of type 'MyError' cannot match 'Never'}}
9190
}
9291

9392
func fullNameTest() {

test/StringProcessing/Parse/forward-slash-regex.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ default:
262262
}
263263

264264
do {} catch /x/ {}
265-
// expected-error@-1 {{expression pattern of type 'Regex<Substring>' cannot match values of type 'Never'}}
265+
// expected-error@-1 {{expression pattern of type 'Regex<Substring>' cannot match values of type 'any Error'}}
266266
// expected-warning@-2 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
267267

268268
switch /x/ {

test/stmt/typed_throws.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,8 @@ func testTryIncompatibleTyped(cond: Bool) throws(HomeworkError) {
134134
}
135135
} catch let error as Never {
136136
// expected-warning@-1{{'catch' block is unreachable because no errors are thrown in 'do' block}}
137-
// expected-warning@-2{{'as' test is always true}}
138137
throw .forgot
139-
}
138+
} // expected-error {{thrown expression type 'any Error' cannot be converted to error type 'HomeworkError'}}
140139
}
141140

142141
func doSomethingWithoutThrowing() { }
@@ -145,7 +144,6 @@ func testDoCatchWithoutThrowing() {
145144
do {
146145
try doSomethingWithoutThrowing() // expected-warning{{no calls to throwing functions occur within 'try' expression}}
147146
} catch HomeworkError.forgot { // expected-warning{{'catch' block is unreachable because no errors are thrown in 'do' block}}
148-
// expected-error@-1{{pattern of type 'HomeworkError' cannot match 'Never'}}
149147
} catch {
150148
}
151149
}

0 commit comments

Comments
 (0)