Swiftの型システムを読む その19 - Member制約とLookup

December 21, 2017

今回から何回かX[.name] == YのようなMemberというタイプの制約の生成、単一化周りを見てみる。まずは用語などを整理をしてみる。

Member

要はプロパティやメソッドなど。.(ドット)でアクセスする。

struct Dog {
     var name: String
     func bark() { print("わんわん") }
}
dog.name
dog.bark()

もうちょっというとValueDeclのサブクラスはだいたいメンバーになれるので、例えばプロパティ、メソッド以外にもネストしたstruct/class/enumの定義や、typealiasなども含まれそう。

また、そもそもMemberを持てる型は大きく2種類。

  • Nominalな型
    • つまりclass / struct / enum / protocol
  • ArchetypeType(制約付き)

MemberLookup/NameLookup

与えられた名前からメンバーを探すことをMemberLookupという。 Sema内ではConstraintSystem::performMemberLookupがエントリーポイントで、幾つかのSema関連クラスを通ってASTNameLookup.cppの関数を呼び出している。

スクリーンショット 2017-12-21 18.41.24.png (171.7 kB)

いつperformMemberLookupがされるかというと、主にMemberに関する制約生成~Simplify時だが、大きく分けると2つの関数から呼ばれる。

  • ConstraintSystem::addValueMemberConstraint
  • ConstraintSystem::addUnresolvedValueMemberConstraint

UnresolvedなExprたち

いくつかの文脈でUnresolvedという単語がでてくるので確認しておく。 基本的には意味どおり「まだ何を指しているかわからない状態」。

例えば以下のようなコードのparse直後のASTを見てみると

enum E { case a }
func f(_ e: E) { }
f(.a)
(call_expr type='<null>' arg_labels=_:
  (unresolved_decl_ref_expr type='<null>' name=f function_ref=unapplied)
  (paren_expr type='<null>'
    (unresolved_member_expr type='<null>' name='a' arg_labels='))))))
  • unresolved_decl_ref_expr
    • 関数など、なにか他のところで定義されたものを指しているが、分からない状態。上で言うとf
  • unresolved_member_expr
    • そのメンバーが属するstruct/class/enumなどが省略された場合はこれになる。上で言うと.a

もし.aを省略せずにE.aと書いた場合にはまた別のASTになる。

(call_expr type='<null>' arg_labels=_:
  (unresolved_decl_ref_expr type='<null>' name=f function_ref=unapplied)
  (paren_expr type='<null>'
    (unresolved_dot_expr type='<null>' field 'a' function_ref=unapplied
      (unresolved_decl_ref_expr type='<null>' name=E function_ref=unapplied)))))))
  • unresolved_dot_expr
    • そのメンバーが属するstruct/class/enumなどが明示的に書かれている場合には.aはこのASTになる。

Unresolvedはいつ解決される?

  • unresolved_dot_exprの場合は制約生成時にConstraintGenerator::addValueMemberConstraintで制約追加される。その際にperformMemberLookupされる。

  • unresolved_member_exprの場合は制約生成時にConstraintGenerator:: addUnresolvedValueMemberConstraint で制約追加される。その際にperformMemberLookupされる。

  • unresolved_decl_ref_exprの場合はExprの型チェックのPreCheckと呼ばれるフェーズで解決される。

Qualified/Unqualified

fとかのように何かのメンバーでないものを指すときは「Unqualified」。 E.aのように何かのメンバーであるものを指すときは「Qualified」

AST内でのNameLookup時は区別される。

まとめ

とりあえず用語をみたので、次はもう少し具体的に型推論周りなど見てみる。

このエントリーをはてなブックマークに追加