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

Error when declaring a constant within another constant declaration #12566

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
10 changes: 10 additions & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,16 @@ module Crystal
assert_syntax_error "{1, ->do\n|x| x\end }", "unexpected token: \"|\", proc literals specify their parameters like this: ->(x : Type) { ... }"
assert_syntax_error "{1, ->{ |_| x } }", "unexpected token: \"|\", proc literals specify their parameters like this: ->(param : Type) { ... }"

# #2874
assert_syntax_error "A = B = 1", "dynamic constant assignment"
assert_syntax_error "A = (B = 1)", "dynamic constant assignment"
assert_syntax_error "A = foo(B = 1)", "dynamic constant assignment"
assert_syntax_error "A = foo { B = 1 }", "dynamic constant assignment"
assert_syntax_error "A = begin; B = 1; end", "dynamic constant assignment"
assert_syntax_error "A = begin; 1; rescue; B = 1; end", "dynamic constant assignment"
assert_syntax_error "A = begin; 1; rescue; 1; else; B = 1; end", "dynamic constant assignment"
assert_syntax_error "A = begin; 1; ensure; B = 1; end", "dynamic constant assignment"

assert_syntax_error "1 while 3", "trailing `while` is not supported"
assert_syntax_error "1 until 3", "trailing `until` is not supported"
assert_syntax_error "x++", "postfix increment is not supported, use `exp += 1`"
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module Crystal
@def_nest = 0
@fun_nest = 0
@type_nest = 0
@is_constant_assignment = false

# Keeps track of current call args starting locations,
# so if we parse a type declaration exactly at those points we
Expand Down Expand Up @@ -370,10 +371,12 @@ module Crystal
else
break unless can_be_assigned?(atomic)

if atomic.is_a?(Path) && (inside_def? || inside_fun?)
if atomic.is_a?(Path) && (inside_def? || inside_fun? || @is_constant_assignment)
raise "dynamic constant assignment. Constants can only be declared at the top level or inside other types."
end

@is_constant_assignment = true if atomic.is_a?(Path)

if atomic.is_a?(Var) && atomic.name == "self"
raise "can't change the value of self", location
end
Expand Down Expand Up @@ -422,6 +425,8 @@ module Crystal
end
end

@is_constant_assignment = false if atomic.is_a?(Path)

push_var atomic

atomic = Assign.new(atomic, atomic_value).at(location)
Expand Down