Skip to content

Commit caad4a8

Browse files
committed
[MiscDiagnostics] Run opaque return checker only if all of the return expressions are correct
1 parent 1f1e8d9 commit caad4a8

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2218,6 +2218,9 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
22182218
AbstractFunctionDecl *Implementation;
22192219
OpaqueTypeDecl *OpaqueDecl;
22202220
SmallVector<std::pair<Expr*, Type>, 4> Candidates;
2221+
2222+
bool HasInvalidReturn = false;
2223+
22212224
public:
22222225
OpaqueUnderlyingTypeChecker(TypeChecker &TC,
22232226
AbstractFunctionDecl *Implementation,
@@ -2231,7 +2234,13 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
22312234

22322235
void check() {
22332236
Implementation->getBody()->walk(*this);
2234-
2237+
2238+
// If given function has any invalid returns in the body
2239+
// let's not try to validate the types, since it wouldn't
2240+
// be accurate.
2241+
if (HasInvalidReturn)
2242+
return;
2243+
22352244
// If there are no candidates, then the body has no return statements, and
22362245
// we have nothing to infer the underlying type from.
22372246
if (Candidates.empty()) {
@@ -2310,6 +2319,20 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
23102319
}
23112320
return std::make_pair(false, E);
23122321
}
2322+
2323+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
2324+
if (auto *RS = dyn_cast<ReturnStmt>(S)) {
2325+
if (RS->hasResult()) {
2326+
auto resultTy = RS->getResult()->getType();
2327+
// If expression associated with return statement doesn't have
2328+
// a type or type has an error, checking opaque types is going
2329+
// to produce incorrect diagnostics.
2330+
HasInvalidReturn |= resultTy.isNull() || resultTy->hasError();
2331+
}
2332+
}
2333+
2334+
return {true, S};
2335+
}
23132336
};
23142337

23152338
} // end anonymous namespace

test/type/opaque.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,36 +319,40 @@ func diagnose_requirement_failures() {
319319
struct S {
320320
var foo: some P { return S() } // expected-note {{declared here}}
321321
// expected-error@-1 {{return type of property 'foo' requires that 'S' conform to 'P'}}
322-
// expected-error@-2 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
323322

324323
subscript(_: Int) -> some P { // expected-note {{declared here}}
325-
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
326324
return S()
327325
// expected-error@-1 {{return type of subscript 'subscript(_:)' requires that 'S' conform to 'P'}}
328326
}
329327

330328
func bar() -> some P { // expected-note {{declared here}}
331-
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
332329
return S()
333330
// expected-error@-1 {{return type of instance method 'bar()' requires that 'S' conform to 'P'}}
334331
}
335332

336333
static func baz(x: String) -> some P { // expected-note {{declared here}}
337-
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
338334
return S()
339335
// expected-error@-1 {{return type of static method 'baz(x:)' requires that 'S' conform to 'P'}}
340336
}
341337
}
342338

343339
func fn() -> some P { // expected-note {{declared here}}
344-
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
345340
return S()
346341
// expected-error@-1 {{return type of local function 'fn()' requires that 'S' conform to 'P'}}
347342
}
348343
}
349344

350345
func global_function_with_requirement_failure() -> some P { // expected-note {{declared here}}
351-
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
352346
return 42 as Double
353347
// expected-error@-1 {{return type of global function 'global_function_with_requirement_failure()' requires that 'Double' conform to 'P'}}
354348
}
349+
350+
func recursive_func_is_invalid_opaque() {
351+
func rec(x: Int) -> some P {
352+
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
353+
if x == 0 {
354+
return rec(x: 0)
355+
}
356+
return rec(x: x - 1)
357+
}
358+
}

0 commit comments

Comments
 (0)