Skip to content

Commit

Permalink
Compiler: require free vars to be specified with forall
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Dec 23, 2016
1 parent 352d5f0 commit 991e39b
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 9 deletions.
11 changes: 11 additions & 0 deletions spec/compiler/semantic/restrictions_spec.cr
Expand Up @@ -407,4 +407,15 @@ describe "Restrictions" do
),
"no overload matches"
end

it "errors if using free var without forall" do
assert_error %(
def foo(x : T)
T
end
foo(1)
),
"undefined constant T"
end
end
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/default_arguments.cr
Expand Up @@ -128,7 +128,7 @@ class Crystal::Def
# a temporary variable (tmp_var) and then replace all ocurrences of that free var with typeof(tmp_var)
# to achieve the same effect, since we can't define a type alias inside a method.
restriction = arg.restriction
if restriction.is_a?(Path) && restriction.names.size == 1 && (Parser.free_var_name?(restriction.names.first) || free_vars.try(&.includes?(restriction.names.first)))
if restriction.is_a?(Path) && restriction.names.size == 1 && free_vars.try(&.includes?(restriction.names.first))
restriction_name = program.new_temp_var_name
new_body << Assign.new(Var.new(restriction_name), Var.new(arg.name))
body = body.transform(ReplaceFreeVarTransformer.new(restriction.names.first, restriction_name))
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/restrictions.cr
Expand Up @@ -377,7 +377,7 @@ module Crystal

if single_name
first_name = other.names.first
if context.defining_type.type_var?(first_name) || Parser.free_var_name?(first_name)
if context.defining_type.type_var?(first_name)
return context.set_free_var(first_name, self)
end
end
Expand Down Expand Up @@ -856,7 +856,7 @@ module Crystal
single_name = other.names.size == 1
if single_name
first_name = other.names.first
if context.defining_type.type_var?(first_name) || Parser.free_var_name?(first_name)
if context.defining_type.type_var?(first_name)
return context.set_free_var(first_name, self)
else
other.raise_undefined_constant(context.defining_type)
Expand Down
4 changes: 0 additions & 4 deletions src/compiler/crystal/syntax/parser.cr
Expand Up @@ -5359,9 +5359,5 @@ module Crystal
@visibility = old_visibility
value
end

def self.free_var_name?(name)
name.size == 1 || (name.size == 2 && name[1].ascii_number?)
end
end
end
4 changes: 2 additions & 2 deletions src/enumerable.cr
Expand Up @@ -91,7 +91,7 @@ module Enumerable(T)
# * `Enumerable::Chunk::Alone` specifies that the element should be chunked by itself
#
# See also: `Iterator#chunk`
def chunks(&block : T -> U)
def chunks(&block : T -> U) forall U
res = [] of Tuple(U, Array(T))
chunks_internal(block) { |k, v| res << {k, v} }
res
Expand Down Expand Up @@ -160,7 +160,7 @@ module Enumerable(T)
end
end

private def chunks_internal(original_block : T -> U)
private def chunks_internal(original_block : T -> U) forall U
acc = Chunk::Accumulator(T, U).new
each do |val|
key = original_block.call(val)
Expand Down

0 comments on commit 991e39b

Please sign in to comment.