Skip to content

Commit

Permalink
Allow to annotate "self" on toplevel
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tk0miya committed Jan 3, 2025
1 parent 850c66f commit 89941cd
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 15 deletions.
29 changes: 22 additions & 7 deletions lib/steep/services/type_check_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions smoke/toplevel_annotations/Steepfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
target :test do
check "*.rb"

implicitly_returns_nil! true

configure_code_diagnostics(Steep::Diagnostic::Ruby.all_error)
end
7 changes: 7 additions & 0 deletions smoke/toplevel_annotations/a.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @type self: String

succ
to_s
each_line do |line|
puts line
end
1 change: 1 addition & 0 deletions smoke/toplevel_annotations/test_expectations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--- []
29 changes: 21 additions & 8 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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
Expand Down

0 comments on commit 89941cd

Please sign in to comment.