crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.45k stars 1.62k forks source link

Bug: Can't assign block parameter to class var in block scope #7305

Open sudo-nice opened 5 years ago

sudo-nice commented 5 years ago

This code fails to compile:

require "option_parser"

ARGV.concat %w[--foo FOO]

module Options
  class_getter foo = ""

  OptionParser.parse! do |parser|
    parser.on("--foo STRING", "Foo it") { |str| @@foo = str }
  end
end

Weird error:

undefined method 'str' (If you declared 'str' in a suffix if, declare it in
a regular if for this to work. If the variable was declared in a macro it's not
visible outsid e it)

    parser.on("--foo STRING", "Foo it") { |str| @@foo = str }
                                                        ^~~

But this works:

require "option_parser"

ARGV << "--foo"

module Options
  class_getter foo = false

  OptionParser.parse! do |parser|
    parser.on("--foo", "Foo it") { @@foo = true }
  end
end

Options.foo # => true

Crystal 0.27.0 [c9d1eef8f] (2018-11-01)

LLVM: 4.0.0 Default target: x86_64-unknown-linux-gnu

sudo-nice commented 4 years ago

Another example:

require "option_parser"

module Opts
  extend self
  class_property foos = [] of String
  class_property bar : String?

  def parse(args)
    OptionParser.parse(args) do |opts|
      opts.on("--foo FOO", "It's foo") { |o| foos << o }
      opts.on("--bar BAR", "It's bar") { |o| bar = o }
      # But would work this way:
      # opts.on("--bar BAR", "It's bar") { |o| Opts.bar = o }
    end
  end
end

Opts.parse %w[--foo foo_arg --bar bar_arg]

p Opts.foos # => ["foo_arg"]
p Opts.bar  # => nil (but expected to be "bar_arg")
HertzDevil commented 2 years ago

Reduced:

def foo(&)
  yield 1
end

module Foo
  @@x = 2

  foo { |y| @@x = y } # Error: undefined method 'y' for Foo:Module
end