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

Stop regenerating all value constants for reopened types #1385

Merged
merged 2 commits into from
Feb 9, 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
14 changes: 14 additions & 0 deletions lib/tapioca/gem/pipeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ def symbol_in_payload?(symbol_name)
@payload_symbols.include?(symbol_name)
end

sig { params(name: T.any(String, Symbol)).returns(T::Boolean) }
def constant_in_gem?(name)
return true unless Object.respond_to?(:const_source_location)

source_location, _ = Object.const_source_location(name)
return true unless source_location
# If the source location of the constant is "(eval)", all bets are off.
return true if source_location == "(eval)"

gem.contains_path?(source_location)
end

sig { params(method: UnboundMethod).returns(T::Boolean) }
def method_in_gem?(method)
source_location = method.source_location&.first
Expand Down Expand Up @@ -216,6 +228,7 @@ def compile_alias(name, constant)
mark_seen(name)

return if symbol_in_payload?(name)
return unless constant_in_gem?(name)

target = name_of(constant)
# If target has no name, let's make it an anonymous class or module with `Class.new` or `Module.new`
Expand All @@ -237,6 +250,7 @@ def compile_object(name, value)
mark_seen(name)

return if symbol_in_payload?(name)
return unless constant_in_gem?(name)

klass = class_of(value)

Expand Down
36 changes: 26 additions & 10 deletions spec/tapioca/cli/gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ class GemSpec < SpecWithProject
module Foo
PI = 3.1415

def self.bar(a = 1, b: 2, **opts)
def self.foo(a = 1, b: 2, **opts)
number = opts[:number] || 0
39 + a + b + number
end
end

module Reopened
E = 2.718281828459045
end
RB

FOO_RBI = <<~RBI
Expand All @@ -28,11 +32,13 @@ def self.bar(a = 1, b: 2, **opts)

module Foo
class << self
def bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
def foo(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
end
end

Foo::PI = T.let(T.unsafe(nil), Float)
module Reopened; end
Reopened::E = T.let(T.unsafe(nil), Float)
RBI

BAR_RB = <<~RB
Expand All @@ -44,6 +50,11 @@ def self.bar(a = 1, b: 2, **opts)
39 + a + b + number
end
end

module Reopened
PI = Math::PI
TAU = 2 * PI
end
RB

BAR_RBI = <<~RBI
Expand All @@ -60,6 +71,9 @@ def bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
end

Bar::PI = T.let(T.unsafe(nil), Float)
module Reopened; end
Reopened::PI = T.let(T.unsafe(nil), Float)
Reopened::TAU = T.let(T.unsafe(nil), Float)
RBI

BAZ_RB = <<~RB
Expand Down Expand Up @@ -282,7 +296,7 @@ class << self
write("rbi/foo.rbi", <<~RBI)
module Foo
sig { params(a: String, b: Integer, opts: T.untyped).void }
def self.bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
def self.foo(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
end
RBI

Expand All @@ -293,7 +307,7 @@ def foo; end
RBI

write("rbi/foo/bar/baz.rbi", <<~RBI)
module Foo:: Bar
module Foo::Bar
def bar; end
end
RBI
Expand All @@ -318,7 +332,7 @@ def foo; end

class << self
sig { params(a: String, b: Integer, opts: T.untyped).void }
def bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
def foo(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end
end
end

Expand All @@ -327,6 +341,8 @@ def bar; end
end

Foo::PI = T.let(T.unsafe(nil), Float)
module Reopened; end
Reopened::E = T.let(T.unsafe(nil), Float)
RBI

assert_empty_stderr(result)
Expand Down Expand Up @@ -435,7 +451,7 @@ def foo(a, b, c); end
write("rbi/foo.rbi", <<~RBI)
module Foo
class << self
def bar; end
def foo; end
end
end
RBI
Expand Down Expand Up @@ -483,7 +499,7 @@ def bar; end
it "must perform postrequire properly" do
foo = mock_gem("foo", "0.0.1") do
write("lib/foo.rb", FOO_RB)
write("lib/foo/secret.rb", "class Foo::Secret; end")
write("lib/foo/secret.rb", "class Secret; end")
end

@project.require_mock_gem(foo)
Expand All @@ -501,7 +517,7 @@ def bar; end

assert_project_file_equal("sorbet/rbi/gems/[email protected]", template(<<~RBI))
#{FOO_RBI.rstrip}
class Foo::Secret; end
class Secret; end
RBI

assert_empty_stderr(result)
Expand All @@ -511,7 +527,7 @@ class Foo::Secret; end
it "loads gems that are marked `require: false`" do
foo = mock_gem("foo", "0.0.1") do
write("lib/foo.rb", FOO_RB)
write("lib/foo/secret.rb", "class Foo::Secret; end")
write("lib/foo/secret.rb", "class Secret; end")
end

bar = mock_gem("bar", "1.0.0") do
Expand Down Expand Up @@ -543,7 +559,7 @@ module Foo
refute_project_file_exist("sorbet/rbi/gems/[email protected]")
assert_project_file_equal("sorbet/rbi/gems/[email protected]", template(<<~RBI))
#{FOO_RBI.rstrip}
class Foo::Secret; end
class Secret; end
RBI

assert_empty_stderr(result)
Expand Down
8 changes: 7 additions & 1 deletion spec/tapioca/gem/pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3639,7 +3639,7 @@ def tag?; end
assert_equal(output, compile)
end

it "handles class_env created classes and modules" do
it "handles class_eval created classes and modules" do
add_ruby_file("container.rb", <<~RUBY)
class Container
class_eval <<~EOF
Expand All @@ -3651,12 +3651,18 @@ module FooModule

Bar = 42
EOF

class_eval <<~EOF, __FILE__, __LINE__ + 1
class Baz
end
EOF
end
RUBY

output = template(<<~RBI)
class Container; end
Container::Bar = T.let(T.unsafe(nil), Integer)
class Container::Baz; end
class Container::FooClass; end
module Container::FooModule; end
RBI
Expand Down