Skip to content

Instantly share code, notes, and snippets.

@omochi
Created August 9, 2018 05:05
Show Gist options
  • Save omochi/c2e32ca157fa70dc2a76c46e8fd6d7d7 to your computer and use it in GitHub Desktop.
Save omochi/c2e32ca157fa70dc2a76c46e8fd6d7d7 to your computer and use it in GitHub Desktop.

元ネタ

https://twitter.com/orga_chem/status/1026420884196605952


基本の形

func a(_ f: @escaping (Int) -> Void) {}

func b(_ f: (Int) -> Void) {
    a(f)
}

aaa.swift:26:7: error: passing non-escaping parameter 'f' to function expecting an @escaping closure

正しく @escaping についての問題であると表示している。

この出力が構築されるのは、 FailureDiagnosis::diagnoseContextualConversionError -> tryDiagnoseNonEscapingParameterToEscaping で diag::passing_noescape_to_escaping になるから。


今回の形だが問題が無い場合

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

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

一般の変換失敗エラーとして表示しているが、@escaping を表示しているので、問題点はわかる。

基本の形で発動した、 FailureDiagnosis::diagnoseContextualConversionError -> tryDiagnoseNonEscapingParameterToEscaping にはヒットしない

// Try to simplify irrelevant details of function types. のフローに入るが、特にどのパターンにも当たらず、すり抜ける。 ここでチェックしているのは関数それ自体の属性であって、 関数が引数に受ける関数の属性(ここで問題になっているescaping)には関係ない。 よって、デフォルトの diag::cannot_convert_argument_value のまま進行する。

最終的に関数 DiagnosticEngine::formatDiagnosticText の中の formatDiagnosticArgument の中で type->getString() された結果が、文言として埋め込まれる。 それが "(@escaping (Int) -> Void) -> Void" になっている。


今回の問題が出る場合

func c(_ g: @escaping (Int) -> Void) {}

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

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

このように、 g の型を明記せずに、 推論によって構築させると、 escaping が表示されない。

コンパイラのフローは同じだが、 最終的に type->getString() が "((Int) -> Void) -> Void" を返している!


さかのぼって調べると、

FailureDiagnosis::diagnoseContextualConversionError において、

auto srcFT = exprType->getAs<FunctionType>();
srcFT->getParams()[0].isEscaping()

の時点で false になっている。

よって、Semaで推論してFunctionTypeを構築するときに、 ParamのParameterTypeFlagsを正しくコピーできていない気がする!

@omochi
Copy link
Author

omochi commented Aug 9, 2018

エラーが不親切な件を調べてみました。
直接の原因はわかりました。
根っこの原因は、Sema(型推論)モジュールのバグではないか、というところまで推測したところです。
下記にわかったことを整理しています。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment