rbs 1.7.0 → 2.0.0.pre1
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 +4 -4
- data/CHANGELOG.md +95 -3
- data/core/array.rbs +3 -3
- data/core/builtin.rbs +4 -0
- data/core/enumerable.rbs +3 -3
- data/core/thread.rbs +1 -1
- data/docs/collection.md +23 -1
- data/docs/syntax.md +117 -61
- data/ext/rbs_extension/constants.c +2 -6
- data/ext/rbs_extension/constants.h +1 -2
- data/ext/rbs_extension/parser.c +221 -185
- data/ext/rbs_extension/parserstate.c +6 -2
- data/ext/rbs_extension/parserstate.h +10 -0
- data/ext/rbs_extension/ruby_objs.c +17 -17
- data/ext/rbs_extension/ruby_objs.h +3 -4
- data/lib/rbs/ast/declarations.rb +6 -99
- data/lib/rbs/ast/type_param.rb +134 -0
- data/lib/rbs/cli.rb +33 -5
- data/lib/rbs/collection/config/lockfile_generator.rb +26 -18
- data/lib/rbs/collection/sources/git.rb +18 -7
- data/lib/rbs/collection/sources/rubygems.rb +7 -0
- data/lib/rbs/collection/sources/stdlib.rb +6 -0
- data/lib/rbs/definition.rb +9 -0
- data/lib/rbs/definition_builder.rb +78 -16
- data/lib/rbs/environment.rb +32 -8
- data/lib/rbs/environment_loader.rb +0 -2
- data/lib/rbs/environment_walker.rb +4 -1
- data/lib/rbs/errors.rb +31 -6
- data/lib/rbs/location_aux.rb +2 -0
- data/lib/rbs/method_type.rb +29 -6
- data/lib/rbs/prototype/rb.rb +3 -3
- data/lib/rbs/prototype/rbi.rb +8 -6
- data/lib/rbs/prototype/runtime.rb +4 -4
- data/lib/rbs/type_alias_regularity.rb +115 -0
- data/lib/rbs/types.rb +100 -23
- data/lib/rbs/validator.rb +99 -15
- data/lib/rbs/variance_calculator.rb +60 -31
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +2 -14
- data/lib/rbs.rb +2 -0
- data/schema/decls.json +19 -46
- data/schema/methodType.json +1 -1
- data/schema/typeParam.json +36 -0
- data/schema/types.json +8 -2
- data/sig/collection/collections.rbs +13 -2
- data/sig/collection/config.rbs +2 -2
- data/sig/declarations.rbs +15 -62
- data/sig/definition.rbs +11 -1
- data/sig/definition_builder.rbs +37 -1
- data/sig/environment.rbs +7 -1
- data/sig/environment_walker.rbs +26 -0
- data/sig/errors.rbs +28 -3
- data/sig/location.rbs +3 -1
- data/sig/locator.rbs +1 -1
- data/sig/method_types.rbs +25 -4
- data/sig/type_alias_regularity.rbs +92 -0
- data/sig/type_param.rbs +74 -0
- data/sig/types.rbs +37 -8
- data/sig/validator.rbs +38 -2
- data/sig/variance_calculator.rbs +50 -0
- data/sig/writer.rbs +1 -1
- data/stdlib/bigdecimal-math/0/manifest.yaml +2 -0
- data/stdlib/csv/0/manifest.yaml +2 -0
- data/stdlib/date/0/date.rbs +2 -2
- data/stdlib/logger/0/manifest.yaml +2 -0
- data/stdlib/net-http/0/manifest.yaml +2 -0
- data/stdlib/openssl/0/manifest.yaml +2 -0
- data/stdlib/prime/0/manifest.yaml +2 -0
- data/stdlib/resolv/0/manifest.yaml +3 -0
- data/stdlib/set/0/set.rbs +3 -3
- data/stdlib/uri/0/common.rbs +10 -5
- data/stdlib/uri/0/ftp.rbs +10 -0
- data/stdlib/uri/0/mailto.rbs +5 -0
- data/stdlib/uri/0/ws.rbs +10 -0
- data/stdlib/uri/0/wss.rbs +7 -0
- data/stdlib/yaml/0/manifest.yaml +3 -0
- data/steep/Gemfile.lock +10 -10
- metadata +21 -5
- data/lib/ruby/signature.rb +0 -7
    
        data/lib/rbs/ast/declarations.rb
    CHANGED
    
    | @@ -4,103 +4,6 @@ module RBS | |
| 4 4 | 
             
                  class Base
         | 
| 5 5 | 
             
                  end
         | 
| 6 6 |  | 
| 7 | 
            -
                  class ModuleTypeParams
         | 
| 8 | 
            -
                    attr_reader :params
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                    TypeParam = _ = Struct.new(:name, :variance, :skip_validation, :location, keyword_init: true) do
         | 
| 11 | 
            -
                      # @implements TypeParam
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                      def to_json(state = _ = nil)
         | 
| 14 | 
            -
                        {
         | 
| 15 | 
            -
                          name: name,
         | 
| 16 | 
            -
                          variance: variance,
         | 
| 17 | 
            -
                          skip_validation: skip_validation,
         | 
| 18 | 
            -
                        }.to_json(state)
         | 
