Skip to content

Commit

Permalink
Merge pull request #929 from ruby/environment
Browse files Browse the repository at this point in the history
Fix Environment type checking
  • Loading branch information
soutaro authored Mar 19, 2022
2 parents 35eeb7f + ae843e3 commit 222a2e4
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 47 deletions.
36 changes: 23 additions & 13 deletions lib/rbs/environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ class Environment
attr_reader :global_decls

module ContextUtil
def context
@context ||=
begin
# @type var decls: Array[_ModuleOrClass]
decls = outer + [decl]

decls.each.with_object([Namespace.root]) do |decl, array|
first = array.first or raise
array.unshift(first + decl.name.to_namespace)
end
end
def calculate_context(decls)
decls.each.with_object([Namespace.root]) do |decl, array|
first = array.first or raise
array.unshift(first + decl.name.to_namespace)
end
end
end

class MultiEntry
D = _ = Struct.new(:decl, :outer, keyword_init: true) do
# @implements D[M]

include ContextUtil

def context
@context ||= calculate_context(outer + [decl])
end
end

attr_reader :name
Expand Down Expand Up @@ -88,6 +88,12 @@ def primary
end
end

def foo
a = [1].sample()
return unless a
a + 1
end

class ClassEntry < MultiEntry
def primary
@primary ||= begin
Expand All @@ -98,8 +104,6 @@ def primary
end

class SingleEntry
include ContextUtil

attr_reader :name
attr_reader :outer
attr_reader :decl
Expand All @@ -109,6 +113,12 @@ def initialize(name:, decl:, outer:)
@decl = decl
@outer = outer
end

include ContextUtil

def context
@context = calculate_context(outer)
end
end

def initialize
Expand Down
26 changes: 16 additions & 10 deletions sig/environment.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ module RBS
def type_params: () -> Array[AST::TypeParam]
end

interface _WithContext[M < _ModuleOrClass]
def outer: () -> Array[module_decl]

def decl: () -> M
interface _NamedDecl
def name: () -> TypeName
end

module ContextUtil[M < _ModuleOrClass] : _WithContext[M]
def context: () -> Array[Namespace]
module ContextUtil
def calculate_context: (Array[_NamedDecl]) -> Array[Namespace]
end

class MultiEntry[M < _ModuleOrClass]
Expand All @@ -25,7 +23,11 @@ module RBS

def initialize: (decl: M, outer: Array[module_decl]) -> void

include ContextUtil[M]
include ContextUtil

@context: Array[Namespace]

def context: () -> Array[Namespace]
end

attr_reader name: TypeName
Expand All @@ -52,13 +54,17 @@ module RBS
end

class SingleEntry[N, D]
include ContextUtil[D]

attr_reader name: N
attr_reader decl: D
attr_reader outer: Array[module_decl]

def initialize: (name: N, decl: D, outer: Array[module_decl]) -> void

include ContextUtil

@context: Array[Namespace]

def context: () -> Array[Namespace]
end

# Top level declarations.
Expand All @@ -76,7 +82,7 @@ module RBS

def self.from_loader: (EnvironmentLoader) -> Environment

def cache_name: [Key, D] (Hash[Key, SingleEntry[Key, D]] cache, name: Key, decl: D, outer: Array[module_decl]) -> SingleEntry[Key, D]
def cache_name: [N, D] (Hash[N, SingleEntry[N, D]] cache, name: N, decl: D, outer: Array[module_decl]) -> SingleEntry[N, D]

def insert_decl: (AST::Declarations::t, outer: Array[module_decl], namespace: Namespace) -> void

Expand Down
46 changes: 23 additions & 23 deletions sig/environment_loader.rbs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
module RBS
# EnvironmentLoader is an object to load RBS files from filesystem.
#
#
# Set up your configuration through repository and `#add` method.
#
#
# # Set up the repository to load library RBSs from.
# repo = RBS::Repository.default
# repo.add(Pathname("vendor/rbs/gem-rbs"))
# repo.add(Pathname("vendor/rbs/internal-rbs"))
#
#
# loader = RBS::EnvironmentLoader.new(repository: repo)
#
#
# # Add libraries to load RBS files.
# loader.add(library: "minitest")
# loader.add(library: "rbs", version: "1.0.0")
#
#
# # Add dirs to load RBS files from.
# loader.add(path: Pathname("sig"))
#
#
# # Load RBSs into an environment.
# environment = RBS::Environment.new()
# loader.load(env: environment)
#
#
class EnvironmentLoader
class UnknownLibraryError < StandardError
attr_reader library: Library
Expand All @@ -44,64 +44,64 @@ module RBS
attr_reader dirs: Array[Pathname]

# The source where the RBS comes from.
#
#
# `:core` means it is part of core library.
# `Library` means it is from library.
# `Pathname` means it is loaded from a directory.
#
#
type source = :core
| Library
| Pathname

# Accepts two optional keyword arguments.
#
#
# `core_root` is the path to the directory with RBSs for core classes.
# The default value is the core library included in RBS gem. (EnvironmentLoader::DEFAULT_CORE_ROOT)
# Passing `nil` means it skips loading core class definitions.
#
#
# `repository` is the repository for library classes.
# The default value is repository only with stdlib classes. (Repository.new)
#
#
def initialize: (?core_root: Pathname?, ?repository: Repository) -> void

# Add a path or library to load RBSs from.
#
#
# `path` can be a file or a directory.
# All `.rbs` files from the given directory will be loaded.
# Specifying a file will load the file regardless the extension of the file is.
#
#
# `library` can be a name of a gem.
# Specifying `nil` to `version` will load any version available.
# It first tries to load RBS files from gem with specified version.
# If RBS files cannot be found in the gem, it tries to load RBSs from repository.
#
#
def add: (path: Pathname) -> void
| (library: String, version: String?) -> void

# Add repository path and libraries via rbs_collection.lock.yaml.
def add_collection: (Collection::Config collection_config) -> void

# This is helper function to test if RBS for a library is available or not.
#
#
def has_library?: (library: String, version: String?) -> bool

# Add all declarations to environment.
#
#
# Raises `UnknownLibraryError` if RBS cannot be loaded from a library.
#
#
# Returns an array of tuples of the declaration, path to the file, and the source.
#
#
def load: (env: Environment) -> Array[[AST::Declarations::t, Pathname, source]]

# Returns a pair of spec and path for a gem with RBS.
# Returns nil if the gem is not installed, or the gem doesn't provide RBS.
#
#
def self.gem_sig_path: (String name, String? version) -> [Gem::Specification, Pathname]?

def each_decl: () { (AST::Declarations::t, Buffer, source, Pathname) -> void } -> void

def each_dir: { (source, Pathname) -> void } -> void

def each_file: (Pathname path, immediate: boolish, skip_hidden: boolish) { (Pathname) -> void } -> void
end
end
1 change: 0 additions & 1 deletion test/rbs/environment_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ module Baz
)

assert_equal [
type_name("::Foo::Bar::Baz").to_namespace,
type_name("::Foo::Bar").to_namespace,
type_name("::Foo").to_namespace,
Namespace.root
Expand Down

0 comments on commit 222a2e4

Please sign in to comment.