From 89941cd4a33da22d16879bd8ab57a92d9d4d0b91 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 3 Jan 2025 20:50:14 +0900 Subject: [PATCH] Allow to annotate "self" on toplevel To support ERB, this allows to annotate "self" on the top level context. It effects to the whole of the file. It will also help to support other DSLs (ex. Gemfile, Rakefile, and so on). Example: ``` # @type self: Gemfile group :develop do gem 'steep' gem 'rbs' end ``` ``` # @type self: Raketask namespace :my_group do desc "My Task" task :my_task do ... end end ``` refs: #1409 --- lib/steep/services/type_check_service.rb | 29 ++++++++++++++----- smoke/toplevel_annotations/Steepfile | 7 +++++ smoke/toplevel_annotations/a.rb | 7 +++++ .../test_expectations.yml | 1 + test/test_helper.rb | 29 ++++++++++++++----- 5 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 smoke/toplevel_annotations/Steepfile create mode 100644 smoke/toplevel_annotations/a.rb create mode 100644 smoke/toplevel_annotations/test_expectations.yml diff --git a/lib/steep/services/type_check_service.rb b/lib/steep/services/type_check_service.rb index 3f91e8417..1c2fd4fdc 100644 --- a/lib/steep/services/type_check_service.rb +++ b/lib/steep/services/type_check_service.rb @@ -302,7 +302,22 @@ def type_check_file(target:, subtyping:, path:, text:) 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) + case annotations.self_type + when AST::Types::Name::Instance + module_name = annotations.self_type.name + module_type = AST::Types::Name::Singleton.new(name: module_name) + instance_type = annotations.self_type + when AST::Types::Name::Singleton + module_name = annotations.self_type.name + module_type = annotations.self_type + instance_type = annotations.self_type + else + module_name = AST::Builtin::Object.module_name + module_type = AST::Builtin::Object.module_type + instance_type = AST::Builtin::Object.instance_type + end + + definition = subtyping.factory.definition_builder.build_instance(module_name) const_env = TypeInference::ConstantEnv.new( factory: subtyping.factory, @@ -321,17 +336,17 @@ def self.type_check(source:, subtyping:, constant_resolver:, cursor:) 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, + instance_type: instance_type, + module_type: 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) + class_name: module_name, + instance_definition: subtyping.factory.definition_builder.build_instance(module_name), + module_definition: subtyping.factory.definition_builder.build_singleton(module_name) ), method_context: nil, break_context: nil, - self_type: AST::Builtin::Object.instance_type, + self_type: instance_type, type_env: type_env, call_context: TypeInference::MethodCall::TopLevelContext.new, variable_context: TypeInference::Context::TypeVariableContext.empty diff --git a/smoke/toplevel_annotations/Steepfile b/smoke/toplevel_annotations/Steepfile new file mode 100644 index 000000000..2a84dd117 --- /dev/null +++ b/smoke/toplevel_annotations/Steepfile @@ -0,0 +1,7 @@ +target :test do + check "*.rb" + + implicitly_returns_nil! true + + configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error) +end diff --git a/smoke/toplevel_annotations/a.rb b/smoke/toplevel_annotations/a.rb new file mode 100644 index 000000000..175ad617f --- /dev/null +++ b/smoke/toplevel_annotations/a.rb @@ -0,0 +1,7 @@ +# @type self: String + +succ +to_s +each_line do |line| + puts line +end diff --git a/smoke/toplevel_annotations/test_expectations.yml b/smoke/toplevel_annotations/test_expectations.yml new file mode 100644 index 000000000..dcd024e99 --- /dev/null +++ b/smoke/toplevel_annotations/test_expectations.yml @@ -0,0 +1 @@ +--- [] diff --git a/test/test_helper.rb b/test/test_helper.rb index f4745e7bf..2abcb3b29 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -624,12 +624,25 @@ module TypeConstructionHelper # @rbs (Subtyping::Check, Source, ?cursor: untyped) { (TypeConstruction, Typing) -> void } -> void def with_standard_construction(checker, source, cursor: nil) - self_type = parse_type("::Object") - annotations = source.annotations(block: source.node, factory: checker.factory, context: nil) resolver = RBS::Resolver::ConstantResolver.new(builder: checker.factory.definition_builder) const_env = ConstantEnv.new(factory: checker.factory, context: nil, resolver: resolver) + case annotations.self_type + when AST::Types::Name::Instance + module_name = annotations.self_type.name + module_type = AST::Types::Name::Singleton.new(name: module_name) + instance_type = annotations.self_type + when AST::Types::Name::Singleton + module_name = annotations.self_type.name + module_type = annotations.self_type + instance_type = annotations.self_type + else + module_name = AST::Builtin::Object.module_name + module_type = AST::Builtin::Object.module_type + instance_type = AST::Builtin::Object.instance_type + end + rbs_env = checker.factory.env type_env = Steep::TypeInference::TypeEnvBuilder.new( Steep::TypeInference::TypeEnvBuilder::Command::ImportGlobalDeclarations.new(checker.factory), @@ -642,16 +655,16 @@ def with_standard_construction(checker, source, cursor: nil) block_context: nil, method_context: nil, module_context: Context::ModuleContext.new( - instance_type: AST::Builtin::Object.instance_type, - module_type: AST::Builtin::Object.module_type, + instance_type: instance_type, + module_type: module_type, implement_name: nil, nesting: nil, - class_name: AST::Builtin::Object.module_name, - instance_definition: checker.factory.definition_builder.build_instance(AST::Builtin::Object.module_name), - module_definition: checker.factory.definition_builder.build_singleton(AST::Builtin::Object.module_name) + class_name: module_name, + instance_definition: checker.factory.definition_builder.build_instance(module_name), + module_definition: checker.factory.definition_builder.build_singleton(module_name) ), break_context: nil, - self_type: self_type, + self_type: instance_type, type_env: type_env, call_context: TypeInference::MethodCall::TopLevelContext.new(), variable_context: Context::TypeVariableContext.empty