Skip to content

It defines wrong Class#new type from initialize #459

@pocke

Description

@pocke

DefinitionBuilder defines Class#new method if it doesn't exist and initialize is available for the instance.

unless definition.methods.key?(:new)
instance = build_instance(type_name)
initialize = instance.methods[:initialize]
if initialize
class_params = entry.type_params.each.map(&:name)
initialize_defs = initialize.defs
definition.methods[:new] = Definition::Method.new(
super_method: nil,
defs: initialize_defs.map do |initialize_def|
method_type = initialize_def.type
class_type_param_vars = Set.new(class_params)
method_type_param_vars = Set.new(method_type.type_params)
if class_type_param_vars.intersect?(method_type_param_vars)
renamed_method_params = method_type.type_params.map do |name|
if class_type_param_vars.include?(name)
Types::Variable.fresh(name).name
else
name
end
end
method_params = class_params + renamed_method_params
sub = Substitution.build(method_type.type_params, Types::Variable.build(renamed_method_params))
else
method_params = class_params + method_type.type_params
sub = Substitution.build([], [])
end
method_type = method_type.map_type {|ty| ty.sub(sub) }
method_type = method_type.update(
type_params: method_params,
type: method_type.type.with_return_type(Types::Bases::Instance.new(location: nil))
)
Definition::Method::TypeDef.new(
type: method_type,
member: initialize_def.member,
defined_in: initialize_def.defined_in,
implemented_in: initialize_def.implemented_in
)
end,
accessibility: :public,
annotations: [AST::Annotation.new(location: nil, string: "rbs:test:target")]
)
end
end

But it has two problems.

First, it conceals new method that is defined in an ancestor.
For example:

# RBS

class C
  def self.new: (String) -> untyped
end

class C2 < C
end
# it is ok.
$ rbs -I . method --singleton C new
::C.new
  defined_in: ::C
  implementation: ::C
  accessibility: public
  types:
      (::String) -> untyped

# It should be `(::String) -> untyped`, but doesn't.
$ rbs -I . method --singleton C2 new
::C2.new
  defined_in: 
  implementation: 
  accessibility: public
  types:
      () -> ::C2

Second, it defines new method for Module unexpectedly.
For example:

# RBS

module M
  def initialize: (String, Integer) -> void
end
# M.new should not exist, but it exists.
$ rbs -I . method --singleton M new
::M.new
  defined_in: 
  implementation: 
  accessibility: public
  types:
      (::String, ::Integer) -> ::M

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions