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

Disable mixin tracking when we do includes for probing #1019

Merged
merged 2 commits into from
Jun 29, 2022
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
34 changes: 18 additions & 16 deletions lib/tapioca/runtime/dynamic_mixin_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,24 @@ def initialize(constant)
# before the actual include
before = singleton_class.ancestors
# Call the actual `include` method with the supplied module
super(mod).tap do
# Take a snapshot of the list of singleton class ancestors
# after the actual include
after = singleton_class.ancestors
# The difference is the modules that are added to the list
# of ancestors of the singleton class. Those are all the
# modules that were `extend`ed due to the `include` call.
#
# We record those modules on our lookup table keyed by
# the included module with the values being all the modules
# that that module pulls into the singleton class.
#
# We need to reverse the order, since the extend order should
# be the inverse of the ancestor order. That is, earlier
# extended modules would be later in the ancestor chain.
mixins_from_modules[mod] = (after - before).reverse!
::Tapioca::Runtime::Trackers::Mixin.with_disabled_registration do
super(mod).tap do
# Take a snapshot of the list of singleton class ancestors
# after the actual include
after = singleton_class.ancestors
# The difference is the modules that are added to the list
# of ancestors of the singleton class. Those are all the
# modules that were `extend`ed due to the `include` call.
#
# We record those modules on our lookup table keyed by
# the included module with the values being all the modules
# that that module pulls into the singleton class.
#
# We need to reverse the order, since the extend order should
# be the inverse of the ancestor order. That is, earlier
# extended modules would be later in the ancestor chain.
mixins_from_modules[mod] = (after - before).reverse!
end
end
rescue Exception # rubocop:disable Lint/RescueException
# this is a best effort, bail if we can't perform this
Expand Down
16 changes: 16 additions & 0 deletions lib/tapioca/runtime/trackers/mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Mixin

@constants_to_mixin_locations = {}.compare_by_identity
@mixins_to_constants = {}.compare_by_identity
@enabled = true

class Type < T::Enum
enums do
Expand All @@ -18,6 +19,19 @@ class Type < T::Enum
end
end

sig do
type_parameters(:Result)
.params(block: T.proc.returns(T.type_parameter(:Result)))
.returns(T.type_parameter(:Result))
end
def self.with_disabled_registration(&block)
@enabled = false

block.call
ensure
@enabled = true
end

sig do
params(
constant: Module,
Expand All @@ -26,6 +40,8 @@ class Type < T::Enum
).void
end
def self.register(constant, mixin, mixin_type)
return unless @enabled

location = Reflection.required_from_location

constants = constants_with_mixin(mixin)
Expand Down
32 changes: 32 additions & 0 deletions spec/tapioca/gem/pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,38 @@ def hello; end
assert_includes(compiled, object_output)
end

it "compiles dynamic includes into Object" do
add_ruby_file("ext.rb", <<~RUBY)
module Foo
# This class will trigger an include into
# Object every time it is included. This will end
# up triggering a mixin from `DynamicMixinCompiler`
# which will mess up mixin attribution if we have
# not disabled mixin tracking from dynamic mixin
# compiler.
module API
def self.included(_mod)
Object.send(:include, Foo::ObjectMethods)
end
end

module ObjectMethods; end
end

module Bar
include Foo::API
end
RUBY

output = template(<<~RBI)
class Object < ::BasicObject
include ::Foo::ObjectMethods
end
RBI

assert_includes(compile, output)
end

it "compiles mixins in the correct order" do
add_ruby_file("bar.rb", <<~RUBY)
module ModuleA
Expand Down