Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,8 @@ NOTE(selector_construction_suppress_warning,none,

ERROR(cannot_return_value_from_void_func,none,
"unexpected non-void return value in void function", ())
NOTE(add_return_type_note,none,
"did you mean to add a return type?", ())

//------------------------------------------------------------------------------
// MARK: Name Binding
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4792,6 +4792,21 @@ bool InvalidUseOfAddressOf::diagnoseAsError() {
bool ExtraneousReturnFailure::diagnoseAsError() {
auto *anchor = getAnchor();
emitDiagnostic(anchor->getLoc(), diag::cannot_return_value_from_void_func);
if (auto FD = dyn_cast<FuncDecl>(getDC())) {
// We only want to emit the note + fix-it if the function does not
// have an explicit return type. The reason we also need to check
// whether the parameter list has a valid loc is to guard against
// cases like like 'var foo: () { return 1 }' as here that loc will
// be invalid.
if (FD->getBodyResultTypeLoc().getLoc().isInvalid() &&
FD->getParameters()->getStartLoc().isValid()) {
auto fixItLoc = Lexer::getLocForEndOfToken(
getASTContext().SourceMgr, FD->getParameters()->getEndLoc());
emitDiagnostic(anchor->getLoc(), diag::add_return_type_note)
.fixItInsert(fixItLoc, " -> <# Return Type #>");
}
}

return true;
}

Expand Down
50 changes: 50 additions & 0 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1315,3 +1315,53 @@ takesGenericFunction(true) // expected-error {{cannot convert value of type 'Boo
func takesTuple<T>(_ x: ([T], [T])) {} // expected-note {{in call to function 'takesTuple'}}
takesTuple(true) // expected-error {{cannot convert value of type 'Bool' to expected argument type '([T], [T])'}}
// expected-error@-1 {{generic parameter 'T' could not be inferred}}

// Void function returns non-void result fix-it

func voidFunc() {
return 1
// expected-error@-1 {{unexpected non-void return value in void function}}
// expected-note@-2 {{did you mean to add a return type?}}{{15-15= -> <# Return Type #>}}
}

func voidFuncWithArgs(arg1: Int) {
return 1
// expected-error@-1 {{unexpected non-void return value in void function}}
// expected-note@-2 {{did you mean to add a return type?}}{{33-33= -> <# Return Type #>}}
}

func voidFuncWithCondFlow() {
if Bool.random() {
return 1
// expected-error@-1 {{unexpected non-void return value in void function}}
// expected-note@-2 {{did you mean to add a return type?}}{{28-28= -> <# Return Type #>}}
} else {
return 2
// expected-error@-1 {{unexpected non-void return value in void function}}
// expected-note@-2 {{did you mean to add a return type?}}{{28-28= -> <# Return Type #>}}
}
}

func voidFuncWithNestedVoidFunc() {
func nestedVoidFunc() {
return 1
// expected-error@-1 {{unexpected non-void return value in void function}}
// expected-note@-2 {{did you mean to add a return type?}}{{24-24= -> <# Return Type #>}}
}
}

// Special cases: These should not offer a note + fix-it

func voidFuncExplicitType() -> Void {
return 1 // expected-error {{unexpected non-void return value in void function}}
}

class ClassWithDeinit {
deinit {
return 0 // expected-error {{unexpected non-void return value in void function}}
}
}

class ClassWithVoidProp {
var propertyWithVoidType: () { return 5 } // expected-error {{unexpected non-void return value in void function}}
}