Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-11223] Generics Type Resolution Regression on Linux DEVELOPMENT-SNAPSHOT-2019-07-26-a (61261fcddf) #53624

Closed
Mordil opened this issue Jul 29, 2019 · 30 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself regression swift 5.2

Comments

@Mordil
Copy link

Mordil commented Jul 29, 2019

Previous ID SR-11223
Radar rdar://problem/53664957
Original Reporter @Mordil
Type Bug
Status Resolved
Resolution Done
Environment

Ubuntu 16.04

Swift DEVELOPMENT-SNAPSHOT-2019-07-26-a

Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Bug, 5.2Regression
Assignee @theblixguy
Priority Medium

md5: 665b8c631694dff27c64b4d3ef5cb046

Issue Description:

RediStack builds against the nightly Swift builds on Ubuntu 16.04 to catch any errors that might crop up in the future.

Between 2 weeks ago and now, I am seeing an assertion failure that states

Assertion failed: file /redi-stack/.build/checkouts/swift-nio/Sources/NIO/NIOAny.swift, line 75

while running unit tests.

Which in NIOAny.swift is

@inlinable
init<T>(_ value: T) {
    switch value {
    ... // omitted for sake of brevity
    default:
        assert(!(value is NIOAny)) // assert that is triggered
        self = .other(value)
    }
} 

This initializer is triggered from these methods in SwiftNIO's Channel.swift:

    public func write<T>(_ any: T) -> EventLoopFuture<Void> {

        return self.write(NIOAny(any))

    }

    public func write<T>(_ any: T, promise: EventLoopPromise<Void>?) {

        self.write(NIOAny(any), promise: promise)

    }

    public func writeAndFlush<T>(_ any: T) -> EventLoopFuture<Void> {

        return self.writeAndFlush(NIOAny(any))

    }

    public func writeAndFlush<T>(_ any: T, promise: EventLoopPromise<Void>?) {

        self.writeAndFlush(NIOAny(any), promise: promise)

    }

Which are called by this single code snippet in RedisConnection.swift:

// 'command' is a local variable of the struct 'RedisCommand'
// that holds a reference to an 'EventLoopPromise<RESPValue>' class
// and 'RESPValue' enum with associated types

if self.sendCommandsImmediately {
    return channel.writeAndFlush(command).flatMap { promise.futureResult }
} else {
    return channel.write(command).flatMap { promise.futureResult }
}

Full stack trace:

