Project

General

Profile

Actions

Bug #21784

open

Proc#source_location start column seems strange for -> {}

Bug #21784: Proc#source_location start column seems strange for -> {}

Added by Eregon (Benoit Daloze) 1 day ago. Updated about 9 hours ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.0dev (2025-12-14T07:11:02Z master 711d14992e) +PRISM [x86_64-linux]
[ruby-core:124207]

Description

$ ruby -e 'p -> { a }.source_location' 
["-e", 1, 4, 1, 10]

So it considers the stabby lambda to be at:

p -> { a }.source_location
    ^^^^^^

Note it starts at a whitespace after the ->.
I think it should just include the ->, i.e. return ["-e", 1, 2, 1, 10].
Or possibly start at the {, i.e. return ["-e", 1, 3, 1, 10].
But starting on a whitespace like here seems really strange, it looks like a bug.

It's the same result with --parser=parse.y, so I don't show it.


For context:
For Procs/block it looks like this:

$ ruby -e 'p proc { a }.source_location'
["-e", 1, 7, 1, 12]
p proc { a }.source_location
       ^^^^^

This looks fine.
The block could of course be given to any other method so it won't always be proc in front.
Maybe it could include the method too (so it would return start column 2 here), I think either is fine.

For for blocks it looks like this:

$ ruby -e '                                                             
def self.each(&b); yield b; end;
for b in self
  42
end
p b.source_location'
["-e", 3, 0, 5, 3]

That is, it covers the entire for expression from for until end.
I think that's good and fine as-is.

For def methods it covers everything from def to end (or end of line for def m = 42), as expected.


Related issues 2 (2 open0 closed)

Related to Ruby - Feature #21005: Update the source location method to include line start/stop and column start/stop detailsOpenActions
Related to Ruby - Feature #6012: Proc#source_location also return the columnOpennobu (Nobuyoshi Nakada)Actions

Updated by Eregon (Benoit Daloze) 1 day ago Actions #1

  • Related to Feature #21005: Update the source location method to include line start/stop and column start/stop details added

Updated by Eregon (Benoit Daloze) 1 day ago Actions #2

  • Related to Feature #6012: Proc#source_location also return the column added

Updated by tompng (tomoya ishida) about 20 hours ago Actions #3 [ruby-core:124213]

Except the problematic case -> { }, start position consistently excludes whitespaces just after ->.
So I think -> { }'s source location should be { }.

-> ( ) { }.source_location # ["(irb)", 1, 3, 1, 10]
   ^^^^^^^
-> * { }.source_location   # ["(irb)", 1, 3, 1, 8]
   ^^^^^
-> a { }.source_location   # ["(irb)", 1, 3, 1, 8]
   ^^^^^
->   { }.source_location   # ["(irb)", 1, 2, 1, 8]
  ^^^^^^ (current)
     ^^^ (expected IMO)

Updated by Eregon (Benoit Daloze) about 19 hours ago 1Actions #4 [ruby-core:124214]

Interesting.
The arguments (parameters) between -> and { are AFAIK integral part of the stabby lambda syntax, so I think it should be either:

  • All cases start at the {:
    • consistent with non-stabby-lambda Procs
    • but does not include the arguments which is an critical part of the lambda declaration (and this is not an issue for non-stabby-lambda Procs as the arguments come after { like { |args|)
  • All cases start at the ->
    • covers the whole expression
    • intuitive, I think most users would expect this one
    • Also enables e.g. eval()'ing the source string (in the right context)
    • Consistent with for

Starting at the arguments but skipping -> and some spaces seems strange/inconsistent.

Updated by zverok (Victor Shepelev) about 19 hours ago Actions #5 [ruby-core:124215]

I too, would expect the whole expression to be covered. This would be also consistent with Method#source_location which includes def (and not starts from the argument, or from the beginning of the body).

Updated by Eregon (Benoit Daloze) about 15 hours ago Actions #6 [ruby-core:124219]

I made a PR to fix this: https://github.com/ruby/ruby/pull/15568
Looking at https://github.com/ruby/ruby/pull/9872/files it's clear in Prism it was just done to be compatible with parse.y.

And in parse.y it's probably not intentional to use the beginning of the args as the start location for the scope, the whole -> {} defines a new scope.
In fact the lambda itself already had the right location with RubyVM::AbstractSyntaxTree, just the scope within it had the wrong location:

$ RUBYOPT=--parser=parse.y irb                       
irb(main):001> l = -> { a }
=> #<Proc:0x00007fc276e9d8c0 (irb):1 (lambda)>
irb(main):002> a=RubyVM::AbstractSyntaxTree.of(l)
=> 
(LAMBDA@1:4-1:12
...
irb(main):003> a.locations
=> 
[#<RubyVM::AbstractSyntaxTree::Location:@1:4-1:12>,
 #<RubyVM::AbstractSyntaxTree::Location:@1:4-1:6>,
 #<RubyVM::AbstractSyntaxTree::Location:@1:7-1:8>,
 #<RubyVM::AbstractSyntaxTree::Location:@1:11-1:12>]
irb(main):004> a
=> 
(LAMBDA@1:4-1:12
   (SCOPE@1:6-1:12
    tbl: []
    args:
      (ARGS@1:6-1:6
       pre_num: 0
       pre_init: nil
       opt: nil
       first_post: nil
       post_num: 0
       post_init: nil
       rest: nil
       kw: nil
       kwrest: nil
       block: nil)
    body: (VCALL@1:9-1:10 :a)))

Updated by matz (Yukihiro Matsumoto) about 9 hours ago Actions #7 [ruby-core:124222]

The column information from source_location will be canceled in 4.0. Let us discuss for the future. I think it's a matter of taste. I don't really care much.

Matz.

Actions

Also available in: PDF Atom