| 19 | 
            -
                      end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                      def ==(other)
         | 
| 22 | 
            -
                        other.is_a?(TypeParam) &&
         | 
| 23 | 
            -
                          other.name == name &&
         | 
| 24 | 
            -
                          other.variance == variance &&
         | 
| 25 | 
            -
                          other.skip_validation == skip_validation
         | 
| 26 | 
            -
                      end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                      alias eql? ==
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                      def hash
         | 
| 31 | 
            -
                        self.class.hash ^ name.hash ^ variance.hash ^ skip_validation.hash
         | 
| 32 | 
            -
                      end
         | 
| 33 | 
            -
                    end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                    def initialize()
         | 
| 36 | 
            -
                      @params = []
         | 
| 37 | 
            -
                    end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                    def add(param)
         | 
| 40 | 
            -
                      params << param
         | 
| 41 | 
            -
                      self
         | 
| 42 | 
            -
                    end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                    def ==(other)
         | 
| 45 | 
            -
                      other.is_a?(ModuleTypeParams) && other.params == params
         | 
| 46 | 
            -
                    end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                    alias eql? ==
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    def hash
         | 
| 51 | 
            -
                      params.hash
         | 
| 52 | 
            -
                    end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                    def [](name)
         | 
| 55 | 
            -
                      params.find {|p| p.name == name }
         | 
| 56 | 
            -
                    end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                    def to_json(state = _ = nil)
         | 
| 59 | 
            -
                      {
         | 
| 60 | 
            -
                        params: params
         | 
| 61 | 
            -
                      }.to_json(state)
         | 
| 62 | 
            -
                    end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                    def each(&block)
         | 
| 65 | 
            -
                      if block
         | 
| 66 | 
            -
                        params.each(&block)
         | 
| 67 | 
            -
                      else
         | 
| 68 | 
            -
                        params.each
         | 
| 69 | 
            -
                      end
         | 
| 70 | 
            -
                    end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                    def self.empty
         | 
| 73 | 
            -
                      new
         | 
| 74 | 
            -
                    end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                    def variance(name)
         | 
| 77 | 
            -
                      var = self[name] or raise
         | 
| 78 | 
            -
                      var.variance
         | 
| 79 | 
            -
                    end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                    def skip_validation?(name)
         | 
| 82 | 
            -
                      var = self[name] or raise
         | 
| 83 | 
            -
                      var.skip_validation
         | 
| 84 | 
            -
                    end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                    def empty?
         | 
| 87 | 
            -
                      params.empty?
         | 
| 88 | 
            -
                    end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                    def size
         | 
| 91 | 
            -
                      params.size
         | 
| 92 | 
            -
                    end
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                    def rename_to(names)
         | 
| 95 | 
            -
                      ModuleTypeParams.new().tap do |params|
         | 
| 96 | 
            -
                        names.each.with_index do |new_name, index|
         | 
| 97 | 
            -
                          param = self.params[index]
         | 
| 98 | 
            -
                          params.add(TypeParam.new(name: new_name, variance: param.variance, skip_validation: param.skip_validation, location: param.location))
         | 
| 99 | 
            -
                        end
         | 
| 100 | 
            -
                      end
         | 
| 101 | 
            -
                    end
         | 
| 102 | 
            -
                  end
         | 
| 103 | 
            -
             | 
| 104 7 | 
             
                  module NestedDeclarationHelper
         | 
| 105 8 | 
             
                    def each_member
         | 
| 106 9 | 
             
                      if block_given?
         | 
| @@ -362,13 +265,15 @@ module RBS | |
| 362 265 |  | 
| 363 266 | 
             
                  class Alias < Base
         | 
| 364 267 | 
             
                    attr_reader :name
         | 
| 268 | 
            +
                    attr_reader :type_params
         | 
| 365 269 | 
             
                    attr_reader :type
         | 
| 366 270 | 
             
                    attr_reader :annotations
         | 
| 367 271 | 
             
                    attr_reader :location
         | 
| 368 272 | 
             
                    attr_reader :comment
         | 
| 369 273 |  | 
| 370 | 
            -
                    def initialize(name:, type:, annotations:, location:, comment:)
         | 
| 274 | 
            +
                    def initialize(name:, type_params:, type:, annotations:, location:, comment:)
         | 
| 371 275 | 
             
                      @name = name
         | 
| 276 | 
            +
                      @type_params = type_params
         | 
| 372 277 | 
             
                      @type = type
         | 
| 373 278 | 
             
                      @annotations = annotations
         | 
| 374 279 | 
             
                      @location = location
         | 
| @@ -378,19 +283,21 @@ module RBS | |
| 378 283 | 
             
                    def ==(other)
         | 
| 379 284 | 
             
                      other.is_a?(Alias) &&
         | 
| 380 285 | 
             
                        other.name == name &&
         | 
| 286 | 
            +
                        other.type_params == type_params &&
         | 
| 381 287 | 
             
                        other.type == type
         | 
| 382 288 | 
             
                    end
         | 
| 383 289 |  | 
| 384 290 | 
             
                    alias eql? ==
         | 
| 385 291 |  | 
| 386 292 | 
             
                    def hash
         | 
| 387 | 
            -
                      self.class.hash ^ name.hash ^ type.hash
         | 
