tapioca 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e53d805bebee7cb1898eb795daebc5c7f586b5dea934a6056dfc2e1037168e83
4
- data.tar.gz: a9baac8cc53cc87f24495961dfe738603900e9818542c722b79211da2aaea84a
3
+ metadata.gz: c9cda50b7996366aafe00f6b8643f17385088e842c9626c23b922202702d8ee4
4
+ data.tar.gz: 040d9732ca74f020d475c3965392b63c2b9a525876cfd765b2c21fa0d031df54
5
5
  SHA512:
6
- metadata.gz: 101e3405eb9fbc011e3ddb8ad33a622c74f18cde1d3b6be204aa7840fc7d1f89b1c61e61585cfe9d26c397e67839d09fcd85671c5c0b92f2c8b78741ee4e5ded
7
- data.tar.gz: 0a7ad144e5860f72158c194de01213809a5294b69eb2a6de12288d827ca574efdc8937c967ec5c578b1a7c429d4f9e29bd5a1ee6738a373cf4cc57ca2ed8163a
6
+ metadata.gz: a7678c337e77326cedb49b06088ec1b24ae9b08f2047f02efc741134dc6a6efe851a702f45e02c571850c1762aca4de134067015aa8f2da06be9aa1cabb2050b
7
+ data.tar.gz: edd3d2148f8c4ee3c04bdc5025502e859f8d726bf38c741d4357a152770608ba639ad420070a8e071a261b4459bb20b7b637a390991877fd757e9d04a3d0d4b7
@@ -45,12 +45,19 @@ module Tapioca
45
45
  path = Pathname.new(file)
46
46
  return unless File.exist?(path)
47
47
 
48
+ # On native extensions, the source location may point to a shared object (.so, .bundle) file, which we cannot
49
+ # use for jump to definition. Only add source comments on Ruby files
50
+ return unless path.extname == ".rb"
51
+
48
52
  path = if path.realpath.to_s.start_with?(gem.full_gem_path)
49
53
  "#{gem.name}-#{gem.version}/#{path.realpath.relative_path_from(gem.full_gem_path)}"
50
54
  else
51
- path.sub("#{Bundler.bundle_path}/gems/", "")
55
+ path.sub("#{Bundler.bundle_path}/gems/", "").to_s
52
56
  end
53
57
 
58
+ # Strip out the RUBY_ROOT prefix, which is different for each user
59
+ path = path.sub(RbConfig::CONFIG["rubylibdir"], "RUBY_ROOT")
60
+
54
61
  node.comments << RBI::Comment.new("") if node.comments.any?
55
62
  node.comments << RBI::Comment.new("source://#{path}:#{line}")
56
63
  end
@@ -93,15 +93,36 @@ module Tapioca
93
93
 
94
94
  sig { params(name: String).returns(T::Boolean) }
95
95
  def valid_method_name?(name)
96
- name == "==" || !(
97
- name.to_sym.inspect.start_with?(':"', ":@", ":$") ||
98
- name.delete_suffix("=").to_sym.inspect.start_with?(':"', ":@", ":$")
99
- )
96
+ # try to parse a method definition with this name
97
+ iseq = RubyVM::InstructionSequence.compile("def #{name}; end", nil, nil, 0, false)
98
+ # pull out the first operation in the instruction sequence and its first argument
99
+ op, arg, _data = iseq.to_a.dig(-1, 0)
100
+ # make sure that the operation is a method definition and the method that was
101
+ # defined has the expected name, for example, for `def !foo; end` we don't get
102
+ # a syntax error but instead get a method defined as `"foo"`
103
+ op == :definemethod && arg == name.to_sym
104
+ rescue SyntaxError
105
+ false
100
106
  end
101
107
 
102
108
  sig { params(name: String).returns(T::Boolean) }
103
109
  def valid_parameter_name?(name)
104
- /^([[:lower:]]|_|[^[[:ascii:]]])([[:alnum:]]|_|[^[[:ascii:]]])*$/.match?(name)
110
+ sentinel_method_name = :sentinel_method_name
111
+ # try to parse a method definition with this name as the name of a
112
+ # keyword parameter. If we use a positional parameter, then parameter names
113
+ # like `&` (and maybe others) will be treated like `def foo(&); end` and will
114
+ # thus be considered valid. Using a required keyword parameter prevents that
115
+ # confusion between Ruby syntax and parameter name.
116
+ iseq = RubyVM::InstructionSequence.compile("def #{sentinel_method_name}(#{name}:); end", nil, nil, 0, false)
117
+ # pull out the first operation in the instruction sequence and its first argument and data
118
+ op, arg, data = iseq.to_a.dig(-1, 0)
119
+ # make sure that:
120
+ # 1. a method was defined, and
121
+ # 2. the method has the expected method name, and
122
+ # 3. the method has a keyword parameter with the expected name
123
+ op == :definemethod && arg == sentinel_method_name && data.dig(11, :keyword, 0) == name.to_sym
124
+ rescue SyntaxError
125
+ false
105
126
  end
106
127
  end
107
128
  end
@@ -34,6 +34,7 @@ require "tapioca/helpers/rbi_helper"
34
34
  require "tapioca/sorbet_ext/fixed_hash_patch"
35
35
  require "tapioca/sorbet_ext/name_patch"
36
36
  require "tapioca/sorbet_ext/generic_name_patch"
37
+ require "tapioca/sorbet_ext/proc_bind_patch"
37
38
  require "tapioca/runtime/generic_type_registry"
38
39
 
39
40
  require "tapioca/helpers/cli_helper"
@@ -25,16 +25,16 @@ module Tapioca
25
25
 
26
26
  key = tp.self
27
27
 
28
- if tp.path == "(eval)"
28
+ path = tp.path
29
+ if File.exist?(path)
30
+ loc = build_constant_location(tp, caller_locations)
31
+ else
29
32
  caller_location = T.must(caller_locations)
30
- .drop_while { |loc| loc.path == "(eval)" }
31
- .first
33
+ .find { |loc| loc.path && File.exist?(loc.path) }
32
34
 
33
35
  next unless caller_location
34
36
 
35
37
  loc = ConstantLocation.new(path: caller_location.absolute_path || "", lineno: caller_location.lineno)
36
- else
37
- loc = build_constant_location(tp, caller_locations)
38
38
  end
39
39
 
40
40
  (@class_files[key] ||= Set.new) << loc
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module T
5
+ module Types
6
+ module ProcBindPatch
7
+ def initialize(arg_types, returns, bind = T::Private::Methods::ARG_NOT_PROVIDED)
8
+ super(arg_types, returns)
9
+
10
+ unless bind == T::Private::Methods::ARG_NOT_PROVIDED
11
+ @bind = T.let(T::Utils.coerce(bind), T::Types::Base)
12
+ end
13
+ end
14
+
15
+ def name
16
+ name = super
17
+ name = name.sub("T.proc", "T.proc.bind(#{@bind})") unless @bind.nil?
18
+ name
19
+ end
20
+ end
21
+
22
+ Proc.prepend(ProcBindPatch)
23
+ end
24
+ end
25
+
26
+ module T
27
+ module Private
28
+ module Methods
29
+ module ProcBindPatch
30
+ def finalize_proc(decl)
31
+ super
32
+
33
+ T.unsafe(T::Types::Proc).new(decl.params, decl.returns, decl.bind)
34
+ end
35
+ end
36
+
37
+ singleton_class.prepend(ProcBindPatch)
38
+ end
39
+ end
40
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.9.1"
5
+ VERSION = "0.9.2"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapioca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2022-07-14 00:00:00.000000000 Z
14
+ date: 2022-07-19 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -256,6 +256,7 @@ files:
256
256
  - lib/tapioca/sorbet_ext/fixed_hash_patch.rb
257
257
  - lib/tapioca/sorbet_ext/generic_name_patch.rb
258
258
  - lib/tapioca/sorbet_ext/name_patch.rb
259
+ - lib/tapioca/sorbet_ext/proc_bind_patch.rb
259
260
  - lib/tapioca/static/requires_compiler.rb
260
261
  - lib/tapioca/static/symbol_loader.rb
261
262
  - lib/tapioca/static/symbol_table_parser.rb