Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
ff6c1b2
Add YARD macro support for DSL methods (#1187)
lekemula May 17, 2026
d282a3b
YARD macros - More typecheck fixes (#1188)
lekemula May 17, 2026
44917c8
Macro fixes (#1189)
castwide May 18, 2026
3cc4c9b
Unused macro methods (#1191)
castwide May 18, 2026
6ffe726
Infer method calls with parameter names in return types
castwide May 21, 2026
5dbd500
Retain existing tags
castwide May 21, 2026
a90492d
JIT macro expansion
castwide May 21, 2026
f2b4c7e
Expand types from chain calls
castwide May 22, 2026
d9c8522
Typedef classes
castwide May 22, 2026
11bc2b8
ComplexType to Typedef::Type
castwide May 22, 2026
b7c02db
Resolve named tokens
castwide May 22, 2026
4bc3614
Resolve rooted paths
castwide May 22, 2026
abac126
Type resolves rooted params
castwide May 22, 2026
6161eab
First iteration of Typedef-based inference
castwide May 22, 2026
7656f90
Typedef resolves generics
castwide May 22, 2026
68e3199
Generic syntax
castwide May 22, 2026
74f91b7
Typedef chain inference
castwide May 22, 2026
7d42b49
Typedef::Dictionary
castwide May 23, 2026
b0f78df
Dictionary#closure
castwide May 23, 2026
e971284
Replace Inference with Dictionary
castwide May 23, 2026
b8ce2fe
DRY Dictionary#define
castwide May 23, 2026
356bb2e
Typedef::Linker
castwide May 24, 2026
6a48f8a
Dictionary#initialize parameters
castwide May 24, 2026
3ec3101
Param documentation
castwide May 24, 2026
2389353
Probe from Dictionary#infer
castwide May 24, 2026
dedc649
Unneeded path exception
castwide May 24, 2026
1c1fb45
Typedef inspects invalid token values
castwide May 24, 2026
8afe0ae
Redundant code
castwide May 24, 2026
b040722
Infer from new
castwide May 24, 2026
9821d07
Token resolution and probes in Dictionary#infer_from
castwide May 24, 2026
ff952e8
Return closure pin for undefined chains
castwide May 24, 2026
2177735
Fixed expectation
castwide May 24, 2026
4722395
All dictionary linker specs
castwide May 24, 2026
35ca4a2
Strings and symbols in Typedef tokens
castwide May 24, 2026
34bfedc
Pending and corrected specs
castwide May 24, 2026
a622dad
Or specs
castwide May 24, 2026
65e4d90
Todo comment
castwide May 24, 2026
ff6ef35
Linker classes
castwide May 24, 2026
d15d3e5
Inference with probes
castwide May 24, 2026
134554c
Resolve class methods from linker
castwide May 24, 2026
e54cf0f
ComplexType#to_typedef_types spec
castwide May 24, 2026
bb12f43
Spec for generic class method return values
castwide May 24, 2026
26e8ee4
More call specs
castwide May 25, 2026
41da080
Typedef::Type scopes
castwide May 25, 2026
559c875
Two more specs
castwide May 25, 2026
c654172
Or links do not call Chain#infer
castwide May 25, 2026
518bb5c
Pin probe exception for local variables
castwide May 25, 2026
53da7f9
Or linker placeholder
castwide May 25, 2026
adad28c
infer_from -> infer_proxies
castwide May 25, 2026
eaaeb54
Stubbed local variable inference
castwide May 25, 2026
455a247
Typedef::Type#generic?
castwide May 26, 2026
2ae4470
Linker::Call#resolve prefers defined local variable types
castwide May 26, 2026
eae0562
Proper token expansion
castwide May 26, 2026
1480c38
Edge case spec
castwide May 26, 2026
56f1c79
Placeholder for signature matching
castwide May 26, 2026
e136aba
Typedef::Helpers
castwide May 26, 2026
0c9009f
Partial fix for call links referencing local variables
castwide May 26, 2026
952d67c
Memos
castwide May 26, 2026
60e1f9a
Avoid recursive memos
castwide May 26, 2026
bd4e1a0
Test pending memo tracking
castwide May 26, 2026
a62f811
Infer local variables
castwide May 26, 2026
7a4688e
Or linker
castwide May 26, 2026
104fbde
Dictionary drills into method bodies
castwide May 26, 2026
17b8b57
ClassVariable linker
castwide May 26, 2026
2d26a21
Expand tokens with receiver's binder
castwide May 26, 2026
209835d
Ignore nil navigation on receivers without nil return types
castwide May 26, 2026
3d7340c
Use next_chain for variable pins
castwide May 26, 2026
87b51e7
Memos recover from recursive keys
castwide May 26, 2026
d340c1c
Nil guards
castwide May 26, 2026
1a9982b
Recursive definition warning
castwide May 26, 2026
e4b924d
Fix call linker
castwide May 26, 2026
de8ccce
Remove Typedef::Helpers
castwide May 26, 2026
c48e29a
Infer unique types
castwide May 26, 2026
b0eaef1
Closure traversal
castwide May 26, 2026
c6096fd
Redundant variable
castwide May 26, 2026
e1c6207
WIP
castwide May 26, 2026
1707fde
Working spec
castwide May 26, 2026
c2b09b8
Pending block support
castwide May 26, 2026
c7983bd
Use context and binder in call linker
castwide May 26, 2026
d6643ae
Linting
castwide May 26, 2026
3639907
Documentation
castwide May 26, 2026
1544738
resolve_named_tokens -> expand
castwide May 26, 2026
fa9da37
First iteration of block support
castwide May 26, 2026
d95b39e
Call linker finds parameters
castwide May 26, 2026
55bc3e6
Better proxies
castwide May 26, 2026
f00e2aa
Rework define_from
castwide May 27, 2026
ef7dbb9
Enable nilable types
castwide May 27, 2026
0fc8094
Redundant line
castwide May 27, 2026
e41ff02
Dictionary handles local variable inference
castwide May 27, 2026
aa195e4
Minor refactoring
castwide May 27, 2026
5bd452d
Expand on Dictionary#infer
castwide May 27, 2026
cb60eef
Move local variable inference back to call linker
castwide May 27, 2026
f81dbdc
First iteration of generics
castwide May 27, 2026
e8dbb68
Tweaking infer_proxies
castwide May 27, 2026
5ba33d1
Comment
castwide May 27, 2026
bcea361
Expansion and inference issues
castwide May 27, 2026
16ef90b
Fix variable inference from dictionary
castwide May 27, 2026
190e915
Expand generics from same pin
castwide May 27, 2026
e7d3a84
Minor refactoring
castwide May 28, 2026
37238f7
Generics class
castwide May 28, 2026
aeeaa18
Refactor Generics
castwide May 28, 2026
b431bad
WIP specs
castwide May 28, 2026
1b631e8
Organize specs
castwide May 28, 2026
a3dfbe5
Move more generics specs
castwide May 28, 2026
63518dd
Generics#names
castwide May 28, 2026
2c46b27
Type/Pin conversions
castwide May 28, 2026
a7f479e
Pin::Base#typedef_generics
castwide May 28, 2026
af0d1bd
Concrete Generics#names specs
castwide May 28, 2026
215dd0e
Enable stubbed specs
castwide May 28, 2026
40efc04
Typedef::Typeset
castwide May 28, 2026
b03e141
Typeset specs
castwide May 28, 2026
475af41
Typeset#expand
castwide May 28, 2026
eaac7f6
Copyedit
castwide May 28, 2026
4cbc353
Merge branch 'master' into typedefs
castwide May 28, 2026
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
1 change: 1 addition & 0 deletions lib/solargraph.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class InvalidRubocopVersionError < RuntimeError; end
autoload :RbsMap, 'solargraph/rbs_map'
autoload :GemPins, 'solargraph/gem_pins'
autoload :PinCache, 'solargraph/pin_cache'
autoload :Typedef, 'solargraph/typedef'

dir = File.dirname(__FILE__)
VIEWS_PATH = File.join(dir, 'solargraph', 'views')
Expand Down
23 changes: 22 additions & 1 deletion lib/solargraph/api_map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ def get_instance_variable_pins namespace, scope = :instance
# @param candidates [Array<Pin::BaseVariable>]
# @param name [String]
# @param closure [Pin::Closure]
# @param location [Location]
# @param location [Location, nil]
#
# @return [Pin::BaseVariable, nil]
def var_at_location candidates, name, closure, location
Expand Down Expand Up @@ -520,6 +520,27 @@ def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
result
end

# @param path [Typedef::Path]
# @return [Array<Pin::Method>]
def typedef_path_methods path
# @todo Can we just try to resolve the path here? I guess we'd need gates.
if path.resolved?
get_methods(path.to_s)
else
[]
end
end

# @param type [Typedef::Type]
# @return [Array<Pin::Method>]
def typedef_type_methods type
if type.class?
get_methods(type.params.first.to_s, scope: :class)
else
get_methods(type.base.to_s, scope: :instance)
end
end

# Get an array of method pins for a complex type.
#
# The type's namespace and the context should be fully qualified. If the
Expand Down
10 changes: 10 additions & 0 deletions lib/solargraph/complex_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,16 @@
ComplexType.new(types)
end

# @return [Array<Typedef::Type>]
def to_typedef_types
# @todo Quick and dirty hack
return [Typedef::Type::ROOT] if to_s == 'Class<>'

items.map do |item|

Check warning on line 407 in lib/solargraph/complex_type.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Pass `&:to_typedef_types` as an argument to `map` instead of a block. Raw Output: lib/solargraph/complex_type.rb:407:17: C: Style/SymbolProc: Pass `&:to_typedef_types` as an argument to `map` instead of a block.
item.to_typedef_types
end
end

protected

def equality_fields
Expand Down
10 changes: 10 additions & 0 deletions lib/solargraph/complex_type/unique_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,16 @@ def can_root_name? name_to_check = name
self.class.can_root_name?(name_to_check)
end

def to_typedef_types
# @todo Quick and dirty hack
return Typedef::Type.new(Typedef.tokenize(to_s)) if to_s.start_with?('generic<')

base = name
base = "::#{base}" if rooted? && base =~ /^[A-Z]/
params = all_params.map(&:to_typedef_types)
Typedef::Type.new(base, *params)
end

# @param name [String]
def self.can_root_name? name
# name is not lowercase
Expand Down
23 changes: 22 additions & 1 deletion lib/solargraph/pin/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
# Between 2 pins, the one with the higher priority gets chosen. If the priorities are equal, they are combined.
attr_reader :combine_priority

attr_reader :expansions

def presence_certain?
true
end
Expand All @@ -47,7 +49,7 @@
# @param directives [::Array<YARD::Tags::Directive>, nil]
# @param combine_priority [::Numeric, nil] See attr_reader for combine_priority
def initialize location: nil, type_location: nil, closure: nil, source: nil, name: '', comments: '',
docstring: nil, directives: nil, combine_priority: nil
docstring: nil, directives: nil, combine_priority: nil, expansions: {}
@location = location
@type_location = type_location
@closure = closure
Expand All @@ -60,11 +62,26 @@
@combine_priority = combine_priority
# @type [ComplexType, ComplexType::UniqueType, nil]
@binder = nil
@expansions = expansions

assert_source_provided
assert_location_provided
end

def typedef_path
Typedef::Path.new(path.to_s, rooted: return_type.rooted?)
end

# @return [Array<Typedef::Type>]
def typedef_return_types
[Typedef::Type.from_complex_type(return_type)].flatten
end


Check warning on line 80 in lib/solargraph/pin/base.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Extra blank line detected. Raw Output: lib/solargraph/pin/base.rb:80:1: C: Layout/EmptyLines: Extra blank line detected.
def expansions

Check warning on line 81 in lib/solargraph/pin/base.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Method `Solargraph::Pin::Base#expansions` is defined at both lib/solargraph/pin/base.rb:36 and lib/solargraph/pin/base.rb:81. Raw Output: lib/solargraph/pin/base.rb:81:7: W: Lint/DuplicateMethods: Method `Solargraph::Pin::Base#expansions` is defined at both lib/solargraph/pin/base.rb:36 and lib/solargraph/pin/base.rb:81.

Check warning on line 81 in lib/solargraph/pin/base.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Expected 1 empty line between method definitions; found 2. Raw Output: lib/solargraph/pin/base.rb:81:7: C: Layout/EmptyLineBetweenDefs: Expected 1 empty line between method definitions; found 2.
@expansions ||= {}
end

# @return [void]
def assert_location_provided
return unless best_location.nil? && %i[yardoc source rbs].include?(source)
Expand Down Expand Up @@ -711,6 +728,10 @@
end
end

def typedef_generics
@generics ||= docstring.tags(:generic).map(&:name)

Check warning on line 732 in lib/solargraph/pin/base.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Memoized variable `@generics` does not match method name `typedef_generics`. Use `@typedef_generics` instead. Raw Output: lib/solargraph/pin/base.rb:732:9: C: Naming/MemoizedInstanceVariableName: Memoized variable `@generics` does not match method name `typedef_generics`. Use `@typedef_generics` instead.
end

protected

# @sg-ignore def should infer as symbol - "Not enough arguments to Module#protected"
Expand Down
18 changes: 18 additions & 0 deletions lib/solargraph/pin/callable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,24 @@
callable
end

# @param api_map [ApiMap]
# @return [Array<Typedef::Type>]
def typedef_resolve_rooted api_map
typedef_return_types.map { |rt| rt.resolve_rooted(api_map, gates) }
end

# @param arguments [Array<Typedef::Type>]
# @return [Array<Typedef::Type>]
def typedef_resolve_call(arguments)

Check warning on line 171 in lib/solargraph/pin/callable.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Use def without parentheses. Raw Output: lib/solargraph/pin/callable.rb:171:31: C: Style/MethodDefParentheses: Use def without parentheses.
# named_values = closure.generics
# .map { |name| "generic[#{name}]" }
# .zip(arguments)
# .to_h
# puts "Named values from typedef_resolve_call #{named_values.inspect}"
# puts "With arguments #{arguments.inspect}"
typedef_return_types
end

def typify api_map
type = return_type
return type.qualify(api_map, *gates) if type.defined?
Expand Down
5 changes: 5 additions & 0 deletions lib/solargraph/pin/parameter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
@decl = decl
end

# @param arguments [Array<Typedef::Type>]
def typedef_resolve_generics(arguments)

Check warning on line 26 in lib/solargraph/pin/parameter.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Use def without parentheses. Raw Output: lib/solargraph/pin/parameter.rb:26:35: C: Style/MethodDefParentheses: Use def without parentheses.

Check warning on line 26 in lib/solargraph/pin/parameter.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Put empty method definitions on a single line. Raw Output: lib/solargraph/pin/parameter.rb:26:7: C: Style/EmptyMethod: Put empty method definitions on a single line.

Check warning on line 27 in lib/solargraph/pin/parameter.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Trailing whitespace detected. Raw Output: lib/solargraph/pin/parameter.rb:27:1: C: Layout/TrailingWhitespace: Trailing whitespace detected.
end

def type_location
super || closure&.type_location
end
Expand Down
5 changes: 4 additions & 1 deletion lib/solargraph/pin/proxy_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
module Solargraph
module Pin
class ProxyType < Base
attr_reader :generics

# @param return_type [ComplexType, ComplexType::UniqueType]
# @param gates [Array<String>, nil] Namespaces to try while resolving non-rooted types
# @param binder [ComplexType, ComplexType::UniqueType, nil]
# @param gates [Array<String>, nil]
# @param [Hash{Symbol => Object}] splat
def initialize return_type: ComplexType::UNDEFINED, binder: nil, gates: nil, **splat
def initialize return_type: ComplexType::UNDEFINED, binder: nil, gates: nil, generics: [], **splat
super(**splat)
@gates = gates
@return_type = return_type
@binder = binder if binder
@generics = generics
end

def context
Expand Down
3 changes: 2 additions & 1 deletion lib/solargraph/rbs_map/core_fills.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ module CoreFills
source: :core_fill),
# RBS does not define Class with a generic, so all calls to
# generic() return an 'untyped'. We can do better:
Override.method_return('Class#allocate', 'self', source: :core_fill)
Override.method_return('Class#allocate', 'self', source: :core_fill),
Override.method_return('Class#new', 'self', source: :core_fill)
].freeze

# @todo I don't see any direct link in RBS to build this from -
Expand Down
64 changes: 64 additions & 0 deletions lib/solargraph/typedef.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module Solargraph
module Typedef
autoload :Path, 'solargraph/typedef/path'
autoload :Token, 'solargraph/typedef/token'
autoload :Type, 'solargraph/typedef/type'
autoload :Linker, 'solargraph/typedef/linker'
autoload :Memos, 'solargraph/typedef/memos'
autoload :Dictionary, 'solargraph/typedef/dictionary'
autoload :Generics, 'solargraph/typedef/generics'
autoload :Typeset, 'solargraph/typedef/typeset'

# Convert a value to a Path or Token
# @param value [String, Path, Token, Type, Array<String, Path, Token, Type>]
# @return [Path, Token, Type]
def self.tokenize value
case value
when String
convert value
when Path, Token, Type
value
when Array
Typedef::Type.new(*value)
else
raise "Invalid value #{value.inspect}"
end
end

def self.memos
@memos ||= Memos.new
end

class << self
private

# @param string [String]
# @return [Path, Token]
def convert string
case string
when ""

Check warning on line 41 in lib/solargraph/typedef.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] reported by reviewdog 🐶 Prefer single-quoted strings when you don't need string interpolation or special symbols. Raw Output: lib/solargraph/typedef.rb:41:14: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
Path::ROOT
# @todo Should interfaces (e.g, `_Each`) be paths?
# (Probably)
when /^(::)?[A-Z_][A-Za-z_(::)]*?/
Path.new(string)
when /^generic<[A-Za-z\d_]*>$/
Token.new(string)
when /^?[a-z\d_]*?$/
Token.new(string)
when /^"?[a-z\d_]*?"$/
Token.new(string)
when /^\:?[a-z\d_]*?$/
Token.new(string)
# @todo How to handle integers?
when /^\d+$/
Token.new(string)
else
raise "Invalid Typedef token string: #{string.inspect}"
end
end
end
end
end
Loading
Loading