Current stack trace:
0    libswiftCore.so      0x00007f3f2c58f652    swift_reportError + 50 
1    libswiftCore.so      0x00007f3f2c5fdc53    _swift_stdlib_reportFatalErrorInFile + 115 
2    libswiftCore.so      0x00007f3f2c52a7b8    function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Exploded> of closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 296 
3    libswiftCore.so      0x00007f3f2c52a947    function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Exploded> of closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 87 
4    libswiftCore.so      0x00007f3f2c2ffa62    function signature specialization <Arg[1] = [Closure Propagated : closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #&#8203;1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never, Argument Types : [Swift.StaticStringSwift.UnsafeBufferPointer<Swift.UInt8>Swift.UIntSwift.UInt32]> of generic specialization <()> of Swift.String.withUTF8<A>((Swift.UnsafeBufferPointer<Swift.UInt8>) throws -> A) throws -> A + 258 
5    libswiftCore.so      0x00007f3f2c4fb734    function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded> of Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 516 
6    libswiftCore.so      0x00007f3f2c2ff0a9    Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 25 
7    redi-stackPackageTests.xctest 0x00005556f235e1c6    NIO.NIOAny._NIOAny.init<A>(A) -> NIO.NIOAny._NIOAny + 2214 at NIOAny.swift:75
8    redi-stackPackageTests.xctest 0x00005556f235d8b2    NIO.NIOAny.init<A>(A) -> NIO.NIOAny + 162 at NIOAny.swift:54
9    redi-stackPackageTests.xctest 0x00005556f22bef91    (extension in NIO):NIO.Channel.writeAndFlush<A>(A1) -> NIO.EventLoopFuture<()> + 129 at Channel.swift:246
10   redi-stackPackageTests.xctest 0x00005556f22befb0    (extension in NIO):NIO.Channel.writeAndFlush<A>(A1) -> NIO.EventLoopFuture<()> + 160 at Channel.swift:246
11   redi-stackPackageTests.xctest 0x00005556f2413a72    RediStack.RedisConnection.send(command: Swift.String, with: Swift.Array<RediStack.RESPValue>) -> NIO.EventLoopFuture<RediStack.RESPValue> + 2434 at RedisConnection.swift:213
12   redi-stackPackageTests.xctest 0x00005556f2415950    protocol witness for RediStack.RedisClient.send(command: Swift.String, with: Swift.Array<RediStack.RESPValue>) -> NIO.EventLoopFuture<RediStack.RESPValue> in conformance RediStack.RedisConnection : RediStack.RedisClient in RediStack + 16 at <compiler-generated>:0
13   redi-stackPackageTests.xctest 0x00005556f2400c87    (extension in RediStack):RediStack.RedisClient.set<A where A1: RediStack.RESPValueConvertible>(_: Swift.String, to: A1) -> NIO.EventLoopFuture<()> + 503 at StringCommands.swift:87
14   redi-stackPackageTests.xctest 0x00005556f241bbc2    RediStackIntegrationTests.BasicCommandsTests.test_delete() throws -> () + 1138 at BasicCommandsTests.swift:26
15   redi-stackPackageTests.xctest 0x00005556f2494a29    partial apply forwarder for RediStackIntegrationTests.BasicCommandsTests.test_delete() throws -> () + 9 at <compiler-generated>:0
16   redi-stackPackageTests.xctest 0x00005556f228c8cf    reabstraction thunk helper from @escaping @callee_guaranteed () -> (@error @owned Swift.Error) to @escaping @callee_guaranteed () -> (@out (), @error @owned Swift.Error) + 15 at <compiler-generated>:0
17   redi-stackPackageTests.xctest 0x00005556f2494a14    reabstraction thunk helper from @escaping @callee_guaranteed () -> (@error @owned Swift.Error) to @escaping @callee_guaranteed () -> (@out (), @error @owned Swift.Error)partial apply forwarder with unmangled suffix ".385" + 20 at <compiler-generated>:0
18   libXCTest.so         0x00007f3f2c7fdf11    partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed () -> (@out (), @error @owned Swift.Error) to @escaping @callee_guaranteed () -> (@error @owned Swift.Error) + 17 
19   libXCTest.so         0x00007f3f2c7fdd1e    partial apply forwarder for closure #&#8203;1 (XCTest.XCTestCase) throws -> () in XCTest.(test in _3BE257A46ADB477C7BF2D39968B39F9D)<A where A: XCTest.XCTestCase>((A) -> () throws -> ()) -> (XCTest.XCTestCase) throws -> () + 78 
20   libXCTest.so         0x00007f3f2c7fdc94    partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed XCTest.XCTestCase) -> (@error @owned Swift.Error) to @escaping @callee_guaranteed (@in_guaranteed XCTest.XCTestCase) -> (@out (), @error @owned Swift.Error) + 20 
21   libXCTest.so         0x00007f3f2c7fe819    reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed XCTest.XCTestCase) -> (@error @owned Swift.Error) to @escaping @callee_guaranteed (@in_guaranteed XCTest.XCTestCase) -> (@out (), @error @owned Swift.Error)partial apply forwarder with unmangled suffix ".16" + 9 
22   libXCTest.so         0x00007f3f2c7f0bd7    partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed XCTest.XCTestCase) -> (@out (), @error @owned Swift.Error) to @escaping @callee_guaranteed (@guaranteed XCTest.XCTestCase) -> (@error @owned Swift.Error) + 39 
23   libXCTest.so         0x00007f3f2c7fcfe9    XCTest.XCTestCase.invokeTest() -> () + 73 
24   libXCTest.so         0x00007f3f2c7fccac    XCTest.XCTestCase.perform(XCTest.XCTestRun) -> () + 172 
25   libXCTest.so         0x00007f3f2c800f1f    XCTest.XCTest.run() -> () + 191 
26   libXCTest.so         0x00007f3f2c7feb78    XCTest.XCTestSuite.perform(XCTest.XCTestRun) -> () + 232 
27   libXCTest.so         0x00007f3f2c800f1f    XCTest.XCTest.run() -> () + 191 
28   libXCTest.so         0x00007f3f2c7feb78    XCTest.XCTestSuite.perform(XCTest.XCTestRun) -> () + 232 
29   libXCTest.so         0x00007f3f2c800f1f    XCTest.XCTest.run() -> () + 191 
30   libXCTest.so         0x00007f3f2c7feb90    XCTest.XCTestSuite.perform(XCTest.XCTestRun) -> () + 256 
31   libXCTest.so         0x00007f3f2c800f1f    XCTest.XCTest.run() -> () + 191 
32   libXCTest.so         0x00007f3f2c7fbc63    XCTest.XCTMain(Swift.Array<(testCaseClass: XCTest.XCTestCase.Type, allTests: Swift.Array<(Swift.String, (XCTest.XCTestCase) throws -> ())>)>) -> Swift.Never + 1091 
33   redi-stackPackageTests.xctest 0x00005556f24ddfa1    main + 321 at LinuxMain.swift:10
34   libc.so.6                          0x00007f3f2aa1b740 __libc_start_main + 240
35   redi-stackPackageTests.xctest 0x00005556f225fd69    _start + 41
@Mordil
Copy link
Author

