Skip to content
5 changes: 5 additions & 0 deletions lib/rbs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require "logger"
require "tsort"
require "strscan"
require "prism"

require "rbs/errors"
require "rbs/buffer"
Expand All @@ -24,7 +25,11 @@
require "rbs/ast/members"
require "rbs/ast/annotation"
require "rbs/ast/visitor"
require "rbs/ast/ruby/helpers/constant_helper"
require "rbs/ast/ruby/helpers/location_helper"
require "rbs/ast/ruby/declarations"
require "rbs/source"
require "rbs/inline_parser"
require "rbs/environment"
require "rbs/environment/use_map"
require "rbs/environment/class_entry"
Expand Down
86 changes: 86 additions & 0 deletions lib/rbs/ast/ruby/declarations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

module RBS
module AST
module Ruby
module Declarations
class Base
attr_reader :buffer

include Helpers::ConstantHelper
include Helpers::LocationHelper

def initialize(buffer)
@buffer = buffer
end
end

class ClassDecl < Base
attr_reader :class_name

attr_reader :members

attr_reader :node

def initialize(buffer, name, node)
super(buffer)
@class_name = name
@node = node
@members = []
end

def each_decl(&block)
return enum_for(:each_decl) unless block

@members.each do |member|
if member.is_a?(Base)
yield member
end
end
end

def super_class = nil

def type_params = []

def location
rbs_location(node.location)
end
end

class ModuleDecl < Base
attr_reader :module_name

attr_reader :members

attr_reader :node

def initialize(buffer, name, node)
super(buffer)
@module_name = name
@node = node
@members = []
end

def each_decl(&block)
return enum_for(:each_decl) unless block

@members.each do |member|
if member.is_a?(Base)
yield member
end
end
end

def type_params = []

def self_types = []

def location
rbs_location(node.location)
end
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/rbs/ast/ruby/helpers/constant_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module RBS
module AST
module Ruby
module Helpers
module ConstantHelper
module_function

def constant_as_type_name(node)
case node
when Prism::ConstantPathNode, Prism::ConstantReadNode
begin
TypeName.parse(node.full_name)
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
nil
end
end
end
end
end
end
end
end
15 changes: 15 additions & 0 deletions lib/rbs/ast/ruby/helpers/location_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module RBS
module AST
module Ruby
module Helpers
module LocationHelper
def rbs_location(location)
Location.new(buffer, location.start_character_offset, location.end_character_offset)
end
end
end
end
end
end
61 changes: 33 additions & 28 deletions lib/rbs/cli/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,38 +170,43 @@ def validate_class_module_definition
TypeParamDefaultReferenceError.check!(d.type_params)

entry.each_decl do |decl|
decl.each_member do |member|
case member
when AST::Members::MethodDefinition
@validator.validate_method_definition(member, type_name: name)
member.overloads.each do |ov|
void_type_context_validator(ov.method_type)
end
when AST::Members::Attribute
void_type_context_validator(member.type)
when AST::Members::Mixin
member.args.each do |arg|
no_self_type_validator(arg)
unless arg.is_a?(Types::Bases::Void)
void_type_context_validator(arg, true)
case decl
when AST::Declarations::Base
decl.each_member do |member|
case member
when AST::Members::MethodDefinition
@validator.validate_method_definition(member, type_name: name)
member.overloads.each do |ov|
void_type_context_validator(ov.method_type)
end
end
params =
if member.name.class?
module_decl = @env.normalized_module_entry(member.name) or raise
module_decl.type_params
else
interface_decl = @env.interface_decls.fetch(member.name)
interface_decl.decl.type_params
when AST::Members::Attribute
void_type_context_validator(member.type)
when AST::Members::Mixin
member.args.each do |arg|
no_self_type_validator(arg)
unless arg.is_a?(Types::Bases::Void)
void_type_context_validator(arg, true)
end
end
params =
if member.name.class?
module_decl = @env.normalized_module_entry(member.name) or raise
module_decl.type_params
else
interface_decl = @env.interface_decls.fetch(member.name)
interface_decl.decl.type_params
end
InvalidTypeApplicationError.check!(type_name: member.name, params: params, args: member.args, location: member.location)
when AST::Members::Var
@validator.validate_variable(member)
void_type_context_validator(member.type)
if member.is_a?(AST::Members::ClassVariable)
no_self_type_validator(member.type)
end
InvalidTypeApplicationError.check!(type_name: member.name, params: params, args: member.args, location: member.location)
when AST::Members::Var
@validator.validate_variable(member)
void_type_context_validator(member.type)
if member.is_a?(AST::Members::ClassVariable)
no_self_type_validator(member.type)
end
end
else
raise "Unknown declaration: #{decl.class}"
end
end
rescue BaseError => error
Expand Down
4 changes: 4 additions & 0 deletions lib/rbs/definition_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@ def source_location(source, decl)
case decl
when AST::Declarations::Class
decl.super_class&.location
when AST::Ruby::Declarations::ClassDecl
nil
else
raise "Unexpected `:super` source location with #{decl.class}"
end
else
source.location
Expand Down
95 changes: 50 additions & 45 deletions lib/rbs/definition_builder/ancestor_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,68 +348,73 @@ def one_interface_ancestors(type_name)
end

def mixin_ancestors0(decl, type_name, align_params:, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:)
decl.each_mixin do |member|
case member
when AST::Members::Include
module_name = member.name
module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }
case decl
when AST::Declarations::Base
decl.each_mixin do |member|
case member
when AST::Members::Include
module_name = member.name
module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }

case
when member.name.class? && included_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)
case
when member.name.class? && included_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)

module_decl = env.normalized_module_entry(module_name) or raise
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)
module_decl = env.normalized_module_entry(module_name) or raise
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

module_name = env.normalize_module_name(module_name)
included_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
when member.name.interface? && included_interfaces
NoMixinFoundError.check!(member.name, env: env, member: member)
module_name = env.normalize_module_name(module_name)
included_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
when member.name.interface? && included_interfaces
NoMixinFoundError.check!(member.name, env: env, member: member)

interface_decl = env.interface_decls.fetch(module_name)
module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)
interface_decl = env.interface_decls.fetch(module_name)
module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)

included_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
end
included_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
end

when AST::Members::Prepend
if prepended_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)
when AST::Members::Prepend
if prepended_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)

module_decl = env.normalized_module_entry(member.name) or raise
module_name = module_decl.name
module_decl = env.normalized_module_entry(member.name) or raise
module_name = module_decl.name

module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)
module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

prepended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
end
prepended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
end

when AST::Members::Extend
module_name = member.name
module_args = member.args
when AST::Members::Extend
module_name = member.name
module_args = member.args

case
when member.name.class? && extended_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)
case
when member.name.class? && extended_modules
MixinClassError.check!(type_name: type_name, env: env, member: member)
NoMixinFoundError.check!(member.name, env: env, member: member)

module_decl = env.normalized_module_entry(module_name) or raise
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)
module_decl = env.normalized_module_entry(module_name) or raise
module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

module_name = env.normalize_module_name(module_name)
extended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
when member.name.interface? && extended_interfaces
NoMixinFoundError.check!(member.name, env: env, member: member)
module_name = env.normalize_module_name(module_name)
extended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
when member.name.interface? && extended_interfaces
NoMixinFoundError.check!(member.name, env: env, member: member)

interface_decl = env.interface_decls.fetch(module_name)
module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)
interface_decl = env.interface_decls.fetch(module_name)
module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)

extended_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
extended_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
end
end
end
when AST::Ruby::Declarations::Base
# noop
end
end

Expand Down
Loading