Skip to content

Commit

Permalink
Raise an error if a class definition inherits a module
Browse files Browse the repository at this point in the history
  • Loading branch information
soutaro committed Nov 17, 2022
1 parent adc38f8 commit d939368
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lib/rbs/definition_builder/ancestor_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ def one_instance_ancestors(type_name)
end

NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
if super_class
InheritModuleError.check!(super_class, env: env)
end

ancestors = OneAncestors.class_instance(
type_name: type_name,
Expand Down Expand Up @@ -268,6 +271,9 @@ def one_singleton_ancestors(type_name)
end

NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
if super_class
InheritModuleError.check!(super_class, env: env)
end

ancestors = OneAncestors.singleton(
type_name: type_name,
Expand Down
22 changes: 21 additions & 1 deletion lib/rbs/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,27 @@ def initialize(type_name:, location:)
end

def self.check!(type_name, env:, location:)
env.class_decls.key?(type_name) or raise new(type_name: type_name, location: location)
if decl = env.class_decls[type_name]
return
end

raise new(type_name: type_name, location: location)
end
end

class InheritModuleError < DefinitionError
attr_reader :super_decl

def initialize(super_decl)
@super_decl = super_decl

super "#{Location.to_string(super_decl.location)}: Cannot inherit a module: #{super_decl.name}"
end

def self.check!(super_decl, env:)
return if env.class_decls[super_decl.name].is_a?(Environment::ClassEntry)

raise new(super_decl)
end
end

Expand Down
14 changes: 14 additions & 0 deletions sig/errors.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ module RBS
def location: () -> Location[untyped, untyped]?
end

# MixinClassError is raised if a include/prepend/extend has a class (not a module) to mix-in
#
class MixinClassError < DefinitionError
type member = AST::Members::Include | AST::Members::Prepend | AST::Members::Extend

Expand All @@ -212,6 +214,18 @@ module RBS
def mixin_name: () -> String
end

# InheritModuleError is raised if a class definition inherits a module (not a class)
#
class InheritModuleError < DefinitionError
attr_reader super_decl: AST::Declarations::Class::Super

def initialize: (AST::Declarations::Class::Super) -> void

def location: () -> Location[untyped, untyped]?

def self.check!: (AST::Declarations::Class::Super, env: Environment) -> void
end

class RecursiveTypeAliasError < BaseError
attr_reader alias_names: Array[TypeName]
attr_reader location: Location[untyped, untyped]?
Expand Down
19 changes: 19 additions & 0 deletions test/rbs/definition_builder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2243,4 +2243,23 @@ class Foo
end
end
end

def test_class_definition_inheriting_module
SignatureManager.new do |manager|
manager.files.merge!(Pathname("foo.rbs") => <<~EOF)
module Mod
end
class Foo < Mod
end
EOF

manager.build do |env|
builder = DefinitionBuilder.new(env: env)

assert_raises(RBS::InheritModuleError) { builder.build_instance(type_name("::Foo")) }
assert_raises(RBS::InheritModuleError) { builder.build_singleton(type_name("::Foo")) }
end
end
end
end

0 comments on commit d939368

Please sign in to comment.