Issue #15118 has been updated by shevegen (Robert A. Heiler).


Interesting.

I just tested with this code:

    #!/System/Index/bin/ruby -w
    # Encoding: ISO-8859-1
    # frozen_string_literal: true
    # =========================================================================== #
    NopProc = proc {|a| a }

    def foobar
      result = NopProc["sometext"]
      result
    end

    x = foobar

    puts x.class
    puts x.frozen?

    y = 'abc'
    puts y.frozen?

    # Result:
    #   String
    #   false
    #   true

And I think you are right. I am testing .frozen? twice; the 'abc'
string is indeed frozen whereas the variant returned by [] does
not seem to honour the instruction in the "magic" comment section.

Very good catch. May I ask, for curiosity, how you discovered it?
I assume you may have tested somehow systematically or something?

----------------------------------------
Bug #15118: Method [] does not respect frozen_string_literal: true comment
https://bugs.ruby-lang.org/issues/15118#change-74033

* Author: chopraanmol1 (Anmol Chopra)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-09-13 trunk 64736) [x86_64-linux]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
Calling ["something"] on object or proc (non-hash aref implementation) does not respect frozen_string_literal: true comment

**Script:**

~~~
# frozen_string_literal: true

require 'benchmark'
require 'memory_profiler'
class NopId
  def self.[](str)
    str.__id__
  end
end

SampleHash = {"sometext" => 0}

NopProc = proc{|a| a.__id__}

N = 1_000_000

def method1
  NopId["sometext"]
end

def method2
  SampleHash["sometext"]
end

def method3
  NopProc["sometext"]
end

def print_iseq method_name
  puts "-+"*20
  puts RubyVM::InstructionSequence.disasm method(method_name)
  puts "-+"*20
end

def print_memory_profiler title, &block
  puts "-+"*20
  puts title
  MemoryProfiler.report{N.times(&block)}.pretty_print(detailed_report: false, allocated_strings: 0, retained_strings: 0)
  puts "-+"*20
end


print_iseq :method1
print_iseq :method2
print_iseq :method3

Benchmark.bm(10) do |bm|
  bm.report("method[]"){ N.times{ method1 } }
  bm.report("hash[]"){ N.times{ method2 } }
  bm.report("proc[]"){ N.times{ method3 } }
end

print_memory_profiler("method[]"){method1}
print_memory_profiler("hash[]"){method2}
print_memory_profiler("proc[]"){method3}
~~~

**Output:**

~~~
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method1@../test_aref.rb:17 (17,0)-(19,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  18)[LiCa]
0003 getconstant                  :NopId
0005 setinlinecache               <is:0>
0007 opt_aref_with                "sometext", <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0011 leave                                                            (  19)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method2@../test_aref.rb:21 (21,0)-(23,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  22)[LiCa]
0003 getconstant                  :SampleHash
0005 setinlinecache               <is:0>
0007 opt_aref_with                "sometext", <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0011 leave                                                            (  23)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method3@../test_aref.rb:25 (25,0)-(27,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  26)[LiCa]
0003 getconstant                  :NopProc
0005 setinlinecache               <is:0>
0007 opt_aref_with                "sometext", <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0011 leave                                                            (  27)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 user     system      total        real
method[]     0.120000   0.000000   0.120000 (  0.121639)
hash[]       0.088000   0.000000   0.088000 (  0.089411)
proc[]       0.136000   0.000000   0.136000 (  0.133279)
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
method[]
Total allocated: 40000000 bytes (1000000 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
hash[]
Total allocated: 0 bytes (0 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
proc[]
Total allocated: 40000000 bytes (1000000 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~~~

As you can observe calling NopClass["something"] & NopProc["something"] doesnot respect frozen_string_literal: true comment

**Patch:**
**https://github.com/ruby/ruby/pull/1957**

**After Patch Result:**

~~~
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method1@../test_aref.rb:17 (17,0)-(19,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  18)[LiCa]
0003 getconstant                  :NopId
0005 setinlinecache               <is:0>
0007 putobject                    "sometext"
0009 opt_aref                     <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0012 leave                                                            (  19)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method2@../test_aref.rb:21 (21,0)-(23,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  22)[LiCa]
0003 getconstant                  :SampleHash
0005 setinlinecache               <is:0>
0007 putobject                    "sometext"
0009 opt_aref                     <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0012 leave                                                            (  23)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
== disasm: #<ISeq:method3@../test_aref.rb:25 (25,0)-(27,3)> (catch: FALSE)
0000 getinlinecache               7, <is:0>                           (  26)[LiCa]
0003 getconstant                  :NopProc
0005 setinlinecache               <is:0>
0007 putobject                    "sometext"
0009 opt_aref                     <callinfo!mid:[], argc:1, ARGS_SIMPLE>, <callcache>
0012 leave                                                            (  27)[Re]
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 user     system      total        real
method[]     0.100000   0.004000   0.104000 (  0.100786)
hash[]       0.088000   0.000000   0.088000 (  0.089176)
proc[]       0.108000   0.000000   0.108000 (  0.107366)
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
method[]
Total allocated: 0 bytes (0 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
hash[]
Total allocated: 0 bytes (0 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
proc[]
Total allocated: 0 bytes (0 objects)
Total retained:  0 bytes (0 objects)


-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~~~



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>