lib/steep/drivers/check.rb
module Steep
module Drivers
class Check
attr_reader :source_paths
attr_reader :signature_dirs
attr_reader :stdout
attr_reader :stderr
attr_accessor :verbose
attr_accessor :accept_implicit_any
attr_accessor :dump_all_types
attr_accessor :fallback_any_is_error
attr_accessor :allow_missing_definitions
attr_reader :labeling
include Utils::EachSignature
def initialize(source_paths:, signature_dirs:, stdout:, stderr:)
@source_paths = source_paths
@signature_dirs = signature_dirs
@stdout = stdout
@stderr = stderr
self.verbose = false
self.accept_implicit_any = false
self.dump_all_types = false
self.fallback_any_is_error = false
self.allow_missing_definitions = true
@labeling = ASTUtils::Labeling.new
end
def run
Steep.logger.level = Logger::DEBUG if verbose
env = AST::Signature::Env.new
each_signature(signature_dirs, verbose) do |signature|
env.add signature
end
builder = Interface::Builder.new(signatures: env)
check = Subtyping::Check.new(builder: builder)
validator = Utils::Validator.new(stdout: stdout, stderr: stderr, verbose: verbose)
validated = validator.run(env: env, builder: builder, check: check) do |sig|
stderr.puts "Validating #{sig.name} (#{sig.location.name}:#{sig.location.start_line})..." if verbose
end
unless validated
return 1
end
sources = []
each_ruby_source(source_paths, verbose) do |source|
sources << source
end
typing = Typing.new
sources.each do |source|
Steep.logger.tagged source.path do
Steep.logger.debug "Typechecking..."
annotations = source.annotations(block: source.node, builder: check.builder, current_module: AST::Namespace.root)
pp annotations if verbose
const_env = TypeInference::ConstantEnv.new(builder: check.builder, context: nil)
type_env = TypeInference::TypeEnv.build(annotations: annotations,
subtyping: check,
const_env: const_env,
signatures: check.builder.signatures)
construction = TypeConstruction.new(
checker: check,
annotations: annotations,
source: source,
self_type: AST::Builtin::Object.instance_type,
block_context: nil,
module_context: TypeConstruction::ModuleContext.new(
instance_type: nil,
module_type: nil,
implement_name: nil,
current_namespace: AST::Namespace.root,
const_env: const_env
),
method_context: nil,
typing: typing,
break_context: nil,
type_env: type_env
)
construction.synthesize(source.node)
end
end
if dump_all_types
lines = []
typing.nodes.each_value do |node|
begin
type = typing.type_of(node: node)
lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, type]
rescue
lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, nil]
end
end
lines.sort {|x,y| y <=> x }.reverse_each do |line|
source = line[3].loc.expression.source
stdout.puts "#{line[0]}:(#{line[2].join(",")}):(#{line[1].join(",")}):\t#{line[3].type}:\t#{line[4]}\t(#{source.split(/\n/).first})"
end
end
typing.errors.each do |error|
next if error.is_a?(Errors::FallbackAny) && !fallback_any_is_error
next if error.is_a?(Errors::MethodDefinitionMissing) && allow_missing_definitions
error.print_to stdout
end
end
end
end
end