Mordil commented Jul 29, 2019

This pipeline passed on the trunk version of Swift 2 weeks ago: https://gitlab.com/Mordil/swift-redi-stack/pipelines/70820924

Now, it's failing as mentioned above, with no changes to RedisConnection, NIOAny, and Channel.

@belkadan
Copy link
Contributor

@swift-ci create

@mikeash
Copy link
Contributor

mikeash commented Aug 2, 2019

Looks like an error in the RediStack. The call stack when the assertion fires contains:

frame #&#8203;21: 0x0000000106e94f9b libswiftCore.dylib`_assertionFailure(prefix=<unavailable>, message=<unavailable>, file=<unavailable>, line=<unavailable>, flags=<unavailable>) at AssertCommon.swift:116:10
frame #&#8203;22: 0x000000010690699e redi-stackPackageTests`NIOAny._NIOAny.init<T>(value=<no summary available>) at NIOAny.swift:78:17
frame #&#8203;23: 0x0000000106905f82 redi-stackPackageTests`NIOAny.init<T>(value=<no summary available>) at NIOAny.swift:54:25
frame #&#8203;24: 0x0000000106865d40 redi-stackPackageTests`Channel.writeAndFlush<Self>(any=<no summary available>, self=<no summary available>) at Channel.swift:246:35
frame #&#8203;25: 0x00000001068b2511 redi-stackPackageTests`EmbeddedChannel.writeOutbound<T>(data=<no summary available>, self=<unavailable>) at Embedded.swift:503:13

The source code for frame 25 is:

502 @discardableResult public func writeOutbound<T>(_ data: T) throws -> BufferState {
-> 503 try writeAndFlush(NIOAny(data)).wait()

And frame 24 is:

245 public func writeAndFlush<T>(_ any: T) -> EventLoopFuture<Void> {
-> 246 return self.writeAndFlush(NIOAny(any))

So data gets wrapped in a NIOAny twice, which is not allowed.

I don't know why it didn't fail before, but it looks like the failure is correct.

@Mordil
Copy link
Author

Mordil commented Aug 2, 2019

CC @Lukasa @weissi

@weissi
Copy link
Member

weissi commented Aug 5, 2019

@mikeash but extension Channel has both

    public func writeAndFlush(_ data: NIOAny, promise: EventLoopPromise<Void>?) {
        pipeline.writeAndFlush(data, promise: promise)
    }

    public func writeAndFlush<T>(_ any: T) -> EventLoopFuture<Void> {
        return self.writeAndFlush(NIOAny(any))
    }

EmbeddedChannel does indeed (unnecessarily – artefact from a long time ago) wrap the value in NIOAny. But previously Swift was just fine with this and would select Channel.writeAndFlush(_ data: NIOAny) and now it seems to select Channel.writeAndFlush<T>(_ data: T) which then itself wraps in another NIOAny which is illegal.

I'm not saying we couldn't work around this issue in NIO but the problem is that it always worked and suddenly it doesn't seem to work anymore. @Mordil you can confirm that the very same code works on Swift 5.0, right?

@Mordil
Copy link
Author

Mordil commented Aug 5, 2019

Yes. This exact code works with Swift 5, and 5.1 on both Linux and macOS

@mikeash
Copy link
Contributor

mikeash commented Aug 5, 2019

How would it select the first writeAndFlush variant if it's not passing a second parameter?

@weissi
Copy link
Member

weissi commented Aug 5, 2019

@mikeash like so:

$ cat /tmp/test.swift
func foo<T>(_ data: T) {
    print("generic \(data)")
}

func foo(_ data: NIOAny) {
    print("boxed \(data)")
}

struct NIOAny {}

foo(NIOAny())
$ swift /tmp/test.swift
boxed NIOAny()

@mikeash
Copy link
Contributor

mikeash commented Aug 5, 2019

Right, but your quoted code has a promise parameter as well, which prevents that override from being selected. The analogous small example would be func foo(_ data: NIOAny, promise: Promise?). Is there a third override without the promise parameter?

@weissi
Copy link
Member

weissi commented Aug 5, 2019

@mikeash sorry, my bad, there's still two of those:

    public func writeAndFlush<T>(_ any: T, promise: EventLoopPromise<Void>?) {
        self.writeAndFlush(NIOAny(any), promise: promise)
    }
    public func writeAndFlush(_ data: NIOAny, promise: EventLoopPromise<Void>?) {
        pipeline.writeAndFlush(data, promise: promise)
    }

@weissi
Copy link
Member

weissi commented Aug 5, 2019

so we have all of those:

$ git grep 'public func writeAndFlush' | grep -v ChannelPipeline
Sources/NIO/Channel.swift:    public func writeAndFlush(_ data: NIOAny, promise: EventLoopPromise<Void>?) {
Sources/NIO/Channel.swift:    public func writeAndFlush<T>(_ any: T) -> EventLoopFuture<Void> {
Sources/NIO/Channel.swift:    public func writeAndFlush<T>(_ any: T, promise: EventLoopPromise<Void>?) {
Sources/NIO/ChannelInvoker.swift:    public func writeAndFlush(_ data: NIOAny, file: StaticString = #file, line: UInt = #line) -> EventLoopFuture<Void> {

and Channel is also a ChannelOutboundInvoker.

@mikeash
Copy link
Contributor

mikeash commented Aug 5, 2019

Got it, that should definitely be invoking the more specific variant of writeAndFlush then. If I modify the toy case to include a variant with file and line like that, it does indeed pick the right one, but it's clearly picking the wrong one in your real codebase. I'll bring this to the attention of the compiler team.

@mikeash
Copy link
Contributor

mikeash commented Aug 6, 2019

This simple test case illustrates the problem:

func foo<T>(_ data: T) {
  print("generic \(data)")
}
func foo(_ data: NIOAny, file: StaticString = #file) {
  print("boxed \(data)")
}
struct NIOAny {}
foo(NIOAny())

On current master, it calls the "generic" one, but it should call "boxed."

@xedin
Copy link
Member

xedin commented Aug 12, 2019

Oh, I think I know what is going on here. You'd need not one more `foo(NIOAny())` to see this:

On first `foo(NIOAny())` solver has this behavior:

---Constraint solving for the expression at [/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 - line:11:13]---
  (overload set choice binding $T2 := () -> NIOAny)
(common result type for $T0 is ())
---Initial constraints for the given expression---
(call_expr type='()' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 - line:11:13] arg_labels=_:
  (overloaded_decl_ref_expr type='$T0' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 - line:11:1] name=foo number_of_decls=2 function_ref=single decls=[
    rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6,
    rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6])
  (paren_expr type='(NIOAny)' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:4 - line:11:13]
    (call_expr type='NIOAny' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 - line:11:12] arg_labels=
      (type_expr type='NIOAny.Type' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 - line:11:5] typerepr='NIOAny')
      (tuple_expr type='()' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:11:11 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:11:11 - line:11:12]))))
Score: 0 0 0 0 0 0 0 0 0 0 0 0
Type Variables:
  $T0 [lvalue allowed] [noescape allowed] subtype_of_existential involves_type_vars bindings={} @ locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]
  $T1 [noescape allowed] as NIOAny @ locator@0x7fccb80ce1c0 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 -> function result]
  $T2 [noescape allowed] as () -> NIOAny @ locator@0x7fccb80ce230 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 -> apply function]
  $T3 [lvalue allowed] [inout allowed] [noescape allowed] as () @ locator@0x7fccb80ce380 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:5 -> apply argument]
  $T4 [noescape allowed] as () @ locator@0x7fccb80ce3d0 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 -> function result]

