Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cases where Module#constants has been redefined #1591

Merged
merged 4 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require: rubocop-rubycw
AllCops:
TargetRubyVersion: 2.7
TargetRubyVersion: 3.0
DisabledByDefault: true
Exclude:
- 'vendor/bundle/**/*'
Expand Down
16 changes: 6 additions & 10 deletions lib/rbs/prototype/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require_relative 'runtime/helpers'
require_relative 'runtime/value_object_generator'
require_relative 'runtime/reflection'

module RBS
module Prototype
Expand Down Expand Up @@ -422,7 +423,7 @@ def generate_methods(mod, module_name, members)

def generate_constants(mod, decls)
module_name = const_name!(mod)
mod.constants(false).sort.each do |name|
Reflection.constants_of(mod, false).sort.each do |name|
next if todo_object&.skip_constant?(module_name: module_name, name: name)

begin
Expand All @@ -432,10 +433,10 @@ def generate_constants(mod, decls)
next
end

next if object_class(value).equal?(Class)
next if object_class(value).equal?(Module)
next if Reflection.object_class(value).equal?(Class)
next if Reflection.object_class(value).equal?(Module)

unless object_class(value).name
unless Reflection.object_class(value).name
RBS.logger.warn("Skipping constant #{name} #{value} of #{mod} as an instance of anonymous class")
next
end
Expand All @@ -453,7 +454,7 @@ def generate_constants(mod, decls)
when ENV
Types::ClassInstance.new(name: TypeName("::RBS::Unnamed::ENVClass"), args: [], location: nil)
else
value_type_name = to_type_name(const_name!(object_class(value)), full_name: true).absolute!
value_type_name = to_type_name(const_name!(Reflection.object_class(value)), full_name: true).absolute!
args = type_args(value_type_name)
Types::ClassInstance.new(name: value_type_name, args: args, location: nil)
end
Expand Down Expand Up @@ -631,11 +632,6 @@ def ensure_outer_module_declarations(mod)
destination
end

def object_class(value)
@object_class ||= Object.instance_method(:class)
@object_class.bind_call(value)
end

def type_args(type_name)
if class_decl = env.class_decls.fetch(type_name.absolute!, nil)
class_decl.type_params.size.times.map { Types::Bases::Any.new(location: nil) }
Expand Down
19 changes: 19 additions & 0 deletions lib/rbs/prototype/runtime/reflection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module RBS
module Prototype
class Runtime
module Reflection
def self.object_class(value)
@object_class ||= Object.instance_method(:class)
@object_class.bind_call(value)
end

def self.constants_of(mod, inherit = true)
@constants_of ||= Module.instance_method(:constants)
@constants_of.bind_call(mod, inherit)
end
end
end
end
end
6 changes: 6 additions & 0 deletions sig/prototype/runtime.rbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
module RBS
module Prototype
class Runtime
module Reflection
def self.object_class: (Module value) -> Class

def self.constants_of: (Module mod, ?bool inherit) -> Array[Symbol]
end

module Helpers
private

Expand Down
26 changes: 26 additions & 0 deletions test/rbs/runtime_prototype_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -931,4 +931,30 @@ class DataDirectInherit < ::Data
end
end
end

class Redefined
def self.constants = raise
def class = raise
end

def test_reflection
SignatureManager.new do |manager|
manager.build do |env|
p = Runtime.new(patterns: ["RBS::RuntimePrototypeTest::Redefined"], env: env, merge: false)
assert_write p.decls, <<~RBS
module RBS
class RuntimePrototypeTest < ::Test::Unit::TestCase
class Redefined
def self.constants: () -> untyped

public

def class: () -> untyped
end
end
end
RBS
end
end
end
end