Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect cyclic includes between generic modules #10529

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions spec/compiler/semantic/module_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,67 @@ describe "Semantic: module" do
", "cyclic include detected"
end

it "gives error when including self, generic module" do
assert_error "
module Foo(T)
include self
end
", "cyclic include detected"
end

it "gives error when including instantiation of self, generic module" do
assert_error "
module Foo(T)
include Foo(Int32)
end
", "cyclic include detected"
end

it "gives error with cyclic include, generic module" do
assert_error "
module Foo(T)
end

module Bar(T)
include Foo(T)
end

module Foo(T)
include Bar(T)
end
", "cyclic include detected"
end

it "gives error with cyclic include between non-generic and generic module" do
assert_error "
module Foo
end

module Bar(T)
include Foo
end

module Foo
include Bar(Int32)
end
", "cyclic include detected"
end

it "gives error with cyclic include between non-generic and generic module (2)" do
assert_error "
module Bar(T)
end

module Foo
include Bar(Int32)
end

module Bar(T)
include Foo
end
", "cyclic include detected"
end

it "finds types close to included module" do
assert_type("
module Foo
Expand Down
20 changes: 13 additions & 7 deletions src/compiler/crystal/types.cr
Original file line number Diff line number Diff line change
Expand Up @@ -944,16 +944,22 @@ module Crystal
end

def include(mod)
if mod == self
raise TypeException.new "cyclic include detected"
elsif mod.ancestors.includes?(self)
generic_module = mod.is_a?(GenericModuleInstanceType) ? mod.generic_type : mod

if generic_module == self
raise TypeException.new "cyclic include detected"
else
unless parents.includes?(mod)
parents.insert 0, mod
mod.add_including_type(self)
end

generic_module.ancestors.each do |ancestor|
if ancestor == self || ancestor.is_a?(GenericModuleInstanceType) && ancestor.generic_type == self
raise TypeException.new "cyclic include detected"
end
end

unless parents.includes?(mod)
parents.insert 0, mod
mod.add_including_type(self)
end
end

def type_desc
Expand Down