Active Constraints:

Inactive Constraints:
  disjunction [[locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]]]:$T0 bound to decl rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 : <T> (T) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 [[locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]]]; or $T0 bound to decl rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 : (NIOAny, StaticString) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 [[locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]]];
  (NIOAny) -> $T4 applicable fn $T0 [[locator@0x7fccb80ce458 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1 -> apply function]]];
Resolved overloads:
  selected overload set choice NIOAny.Type.init: $T2 == () -> NIOAny

  (attempting disjunction choice $T0 bound to decl rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 : <T> (T) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 [[locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]]];
    (overload set choice binding $T0 := ($T5) -> ())
    ($T5 potentially_incomplete bindings={(supertypes of) NIOAny})
    Initial bindings: $T5 := NIOAny
    (attempting type variable $T5 := NIOAny
      (found solution 0 0 0 0 0 0 0 0 0 0 0 0)
    )
  )
  (attempting disjunction choice $T0 bound to decl rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 : (NIOAny, StaticString) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 [[locator@0x7fccb80ce000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:11:1]]];
    (overload set choice binding $T0 := (NIOAny, StaticString) -> ())
    ($T6 bindings={(subtypes of) StaticString})
    Initial bindings: $T6 := StaticString
    (attempting type variable $T6 := StaticString
      (increasing score due to non-default literal)
      (solution is worse than the best solution)
    )
  )

But the second time around this happens:

---Constraint solving for the expression at [/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 - line:12:13]---
  (overload set choice binding $T2 := () -> NIOAny)
(common result type for $T0 is ())
---Initial constraints for the given expression---
(call_expr type='()' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 - line:12:13] arg_labels=_:
  (overloaded_decl_ref_expr type='$T0' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 - line:12:1] name=foo number_of_decls=2 function_ref=single decls=[
    rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6,
    rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6])
  (paren_expr type='(NIOAny)' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:4 - line:12:13]
    (call_expr type='NIOAny' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 - line:12:12] arg_labels=
      (type_expr type='NIOAny.Type' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 - line:12:5] typerepr='NIOAny')
      (tuple_expr type='()' location=/Users/xedin/work/swift/rdars/rdar53664957.swift:12:11 range=[/Users/xedin/work/swift/rdars/rdar53664957.swift:12:11 - line:12:12]))))
Score: 0 0 0 0 0 0 0 0 0 0 0 0
Type Variables:
  $T0 [lvalue allowed] [noescape allowed] subtype_of_existential involves_type_vars bindings={} @ locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]
  $T1 [noescape allowed] as NIOAny @ locator@0x7fcca80071c0 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 -> function result]
  $T2 [noescape allowed] as () -> NIOAny @ locator@0x7fcca8007230 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 -> apply function]
  $T3 [lvalue allowed] [inout allowed] [noescape allowed] as () @ locator@0x7fcca8007380 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:5 -> apply argument]
  $T4 [noescape allowed] as () @ locator@0x7fcca80073d0 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 -> function result]

Active Constraints:

Inactive Constraints:
  disjunction [[locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]]]:$T0 bound to decl rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 : <T> (T) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 [[locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]]]; or $T0 bound to decl rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 : (NIOAny, StaticString) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 [[locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]]];
  (NIOAny) -> $T4 applicable fn $T0 [[locator@0x7fcca8007458 [Call@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1 -> apply function]]];
Resolved overloads:
  selected overload set choice NIOAny.Type.init: $T2 == () -> NIOAny

  (attempting disjunction choice $T0 bound to decl rdar53664957.(file).foo@/Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 : <T> (T) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:1:6 [[locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]]];
    (overload set choice binding $T0 := ($T5) -> ())
    ($T5 potentially_incomplete bindings={(supertypes of) NIOAny})
    Initial bindings: $T5 := NIOAny
    (attempting type variable $T5 := NIOAny
      (found solution 0 0 0 0 0 0 0 0 0 0 0 0)
    )
  )
  (attempting disjunction choice $T0 bound to decl rdar53664957.(file).foo(_:file:)@/Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 : (NIOAny, StaticString) -> () at /Users/xedin/work/swift/rdars/rdar53664957.swift:5:6 [[locator@0x7fcca8007000 [OverloadedDeclRef@/Users/xedin/work/swift/rdars/rdar53664957.swift:12:1]]];
    (overload set choice binding $T0 := (NIOAny, StaticString) -> ())
    (found solution 0 0 0 0 0 0 0 0 0 0 0 0)
  )