| 293 | 
            +
                      self.class.hash ^ name.hash ^ type_params.hash ^ type.hash
         | 
| 388 294 | 
             
                    end
         | 
| 389 295 |  | 
| 390 296 | 
             
                    def to_json(state = _ = nil)
         | 
| 391 297 | 
             
                      {
         | 
| 392 298 | 
             
                        declaration: :alias,
         | 
| 393 299 | 
             
                        name: name,
         | 
| 300 | 
            +
                        type_params: type_params,
         | 
| 394 301 | 
             
                        type: type,
         | 
| 395 302 | 
             
                        annotations: annotations,
         | 
| 396 303 | 
             
                        location: location,
         | 
| @@ -0,0 +1,134 @@ | |
| 1 | 
            +
            module RBS
         | 
| 2 | 
            +
              module AST
         | 
| 3 | 
            +
                class TypeParam
         | 
| 4 | 
            +
                  attr_reader :name, :variance, :location, :upper_bound
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(name:, variance:, upper_bound:, location:)
         | 
| 7 | 
            +
                    @name = name
         | 
| 8 | 
            +
                    @variance = variance
         | 
| 9 | 
            +
                    @upper_bound = upper_bound
         | 
| 10 | 
            +
                    @location = location
         | 
| 11 | 
            +
                    @unchecked = false
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def unchecked!(value = true)
         | 
| 15 | 
            +
                    @unchecked = value ? true : false
         | 
| 16 | 
            +
                    self
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def unchecked?
         | 
| 20 | 
            +
                    @unchecked
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def ==(other)
         | 
| 24 | 
            +
                    other.is_a?(TypeParam) &&
         | 
| 25 | 
            +
                      other.name == name &&
         | 
| 26 | 
            +
                      other.variance == variance &&
         | 
| 27 | 
            +
                      other.upper_bound == upper_bound &&
         | 
| 28 | 
            +
                      other.unchecked? == unchecked?
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  alias eql? ==
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def hash
         | 
| 34 | 
            +
                    self.class.hash ^ name.hash ^ variance.hash ^ upper_bound.hash ^ unchecked?.hash
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def to_json(state = JSON::State.new)
         | 
| 38 | 
            +
                    {
         | 
| 39 | 
            +
                      name: name,
         | 
| 40 | 
            +
                      variance: variance,
         | 
| 41 | 
            +
                      unchecked: unchecked?,
         | 
| 42 | 
            +
                      location: location,
         | 
| 43 | 
            +
                      upper_bound: upper_bound
         | 
| 44 | 
            +
                    }.to_json(state)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def rename(name)
         | 
| 48 | 
            +
                    TypeParam.new(
         | 
| 49 | 
            +
                      name: name,
         | 
| 50 | 
            +
                      variance: variance,
         | 
| 51 | 
            +
                      upper_bound: upper_bound,
         | 
| 52 | 
            +
                      location: location
         | 
| 53 | 
            +
                    ).unchecked!(unchecked?)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def map_type(&block)
         | 
| 57 | 
            +
                    if b = upper_bound
         | 
| 58 | 
            +
                      _upper_bound = yield(b)
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    TypeParam.new(
         | 
| 62 | 
            +
                      name: name,
         | 
| 63 | 
            +
                      variance: variance,
         | 
| 64 | 
            +
                      upper_bound: _upper_bound,
         | 
| 65 | 
            +
                      location: location
         | 
| 66 | 
            +
                    ).unchecked!(unchecked?)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def self.resolve_variables(params)
         | 
| 70 | 
            +
                    return if params.empty?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    vars = Set.new(params.map(&:name))
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    params.map! do |param|
         | 
| 75 | 
            +
                      param.map_type {|bound| _ = subst_var(vars, bound) }
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  def self.subst_var(vars, type)
         | 
| 80 | 
            +
                    case type
         | 
| 81 | 
            +
                    when Types::ClassInstance
         | 
| 82 | 
            +
                      namespace = type.name.namespace
         | 
| 83 | 
            +
                      if namespace.relative? && namespace.empty? && vars.member?(type.name.name)
         | 
| 84 | 
            +
                        return Types::Variable.new(name: type.name.name, location: type.location)
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    type.map_type {|t| subst_var(vars, t) }
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  def self.rename(params, new_names:)
         | 
| 92 | 
            +
                    raise unless params.size == new_names.size
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    subst = Substitution.build(new_names, Types::Variable.build(new_names))
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    params.map.with_index do |param, index|
         | 
| 97 | 
            +
                      new_name = new_names[index]
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                      TypeParam.new(
         | 
| 100 | 
            +
                        name: new_name,
         | 
| 101 | 
            +
                        variance: param.variance,
         | 
| 102 | 
            +
                        upper_bound: param.upper_bound&.map_type {|type| type.sub(subst) },
         | 
| 103 | 
            +
                        location: param.location
         | 
| 104 | 
            +
                      ).unchecked!(param.unchecked?)
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  def to_s
         | 
| 109 | 
            +
                    s = ""
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    if unchecked?
         | 
| 112 | 
            +
                      s << "unchecked "
         | 
| 113 | 
            +
                    end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    case variance
         | 
| 116 | 
            +
                    when :invariant
         | 
| 117 | 
            +
                      # nop
         | 
| 118 | 
            +
                    when :covariant
         | 
| 119 | 
            +
                      s << "out "
         | 
| 120 | 
            +
                    when :contravariant
         | 
| 121 | 
            +
                      s << "in "
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                    s << name.to_s
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    if type = upper_bound
         | 
| 127 | 
            +
                      s << " < #{type}"
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                    s
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
            end
         | 
    
        data/lib/rbs/cli.rb
    CHANGED
    
    | @@ -430,7 +430,7 @@ EOU | |
| 430 430 | 
             
                  builder = DefinitionBuilder.new(env: env)
         | 
| 431 431 | 
             
                  validator = Validator.new(env: env, resolver: TypeNameResolver.from_env(env))
         | 
| 432 432 |  | 
| 433 | 
            -
                  env.class_decls. | 
| 433 | 
            +
                  env.class_decls.each do |name, decl|
         | 
| 434 434 | 
             
                    stdout.puts "Validating class/module definition: `#{name}`..."
         | 
| 435 435 | 
             
                    builder.build_instance(name).each_type do |type|
         | 
| 436 436 | 
             
                      validator.validate_type type, context: [Namespace.root]
         | 
| @@ -438,13 +438,43 @@ EOU | |
| 438 438 | 
             
                    builder.build_singleton(name).each_type do |type|
         | 
| 439 439 | 
             
                      validator.validate_type type, context: [Namespace.root]
         | 
| 440 440 | 
             
                    end
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                    d = decl.primary.decl
         | 
| 443 | 
            +
             | 
| 444 | 
            +
                    validator.validate_type_params(
         | 
| 445 | 
            +
                      d.type_params,
         | 
| 446 | 
            +
                      type_name: name,
         | 
| 447 | 
            +
                      location: d.location&.aref(:type_params)
         | 
| 448 | 
            +
                    )
         | 
| 449 | 
            +
             | 
| 450 | 
            +
                    decl.decls.each do |d|
         | 
| 451 | 
            +
                      d.decl.each_member do |member|
         | 
| 452 | 
            +
                        case member
         | 
| 453 | 
            +
                        when AST::Members::MethodDefinition
         | 
| 454 | 
            +
                          validator.validate_method_definition(member, type_name: name)
         | 
| 455 | 
            +
                        end
         | 
| 456 | 
            +
                      end
         | 
| 457 | 
            +
                    end
         | 
| 441 458 | 
             
                  end
         | 
| 442 459 |  | 
| 443 | 
            -
                  env.interface_decls. | 
| 460 | 
            +
                  env.interface_decls.each do |name, decl|
         | 
| 444 461 | 
             
                    stdout.puts "Validating interface: `#{name}`..."
         | 
| 445 462 | 
             
                    builder.build_interface(name).each_type do |type|
         | 
| 446 463 | 
             
                      validator.validate_type type, context: [Namespace.root]
         | 
| 447 464 | 
             
                    end
         | 
| 465 | 
            +
             | 
| 466 | 
            +
                    validator.validate_type_params(
         | 
| 467 | 
            +
                      decl.decl.type_params,
         | 
| 468 | 
            +
                      type_name: name,
         | 
| 469 | 
            +
                      location: decl.decl.location&.aref(:type_params)
         | 
| 470 | 
            +
                    )
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                    decl.decl.members.each do |member|
         | 
| 473 | 
            +
                      case member
         | 
| 474 | 
            +
                      when AST::Members::MethodDefinition
         | 
| 475 | 
            +
                        validator.validate_method_definition(member, type_name: name)
         | 
| 476 | 
            +
                      end
         | 
| 477 | 
            +
                    end
         | 
| 448 478 | 
             
                  end
         | 
| 449 479 |  | 
| 450 480 | 
             
                  env.constant_decls.each do |name, const|
         | 
| @@ -460,7 +490,7 @@ EOU | |
| 460 490 |  | 
| 461 491 | 
             
                  env.alias_decls.each do |name, decl|
         | 
| 462 492 | 
             
                    stdout.puts "Validating alias: `#{name}`..."
         | 
| 463 | 
            -
                    builder. | 
| 493 | 
            +
                    builder.expand_alias1(name).tap do |type|
         | 
| 464 494 | 
             
                      validator.validate_type type, context: [Namespace.root]
         | 
| 465 495 | 
             
                    end
         | 
| 466 496 | 
             
                    validator.validate_type_alias(entry: decl)
         | 
| @@ -836,8 +866,6 @@ EOB | |
| 836 866 | 
             
                end
         | 
| 837 867 |  | 
| 838 868 | 
             
                def run_collection(args, options)
         | 
| 839 | 
            -
                  warn "warning: rbs collection is experimental, and the behavior may change until RBS v2.0"
         | 
| 840 | 
            -
             | 
| 841 869 | 
             
                  opts = collection_options(args)
         | 
| 842 870 | 
             
                  params = {}
         | 
| 843 871 | 
             
                  opts.order args.drop(1), into: params
         | 
| @@ -15,15 +15,20 @@ module RBS | |
| 15 15 | 
             
                      @lock_path = Config.to_lockfile_path(config_path)
         | 
| 16 16 | 
             
                      @lock = Config.from_path(lock_path) if lock_path.exist? && with_lockfile
         | 
| 17 17 | 
             
                      @gemfile_lock = Bundler::LockfileParser.new(gemfile_lock_path.read)
         | 
| 18 | 
            +
                      @gem_queue = []
         | 
| 18 19 | 
             
                    end
         | 
| 19 20 |  | 
| 20 21 | 
             
                    def generate
         | 
| 21 22 | 
             
                      config.gems.each do |gem|
         | 
| 22 | 
            -
                         | 
| 23 | 
            +
                        @gem_queue.push({ name: gem['name'], version: gem['version'] })
         | 
| 23 24 | 
             
                      end
         | 
| 24 25 |  | 
| 25 26 | 
             
                      gemfile_lock_gems do |spec|
         | 
| 26 | 
            -
                         | 
| 27 | 
            +
                        @gem_queue.push({ name: spec.name, version: spec.version })
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      while gem = @gem_queue.shift
         | 
| 31 | 
            +
                        assign_gem(**gem)
         | 
| 27 32 | 
             
                      end
         | 
| 28 33 | 
             
                      remove_ignored_gems!
         | 
| 29 34 |  | 
| @@ -31,30 +36,33 @@ module RBS | |
| 31 36 | 
             
                      config
         | 
| 32 37 | 
             
                    end
         | 
| 33 38 |  | 
| 34 | 
            -
                    private def assign_gem( | 
| 35 | 
            -
                      locked = lock&.gem( | 
| 36 | 
            -
                      specified = config.gem( | 
| 39 | 
            +
                    private def assign_gem(name:, version:)
         | 
| 40 | 
            +
                      locked = lock&.gem(name)
         | 
| 41 | 
            +
                      specified = config.gem(name)
         | 
| 37 42 |  | 
| 38 43 | 
             
                      return if specified&.dig('ignore')
         | 
| 39 44 | 
             
                      return if specified&.dig('source') # skip if the source is already filled
         | 
| 40 45 |  | 
| 41 | 
            -
                       | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
                        # Find the gem from gem_collection.
         | 
| 46 | 
            -
                        source = find_source(gem_name: gem_name)
         | 
| 46 | 
            +
                      # If rbs_collection.lock.yaml contain the gem, use it.
         | 
| 47 | 
            +
                      # Else find the gem from gem_collection.
         | 
| 48 | 
            +
                      unless locked
         | 
| 49 | 
            +
                        source = find_source(name: name)
         | 
| 47 50 | 
             
                        return unless source
         | 
| 48 51 |  | 
| 49 52 | 
             
                        installed_version = version
         | 
| 50 | 
            -
                        best_version = find_best_version(version: installed_version, versions: source.versions({ 'name' =>  | 
| 51 | 
            -
                         | 
| 52 | 
            -
             | 
| 53 | 
            -
                          'name' => gem_name,
         | 
| 53 | 
            +
                        best_version = find_best_version(version: installed_version, versions: source.versions({ 'name' => name }))
         | 
| 54 | 
            +
                        locked = {
         | 
| 55 | 
            +
                          'name' => name,
         | 
| 54 56 | 
             
                          'version' => best_version.to_s,
         | 
| 55 57 | 
             
                          'source' => source.to_lockfile,
         | 
| 56 58 | 
             
                        }
         | 
| 57 | 
            -
             | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                      upsert_gem specified, locked
         | 
| 62 | 
            +
                      source = Sources.from_config_entry(locked['source'])
         | 
| 63 | 
            +
                      manifest = source.manifest_of(locked) or return
         | 
| 64 | 
            +
                      manifest['dependencies']&.each do |dep|
         | 
| 65 | 
            +
                        @gem_queue.push({ name: dep['name'], version: nil} )
         | 
| 58 66 | 
             
                      end
         | 
| 59 67 | 
             
                    end
         | 
| 60 68 |  | 
| @@ -76,10 +84,10 @@ module RBS | |
| 76 84 | 
             
                      end
         | 
| 77 85 | 
             
                    end
         | 
| 78 86 |  | 
| 79 | 
            -
                    private def find_source( | 
| 87 | 
            +
                    private def find_source(name:)
         | 
| 80 88 | 
             
                      sources = config.sources
         | 
| 81 89 |  | 
| 82 | 
            -
                      sources.find { |c| c.has?({ 'name' =>  | 
| 90 | 
            +
                      sources.find { |c| c.has?({ 'name' => name, 'revision' => nil } ) }
         | 
| 83 91 | 
             
                    end
         | 
| 84 92 |  | 
| 85 93 | 
             
                    private def find_best_version(version:, versions:)
         | 
| @@ -50,6 +50,15 @@ module RBS | |
| 50 50 | 
             
                      end
         | 
| 51 51 | 
             
                    end
         | 
| 52 52 |  | 
| 53 | 
            +
                    def manifest_of(config_entry)
         | 
| 54 | 
            +
                      gem_name = config_entry['name']
         | 
| 55 | 
            +
                      version = config_entry['version'] or raise
         | 
| 56 | 
            +
                      gem_dir = gem_repo_dir.join(gem_name, version)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                      manifest_path = gem_dir.join('manifest.yaml')
         | 
| 59 | 
            +
                      YAML.safe_load(manifest_path.read) if manifest_path.exist?
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
             | 
| 53 62 | 
             
                    private def _install(dest:, config_entry:)
         | 
| 54 63 | 
             
                      gem_name = config_entry['name']
         | 
| 55 64 | 
             
                      version = config_entry['version'] or raise
         | 
| @@ -104,9 +113,9 @@ module RBS | |
| 104 113 | 
             
                      else
         | 
| 105 114 | 
             
                        begin
         | 
| 106 115 | 
             
                          # git v2.27.0 or greater
         | 
| 107 | 
            -
                          git 'clone', '--filter=blob:none', remote, git_dir.to_s
         | 
| 116 | 
            +
                          git 'clone', '--filter=blob:none', remote, git_dir.to_s, chdir: nil
         | 
| 108 117 | 
             
                        rescue CommandError
         | 
| 109 | 
            -
                          git 'clone', remote, git_dir.to_s
         | 
| 118 | 
            +
                          git 'clone', remote, git_dir.to_s, chdir: nil
         | 
| 110 119 | 
             
                        end
         | 
| 111 120 | 
             
                      end
         | 
| 112 121 |  | 
| @@ -131,7 +140,8 @@ module RBS | |
| 131 140 | 
             
                    private def git_dir
         | 
| 132 141 | 
             
                      @git_dir ||= (
         | 
| 133 142 | 
             
                        base = Pathname(ENV['XDG_CACHE_HOME'] || File.expand_path("~/.cache"))
         | 
| 134 | 
            -
                         | 
| 143 | 
            +
                        cache_key = remote.start_with?('.') ? "#{remote}\0#{Dir.pwd}" : remote
         | 
| 144 | 
            +
                        dir = base.join('rbs', Digest::SHA256.hexdigest(cache_key))
         | 
| 135 145 | 
             
                        dir.mkpath
         | 
| 136 146 | 
             
                        dir
         | 
| 137 147 | 
             
                      )
         | 
| @@ -149,13 +159,14 @@ module RBS | |
| 149 159 | 
             
                      git('rev-parse', 'HEAD').chomp
         | 
| 150 160 | 
             
                    end
         | 
| 151 161 |  | 
| 152 | 
            -
                    private def git(*cmd)
         | 
| 153 | 
            -
                      sh! 'git', *cmd
         | 
| 162 | 
            +
                    private def git(*cmd, **opt)
         | 
| 163 | 
            +
                      sh! 'git', *cmd, **opt
         | 
| 154 164 | 
             
                    end
         | 
| 155 165 |  | 
| 156 | 
            -
                    private def sh!(*cmd)
         | 
| 166 | 
            +
                    private def sh!(*cmd, **opt)
         | 
| 157 167 | 
             
                      RBS.logger.debug "$ #{cmd.join(' ')}"
         | 
| 158 | 
            -
                       | 
| 168 | 
            +
                      opt = { chdir: git_dir }.merge(opt).compact
         | 
| 169 | 
            +
                      (__skip__ = Open3.capture3(*cmd, **opt)).then do |out, err, status|
         | 
| 159 170 | 
             
                        raise CommandError, "Unexpected status #{status.exitstatus}\n\n#{err}" unless status.success?
         | 
| 160 171 |  | 
| 161 172 | 
             
                        out
         | 
| @@ -25,6 +25,13 @@ module RBS | |
| 25 25 | 
             
                      stdout.puts "Using #{name}:#{version} (#{from})"
         | 
| 26 26 | 
             
                    end
         | 
| 27 27 |  | 
| 28 | 
            +
                    def manifest_of(config_entry)
         | 
| 29 | 
            +
                      _, sig_path = gem_sig_path(config_entry)
         | 
| 30 | 
            +
                      sig_path or raise
         | 
| 31 | 
            +
                      manifest_path = sig_path.join('manifest.yaml')
         | 
| 32 | 
            +
                      YAML.safe_load(manifest_path.read) if manifest_path.exist?
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 28 35 | 
             
                    def to_lockfile
         | 
| 29 36 | 
             
                      {
         | 
| 30 37 | 
             
                        'type' => 'rubygems',
         | 
| @@ -23,6 +23,12 @@ module RBS | |
| 23 23 | 
             
                      stdout.puts "Using #{name}:#{version} (#{from})"
         | 
| 24 24 | 
             
                    end
         | 
| 25 25 |  | 
| 26 | 
            +
                    def manifest_of(config_entry)
         | 
| 27 | 
            +
                      version = config_entry['version'] or raise
         | 
| 28 | 
            +
                      manifest_path = gem_dir(config_entry).join(version, 'manifest.yaml')
         | 
| 29 | 
            +
                      YAML.safe_load(manifest_path.read) if manifest_path.exist?
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 26 32 | 
             
                    def to_lockfile
         | 
| 27 33 | 
             
                      {
         | 
| 28 34 | 
             
                        'type' => 'stdlib',
         | 
    
        data/lib/rbs/definition.rb
    CHANGED
    
    | @@ -155,6 +155,15 @@ module RBS | |
| 155 155 | 
             
                    )
         | 
| 156 156 | 
             
                  end
         | 
| 157 157 |  | 
| 158 | 
            +
                  def map_type_bound(&block)
         | 
| 159 | 
            +
                    self.class.new(
         | 
| 160 | 
            +
                      super_method: super_method&.map_type_bound(&block),
         | 
| 161 | 
            +
                      defs: defs.map {|defn| defn.update(type: defn.type.map_type_bound(&block)) },
         | 
| 162 | 
            +
                      accessibility: @accessibility,
         | 
| 163 | 
            +
                      alias_of: alias_of
         | 
| 164 | 
            +
                    )
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
             | 
| 158 167 | 
             
                  def map_method_type(&block)
         | 
| 159 168 | 
             
                    self.class.new(
         | 
| 160 169 | 
             
                      super_method: super_method,
         | 
| @@ -291,6 +291,10 @@ module RBS | |
| 291 291 | 
             
                        end
         | 
| 292 292 |  | 
| 293 293 | 
             
                        one_ancestors.each_extended_module do |mod|
         | 
| 294 | 
            +
                          mod.args.each do |arg|
         | 
| 295 | 
            +
                            validate_type_presence(arg)
         | 
| 296 | 
            +
                          end
         | 
| 297 | 
            +
             | 
| 294 298 | 
             
                          mod_defn = build_instance(mod.name, no_self_types: true)
         | 
| 295 299 | 
             
                          merge_definition(src: mod_defn,
         | 
| 296 300 | 
             
                                           dest: definition,
         | 
| @@ -299,6 +303,10 @@ module RBS | |
| 299 303 |  | 
| 300 304 | 
             
                        interface_methods = {}
         | 
| 301 305 | 
             
                        one_ancestors.each_extended_interface do |mod|
         | 
| 306 | 
            +
                          mod.args.each do |arg|
         | 
| 307 | 
            +
                            validate_type_presence(arg)
         | 
| 308 | 
            +
                          end
         | 
| 309 | 
            +
             | 
| 302 310 | 
             
                          mod_defn = build_interface(mod.name)
         | 
| 303 311 | 
             
                          subst = Substitution.build(mod_defn.type_params, mod.args)
         | 
| 304 312 |  | 
| @@ -377,7 +385,7 @@ module RBS | |
| 377 385 | 
             
                            initialize = instance.methods[:initialize]
         | 
| 378 386 |  | 
| 379 387 | 
             
                            if initialize
         | 
| 380 | 
            -
                              class_params = entry.type_params | 
| 388 | 
            +
                              class_params = entry.type_params
         | 
| 381 389 |  | 
| 382 390 | 
             
                              # Inject a virtual _typed new_.
         | 
| 383 391 | 
             
                              initialize_defs = initialize.defs
         | 
| @@ -386,28 +394,34 @@ module RBS | |
| 386 394 | 
             
                                defs: initialize_defs.map do |initialize_def|
         | 
| 387 395 | 
             
                                  method_type = initialize_def.type
         | 
| 388 396 |  | 
| 389 | 
            -
                                  class_type_param_vars = Set.new(class_params)
         | 
| 390 | 
            -
                                  method_type_param_vars = Set.new(method_type.type_params)
         | 
| 397 | 
            +
                                  class_type_param_vars = Set.new(class_params.map(&:name))
         | 
| 398 | 
            +
                                  method_type_param_vars = Set.new(method_type.type_params.map(&:name))
         | 
| 391 399 |  | 
| 392 400 | 
             
                                  if class_type_param_vars.intersect?(method_type_param_vars)
         | 
| 393 | 
            -
                                     | 
| 394 | 
            -
                                      if class_type_param_vars.include?(name)
         | 
| 395 | 
            -
                                        Types::Variable.fresh(name).name
         | 
| 401 | 
            +
                                    new_method_param_names = method_type.type_params.map do |method_param|
         | 
| 402 | 
            +
                                      if class_type_param_vars.include?(method_param.name)
         | 
| 403 | 
            +
                                        Types::Variable.fresh(method_param.name).name
         | 
| 396 404 | 
             
                                      else
         | 
| 397 | 
            -
                                        name
         | 
| 405 | 
            +
                                        method_param.name
         | 
| 398 406 | 
             
                                      end
         | 
| 399 407 | 
             
                                    end
         | 
| 400 | 
            -
                                    method_params = class_params + renamed_method_params
         | 
| 401 408 |  | 
| 402 | 
            -
                                    sub = Substitution.build( | 
| 409 | 
            +
                                    sub = Substitution.build(
         | 
| 410 | 
            +
                                      method_type.type_params.map(&:name),
         | 
| 411 | 
            +
                                      Types::Variable.build(new_method_param_names)
         | 
| 412 | 
            +
                                    )
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                                    method_params = class_params + AST::TypeParam.rename(method_type.type_params, new_names: new_method_param_names)
         | 
| 415 | 
            +
                                    method_type = method_type
         | 
| 416 | 
            +
                                      .update(type_params: [])
         | 
| 417 | 
            +
                                      .sub(sub)
         | 
| 418 | 
            +
                                      .update(type_params: method_params)
         | 
| 403 419 | 
             
                                  else
         | 
| 404 | 
            -
                                     | 
| 405 | 
            -
             | 
| 420 | 
            +
                                    method_type = method_type
         | 
| 421 | 
            +
                                      .update(type_params: class_params + method_type.type_params)
         | 
| 406 422 | 
             
                                  end
         | 
| 407 423 |  | 
| 408 | 
            -
                                  method_type = method_type.map_type {|ty| ty.sub(sub) }
         | 
| 409 424 | 
             
                                  method_type = method_type.update(
         | 
| 410 | 
            -
                                    type_params: method_params,
         | 
| 411 425 | 
             
                                    type: method_type.type.with_return_type(
         | 
| 412 426 | 
             
                                      Types::ClassInstance.new(
         | 
| 413 427 | 
             
                                        name: type_name,
         | 
| @@ -438,7 +452,7 @@ module RBS | |
| 438 452 |  | 
| 439 453 | 
             
                def validate_params_with(type_params, result:)
         | 
| 440 454 | 
             
                  type_params.each do |param|
         | 
| 441 | 
            -
                    unless param. | 
| 455 | 
            +
                    unless param.unchecked?
         | 
| 442 456 | 
             
                      unless result.compatible?(param.name, with_annotation: param.variance)
         | 
| 443 457 | 
             
                        yield param
         | 
| 444 458 | 
             
                      end
         | 
| @@ -781,9 +795,36 @@ module RBS | |
| 781 795 | 
             
                end
         | 
| 782 796 |  | 
| 783 797 | 
             
                def expand_alias(type_name)
         | 
| 784 | 
            -
                   | 
| 798 | 
            +
                  expand_alias2(type_name, [])
         | 
| 799 | 
            +
                end
         | 
| 800 | 
            +
             | 
| 801 | 
            +
                def expand_alias1(type_name)
         | 
| 802 | 
            +
                  entry = env.alias_decls[type_name] or raise "Unknown alias name: #{type_name}"
         | 
| 803 | 
            +
                  as = entry.decl.type_params.each.map { Types::Bases::Any.new(location: nil) }
         | 
| 804 | 
            +
                  expand_alias2(type_name, as)
         | 
| 805 | 
            +
                end
         | 
| 806 | 
            +
             | 
| 807 | 
            +
                def expand_alias2(type_name, args)
         | 
| 808 | 
            +
                  entry = env.alias_decls[type_name] or raise "Unknown alias name: #{type_name}"
         | 
| 809 | 
            +
             | 
| 785 810 | 
             
                  ensure_namespace!(type_name.namespace, location: entry.decl.location)
         | 
| 786 | 
            -
                  entry.decl. | 
| 811 | 
            +
                  params = entry.decl.type_params.each.map(&:name)
         | 
| 812 | 
            +
             | 
| 813 | 
            +
                  unless params.size == args.size
         | 
| 814 | 
            +
                    as = "[#{args.join(", ")}]" unless args.empty?
         | 
| 815 | 
            +
                    ps = "[#{params.join(", ")}]" unless params.empty?
         | 
| 816 | 
            +
             | 
| 817 | 
            +
                    raise "Invalid type application: type = #{type_name}#{as}, decl = #{type_name}#{ps}"
         | 
| 818 | 
            +
                  end
         | 
| 819 | 
            +
             | 
| 820 | 
            +
                  type = entry.decl.type
         | 
| 821 | 
            +
             | 
| 822 | 
            +
                  unless params.empty?
         | 
| 823 | 
            +
                    subst = Substitution.build(params, args)
         | 
| 824 | 
            +
                    type = type.sub(subst)
         | 
| 825 | 
            +
                  end
         | 
| 826 | 
            +
             | 
| 827 | 
            +
                  type
         | 
| 787 828 | 
             
                end
         | 
| 788 829 |  | 
| 789 830 | 
             
                def update(env:, except:, ancestor_builder:)
         | 
| @@ -804,5 +845,26 @@ module RBS | |
| 804 845 | 
             
                    end
         | 
| 805 846 | 
             
                  end
         | 
| 806 847 | 
             
                end
         | 
| 848 | 
            +
             | 
| 849 | 
            +
                def validate_type_presence(type)
         | 
| 850 | 
            +
                  case type
         | 
| 851 | 
            +
                  when Types::ClassInstance, Types::ClassSingleton, Types::Interface, Types::Alias
         | 
| 852 | 
            +
                    validate_type_name(type.name, type.location)
         | 
| 853 | 
            +
                  end
         | 
| 854 | 
            +
             | 
| 855 | 
            +
                  type.each_type do |type|
         | 
| 856 | 
            +
                    validate_type_presence(type)
         | 
| 857 | 
            +
                  end
         | 
| 858 | 
            +
                end
         | 
| 859 | 
            +
             | 
| 860 | 
            +
                def validate_type_name(name, location)
         | 
| 861 | 
            +
                  name = name.absolute!
         | 
| 862 | 
            +
             | 
| 863 | 
            +
                  return if name.class? && env.class_decls.key?(name)
         | 
| 864 | 
            +
                  return if name.interface? && env.interface_decls.key?(name)
         | 
| 865 | 
            +
                  return if name.alias? && env.alias_decls.key?(name)
         | 
| 866 | 
            +
             | 
| 867 | 
            +
                  raise NoTypeFoundError.new(type_name: name, location: location)
         | 
| 868 | 
            +
                end
         | 
| 807 869 | 
             
              end
         | 
| 808 870 | 
             
            end
         |