Nimble: Xcode 12 beta 5 and 6 build error `ambiguous use of 'expect'`

  • I have read CONTRIBUTING and have done my best to follow them.

What did you do?

I installed Xcode 12 beta 5 and 6 and tried to build our existing (test) code:

it("should throw an error") {
    expect {
        try JSONDecoder().decode(SomeModel.self, from: data)
    }.to(throwError())
}

What did you expect to happen?

I expected the code to compile.

What actually happened instead?

The code failed to compile with a ambiguous use of 'expect' error. With these two candidates:

  • Sources/Nimble/DSL.swift#L1-L8
    • public func expect<T>(_ expression: @autoclosure @escaping () throws -> T?, file: FileString = #file, line: UInt = #line) -> Expectation<T>
  • Sources/Nimble/DSL.swift#L10-L17: Found this candidate
    • public func expect<T>(_ file: FileString = #file, line: UInt = #line, expression: @escaping () throws -> T?) -> Expectation<T>

Environment

List the software versions you’re using:

  • Quick: 2.2.1 + 3.0.0
  • Nimble: 8.1.1 + 9.0.0-rc.1
  • Xcode Version: 12.0 beta 5 (12A8189h), 12.0 beta 6 (12A8189n)
  • Swift Version: Xcode Default

Please also mention which package manager you used and its version. Delete the other package managers in this list:

  • Carthage: 0.35.0

Project that demonstrates the issue

https://github.com/rastersize/Xcode12Beta5Nimble

After cloning do the following:

  1. Run carthage.sh bootstrap
    • The script works around a Carthage bug with Xcode 12 beta 4+ and universal binaries. As newer versions of Xcode 12 will produce an arm64 slice for both the simulator and device, and a universal binary can’t contain two slices for the same architecture.
  2. Open the Xcode project
  3. Build for testing

Workaround

Change the call-site of expect to specify using the non-autoclosure function. That is:

it("should throw an error") {
    expect(expression: {
        try JSONDecoder().decode(SomeModel.self, from: data)
    }).to(throwError())
}

Not as pretty but it works for now.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (5 by maintainers)

Most upvoted comments

Thanks for your work @ikesyo !

I tested out #821 and it resolved a lot of the issues I was facing. On a minor note I noticed that this no longer works

expect({
  if 1 == 1 {
    return .failed(reason: "this failed")
  }
  return .succeeded
}).to(succeed())

This can be fixed by returning a closure instead i.e. return { .succeeded } but I am curious if this regression can be reverted?

@ketenshi Another workaround I found is by adding () -> ToSucceedResult in like so:

expect({ () -> ToSucceedResult in
  if 1 == 1 {
    return .failed(reason: "this failed")
  }
  return .succeeded
}).to(succeed())

Not sure if this behaviour is expected in Nimble 9.

I’m on the same configuration and I’m getting a similar error, Illegal instruction: 4, but always when evaluating expect{}.toEventually()

CompileSwift normal x86_64 (in target 'LoungeFoundationTests' from project 'LoungeFoundation')
[...]
fromType->getCanonicalType() = (bound_generic_struct_type decl=Nimble.(file).Predicate@/Users/ngiancecchi/Projects/ios-app/Carthage/Checkouts/Nimble/Sources/Nimble/Matchers/Predicate.swift:20:15
  (protocol_composition_type))
toType->getCanonicalType() = (bound_generic_struct_type decl=Nimble.(file).Predicate@/Users/ngiancecchi/Projects/ios-app/Carthage/Checkouts/Nimble/Sources/Nimble/Matchers/Predicate.swift:20:15
  (function_type escaping
    (input=function_params num_params=0)
    (output=tuple_type num_elements=0)))
Stack dump:
0.	Program arguments: [...]
1.	Apple Swift version 5.3 (swiftlang-1200.0.28.1 clang-1200.0.30.1)
2.	While evaluating request TypeCheckSourceFileRequest(source_file "/Users/ngiancecchi/Projects/ios-app/Subprojects/LoungeFoundation/LoungeFoundationTests/ConfigTests.swift")
3.	While evaluating request TypeCheckFunctionBodyUntilRequest(LoungeFoundationTests.(file).ConfigTests.testPostsNotification()@/Users/ngiancecchi/Projects/ios-app/Subprojects/LoungeFoundation/LoungeFoundationTests/ConfigTests.swift:46:10, )
4.	While type-checking statement at [/Users/ngiancecchi/Projects/ios-app/Subprojects/LoungeFoundation/LoungeFoundationTests/ConfigTests.swift:46:34 - line:53:5] RangeText="{
        let newConfig: Config = .mockedWith(appDomainID: 5555)
        let expectedNotification = Notification(name: .newConfigAvailable, object: newConfig)

        expect {
            Config.current = newConfig
        }.toEventually(postNotifications(contain(expectedNotification, from: newConfig)))
    "
5.	While type-checking expression at [/Users/ngiancecchi/Projects/ios-app/Subprojects/LoungeFoundation/LoungeFoundationTests/ConfigTests.swift:50:9 - line:52:89] RangeText="expect {
            Config.current = newConfig
        }.toEventually(postNotifications(contain(expectedNotification, from: newConfig))"
0  swift                    0x00000001087a5a85 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
1  swift                    0x00000001087a4a85 llvm::sys::RunSignalHandlers() + 85
2  swift                    0x00000001087a603f SignalHandler(int) + 111
3  libsystem_platform.dylib 0x00007fff6ed735fd _sigtramp + 29
4  libsystem_kernel.dylib   0x00007fff6ecbf35e __ioctl + 10
5  swift                    0x0000000104ff1413 (anonymous namespace)::ExprRewriter::coerceCallArguments(swift::Expr*, swift::AnyFunctionType*, swift::ConcreteDeclRef, swift::ApplyExpr*, llvm::ArrayRef<swift::Identifier>, swift::constraints::ConstraintLocatorBuilder) + 8899
6  swift                    0x0000000104fee352 (anonymous namespace)::ExprRewriter::finishApply(swift::ApplyExpr*, swift::Type, swift::constraints::ConstraintLocatorBuilder, swift::constraints::ConstraintLocatorBuilder) + 11970
7  swift                    0x0000000104ff9b5d (anonymous namespace)::ExprRewriter::visitApplyExpr(swift::ApplyExpr*) + 477
8  swift                    0x0000000104fd0b02 (anonymous namespace)::ExprWalker::walkToExprPost(swift::Expr*) + 18
9  swift                    0x0000000104fc71e3 (anonymous namespace)::ExprWalker::rewriteTarget(swift::constraints::SolutionApplicationTarget) + 371
10 swift                    0x0000000104fc6ed0 swift::constraints::ConstraintSystem::applySolution(swift::constraints::Solution&, swift::constraints::SolutionApplicationTarget) + 6400
11 swift                    0x00000001051aff1a swift::TypeChecker::typeCheckExpression(swift::constraints::SolutionApplicationTarget&, bool&, swift::OptionSet<swift::TypeCheckExprFlags, unsigned int>) + 1242
12 swift                    0x00000001051af988 swift::TypeChecker::typeCheckExpression(swift::Expr*&, swift::DeclContext*, swift::TypeLoc, swift::ContextualTypePurpose, swift::OptionSet<swift::TypeCheckExprFlags, unsigned int>) + 360
13 swift                    0x0000000105294e4b swift::ASTVisitor<(anonymous namespace)::StmtChecker, void, swift::Stmt*, void, void, void, void>::visit(swift::Stmt*) + 9115
14 swift                    0x000000010529069a bool (anonymous namespace)::StmtChecker::typeCheckStmt<swift::BraceStmt>(swift::BraceStmt*&) + 314
15 swift                    0x000000010528f0a7 swift::TypeCheckFunctionBodyUntilRequest::evaluate(swift::Evaluator&, swift::AbstractFunctionDecl*, swift::SourceLoc) const + 2231
16 swift                    0x0000000105297e7d llvm::Expected<swift::TypeCheckFunctionBodyUntilRequest::OutputType> swift::Evaluator::getResultCached<swift::TypeCheckFunctionBodyUntilRequest, (void*)0>(swift::TypeCheckFunctionBodyUntilRequest const&) + 925
17 swift                    0x0000000105290148 swift::TypeCheckFunctionBodyUntilRequest::OutputType swift::evaluateOrDefault<swift::TypeCheckFunctionBodyUntilRequest>(swift::Evaluator&, swift::TypeCheckFunctionBodyUntilRequest, swift::TypeCheckFunctionBodyUntilRequest::OutputType) + 440
18 swift                    0x00000001052cda84 swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&, swift::SourceFile*) const + 1380
19 swift                    0x00000001052d0699 llvm::Expected<swift::TypeCheckSourceFileRequest::OutputType> swift::Evaluator::getResultUncached<swift::TypeCheckSourceFileRequest>(swift::TypeCheckSourceFileRequest const&) + 953
20 swift                    0x00000001052cd394 swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefault<swift::TypeCheckSourceFileRequest>(swift::Evaluator&, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType) + 164
21 swift                    0x0000000104448e78 swift::CompilerInstance::performSemaUpTo(swift::SourceFile::ASTStage_t) + 7576
22 swift                    0x000000010430996d swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6845
23 swift                    0x000000010428e277 main + 1255
24 libdyld.dylib            0x00007fff6eb7acc9 start + 1
25 libdyld.dylib            0x00000000000000d4 start + 18446603338658632716
error: Illegal instruction: 4 (in target 'LoungeFoundationTests' from project 'LoungeFoundation')

Just released v9.0.0-rc.3 including the fix for this. Please try it!

calling a throwing function inside expect no longer works:

That is due to #821 and I now understand that the change was not correct. I’ll revert it.

calls like: expect(something.that.returns.a.bool(), file: file, line: line).toEventually(beTrue()) fail because the expression is now expected after file and line params, not before.

Could you please reorder arguments.

calls like this result in compilation error: extra trailing closure passed in call:

Adding file argument label should fix that: expect(file: file, ...).

As a workaround, adding this function got my tests to run on Nimble 8.x using Xcode 12 GM.

public func expect<T>(_ expression: @escaping () throws -> T?) -> Expectation<T> {
    Nimble.expect(expression: expression)
}

so maybe it’s related to the 8->9 version change?

@rastersize Exactly, those are not related to #820.

@sraiteri Good suggestion, I’ve updated the title and issue description. As well as the SR.

It seems like Xcode Beta 6 is near identical to Beta 5. Same version of swiftc and almost no difference in build version for Xcode itself. Hopefully coming version will fix it 🤞