And since there are two solutions it would pick the one with concrete types from parameters over the generic version as per ranking rules.

I wonder if this is happening because of #26074 @theblixguy do you want to take a closer look at this?

@theblixguy
Copy link
Collaborator

@xedin It is indeed caused by my change! I disabled the change and tested Mike's example above and it worked as expected. This is happening because we're adding an ArgumentConversion constraint (between defaultTy and paramTy).

@xedin
Copy link
Member

xedin commented Aug 12, 2019

Interesting, I think we need to approach this a bit differently then and have it do a conversion just line in "not yet type-checked" case...

@theblixguy
Copy link
Collaborator

@xedin Do you mean when the defaultValueExpr isn't type checked? We only add the constraint when it doesn't have a type.

@xedin
Copy link
Member

xedin commented Aug 12, 2019

Yeah, sorry I mean in the "not yet type-checked" case has to behave exactly the same as if defaultValue has been type-checked already, so it can't increase a score otherwise we'd end up producing different solutions.

@theblixguy
Copy link
Collaborator

Hmm so what do we do in that case? changing the `ArgumentConversion` constraint to just Conversion doesn't make any difference. For the example above, we never succeed the `if (defaultValueExpr->getType()) continue;` check, which means in this case we always end up with a defaultValueExpr of null type and end up adding the `ArgumentConversion` constraint. When we do have a type, we don't actually do anything, we just continue (as mentioned above).

@xedin
Copy link
Member

xedin commented Aug 12, 2019

That's a good question, we probably have no choice but to add conversion regardless whether `defaultValueExpr` has been type-checked or not, otherwise in presence of possibility of implicit conversions there is always going to be a risk to difference in behavior.

@theblixguy
Copy link
Collaborator

Okay, I can create a patch for that, but unfortunately it doesn't fix this issue when we add a Conversion constraint in both cases.

@xedin
Copy link
Member

xedin commented Aug 12, 2019

Sorry, we don't only have to add a constraint, we have to generate constraints for default value expression in both cases.

@theblixguy
Copy link
Collaborator

Hmm no luck in that case as well. Here's my patch:

diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index e469a14c138..e8700cbad8c 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -986,15 +986,12 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
             isa<MagicIdentifierLiteralExpr>(defaultValueExpr)))
         continue;

-      if (defaultValueExpr->getType())
-        continue;
-
       cs.generateConstraints(defaultValueExpr, param->getDeclContext());

       auto defaultTy = cs.getType(defaultValueExpr);
       auto paramTy = param->getType();
       cs.addConstraint(
-          ConstraintKind::ArgumentConversion, defaultTy, paramTy,
+          ConstraintKind::Conversion, defaultTy, paramTy,
           locator.withPathElement(ConstraintLocator::DefaultArgument));

       continue;

@xedin
Copy link
Member

xedin commented Aug 14, 2019

The problem is in ConstraintGenerator::visitLiteralExpr - if the expression has the type set already, it just returns that type instead of adding conformance constraint.

@theblixguy
Copy link
Collaborator

Oh, even if we always add the constraint, it makes no difference

@xedin
Copy link
Member

xedin commented Aug 16, 2019

I think we should revert the changes and re-think the strategy here.

@xedin
Copy link
Member

xedin commented Aug 30, 2019

@theblixguy Could you please revert the original PR until there is a fix for this problem?

@theblixguy
Copy link
Collaborator

Sorry, I missed your previous comment. I’ll create a PR shortly.

@xedin
Copy link
Member

xedin commented Aug 31, 2019

Thank you!

@theblixguy
Copy link
Collaborator

Fixed on master. Please verify using the next available master snapshot and mark the issue as closed. Thanks!

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself regression swift 5.2
Projects
None yet
Development

No branches or pull requests

7 participants