Skip to content

Instantly share code, notes, and snippets.

@omochi omochi/
Last active Aug 11, 2018

What would you like to do?
func c(_ g: @escaping (Int) -> Void) {}

func a() {
    let f: ((Int) -> Void) -> Void
    f = { (g) -> Void in

This code prints this useless error message.

error: cannot assign value of type '((Int) -> Void) -> Void' to type '((Int) -> Void) -> Void'

Expected is

error: cannot assign value of type '(@escaping (Int) -> Void) -> Void' to type '((Int) -> Void) -> Void'

I investigated this issue.

In this case, so type check is failed, type for error message is also reconstructed by ConstraintSystem.

CS say this.

`g` in declaration is ParenType( TypeVariableType(1) )
`g` in call of `c` is super type of (Int) -> Void
(TypeVariable ID is dummy for explanation)

CS find (Int) -> Void as possible binding of TypeVariableType(1). This is FunctionType and it has @escaping by representing isNoEscape == false internally. Finally, type of closure at right hand side of assignment is FunctionType ( ParenType( (Int) -> Void ) -> Void ).

Unfortunately, compiler prints this as ((Int -> Void) -> Void). To print (@escaping (Int -> Void) -> Void), isEscaping flag is needed at ParenType.

But in solving process, ConstraintSystem::simplifyType() just only replace TypeVariableType and does not affect ParenType at one outer side of this. ParenType stay here in first time for (g), ofcource it does not have isEscaping before solving constrains.

I try to rewrite type tree immediately after simplifyType for this pattern: FunctionType ( ParenType ( F1: FunctionType(...) ) -> * ), F1 is converted from TypeVariable. I have succeeded just rewriting. But it cause other problem.

Rewriting type tree breaks necessary equality relation.

func callMethodsOnOpaqueFunction<X, Y, U>(
  o: OpaqueFunction<X, Y>, 
  t: @escaping (X) -> Y, 
  u: U) 
  _ = o.inAndOutTuples(x: 
      { $0 }

class Opaque<T> {
  typealias ObnoxiousTuple = (T, (T) -> T)

  func inAndOutTuples(x: ObnoxiousTuple) -> ObnoxiousTuple { return x }

class OpaqueFunction<U, V>: Opaque<(U) -> V> {}

With this code, compiler fail AST verification.

tuple_expr element type mismatch:
  field: ((X) -> Y) -> (X) -> Y
  element: (@escaping (X) -> Y) -> (X) -> Y

I think that to solve this issue, ConstraintSystem has to track information about @escaping and whether it is explicit or implicit in AST. For example, ((Int) -> Void)? has implicit @escaping. And bind this information to type variable. To do this, current design around ParenType and FunctionType is looking bad. This idea is too hard for my skill so I suspended work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.