diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index 6fb2fe9e56bc4..63907e2820ab4 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -180,6 +180,7 @@ class BraceStmt final : public Stmt, ASTNode getLastElement() const { return getElements().back(); } void setFirstElement(ASTNode node) { getElements().front() = node; } + void setLastElement(ASTNode node) { getElements().back() = node; } /// The elements contained within the BraceStmt. MutableArrayRef getElements() { diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 86024e59b4d71..173bb8ea8edfe 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -700,6 +700,11 @@ class Parser { /// \param DiagText name for the string literal in the diagnostic. Optional getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText); + + /// Returns true when body elements are eligible as single-expression implicit returns. + /// + /// \param Body elements to search for implicit single-expression returns. + bool shouldReturnSingleExpressionElement(ArrayRef Body); /// Returns true to indicate that experimental concurrency syntax should be /// parsed if the parser is generating only a syntax tree or if the user has diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 6471e5ce6e9a2..43d5fcc46f77c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -684,7 +684,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const { assert(hasSingleExpressionBody() && "Not a single-expression body"); auto braceStmt = getBody(); assert(braceStmt != nullptr && "No body currently available."); - auto body = getBody()->getFirstElement(); + auto body = getBody()->getLastElement(); if (auto *stmt = body.dyn_cast()) { if (auto *returnStmt = dyn_cast(stmt)) { return returnStmt->getResult(); @@ -701,7 +701,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const { void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) { assert(hasSingleExpressionBody() && "Not a single-expression body"); - auto body = getBody()->getFirstElement(); + auto body = getBody()->getLastElement(); if (auto *stmt = body.dyn_cast()) { if (auto *returnStmt = dyn_cast(stmt)) { returnStmt->setResult(NewBody); @@ -717,7 +717,7 @@ void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) { return; } } - getBody()->setFirstElement(NewBody); + getBody()->setLastElement(NewBody); } bool AbstractStorageDecl::isTransparent() const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f721934182b05..8dcbc1ec61f5e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1974,10 +1974,10 @@ FORWARD_SOURCE_LOCS_TO(ClosureExpr, Body.getPointer()) Expr *ClosureExpr::getSingleExpressionBody() const { assert(hasSingleExpressionBody() && "Not a single-expression body"); - auto body = getBody()->getFirstElement(); + auto body = getBody()->getLastElement(); if (auto stmt = body.dyn_cast()) { if (auto braceStmt = dyn_cast(stmt)) - return braceStmt->getFirstElement().get(); + return braceStmt->getLastElement().get(); return cast(stmt)->getResult(); } @@ -2003,7 +2003,7 @@ void AutoClosureExpr::setBody(Expr *E) { } Expr *AutoClosureExpr::getSingleExpressionBody() const { - return cast(Body->getFirstElement().get())->getResult(); + return cast(Body->getLastElement().get())->getResult(); } Expr *AutoClosureExpr::getUnwrappedCurryThunkExpr() const { diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index c49be13a8a909..82c1fe24cd494 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -6101,13 +6101,13 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) { // to work via TypeCheckCompletionCallback. static void undoSingleExpressionReturn(DeclContext *DC) { auto updateBody = [](BraceStmt *BS, ASTContext &Ctx) -> bool { - ASTNode FirstElem = BS->getFirstElement(); - auto *RS = dyn_cast_or_null(FirstElem.dyn_cast()); + ASTNode LastElem = BS->getLastElement(); + auto *RS = dyn_cast_or_null(LastElem.dyn_cast()); if (!RS || !RS->isImplicit()) return false; - BS->setFirstElement(RS->getResult()); + BS->setLastElement(RS->getResult()); return true; }; diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 72f856f92f5b3..b015026fe4a20 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -1112,7 +1112,24 @@ class ExprContextAnalyzer { /// in order to avoid a base expression affecting the type. However, now that /// we've typechecked, we will take the context type into account. static bool isSingleExpressionBodyForCodeCompletion(BraceStmt *body) { - return body->getNumElements() == 1 && body->getFirstElement().is(); + if (body->getNumElements() == 2) { + if (auto *D = body->getFirstElement().dyn_cast()) { + // Step into nested active clause. + while (auto *ICD = dyn_cast(D)) { + auto ACE = ICD->getActiveClauseElements(); + if (ACE.size() == 1) { + return body->getLastElement().is(); + } else if (ACE.size() == 2) { + if (auto *ND = ACE.front().dyn_cast()) { + D = ND; + continue; + } + } + break; + } + } + } + return body->getNumElements() == 1 && body->getLastElement().is(); } public: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 362a88740cbc7..abd93cdc6d290 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6656,48 +6656,45 @@ BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) { BraceStmt *BS = Body.get(); AFD->setBodyParsed(BS); - - // If the body consists of a single expression, turn it into a return - // statement. - if (BS->getNumElements() != 1) - return BS; - - auto Element = BS->getFirstElement(); - if (auto *stmt = Element.dyn_cast()) { - if (isa(AFD)) { - if (auto *returnStmt = dyn_cast(stmt)) { - if (!returnStmt->hasResult()) { - auto returnExpr = TupleExpr::createEmpty(Context, - SourceLoc(), - SourceLoc(), - /*implicit*/true); - returnStmt->setResult(returnExpr); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(returnExpr); + + if (Parser::shouldReturnSingleExpressionElement(BS->getElements())) { + auto Element = BS->getLastElement(); + if (auto *stmt = Element.dyn_cast()) { + if (isa(AFD)) { + if (auto *returnStmt = dyn_cast(stmt)) { + if (!returnStmt->hasResult()) { + auto returnExpr = TupleExpr::createEmpty(Context, + SourceLoc(), + SourceLoc(), + /*implicit*/true); + returnStmt->setResult(returnExpr); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(returnExpr); + } } } - } - } else if (auto *E = Element.dyn_cast()) { - if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { - if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { - // This is an assignment. We don't want to implicitly return - // it. - return BS; + } else if (auto *E = Element.dyn_cast()) { + if (auto SE = dyn_cast(E->getSemanticsProvidingExpr())) { + if (SE->getNumElements() > 1 && isa(SE->getElement(1))) { + // This is an assignment. We don't want to implicitly return + // it. + return BS; + } } - } - if (isa(AFD)) { - auto RS = new (Context) ReturnStmt(SourceLoc(), E); - BS->setFirstElement(RS); - AFD->setHasSingleExpressionBody(); - AFD->setSingleExpressionBody(E); - } else if (auto *F = dyn_cast(AFD)) { - if (F->isFailable() && isa(E)) { - // If it's a nil literal, just insert return. This is the only - // legal thing to return. - auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); - BS->setFirstElement(RS); + if (isa(AFD)) { + auto RS = new (Context) ReturnStmt(SourceLoc(), E); + BS->setLastElement(RS); AFD->setHasSingleExpressionBody(); AFD->setSingleExpressionBody(E); + } else if (auto *F = dyn_cast(AFD)) { + if (F->isFailable() && isa(E)) { + // If it's a nil literal, just insert return. This is the only + // legal thing to return. + auto RS = new (Context) ReturnStmt(E->getStartLoc(), E); + BS->setLastElement(RS); + AFD->setHasSingleExpressionBody(); + AFD->setSingleExpressionBody(E); + } } } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index b22c13da29bdf..76b4f9fc051ea 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2839,39 +2839,30 @@ ParserResult Parser::parseExprClosure() { closure->setParameterList(params); closure->setHasAnonymousClosureVars(); } - + // If the body consists of a single expression, turn it into a return // statement. bool hasSingleExpressionBody = false; - if (!missingRBrace && bodyElements.size() == 1) { - // If the closure's only body element is a single return statement, - // use that instead of creating a new wrapping return expression. - Expr *returnExpr = nullptr; + if (!missingRBrace && + Parser::shouldReturnSingleExpressionElement(bodyElements)) { + auto Element = bodyElements.back(); - if (bodyElements[0].is()) { - if (auto returnStmt = - dyn_cast(bodyElements[0].get())) { - + if (Element.is()) { + if (auto returnStmt = dyn_cast(Element.get())) { + hasSingleExpressionBody = true; if (!returnStmt->hasResult()) { - - returnExpr = TupleExpr::createEmpty(Context, - SourceLoc(), - SourceLoc(), - /*implicit*/true); - + auto returnExpr = TupleExpr::createEmpty(Context, + SourceLoc(), + SourceLoc(), + /*implicit*/true); returnStmt->setResult(returnExpr); } - - hasSingleExpressionBody = true; } - } - - // Otherwise, create the wrapping return. - if (bodyElements[0].is()) { + } else if (Element.is()) { + // Create the wrapping return. hasSingleExpressionBody = true; - returnExpr = bodyElements[0].get(); - bodyElements[0] = new (Context) ReturnStmt(SourceLoc(), - returnExpr); + auto returnExpr = Element.get(); + bodyElements.back() = new (Context) ReturnStmt(SourceLoc(), returnExpr); } } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ce02e6849f797..166456285ee3b 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1185,6 +1185,31 @@ Parser::getStringLiteralIfNotInterpolated(SourceLoc Loc, Segments.front().Length)); } +bool Parser::shouldReturnSingleExpressionElement(ArrayRef Body) { + // If the body consists of an #if declaration with a single + // expression active clause, find a single expression. + if (Body.size() == 2) { + if (auto *D = Body.front().dyn_cast()) { + // Step into nested active clause. + while (auto *ICD = dyn_cast(D)) { + auto ACE = ICD->getActiveClauseElements(); + if (ACE.size() == 1) { + assert(Body.back() == ACE.back() && + "active clause not found in body"); + return true; + } else if (ACE.size() == 2) { + if (auto *ND = ACE.front().dyn_cast()) { + D = ND; + continue; + } + } + break; + } + } + } + return Body.size() == 1; +} + struct ParserUnit::Implementation { std::shared_ptr SPActions; LangOptions LangOpts; diff --git a/lib/Sema/CSClosure.cpp b/lib/Sema/CSClosure.cpp index 5788096930edc..3c4c7f06932fb 100644 --- a/lib/Sema/CSClosure.cpp +++ b/lib/Sema/CSClosure.cpp @@ -173,7 +173,11 @@ class ClosureConstraintApplication } void visitDecl(Decl *decl) { - llvm_unreachable("Declarations not supported"); + + if (isa(decl)) + return; + + llvm_unreachable("Unimplemented case for closure body"); } ASTNode visitBraceStmt(BraceStmt *braceStmt) { diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index dfe330d236a00..258e97ef1d081 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1926,7 +1926,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(Evaluator &evaluator, func->getResultInterfaceType()->isVoid()) { // The function returns void. We don't need an explicit return, no matter // what the type of the expression is. Take the inserted return back out. - func->getBody()->setFirstElement(func->getSingleExpressionBody()); + func->getBody()->setLastElement(func->getSingleExpressionBody()); } } @@ -1991,7 +1991,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator, func->getResultInterfaceType()->isVoid()) { // The function returns void. We don't need an explicit return, no matter // what the type of the expression is. Take the inserted return back out. - body->setFirstElement(func->getSingleExpressionBody()); + body->setLastElement(func->getSingleExpressionBody()); } } else if (isa(AFD) && (body->empty() || @@ -2025,12 +2025,12 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator, // that we have eagerly converted something like `{ fatalError() }` // into `{ return fatalError() }` that has to be corrected here. if (isa(AFD) && cast(AFD)->hasSingleExpressionBody()) { - if (auto *stmt = body->getFirstElement().dyn_cast()) { + if (auto *stmt = body->getLastElement().dyn_cast()) { if (auto *retStmt = dyn_cast(stmt)) { if (retStmt->isImplicit() && retStmt->hasResult()) { auto returnType = retStmt->getResult()->getType(); if (returnType && returnType->isUninhabited()) - body->setFirstElement(retStmt->getResult()); + body->setLastElement(retStmt->getResult()); } } } diff --git a/test/FixCode/fixits-omit-return.swift b/test/FixCode/fixits-omit-return.swift index 5c9964d86013c..3b47151316163 100644 --- a/test/FixCode/fixits-omit-return.swift +++ b/test/FixCode/fixits-omit-return.swift @@ -10,4 +10,16 @@ let cl_fixit_addreturn: () -> String = { "foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }} } +func ff_fixit_addreturn_ifdecl() -> String { + #if true + print("entering ff_fixit_addreturn_ifdecl()") + "foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a function expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }} + #endif +} +let cl_fixit_addreturn_ifdecl: () -> String = { + #if true + print("entering cl_fixit_addreturn_ifdecl()") + "foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }} + #endif +} diff --git a/test/Parse/omit_return_fail.swift b/test/Parse/omit_return_fail.swift index 4483617357a80..8b334336d3839 100644 --- a/test/Parse/omit_return_fail.swift +++ b/test/Parse/omit_return_fail.swift @@ -7,3 +7,15 @@ func badIs(_ value: Any, anInstanceOf type: T.Type) -> Bool { func foo() -> Int { return // expected-error {{non-void function should return a value}} } + +func badIs_ifdecl(_ value: Any, anInstanceOf type: T.Type) -> Bool { + #if true + value is type // expected-error {{cannot find type 'type' in scope}} + #endif +} + +func foo_ifdecl() -> Int { + #if true + return // expected-error {{non-void function should return a value}} + #endif +} diff --git a/test/Parse/omit_return_ifdecl.swift b/test/Parse/omit_return_ifdecl.swift new file mode 100644 index 0000000000000..a46d75400e70a --- /dev/null +++ b/test/Parse/omit_return_ifdecl.swift @@ -0,0 +1,2513 @@ +// RUN: %target-swift-frontend %s -typecheck -verify + +// MARK: - Helpers + + + +@discardableResult +func logAndReturn(_ t: T) -> String { + let log = "\(t)" + print(log) + return log +} + +@discardableResult +func failableLogAndReturn(_ t: T) throws -> String { + let log = "\(t)" + print(log) + return log +} + + +typealias MyOwnVoid = () + +func failableIdentity(_ t: T) throws -> T { + #if true + t + #endif +} + +enum MyOwnNever {} + +func myOwnFatalError() -> MyOwnNever { fatalError() } + +struct MyOwnInt : ExpressibleByIntegerLiteral { init(integerLiteral: Int) {} } +struct MyOwnFloat : ExpressibleByFloatLiteral { init(floatLiteral: Double) {} } +struct MyOwnBoolean : ExpressibleByBooleanLiteral { init(booleanLiteral: Bool) {} } +struct MyOwnString : ExpressibleByStringLiteral { init(stringLiteral: String) {} } +struct MyOwnInterpolation : ExpressibleByStringInterpolation { init(stringLiteral: String) {} } + +enum Unit { + case only +} + +struct Initable {} + +struct StructWithProperty { + var foo: Int +} + +@dynamicMemberLookup +struct DynamicStruct { + subscript(dynamicMember input: String) -> String { return input } +} + +struct MyOwnArray : ExpressibleByArrayLiteral { + init(arrayLiteral elements: Element...) {} +} + +struct MyOwnDictionary : ExpressibleByDictionaryLiteral { + init(dictionaryLiteral elements: (Key, Value)...) {} +} + +struct SubscriptableStruct { + subscript(int: Int) -> Int { + #if true + int + #endif + } +} + +extension Int { + var zero: Int { + #if true + 0 + #endif + } +} + +extension Optional where Wrapped == Int { + var someZero: Int? { + #if true + Int?.some(0) + #endif + } +} + +protocol SomeProto { + func foo() -> String +} + +struct SomeProtoConformer : SomeProto { + func foo() -> String { "howdy" } +} + +class Base {} +class Derived : Base {} + +extension Int { + init() { self = 0 } +} + + +// MARK: - Notable Free Functions + + + +func identity(_ t: T) -> T { + #if true + t + #endif +} + +internal func _fatalErrorFlags() -> UInt32 { + #if true + return 0 + #endif +} +internal func _assertionFailure( + _ prefix: StaticString, _ message: String, + flags: UInt32 +) -> Never { + #if true + fatalError() + #endif +} +internal func _diagnoseUnexpectedEnumCaseValue( + type: SwitchedValue.Type, + rawValue: RawValue +) -> Never { + #if true + _assertionFailure("Fatal error", + "unexpected enum case '\(type)(rawValue: \(rawValue))'", + flags: _fatalErrorFlags()) + #endif +} + + +// MARK: - Free Functions + + + +func ff_nop() { + #if true + #endif +} + +func ff_nop_false() { + #if false + #endif +} + +func ff_missing() -> String { + #if true + #endif +} + +func ff_implicit() -> String { + #if true + "hello" + #endif +} + +func ff_explicit() -> String { + #if true + return "hello" + #endif +} + +func ff_explicitClosure() -> () -> Void { + #if true + return { print("howdy") } + #endif +} + +func ff_implicitClosure() -> () -> Void { + #if true + { print("howdy") } + #endif +} + +func ff_explicitMultilineClosure() -> () -> String { + #if true + return { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif +} + +func ff_implicitMultilineClosure() -> () -> String { + #if true + { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif +} + +func ff_implicitWrong() -> String { + #if true + 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif +} + +func ff_explicitWrong() -> String { + #if true + return 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif +} + +func ff_implicitMulti() -> String { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif +} + +func ff_explicitMulti() -> String { + #if true + print("okay") + return "all right" + #endif +} + +func ff_effectfulUsed() -> String { + #if true + logAndReturn("okay") + #endif +} + +// Unused Returns + +func ff_effectfulIgnored() { + #if true + logAndReturn("okay") + #endif +} + +func ff_effectfulIgnoredExplicitReturnTypeVoid() -> Void { + #if true + logAndReturn("okay") + #endif +} + +func ff_effectfulIgnoredExplicitReturnTypeSwiftVoid() -> Swift.Void { + #if true + logAndReturn("okay") + #endif +} + +func ff_effectfulIgnoredExplicitReturnTypeMyVoidTypealias() -> MyOwnVoid { + #if true + logAndReturn("okay") + #endif +} + +func ff_effectfulIgnoredExplicitReturnTypeEmptyTuple() -> () { + #if true + logAndReturn("okay") + #endif +} + +// Stubs + +func ff_stubImplicitReturn() { + #if true + fatalError() + #endif +} + +func ff_stubExplicitReturnTypeVoid() -> Void { + #if true + fatalError() + #endif +} + +func ff_stubExplicitReturnTypeSwiftVoid() -> Swift.Void { + #if true + fatalError() + #endif +} + +func ff_stubExplicitReturnTypeMyVoidTypealias() -> MyOwnVoid { + #if true + fatalError() + #endif +} + +func ff_stubExplicitReturnTypeEmptyTuple() -> () { + #if true + fatalError() + #endif +} + +func ff_stubImplicitReturnNever() -> Never { + #if true + fatalError() + #endif +} + +func ff_stubExplicitReturnNever() -> Never { + #if true + return fatalError() + #endif +} + +func ff_stubExplicitReturnNeverAsMyOwnNever() -> MyOwnNever { + #if true + return fatalError() // expected-error {{cannot convert return expression of type 'Never' to return type 'MyOwnNever'}} + #endif +} + +func ff_stubExplicitReturnMyOwnNeverAsNever() -> Never { + #if true + return myOwnFatalError() // expected-error {{cannot convert return expression of type 'MyOwnNever' to return type 'Never'}} + #endif +} + +func ff_stubImplicitReturnNeverAsMyOwnNever() -> MyOwnNever { + #if true + fatalError() + #endif +} + +func ff_stubImplicitReturnMyOwnNeverAsNever() -> Never { + #if true + myOwnFatalError() + #endif +} + +func ff_stubReturnString() -> String { + #if true + fatalError() + #endif +} + +func ff_stubReturnGeneric() -> T { + #if true + fatalError() + #endif +} + +// Trying + +func ff_tryExplicit() throws -> String { + #if true + return try failableIdentity("shucks") + #endif +} + +func ff_tryImplicit() throws -> String { + #if true + try failableIdentity("howdy") + #endif +} + +func ff_tryExplicitMissingThrows() -> String { + #if true + return try failableIdentity("shucks") // expected-error {{errors thrown from here are not handled}} + #endif +} + +func ff_tryImplicitMissingThrows() -> String { + #if true + try failableIdentity("howdy") // expected-error {{errors thrown from here are not handled}} + #endif +} + +// Forced Trying + +func ff_forceTryExplicit() -> String { + #if true + return try! failableIdentity("howdy") + #endif +} + +func ff_forceTryImplicit() -> String { + #if true + try! failableIdentity("shucks") + #endif +} + +func ff_forceTryExplicitAddingThrows() throws -> String { + #if true + return try! failableIdentity("howdy") + #endif +} + +func ff_forceTryImplicitAddingThrows() throws -> String { + #if true + try! failableIdentity("shucks") + #endif +} + +// Optional Trying + +func ff_optionalTryExplicit() -> String? { + #if true + return try? failableIdentity("howdy") + #endif +} + +func ff_optionalTryImplicit() -> String? { + #if true + try? failableIdentity("shucks") + #endif +} + +func ff_optionalTryExplicitAddingThrows() throws -> String? { + #if true + return try? failableIdentity("shucks") + #endif +} + +func ff_optionalTryImplicitAddingThrows() throws -> String? { + #if true + try? failableIdentity("howdy") + #endif +} + +// Inferred Return Types + +func ff_inferredIntegerLiteralInt() -> Int { + #if true + 0 + #endif +} + +func ff_inferredIntegerLiteralInt8() -> Int8 { + #if true + 0 + #endif +} + +func ff_inferredIntegerLiteralInt16() -> Int16 { + #if true + 0 + #endif +} + +func ff_inferredIntegerLiteralInt32() -> Int32 { + #if true + 0 + #endif +} + +func ff_inferredIntegerLiteralInt64() -> Int64 { + #if true + 0 + #endif +} + +func ff_inferredIntegerLiteralMyOwnInt() -> MyOwnInt { + #if true + 0 + #endif +} + +func ff_nilLiteralInt() -> Int? { + #if true + nil + #endif +} + +func ff_inferredFloatLiteralFloat() -> Float { + #if true + 0.0 + #endif +} + +func ff_inferredFloatLiteralDouble() -> Double { + #if true + 0.0 + #endif +} + +func ff_inferredFloatLiteralMyOwnDouble() -> MyOwnFloat { + #if true + 0.0 + #endif +} + +func ff_inferredBooleanLiteralBool() -> Bool { + #if true + true + #endif +} + +func ff_inferredBooleanLiteralMyOwnBoolean() -> MyOwnBoolean { + #if true + true + #endif +} + +func ff_inferredStringLiteralString() -> String { + #if true + "howdy" + #endif +} + +func ff_inferredStringLiteralMyOwnString() -> MyOwnString { + #if true + "howdy" + #endif +} + +func ff_inferredInterpolatedStringLiteralString() -> String { + #if true + "\(0) \(1)" + #endif +} + +func ff_inferredInterpolatedStringLiteralString() -> MyOwnInterpolation { + #if true + "\(0) \(1)" + #endif +} + +func ff_inferredMagicFile() -> StaticString { + #if true + #file + #endif +} + +func ff_inferredMagicLine() -> UInt { + #if true + #line // expected-error {{#line directive was renamed to #sourceLocation}} + #endif // expected-error {{parameterless closing #sourceLocation() directive without prior opening #sourceLocation(file:,line:) directive}} +} + +func ff_inferredMagicColumn() -> UInt { + #if true + #column + #endif +} + +func ff_inferredMagicFunction() -> StaticString { + #if true + #function + #endif +} + +func ff_inferredMagicDSOHandle() -> UnsafeRawPointer { + #if true + #dsohandle + #endif +} + +func ff_implicitDiscardExpr() { + #if true + _ = 3 + #endif +} + +func ff_implicitMetatype() -> String.Type { + #if true + String.self + #endif +} + +func ff_implicitMemberRef(_ instance: StructWithProperty) -> Int { + #if true + instance.foo + #endif +} + +func ff_implicitDynamicMember(_ s: DynamicStruct) -> String { + #if true + s.foo + #endif +} + +func ff_implicitParenExpr() -> Int { + #if true + (3 + 5) + #endif +} + +func ff_implicitTupleExpr() -> (Int, Int) { + #if true + (3, 5) + #endif +} + +func ff_implicitArrayExprArray() -> [Int] { + #if true + [1, 3, 5] + #endif +} + +func ff_implicitArrayExprSet() -> Set { + #if true + [1, 3, 5] + #endif +} + +func ff_implicitArrayExprMyOwnArray() -> MyOwnArray { + #if true + [1, 3, 5] + #endif +} + +func ff_implicitDictionaryExprDictionary() -> [Int : Int] { + #if true + [1 : 1, 2 : 2] + #endif +} + +func ff_implicitDictionaryExprMyOwnDictionary() -> MyOwnDictionary { + #if true + [1 : 1, 2 : 2] + #endif +} + +func ff_implicitSubscriptExpr(_ s: SubscriptableStruct) -> Int { + #if true + s[13] + #endif +} + +func ff_implicitKeyPathExprWritableKeyPath() -> WritableKeyPath { + #if true + \Int.self + #endif +} + +func ff_implicitKeyPathExprKeyPath() -> WritableKeyPath { + #if true + \Int.self.self + #endif +} + +func ff_implicitTupleElementExpr() -> Int { + #if true + (1,field:2).field + #endif +} + +func ff_implicitBindExpr(_ opt: Int?) -> Int? { + #if true + opt?.zero + #endif +} + +func ff_implicitOptionalEvaluation(_ opt: Int?) -> Int? { + #if true + (opt?.zero.zero).someZero + #endif +} + +func ff_implicitForceValue(_ opt: Int?) -> Int { + #if true + opt! + #endif +} + +func ff_implicitTemporarilyEscapableExpr(_ cl: () -> Void) -> () -> Void { + #if true + withoutActuallyEscaping(cl) { $0 } + #endif +} + +func ff_implicitOpenExistentialExpr(_ f: SomeProto) -> String { + #if true + f.foo() + #endif +} + +func ff_implicitInjectIntoOptionalExpr(_ int: Int) -> Int? { + #if true + int + #endif +} + +func ff_implicitTupleShuffle(_ input: (one: Int, two: Int)) -> (two: Int, one: Int) { + #if true + input // expected-warning {{expression shuffles the elements of this tuple; this behavior is deprecated}} + #endif +} + +func ff_implicitCollectionUpcast(_ deriveds: [Derived]) -> [Base] { + #if true + deriveds + #endif +} + +func ff_implicitErasureExpr(_ conformer: SomeProtoConformer) -> SomeProto { + #if true + conformer + #endif +} + +func ff_implicitAnyHashableErasureExpr(_ int: Int) -> AnyHashable { + #if true + int + #endif +} + +func ff_implicitCallExpr(input: Input, function: (Input) -> Output) -> Output { + #if true + function(input) + #endif +} + +func ff_implicitPrefixUnaryOperator(int: Int) -> Int { + #if true + -int + #endif +} + +func ff_implicitBinaryOperator(lhs: Int, rhs: Int) -> Int { + #if true + lhs - rhs + #endif +} + +func ff_implicitConstructorCallRefExpr(lhs: Int, rhs: Int) -> Int { + #if true + Int() + #endif +} + +func ff_implicitIsExpr(t: T) -> Bool { + #if true + t is Int + #endif +} + +func ff_implicitCoerceExpr() -> T.Type { + #if true + T.self as T.Type + #endif +} + +func ff_implicitConditionalCheckedCastExprAs(t: T) -> Int? { + #if true + t as? Int + #endif +} + +func ff_implicitForceCheckedCastExpr(t: T) -> Int { + #if true + t as! Int + #endif +} + +func ff_conditional(_ condition: Bool) -> Int { + #if true + condition ? 1 : -1 + #endif +} + +var __ff_implicitAssignExpr: Int = 0 +func ff_implicitAssignExpr(newValue: Int) -> Void { + #if true + __ff_implicitAssignExpr = newValue + #endif +} + +func ff_implicitMemberAccessInit() -> Initable { + #if true + Initable.init() + #endif +} + +func ff_implicitMemberAccessEnumCase() -> Unit { + #if true + Unit.only + #endif +} + + + +// MARK: - Free Properties : Implicit Get + + + +var fv_nop: () { + #if true + #endif +} + +var fv_nop_false: () { + #if false + #endif +} + +var fv_missing: String { + #if true + #endif +} + + +var fv_missing_test: String { + get {} +} + +var fv_implicit: String { + #if true + "hello" + #endif +} + +var fv_explicit: String { + #if true + return "hello" + #endif +} + +var fv_explicitClosure: () -> Void { + #if true + return { print("howdy") } + #endif +} + +var fv_implicitClosure: () -> Void { + #if true + { print("howdy") } + #endif +} + +var fv_explicitMultilineClosure: () -> String { + #if true + return { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif +} + +var fv_implicitMultilineClosure: () -> String { + #if true + { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif +} + +var fv_implicitWrong: String { + #if true + 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif +} + +var fv_explicitWrong: String { + #if true + return 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif +} + +var fv_implicitMulti: String { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif +} + +var fv_explicitMulti: String { + #if true + print("okay") + return "all right" + #endif +} + +var fv_effectfulUsed: String { + #if true + logAndReturn("okay") + #endif +} + +// Unused returns + +var fv_effectfulIgnored: () { + #if true + logAndReturn("okay") + #endif +} + +var fv_effectfulIgnoredVoid: Void { + #if true + logAndReturn("okay") + #endif +} + +var fv_effectfulIgnoredSwiftVoid: Swift.Void { + #if true + logAndReturn("okay") + #endif +} + +// Stubs + +var fv_stubEmptyTuple: () { + #if true + fatalError() + #endif +} + +var fv_stubVoid: Void { + #if true + fatalError() + #endif +} + +var fv_stubSwiftVoid: Swift.Void { + #if true + fatalError() + #endif +} + +var fv_stubMyVoidTypealias: MyOwnVoid { + #if true + fatalError() + #endif +} + +var fv_stubImplicitReturnNever: Never { + #if true + fatalError() + #endif +} + +var fv_stubExplicitReturnNever: Never { + #if true + return fatalError() + #endif +} + +var fv_stubExplicitReturnNeverAsMyOwnNever: MyOwnNever { + #if true + return fatalError() // expected-error {{cannot convert return expression of type 'Never' to return type 'MyOwnNever'}} + #endif +} + +var fv_stubExplicitReturnMyOwnNeverAsNever: Never { + #if true + return myOwnFatalError() // expected-error {{cannot convert return expression of type 'MyOwnNever' to return type 'Never'}} + #endif +} + +var fv_stubImplicitReturnNeverAsMyOwnNever: MyOwnNever { + #if true + fatalError() + #endif +} + +var fv_stubImplicitReturnMyOwnNeverAsNever: Never { + #if true + myOwnFatalError() + #endif +} + +var fv_stubString: String { + #if true + fatalError() + #endif +} + +// Forced Trying + +var fv_forceTryUnusedExplicit: () { + #if true + return try! failableLogAndReturn("oh") //expected-error {{unexpected non-void return value in void function}} + #endif +} + +var fv_forceTryUnusedImplicit: () { + #if true + try! failableLogAndReturn("uh") + #endif +} + +var fv_forceTryExplicit: String { + #if true + return try! failableIdentity("shucks") + #endif +} + +var fv_forceTryImplicit: String { + #if true + try! failableIdentity("howdy") + #endif +} + +// Optional Trying + +var fv_optionalTryUnusedExplicit: () { + #if true + return try? failableLogAndReturn("uh") //expected-error {{unexpected non-void return value in void function}} + #endif +} + +var fv_optionalTryUnusedImplicit: () { + #if true + try? failableLogAndReturn("oh") //expected-warning {{result of 'try?' is unused}} + #endif +} + +var fv_optionalTryExplicit: String? { + #if true + return try? failableIdentity("shucks") + #endif +} + +var fv_optionalTryImplicit: String? { + #if true + try? failableIdentity("howdy") + #endif +} + + + +// MARK: - Free Properties : Get + + + +var fvg_nop: () { + get { + #if true + #endif + } +} + +var fvg_nop_false: () { + get { + #if false + #endif + } +} + + +var fvg_missing: String { + get { + #if true + #endif + } +} + +var fvg_implicit: String { + get { + #if true + "hello" + #endif + } +} + +var fvg_explicit: String { + get { + #if true + return "hello" + #endif + } +} + +var fvg_explicitClosure: () -> Void { + get { + #if true + return { print("howdy") } + #endif + } +} + +var fvg_implicitClosure: () -> Void { + get { + #if true + { + #if true + print("howdy") + #endif + } + #endif + } +} + +var fvg_explicitMultilineClosure: () -> String { + get { + #if true + return { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } +} + +var fvg_implicitMultilineClosure: () -> String { + get { + #if true + { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } +} + +var fvg_implicitWrong: String { + get { + #if true + 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } +} + +var fvg_explicitWrong: String { + get { + #if true + return 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } +} + +var fvg_implicitMulti: String { + get { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif + } +} + +var fvg_explicitMulti: String { + get { + #if true + print("okay") + return "all right" + #endif + } +} + +var fvg_effectfulUsed: String { + get { + #if true + logAndReturn("okay") + #endif + } +} + +// Unused returns + +var fvg_effectfulIgnored: () { + get { + #if true + logAndReturn("okay") + #endif + } +} + +var fvg_effectfulIgnoredVoid: Void { + get { + #if true + logAndReturn("okay") + #endif + } +} + +var fvg_effectfulIgnoredSwiftVoid: Swift.Void { + get { + #if true + logAndReturn("okay") + #endif + } +} + +// Stubs + +var fvg_stubEmptyTuple: () { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubVoid: Void { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubSwiftVoid: Swift.Void { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubMyVoidTypealias: MyOwnVoid { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubImplicitReturnNever: Never { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubExplicitReturnNever: Never { + get { + #if true + return fatalError() + #endif + } +} + +var fvg_stubExplicitReturnNeverAsMyOwnNever: MyOwnNever { + get { + #if true + return fatalError() // expected-error {{cannot convert return expression of type 'Never' to return type 'MyOwnNever'}} + #endif + } +} + +var fvg_stubExplicitReturnMyOwnNeverAsNever: Never { + get { + #if true + return myOwnFatalError() // expected-error {{cannot convert return expression of type 'MyOwnNever' to return type 'Never'}} + #endif + } +} + +var fvg_stubImplicitReturnNeverAsMyOwnNever: MyOwnNever { + get { + #if true + fatalError() + #endif + } +} + +var fvg_stubImplicitReturnMyOwnNeverAsNever: Never { + get { + #if true + myOwnFatalError() + #endif + } +} + +var fvg_stubString: String { + get { + #if true + fatalError() + #endif + } +} + +// Forced Trying + +var fvg_forceTryExplicit: String { + get { + #if true + return try! failableIdentity("shucks") + #endif + } +} + +var fvg_forceTryImplicit: String { + get { + #if true + try! failableIdentity("howdy") + #endif + } +} + +// Optional Trying + +var fvg_optionalTryExplicit: String? { + get { + #if true + return try? failableIdentity("shucks") + #endif + } +} + +var fvg_optionalTryImplicit: String? { + get { + #if true + try? failableIdentity("howdy") + #endif + } +} + + + +// MARK: - Free Properties : Set + + + +var fvs_nop: () { + get { + #if true + #endif + } + set { + #if true + #endif + } +} + +var fvs_nop_false: () { + get { + #if false + #endif + } + set { + #if false + #endif + } +} + +var fvs_implicit: String { + get { + #if true + "ok" + #endif + } + set { + #if true + "hello" // expected-warning {{string literal is unused}} + #endif + } +} + +var fvs_explicit: String { + get { + #if true + "ok" + #endif + } + set { + #if true + return "hello" // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +var fvs_explicitClosure: () -> Void { + get { + #if true + return { + #if true + print("howdy") + #endif + } + #endif + } + set { + #if true + return { // expected-error {{unexpected non-void return value in void function}} + #if true + print("howdy") + #endif + } + #endif + } +} + +var fvs_implicitClosure: () -> Void { + get { + #if true + { + #if true + print("howdy") + #endif + } + #endif + } + set { + #if true + { // expected-error {{closure expression is unused}} expected-note {{did you mean to use a 'do' statement?}} + #if true + print("howdy") + #endif + } + #endif + } +} + +var fvs_implicitWrong: String { + get { + #if true + "ok" + #endif + } + set { + #if true + 17 // expected-warning {{integer literal is unused}} + #endif + } +} + +var fvs_explicitWrong: String { + get { + #if true + "ok" + #endif + } + set { + #if true + return 17 // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +var fvs_implicitMulti: String { + get { + #if true + "ok" + #endif + } + set { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif + } +} + +var fvs_explicitMulti: String { + get { + #if true + "ok" + #endif + } + set { + #if true + print("okay") + return "all right" // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +var fvs_effectfulUsed: String { + get { + #if true + "ok" + #endif + } + set { + #if true + logAndReturn("okay") + #endif + } +} + +// Stubs + +var fvs_stub: () { + get { + #if true + () + #endif + } + set { + #if true + fatalError() + #endif + } +} + +var fvs_stubMyOwnFatalError: () { + get { + #if true + () + #endif + } + set { + #if true + myOwnFatalError() + #endif + } +} +// Forced Trying + +var fvs_forceTryExplicit: String { + get { + #if true + "ok" + #endif + } + set { + #if true + return try! failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +var fvs_forceTryImplicit: String { + get { + #if true + "ok" + #endif + } + set { + #if true + try! failableIdentity("howdy") // expected-warning {{result of call to 'failableIdentity' is unused}} + #endif + } +} + +// Optional Trying + +var fvs_optionalTryExplicit: String? { + get { + #if true + "ok" + #endif + } + set { + #if true + return try? failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +var fvs_optionalTryImplicit: String? { + get { + #if true + "ok" + #endif + } + set { + #if true + try? failableIdentity("howdy") // expected-warning {{result of 'try?' is unused}} + #endif + } +} + + + +// MARK: - Free Properties : Read + + + + + + +// MARK: - Free Properties : Modify + + + + + + +// MARK: - Subscripts : Implicit Readonly + + + +enum S_nop { + subscript() -> () { + #if true + #endif + } +} + +enum S_nop_false { + subscript() -> () { + #if false + #endif + } +} + +enum S_missing { + subscript() -> String { + #if true + #endif + } +} + +enum S_implicit { + subscript() -> String { + #if true + "hello" + #endif + } +} + +enum S_explicit { + subscript() -> String { + #if true + return "hello" + #endif + } +} + +enum S_explicitClosure { + subscript() -> () -> Void { + #if true + return { print("howdy") } + #endif + } +} + +enum S_implicitClosure { + subscript() -> () -> Void { + #if true + { + #if true + print("howdy") + #endif + } + #endif + } +} + +enum S_explicitMultilineClosure { + subscript() -> () -> String { + #if true + return { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } +} + +enum S_implicitMultilineClosure { + subscript() -> () -> String { + #if true + { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } +} + +enum S_implicitWrong { + subscript() -> String { + #if true + 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } +} + +enum S_explicitWrong { + subscript() -> String { + #if true + return 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } +} + +enum S_implicitMulti { + subscript() -> String { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif + } +} + +enum S_explicitMulti { + subscript() -> String { + #if true + print("okay") + return "all right" + #endif + } +} + +enum S_effectfulUsed { + subscript() -> String { + #if true + logAndReturn("okay") + #endif + } +} + +// Unused returns + +enum S_effectfulIgnored { + subscript() -> () { + #if true + logAndReturn("okay") + #endif + } +} + +enum S_effectfulIgnoredVoid { + subscript() -> Void { + #if true + logAndReturn("okay") + #endif + } +} + +enum S_effectfulIgnoredSwiftVoid { + subscript() -> Swift.Void { + #if true + logAndReturn("okay") + #endif + } +} + +// Stubs + +enum S_stubEmptyTuple { + subscript() -> () { + #if true + fatalError() + #endif + } +} + +enum S_stubVoid { + subscript() -> Void { + #if true + fatalError() + #endif + } +} + +enum S_stubSwiftVoid { + subscript() -> Swift.Void { + #if true + fatalError() + #endif + } +} + +enum S_stubMyVoidTypealias { + subscript() -> MyOwnVoid { + #if true + fatalError() + #endif + } +} + +enum S_stubImplicitReturnNever { + subscript() -> Never { + #if true + fatalError() + #endif + } +} + +enum S_stubExplicitReturnNever { + subscript() -> Never { + #if true + return fatalError() + #endif + } +} + +enum S_stubExplicitReturnNeverAsMyOwnNever { + subscript() -> MyOwnNever { + #if true + return fatalError() // expected-error {{cannot convert return expression of type 'Never' to return type 'MyOwnNever'}} + #endif + } +} + +enum S_stubExplicitReturnMyOwnNeverAsNever { + subscript() -> Never { + #if true + return myOwnFatalError() // expected-error {{cannot convert return expression of type 'MyOwnNever' to return type 'Never'}} + #endif + } +} + +enum S_stubImplicitReturnNeverAsMyOwnNever { + subscript() -> MyOwnNever { + #if true + fatalError() + #endif + } +} + +enum S_stubImplicitReturnMyOwnNeverAsNever { + subscript() -> Never { + #if true + myOwnFatalError() + #endif + } +} + +enum S_stubString { + subscript() -> String { + #if true + fatalError() + #endif + } +} + +enum S_stubGeneric { + subscript() -> T { + #if true + fatalError() + #endif + } +} + +// Forced Trying + +enum S_forceTryExplicit { + subscript() -> String { + #if true + return try! failableIdentity("shucks") + #endif + } +} + +enum S_forceTryImplicit { + subscript() -> String { + #if true + try! failableIdentity("howdy") + #endif + } +} + +// Optional Trying + +enum S_optionalTryExplicit { + subscript() -> String? { + #if true + return try? failableIdentity("shucks") + #endif + } +} + +enum S_optionalTryImplicit { + subscript() -> String? { + #if true + try? failableIdentity("howdy") + #endif + } +} + + + +// MARK: - Subscripts : Explicit Readonly + + + +enum SRO_nop { + subscript() -> () { + get { + #if true + #endif + } + } +} + +enum SRO_nop_false { + subscript() -> () { + get { + #if false + #endif + } + } +} + +enum SRO_missing { + subscript() -> String { + get { + #if true + #endif + } + } +} + +enum SRO_implicit { + subscript() -> String { + get { + #if true + "hello" + #endif + } + } +} + +enum SRO_explicit { + subscript() -> String { + get { + #if true + return "hello" + #endif + } + } +} + +enum SRO_explicitClosure { + subscript() -> () -> Void { + get { + #if true + return { + #if true + print("howdy") + #endif + } + #endif + } + } +} + +enum SRO_implicitClosure { + subscript() -> () -> Void { + get { + #if true + { + #if true + print("howdy") + #endif + } + #endif + } + } +} + +enum SRO_explicitMultilineClosure { + subscript() -> () -> String { + get { + #if true + return { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } + } +} + +enum SRO_implicitMultilineClosure { + subscript() -> () -> String { + get { + #if true + { + let one = "big a" + let two = "little a" + return "\(one) + \(two)" + } + #endif + } + } +} + +enum SRO_implicitWrong { + subscript() -> String { + get { + #if true + 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } + } +} + +enum SRO_explicitWrong { + subscript() -> String { + get { + #if true + return 17 // expected-error {{cannot convert return expression of type 'Int' to return type 'String'}} + #endif + } + } +} + +enum SRO_implicitMulti { + subscript() -> String { + get { + #if true + print("uh oh") + "shucks howdy" // expected-warning {{string literal is unused}} + #endif + } + } +} + +enum SRO_explicitMulti { + subscript() -> String { + get { + #if true + print("okay") + return "all right" + #endif + } + } +} + +enum SRO_effectfulUsed { + subscript() -> String { + get { + #if true + logAndReturn("okay") + #endif + } + } +} + +// Unused returns + +enum SRO_effectfulIgnored { + subscript() -> () { + get { + #if true + logAndReturn("okay") + #endif + } + } +} + +enum SRO_effectfulIgnoredVoid { + subscript() -> Void { + get { + #if true + logAndReturn("okay") + #endif + } + } +} + +enum SRO_effectfulIgnoredSwiftVoid { + subscript() -> Swift.Void { + get { + #if true + logAndReturn("okay") + #endif + } + } +} + +// Stubs + +enum SRO_stubEmptyTuple { + subscript() -> () { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubVoid { + subscript() -> Void { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubSwiftVoid { + subscript() -> Swift.Void { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubMyVoidTypealias { + subscript() -> MyOwnVoid { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubImplicitReturnNever { + subscript() -> Never { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubExplicitReturnNever { + subscript() -> Never { + get { + #if true + return fatalError() + #endif + } + } +} + +enum SRO_stubExplicitReturnNeverAsMyOwnNever { + subscript() -> MyOwnNever { + get { + #if true + return fatalError() // expected-error {{cannot convert return expression of type 'Never' to return type 'MyOwnNever'}} + #endif + } + } +} + +enum SRO_stubExplicitReturnMyOwnNeverAsNever { + subscript() -> Never { + get { + #if true + return myOwnFatalError() // expected-error {{cannot convert return expression of type 'MyOwnNever' to return type 'Never'}} + #endif + } + } +} + +enum SRO_stubImplicitReturnNeverAsMyOwnNever { + subscript() -> MyOwnNever { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubImplicitReturnMyOwnNeverAsNever { + subscript() -> Never { + get { + #if true + myOwnFatalError() + #endif + } + } +} + +enum SRO_stubString { + subscript() -> String { + get { + #if true + fatalError() + #endif + } + } +} + +enum SRO_stubGeneric { + subscript() -> T { + get { + #if true + fatalError() + #endif + } + } +} + +// Forced Trying + +enum SRO_forceTryExplicit { + subscript() -> String { + get { + #if true + return try! failableIdentity("shucks") + #endif + } + } +} + +enum SRO_forceTryImplicit { + subscript() -> String { + get { + #if true + try! failableIdentity("howdy") + #endif + } + } +} + +// Optional Trying + +enum SRO_optionalTryExplicit { + subscript() -> String? { + get { + #if true + return try? failableIdentity("shucks") + #endif + } + } +} + +enum SRO_optionalTryImplicit { + subscript() -> String? { + get { + #if true + try? failableIdentity("howdy") + #endif + } + } +} + + + +// MARK: - Subscripts : Set + + + + + + +// MARK: - Subscripts : Read/Modify + + + + + + +// MARK: - Constructors + + + +struct C_nop { + init() { + #if true + #endif + } +} + +struct C_nop_false { + init() { + #if false + #endif + } +} + +struct C_missing { + var i: Int + init?() { + #if true + #endif + } +} + +struct C_implicitNil { + init?() { + #if true + nil + #endif + } +} + +struct C_explicitNil { + init?() { + #if true + return nil + #endif + } +} + +struct C_forcedMissing { + var i: Int + init!() { + #if true + #endif + } +} + +struct C_forcedImplicitNil { + init!() { + #if true + nil + #endif + } +} + +struct C_forcedExplicitNil { + init?() { + #if true + return nil + #endif + } +} + +struct C_implicit { + init() { + #if true + "hello" // expected-warning {{string literal is unused}} + #endif + } +} + +struct C_explicit { + init() { + #if true + return "hello" // expected-error {{'nil' is the only return value permitted in an initializer}} + #endif + } +} + + + +// MARK: - Destructors + + + +class D_nop { + deinit { + #if true + #endif + } +} + +class D_nop_false { + deinit { + #if false + #endif + } +} + +class D_implicit { + deinit { + #if true + "bye now" // expected-warning {{string literal is unused}} + #endif + } +} + +class D_explicit { + deinit { + #if true + return "bye now" // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +class D_implicitMulti { + deinit { + #if true + print("okay") + "see ya" // expected-warning {{string literal is unused}} + #endif + } +} + +class D_explicitMulti { + deinit { + #if true + print("okay") + return "see ya" // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +// Unused returns + +class D_effectfulIgnored { + deinit { + #if true + logAndReturn("bye now") + #endif + } +} + +// Stubs + +class D_stub { + deinit { + #if true + fatalError() + #endif + } +} + +class D_stubMyOwnDeinit { + deinit { + #if true + myOwnFatalError() + #endif + } +} + +// Forced Trying + +class D_forceTryUnusedExplicit { + deinit { + #if true + return try! failableLogAndReturn("uh") // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +class D_forceTryUnusedImplicit { + deinit { + #if true + try! failableLogAndReturn("oh") + #endif + } +} + +// Optional Trying + +class D_optionalTryUnusedExplicit { + deinit { + #if true + return try? failableLogAndReturn("uh") // expected-error {{unexpected non-void return value in void function}} + #endif + } +} + +class D_optionalTryUnusedImplicit { + deinit { + #if true + try? failableLogAndReturn("oh") // expected-warning {{result of 'try?' is unused}} + #endif + } +} + + + +// Miscellanceous + +class CSuperExpr_Base { init() {} } +class CSuperExpr_Derived : CSuperExpr_Base { override init() { super.init() } } + +class CImplicitIdentityExpr { func gimme() -> CImplicitIdentityExpr { self } } + +class CImplicitDotSelfExpr { func gimme() -> CImplicitDotSelfExpr { self.self } } + +func badIs(_ value: Any, anInstanceOf type: T.Type) -> Bool { + #if true + value is type // expected-error {{cannot find type 'type' in scope}} + #endif +} + + + +// Autoclosure Discriminators + + + +func embedAutoclosure_standard() -> Int { + #if true + _helpEmbedAutoclosure_standard(42) + #endif +} +func _helpEmbedAutoclosure_standard(_ value: @autoclosure () -> T) -> T { + #if true + value() + #endif +} + +func embedAutoclosure_never() -> Int { + #if true + fatalError("unsupported") + #endif +} + + +// MARK: - If Declaration Variations + +var double_nested_ifdecl: Int { + #if true + #if true + 0 + #endif + #endif +} + +var triple_nested_ifdecl: Int { + #if true + #if true + #if true + 0 + #endif + #endif + #endif +} + +var false_ifdecl: Int { + #if false + 0 + #else + 1 + #endif +} + +var false_nested_ifdecl: Int { + #if false + 0 + #else + 1 + #endif +} + +var mismatched_explicit_return_ifdecl: Int { + #if true + return 0 + #else + 1 + #endif +} + +var mismatched_implicit_return_ifdecl: Int { + #if true + 0 + #else + return 1 + #endif +} diff --git a/test/Parse/omit_return_objc.swift b/test/Parse/omit_return_objc.swift index 6308ecb8b5bb8..0eb99fe037e09 100644 --- a/test/Parse/omit_return_objc.swift +++ b/test/Parse/omit_return_objc.swift @@ -5,7 +5,7 @@ import Foundation class DynamicSubscriptClass { - @objc subscript (i : Int) -> String { "howdy" } + @objc subscript (i : Int) -> String { "howdy" } } func ff_implicitDynamicSubscript(_ c: DynamicSubscriptClass) -> String { @@ -26,3 +26,32 @@ func ff_implicitClassMetatypeToAnyObjectExpr() -> AnyObject { SomeClass.self } +class DynamicSubscriptClass_ifdecl { + #if true + @objc subscript (i : Int) -> String { "howdy" } + #endif +} + +func ff_implicitDynamicSubscript_ifdecl(_ c: DynamicSubscriptClass) -> String { + #if true + c[13] + #endif +} + +func ff_implicitObjcSelectorExpr_ifdecl() -> Selector { + #if true + #selector(NSArray.object(at:)) + #endif +} + +func ff_implicitKeyPathExpr_ifdecl() -> String { + #if true + #keyPath(NSArray.count) + #endif +} + +func ff_implicitClassMetatypeToAnyObjectExpr_ifdecl() -> AnyObject { + #if true + SomeClass.self + #endif +} diff --git a/test/expr/closure/single_expr_ifdecl.swift b/test/expr/closure/single_expr_ifdecl.swift new file mode 100644 index 0000000000000..133cce95c18ec --- /dev/null +++ b/test/expr/closure/single_expr_ifdecl.swift @@ -0,0 +1,235 @@ +// RUN: %target-typecheck-verify-swift + +func takeIntToInt(_ f: (Int) -> Int) { } +func takeIntIntToInt(_ f: (Int, Int) -> Int) { } + +// Simple closures with anonymous arguments +func simple() { + takeIntToInt({ + #if true + $0 + 1 + #else + $0 + 2 + #endif + }) + takeIntIntToInt({ + #if true + $0 + $1 + 1 + #else + $0 + $1 + 2 + #endif + }) +} + +// Anonymous arguments with inference +func myMap(_ array: [T], _ f: (T) -> U) -> [U] {} + +func testMap(_ array: [Int]) { + var farray = myMap(array, { + #if true + Float($0) + #else + Float($0 + 1) + #endif + }) + var _ : Float = farray[0] + let farray2 = myMap(array, { (x : Int) in + #if true + Float(x) + #else + Float(x + 1) + #endif + }) + farray = farray2 + _ = farray +} + +// Nested single-expression closures -- +class NestedSingleExpr { + private var b: Bool = false + private func callClosureA(_ callback: () -> Void) {} + private func callClosureB(_ callback: () -> Void) {} + + func call() { + callClosureA { [weak self] in + #if true + self?.callClosureA { + #if true + self?.b = true + #else + self?.b = false + #endif + } + #else + self?.callClosureB { + #if true + self?.b = true + #else + self?.b = false + #endif + } + #endif + } + } +} + +// Autoclosure nested inside single-expr closure should get discriminator +// Swift compiler "INTERNAL ERROR: this diagnostic should not be produced" +struct Expectation {} +func expect(_ expression: @autoclosure () -> T) -> Expectation { + return Expectation() +} +func describe(_ closure: () -> ()) {} +func f() { + #if true + describe { + #if false + _ = expect("this") + #else + _ = expect("what") + #endif + } + #endif +} + +struct Blob {} + +func withBlob(block: (Blob) -> ()) {} + +protocol Binding {} +extension Int: Binding {} +extension Double: Binding {} +extension String: Binding {} +extension Blob: Binding {} + +struct Stmt { + @discardableResult + func bind(_ values: Binding?...) -> Stmt { + return self + } + + @discardableResult + func bind(_ values: [Binding?]) -> Stmt { + return self + } + + @discardableResult + func bind(_ values: [String: Binding?]) -> Stmt { + return self + } +} + +let stmt = Stmt() +withBlob { + #if true + stmt.bind(1, 2.0, "3", $0) + #endif +} +withBlob { + #if true + stmt.bind([1, 2.0, "3", $0]) + #endif +} +withBlob { + #if true + stmt.bind(["1": 1, "2": 2.0, "3": "3", "4": $0]) + #endif +} + +// +// We shouldn't crash on the call to 'a.dispatch' below. +class A { + func dispatch(_ f : () -> Void) { + f() + } +} + +class C { + var prop = 0 + var a = A() + + func act() { + a.dispatch({() -> Void in + #if true + self.prop // expected-warning {{expression of type 'Int' is unused}} + #endif + }) + } +} + +// Never-returning expressions +func haltAndCatchFire() -> Never { + #if true + while true { } + #else + while false { } + #endif +} +let backupPlan: () -> Int = { + #if true + haltAndCatchFire() + #endif +} +func missionCritical(storage: () -> String) {} +missionCritical(storage: { + #if true + haltAndCatchFire() + #endif +}) + +// +enum E { } +func takesAnotherUninhabitedType(e: () -> E) {} +takesAnotherUninhabitedType { + #if true + haltAndCatchFire() + #endif +} + +// Weak capture bug caught by rdar://problem/67351438 +class Y { + var toggle: Bool = false + + func doSomething(animated: Bool, completionHandler: (Int, Int) -> Void) { } +} + +class X { + private(set) var someY: Y! + + func doSomething() { + someY?.doSomething(animated: true, completionHandler: { [weak someY] _, _ in + #if true + someY?.toggle = true + #else + someY?.toggle = false + #endif + }) + } +} + +var intOrStringClosure_true = { + #if true + 42 + #else + "foo" + #endif +} + +var intOrStringClosure_false = { + #if false + 42 + #else + "foo" + #endif +} + +func testMultiType() { + + let a = intOrStringClosure_true() + _ = a as Int + _ = a as String // expected-error {{cannot convert value of type 'Int' to type 'String'}} + + let b = intOrStringClosure_false() + _ = b as Int // expected-error {{cannot convert value of type 'String' to type 'Int'}} + _ = b as String +}