Skip to content

Conversation

@xedin
Copy link
Contributor

@xedin xedin commented Feb 22, 2020

Enable solver to transitively infer bindings through argument conversion
constraints. That helps to infer bindings for (generic) parameters
from their arguments e.g.

func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
  fatalError()
}

func bar(_: Any?) {}

func test() {
  bar(foo("", ""))
}

In this case T can currently only be inferred as Any?
(based on parameter type of bar) although a complete
set of bindings for that type variable includes String
as well, which comes from use of T in argument position.

Inferring types transitively helps diagnostics as well because
it makes it possible to produce a better solution by attempting
e.g. default literal types inferred for arguments when the
problem is contextual e.g.

func foo<T>(_: T) -> T { ... }
func bar() {
   return foo(42)
}

In cases like this both Int and Void could be attempted for
result type of the function which makes it much easier to diagnose.

Resolves: rdar://problem/56212087

…ve" generic parameters

Consider following example:

```swift
struct MyType<TyA, TyB> {
  var a : TyA, b : TyB
}

typealias B<T1> = MyType<T1, T1>

_ = B(a: "foo", b: 42)
```

Here `T1` is equal to `TyA` and `TyB` so diagnostic about
conflicting arguments ('String' vs. 'Int') should only be
produced for "representative" `T1`.
… argument conversions

Enable solver to transitively infer bindings through argument conversion
constraints. That helps to infer bindings for (generic) parameters
from their arguments e.g.

```swift
func foo<T: ExpressibleByStringLiteral>(_: String, _: T) -> T {
  fatalError()
}

func bar(_: Any?) {}

func test() {
  bar(foo("", ""))
}
```

In this case `T` can currently only be inferred as `Any?`
(based on parameter type of `bar`) although a complete
set of bindings for that type variable includes `String`
as well, which comes from use of `T` in argument position.

Resolves: rdar://problem/56212087
In case of contextual failures such bindings could produce
better solutions with fewer fixes.
@xedin xedin requested a review from hborla February 22, 2020 01:53
@xedin
Copy link
Contributor Author

xedin commented Feb 22, 2020

@swift-ci please test

@xedin
Copy link
Contributor Author

xedin commented Feb 22, 2020

@swift-ci please test source compatibility

@LucianoPAlmeida
Copy link
Contributor

@xedin Just looking at this I was wondering if this in some way also fixes SR-9839

func foo(_ x: @escaping @convention(block) () -> Void) {}

func id<T>(_ x: T) -> T {
  return x
}

var qux: () -> Void = {}

foo(qux)
foo(id(qux)) // error: Cannot convert value of type '() -> Void' to expected argument type '@convention(block) () -> Void'

I'm not exactly sure, because still didn't work too much on it to know what's the problem,
But if I understand this correctly, the solver may be able to use the argument binding to infer the correct type for the generic type 'T' on the id function, so it would be able to infer the correct @convention(block) () -> Void type.
Not really sure, but maybe this makes sense and I thought it was worth asking :)

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 96297b7

@xedin
Copy link
Contributor Author

xedin commented Feb 22, 2020

@LucianoPAlmeida The way to solve problem described in SR-9839 is to make sure that matchFunctionTypes prefers matching convention vs. function type which requires implicit conversion (e.g. from () -> Void to @convention(block) () -> Void). Solver already attempts both types (() -> Void and @convention(block) () -> Void) for id(qux) but can't disambiguate them properly.

@xedin
Copy link
Contributor Author

xedin commented Feb 22, 2020

@swift-ci please test Linux platform

@LucianoPAlmeida
Copy link
Contributor

@LucianoPAlmeida The way to solve problem described in SR-9839 is to make sure that matchFunctionTypes prefers matching convention vs. function type which requires implicit conversion (e.g. from () -> Void to @convention(block) () -> Void). Solver already attempts both types (() -> Void and @convention(block) () -> Void) for id(qux) but can't disambiguate them properly.

@xedin Humm.. got it, Thanks. I’ll resume work there soon, I just thought that since that one involves generic arguments inference too, it could be related to this one in some way :)

@xedin xedin requested a review from DougGregor February 24, 2020 18:21
@xedin xedin merged commit b926250 into swiftlang:master Feb 24, 2020
xedin added a commit to xedin/swift that referenced this pull request Mar 8, 2020
… through argument conversions"

Reverts swiftlang#30006. It caused a regression that we'd like to address before re-landing:

```swift
struct X {
  var cgf: CGFloat
}

func test(x: X?) {
  let _ = (x?.cgf ?? 0) <= 0.5
}
```

This reverts commit 0a6b444.
This reverts commit ed25559.
This reverts commit 3e01160.
This reverts commit 96297b7.

Resolves: rdar://problem/60185506
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants