Steepコードリーディング(8日目)
2週間遅れております。
Steep::Services::TypeCheckService#type_check_file
Source.parse
は内部でparser gemを利用しています。steepアノテーションを拾ってるみたいですね。拾ったアノテーションはSteep::AST::Annotation::Collection
で仕分けされてます。TypeCheckService.type_check
からは何してるのか全然わからない...。
def type_check_file(target:, subtyping:, path:, text:)
Steep.logger.tagged "#type_check_file(#{path}@#{target.name})" do
source = Source.parse(text, path: path, factory: subtyping.factory)
typing = TypeCheckService.type_check(source: source, subtyping: subtyping, constant_resolver: yield, cursor: nil)
ignores = Source::IgnoreRanges.new(ignores: source.ignores)
SourceFile.with_typing(path: path, content: text, node: source.node, typing: typing, ignores: ignores)
end
rescue AnnotationParser::SyntaxError => exn
error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: exn.location)
SourceFile.with_syntax_error(path: path, content: text, error: error)
rescue ::Parser::SyntaxError => exn
error = Diagnostic::Ruby::SyntaxError.new(message: exn.message, location: (_ = exn).diagnostic.location)
SourceFile.with_syntax_error(path: path, content: text, error: error)
rescue EncodingError => exn
SourceFile.no_data(path: path, content: "")
rescue RuntimeError => exn
Steep.log_error(exn)
SourceFile.no_data(path: path, content: text)
end
TypeCheckService#.type_check
subtyping.factory
はSteep::AST::Types::Factory
オブジェクトであり、subtyping.factory.definition_builder
はRBS::DefinitionBuilder.new(env: env)
であり、build_instance(AST::Builtin::Object.module_name)
とはつまり、RBS::DefinitionBuilder.new(env: env).build_instance(AST::Builtin::Object.module_name)
...。ということはdefinitionとはRBS定義を表現するオブジェクトかなぁ。
annotationとdefinitionで型情報が揃うので、それをtypingとして返しているのかな...?
def self.type_check(source:, subtyping:, constant_resolver:, cursor:)
annotations = source.annotations(block: source.node, factory: subtyping.factory, context: nil)
definition = subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name)
const_env = TypeInference::ConstantEnv.new(
factory: subtyping.factory,
context: nil,
resolver: constant_resolver
)
type_env = TypeInference::TypeEnv.new(const_env)
type_env = TypeInference::TypeEnvBuilder.new(
TypeInference::TypeEnvBuilder::Command::ImportConstantAnnotations.new(annotations),
TypeInference::TypeEnvBuilder::Command::ImportGlobalDeclarations.new(subtyping.factory),
TypeInference::TypeEnvBuilder::Command::ImportInstanceVariableDefinition.new(definition, subtyping.factory),
TypeInference::TypeEnvBuilder::Command::ImportInstanceVariableAnnotations.new(annotations),
TypeInference::TypeEnvBuilder::Command::ImportLocalVariableAnnotations.new(annotations)
).build(type_env)
context = TypeInference::Context.new(
block_context: nil,
module_context: TypeInference::Context::ModuleContext.new(
instance_type: AST::Builtin::Object.instance_type,
module_type: AST::Builtin::Object.module_type,
implement_name: nil,
nesting: nil,
class_name: AST::Builtin::Object.module_name,
instance_definition: subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name),
module_definition: subtyping.factory.definition_builder.build_singleton(AST::Builtin::Object.module_name)
),
method_context: nil,
break_context: nil,
self_type: AST::Builtin::Object.instance_type,
type_env: type_env,
call_context: TypeInference::MethodCall::TopLevelContext.new,
variable_context: TypeInference::Context::TypeVariableContext.empty
)
typing = Typing.new(source: source, root_context: context, cursor: cursor)
construction = TypeConstruction.new(
checker: subtyping,
annotations: annotations,
source: source,
context: context,
typing: typing
)
construction.synthesize(source.node) if source.node
typing
end
うーん、ちゃんと理解するにはじっくり読む必要がありそう。隙間時間で理解できるようなものじゃない気がしてきたなぁ。
type_check_fileはRBS定義のSyntaxErrorなどを検査をしながら最終的に型情報のオブジェクトを返している、ような気がする。 違いました。
steepのアノテーションを増やしたいとか何か問題を見つけたらSteep::AST::Annotation::Collection
を見るとよさそうなのはわかった。