From 6b3e658f529da287b28359b4300da10373d7dfa2 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 26 Feb 2025 01:47:17 -0500 Subject: [PATCH 1/2] Reject invalid operator names for implicit object calls --- spec/compiler/parser/parser_spec.cr | 2 ++ src/compiler/crystal/syntax/parser.cr | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr index 69ac1ab452da..26719fa2851a 100644 --- a/spec/compiler/parser/parser_spec.cr +++ b/spec/compiler/parser/parser_spec.cr @@ -1512,6 +1512,8 @@ module Crystal assert_syntax_error "case 1\nin 1; 2", "expression of exhaustive case (case ... in) must be a constant (like `IO::Memory`), a generic (like `Array(Int32)`), a bool literal (true or false), a nil literal (nil) or a question method (like `.red?`)" assert_syntax_error "case 1\nin .nil?; 2", "expression of exhaustive case (case ... in) must be a constant (like `IO::Memory`), a generic (like `Array(Int32)`), a bool literal (true or false), a nil literal (nil) or a question method (like `.red?`)" assert_syntax_error "case 1\nin _;", "'when _' is not supported" + assert_syntax_error "case 1\nwhen .=(2)", %(unexpected token: "=") + assert_syntax_error "case 1\nwhen .+=(2)", %(unexpected token: "+=") it_parses "case 1; when 2 then /foo/; end", Case.new(1.int32, [When.new([2.int32] of ASTNode, RegexLiteral.new("foo".string))], else: nil, exhaustive: false) diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 64e97e320aa8..13a3d2cec5f0 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -4264,6 +4264,10 @@ module Crystal # Not a special call, go on end + if @token.type.op_eq? || @token.type.assignment_operator? + unexpected_token + end + name = @token.value.to_s name_location = @token.location From 423397af4155515f457d80cffb4c17e28525fef0 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 26 Feb 2025 09:20:56 -0500 Subject: [PATCH 2/2] Reject invalid operator names for implicit object calls (pt. 2) --- spec/compiler/parser/parser_spec.cr | 7 +++++-- src/compiler/crystal/syntax/parser.cr | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr index 26719fa2851a..66d3030d8cf3 100644 --- a/spec/compiler/parser/parser_spec.cr +++ b/spec/compiler/parser/parser_spec.cr @@ -1512,8 +1512,11 @@ module Crystal assert_syntax_error "case 1\nin 1; 2", "expression of exhaustive case (case ... in) must be a constant (like `IO::Memory`), a generic (like `Array(Int32)`), a bool literal (true or false), a nil literal (nil) or a question method (like `.red?`)" assert_syntax_error "case 1\nin .nil?; 2", "expression of exhaustive case (case ... in) must be a constant (like `IO::Memory`), a generic (like `Array(Int32)`), a bool literal (true or false), a nil literal (nil) or a question method (like `.red?`)" assert_syntax_error "case 1\nin _;", "'when _' is not supported" - assert_syntax_error "case 1\nwhen .=(2)", %(unexpected token: "=") - assert_syntax_error "case 1\nwhen .+=(2)", %(unexpected token: "+=") + + atomic_methods = Crystal::Parser::AtomicWithMethodCheck.join(", ") + assert_syntax_error "case 1\nwhen .=(2)", "expecting any of these tokens: #{atomic_methods} (not '=')" + assert_syntax_error "case 1\nwhen .+=(2)", "expecting any of these tokens: #{atomic_methods} (not '+=')" + assert_syntax_error "case 1\nwhen .&&(2)", "expecting any of these tokens: #{atomic_methods} (not '&&')" it_parses "case 1; when 2 then /foo/; end", Case.new(1.int32, [When.new([2.int32] of ASTNode, RegexLiteral.new("foo".string))], else: nil, exhaustive: false) diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 13a3d2cec5f0..27ee5e49d224 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -4236,6 +4236,8 @@ module Crystal end_location = token_end_location doc = @token.doc + check AtomicWithMethodCheck + if @token.type.op_bang? # only trigger from `parse_when_expression` obj = Var.new("self").at(location) @@ -4264,10 +4266,6 @@ module Crystal # Not a special call, go on end - if @token.type.op_eq? || @token.type.assignment_operator? - unexpected_token - end - name = @token.value.to_s name_location = @token.location