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

Make self to be eager evaluated when including modules #6557

Merged
merged 1 commit into from
Aug 20, 2018
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
25 changes: 14 additions & 11 deletions spec/compiler/semantic/module_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ describe "Semantic: module" do
end

Baz.new.foo
") { types["Baz"].metaclass }
") { generic_class("Bar", int32).metaclass }
end

it "includes generic module with self (check argument type, success)" do
Expand Down Expand Up @@ -303,15 +303,15 @@ describe "Semantic: module" do
class Baz1 < Bar(Int32)
end

class Baz2 < Bar(Int32)
class Baz2 < Bar(Float64)
end

Baz1.new.foo Baz2.new
", "no overload matches"
end

it "includes generic module with self (check argument superclass type, error)" do
assert_error "
it "includes generic module with self (check argument superclass type, success)" do
assert_type("
module Foo(T)
def foo(x : T)
x
Expand All @@ -322,11 +322,14 @@ describe "Semantic: module" do
include Foo(self)
end

class Baz < Bar(Int32)
class Baz1 < Bar(Int32)
end

Baz.new.foo Bar(Int32).new
", "no overload matches"
class Baz2 < Bar(Int32)
end

Baz1.new.foo Baz2.new
") { types["Baz2"] }
end

it "includes generic module with self (check return type, success)" do
Expand Down Expand Up @@ -376,11 +379,11 @@ describe "Semantic: module" do
include Foo(self)
end

class Baz < Bar(Int32)
class Baz < Bar(Float64)
end

Baz.new.foo
", "type must be Baz, not Bar(Int32)"
", "type must be Bar(Float64), not Bar(Int32)"
end

it "includes generic module with self (check return subclass type, error)" do
Expand All @@ -398,11 +401,11 @@ describe "Semantic: module" do
class Baz1 < Bar(Int32)
end

class Baz2 < Bar(Int32)
class Baz2 < Bar(Float64)
end

Baz1.new.foo
", "type must be Baz1, not Baz2"
", "type must be Bar(Int32), not Baz2"
end

it "includes module but can't access metaclass methods" do
Expand Down
3 changes: 0 additions & 3 deletions src/compiler/crystal/macros/interpreter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,6 @@ module Crystal
end

TypeNode.new(matched_type)
when Self
target = @scope == @program.class_type ? @scope : @scope.instance_type
TypeNode.new(target)
when ASTNode
matched_type
else
Expand Down
2 changes: 0 additions & 2 deletions src/compiler/crystal/semantic/main_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,6 @@ module Crystal
# It's different if from a virtual type we do `v.class.new`
# because the class could be any in the hierarchy.
node.type = check_type_in_type_args(type.remove_alias_if_simple).devirtualize
when Self
node.type = check_type_in_type_args(the_self(node).remove_alias_if_simple)
when ASTNode
type.accept self unless type.type?
node.syntax_replacement = type
Expand Down
2 changes: 0 additions & 2 deletions src/compiler/crystal/semantic/semantic_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,11 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor

def lookup_type(node : ASTNode,
free_vars = nil,
lazy_self = false,
find_root_generic_type_parameters = true)
current_type.lookup_type(
node,
free_vars: free_vars,
allow_typeof: false,
lazy_self: lazy_self,
find_root_generic_type_parameters: find_root_generic_type_parameters
)
end
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
def include_in(current_type, node, kind)
node_name = node.name

type = lookup_type(node_name, lazy_self: true)
type = lookup_type(node_name)
case type
when GenericModuleType
node.raise "wrong number of type vars for #{type} (given 0, expected #{type.type_vars.size})"
Expand Down
21 changes: 7 additions & 14 deletions src/compiler/crystal/semantic/type_lookup.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,28 @@ class Crystal::Type
# ```
#
# If `self` is `Foo` and `Bar(Baz)` is given, the result will be `Foo::Bar(Baz)`.
def lookup_type(node : ASTNode, self_type = self.instance_type, allow_typeof = true, lazy_self = false, free_vars : Hash(String, TypeVar)? = nil, find_root_generic_type_parameters = true) : Type
TypeLookup.new(self, self_type, true, allow_typeof, lazy_self, free_vars, find_root_generic_type_parameters).lookup(node).not_nil!
def lookup_type(node : ASTNode, self_type = self.instance_type, allow_typeof = true, free_vars : Hash(String, TypeVar)? = nil, find_root_generic_type_parameters = true) : Type
TypeLookup.new(self, self_type, true, allow_typeof, free_vars, find_root_generic_type_parameters).lookup(node).not_nil!
end

# Similar to `lookup_type`, but returns `nil` if a type can't be found.
def lookup_type?(node : ASTNode, self_type = self.instance_type, allow_typeof = true, lazy_self = false, free_vars : Hash(String, TypeVar)? = nil, find_root_generic_type_parameters = true) : Type?
TypeLookup.new(self, self_type, false, allow_typeof, lazy_self, free_vars, find_root_generic_type_parameters).lookup(node)
def lookup_type?(node : ASTNode, self_type = self.instance_type, allow_typeof = true, free_vars : Hash(String, TypeVar)? = nil, find_root_generic_type_parameters = true) : Type?
TypeLookup.new(self, self_type, false, allow_typeof, free_vars, find_root_generic_type_parameters).lookup(node)
end

# Similar to `lookup_type`, but the result might also be an ASTNode, for example when
# looking `N` relative to a StaticArray.
def lookup_type_var(node : Path, free_vars : Hash(String, TypeVar)? = nil, find_root_generic_type_parameters = true) : Type | ASTNode
TypeLookup.new(self, self.instance_type, true, false, false, free_vars, find_root_generic_type_parameters).lookup_type_var(node).not_nil!
TypeLookup.new(self, self.instance_type, true, false, free_vars, find_root_generic_type_parameters).lookup_type_var(node).not_nil!
end

# Similar to `lookup_type_var`, but might return `nil`.
def lookup_type_var?(node : Path, free_vars : Hash(String, TypeVar)? = nil, raise = false, find_root_generic_type_parameters = true) : Type | ASTNode | Nil
TypeLookup.new(self, self.instance_type, raise, false, false, free_vars, find_root_generic_type_parameters).lookup_type_var?(node)
TypeLookup.new(self, self.instance_type, raise, false, free_vars, find_root_generic_type_parameters).lookup_type_var?(node)
end

private struct TypeLookup
def initialize(@root : Type, @self_type : Type, @raise : Bool, @allow_typeof : Bool, @lazy_self : Bool, @free_vars : Hash(String, TypeVar)? = nil, @find_root_generic_type_parameters = true)
def initialize(@root : Type, @self_type : Type, @raise : Bool, @allow_typeof : Bool, @free_vars : Hash(String, TypeVar)? = nil, @find_root_generic_type_parameters = true)
@in_generic_args = 0

# If we are looking types inside a non-instantiated generic type,
Expand Down Expand Up @@ -91,8 +91,6 @@ class Crystal::Type
end
when Type
return type_var
when Self
return lookup(type_var)
end

if @raise
Expand Down Expand Up @@ -220,11 +218,6 @@ class Crystal::Type
type_vars = Array(TypeVar).new(node.type_vars.size + 1)
node.type_vars.each do |type_var|
case type_var
when Self
if @lazy_self
type_vars << type_var
next
end
when NumberLiteral
type_vars << type_var
next
Expand Down
5 changes: 5 additions & 0 deletions src/enum.cr
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ struct Enum
value <=> other.value
end

# :nodoc:
def ==(other)
false
end

# Returns `true` if this enum member's value includes *other*. This
# performs a logical "and" between this enum member's value and *other*'s,
# so instead of writing:
Expand Down