0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SteepコードリーディングAdvent Calendar 2024

Day 7

Steepコードリーディング(7日目)

Posted at

Steepコードリーディング(7日目)

7日目とか書いておきながら本日は15日です。まーじでコード読む時間が確保できない...。
今回は型検査してそうなservice.typecheck_sourceを追っていく。

Steep::Services::TypeCheckService

Steep::Services::TypeCheckService#typecheck_source

signature_servicesを見にいく必要がありそうだが、最終的にfile.diagnosticsで型検査をしていそうな雰囲気。

def typecheck_source(path:, target:)
  return unless target

  Steep.logger.tagged "#typecheck_source(path=#{path})" do
    Steep.measure "typecheck" do
      signature_service = signature_services[target.name]
      subtyping = signature_service.current_subtyping

      if subtyping
        text = source_files[path].content
        file = type_check_file(target: target, subtyping: subtyping, path: path, text: text) { signature_service.latest_constant_resolver }
        source_files[path] = file

        file.diagnostics
      end
    end
  end
end

signature_servicesinitializeで作られている。

Steep::Services::TypeCheckService#initialize

target毎にSignatureService.load_from(loader)を保持したHashが入っている。loaderってのが型ファイルを取得するのに必要な情報を持っていそうだが、なんだろう?

def initialize(project:)
  @project = project

  @source_files = {}
  @signature_services = project.targets.each.with_object({}) do |target, hash| #$ Hash[Symbol, SignatureService]
    loader = Project::Target.construct_env_loader(options: target.options, project: project)
    hash[target.name] = SignatureService.load_from(loader)
  end
  @signature_validation_diagnostics = project.targets.each.with_object({}) do |target, hash| #$ Hash[Symbol, Hash[Pathname, Array[Diagnostic::Signature::Base]]]
    hash[target.name] = {}
  end
end

Steep::Project::Target

Steep::Project::Target#.construct_env_loader

RBS::EnvironmentLoaderを返している。RBS::EnvironmentLoaderってなんだろう...。ruby/rbsのコードを見に行ってみたけどよくわからず、なんとなく利用しているgemとそのバージョンを管理しているオブジェクトかなーと予想。

def self.construct_env_loader(options:, project:)
  repo = RBS::Repository.new(no_stdlib: options.paths.customized_stdlib?)

  if options.paths.stdlib_root
    repo.add(project.absolute_path(options.paths.stdlib_root))
  end

  options.paths.repo_paths.each do |path|
    repo.add(project.absolute_path(path))
  end

  core_root_path =
    if options.paths.customized_core?
      if options.paths.core_root
        project.absolute_path(options.paths.core_root)
      end
    else
      RBS::EnvironmentLoader::DEFAULT_CORE_ROOT
    end

  loader = RBS::EnvironmentLoader.new(core_root: core_root_path, repository: repo)

  options.libraries.each do |lib|
    name, version = lib.split(/:/, 2)
    name or raise
    loader.add(library: name, version: version)
  end
  loader.add_collection(options.collection_lock) if options.collection_lock

  loader
end

Steep::SignatureService

Steep::SignatureService#.load_from

うーん、これはRBSのコードリーディングも必要そうだなぁ。
サッと読んでみたけど、これも利用しているgemの型にまつわる何かのようで、ただ具体的に何みたいなのはちょっとよくわからなかった。最終的には自身のインスタンスを返している。

def self.load_from(loader)
  env = RBS::Environment.from_loader(loader).resolve_type_names
  new(env: env)
end

Steep::SignatureService#current_subtyping

statusLoadedStatusオブジェクトであればstatus.subtypingを返し、そうでなければnilを返している。

このあたりで完全に置いてけぼりになっている感覚を感じる。

statusinitializeLoadedStatusオブジェクトが代入されており、それ以外ではSyntaxErrorStatusが再代入されている箇所がある。つまり、SyntaxErrorが起きているようなものでない限りstatus.subtypingを返すというものみたい。

def current_subtyping
  if status.is_a?(LoadedStatus)
    status.subtyping
  end
end

Steep::SignatureService::LoadedStatus#subtyping

builderとはRBS::DefinitionBuilder.new(env: env)←これ。
抽象構文木が出てきたのでいよいよ型検査という雰囲気が出てきた。

def subtyping
  @subtyping ||= begin
    factory = AST::Types::Factory.new(builder: builder)
    interface_builder = Interface::Builder.new(factory)
    Subtyping::Check.new(builder: interface_builder)
  end
end

大部分でよくわからないまま進んでおり、かなり置いてけぼり感を感じているがちゃんと目的は果たせるのだろうか...。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?