From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on starla X-Spam-Level: X-Spam-Status: No, score=0.1 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_BL_SPAMCOP_NET,SPF_HELO_PASS, SPF_PASS autolearn=no autolearn_force=no version=3.4.6 Received: from nue.mailmanlists.eu (nue.mailmanlists.eu [94.130.110.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 4260D1F44D for ; Tue, 23 Apr 2024 21:38:51 +0000 (UTC) Authentication-Results: dcvr.yhbt.net; dkim=pass (1024-bit key; secure) header.d=ml.ruby-lang.org header.i=@ml.ruby-lang.org header.a=rsa-sha256 header.s=mail header.b=owOV2FrZ; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ruby-lang.org header.i=@ruby-lang.org header.a=rsa-sha256 header.s=s1 header.b=UyDeRsl2; dkim-atps=neutral Received: from nue.mailmanlists.eu (localhost [127.0.0.1]) by nue.mailmanlists.eu (Postfix) with ESMTP id D6EC58447B; Tue, 23 Apr 2024 21:38:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ml.ruby-lang.org; s=mail; t=1713908322; bh=b7v/BE3WjO/3H2JSGwZe0pEsfmc28RF2oujky4kZ6Fk=; h=Date:References:To:Reply-To:Subject:List-Id:List-Archive: List-Help:List-Owner:List-Post:List-Subscribe:List-Unsubscribe: From:Cc:From; b=owOV2FrZJtZx9fYgtYINDSce+p1QdBT8GG2+4+T20kMkSsnLZ9Y+871t8lWZ/mzgJ jgLorA0TD/iogQxznGs+IX/YuCcmIF8sPKo9gbifsW2UVe3n8OfTTKqMzAcaBs7zp+ kFkDBAfoyOUoJm+fQ/k0zV6RczJFxP6ecyBpZTuo= Received: from s.wrqvtbkv.outbound-mail.sendgrid.net (s.wrqvtbkv.outbound-mail.sendgrid.net [149.72.123.24]) by nue.mailmanlists.eu (Postfix) with ESMTPS id 608A7842EA for ; Tue, 23 Apr 2024 21:38:39 +0000 (UTC) Authentication-Results: nue.mailmanlists.eu; dkim=pass (2048-bit key; unprotected) header.d=ruby-lang.org header.i=@ruby-lang.org header.a=rsa-sha256 header.s=s1 header.b=UyDeRsl2; dkim-atps=neutral DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ruby-lang.org; h=from:references:subject:mime-version:content-type: content-transfer-encoding:list-id:to:cc:content-type:from:subject:to; s=s1; bh=7ic9nxvnVewLuG3bmwAZ7FeSVyC9xD/ntf0FKn88iQs=; b=UyDeRsl28oZ5q8+1wcLAazBHdPLBurMMmhRb9UCwH0nuZJMgJHGo8B40cosZOdDIXYOh XbGeb0T7m4pzjhqaIBCFK9Y3qQmjrKz6/G0wYH700pWu5LdERglzSkDNxMPh1hlONM8ecp W+JFNsZWJRvqnzhlPgQNawhcmNabLE9OQlOquTQ9Fh+bKPMCDZrqyAOk/G7dpsaPjhY8+b GvGchOnviVMrgiRjBCWf4XlnmQXMNkvDPRoaa2Z0E3g6PpdCqg5o+PPxvGMqmfdPZk2S1s jAxbLQ1mJjXOwIja5AF7v9ANzNBYEttnpHJhBcjONq2iNrWQ+FalNvkRbFWUCl8Q== Received: by recvd-bb7996b79-b6nw2 with SMTP id recvd-bb7996b79-b6nw2-1-66282A5E-A 2024-04-23 21:38:38.337337607 +0000 UTC m=+949103.501939827 Received: from herokuapp.com (unknown) by geopod-ismtpd-canary-0 (SG) with ESMTP id 3BDYggTQREWG7KSNWrhQyw for ; Tue, 23 Apr 2024 21:38:38.316 +0000 (UTC) Date: Tue, 23 Apr 2024 21:38:38 +0000 (UTC) Message-ID: References: Mime-Version: 1.0 X-Redmine-Project: ruby-master X-Redmine-Issue-Tracker: Feature X-Redmine-Issue-Id: 15554 X-Redmine-Issue-Author: ko1 X-Redmine-Issue-Assignee: matz X-Redmine-Issue-Priority: Normal X-Redmine-Sender: Dan0042 X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-Redmine-MailingListIntegration-Message-Ids: 94259 X-SG-EID: =?us-ascii?Q?u001=2EHy4LB1bizMxDg=2Fk6r7dYDS9qUDe3jZN8DIPm4OS+F86l7XdLFEAVX=2F2lh?= =?us-ascii?Q?z0Jj=2Ft7J6DgKnq5Qaf6Ba4+egck=2FoKuUHMa9Cn6?= =?us-ascii?Q?7D+EQ8vUJVvzlPAw7o8gmpdjw87U=2FB2dB9+0xSo?= =?us-ascii?Q?hGdrGhPA6m+Ch2BT9vJ=2F8GKDODOEB1NinrT3rE0?= =?us-ascii?Q?LSib3=2FLamAPB+EgWbU48O3vHE57VWLtCuM+8g90?= =?us-ascii?Q?dbSCEp=2FeT4Bx211Ncql3NXzmbvl=2FeoO4wfphEr+?= =?us-ascii?Q?vKd0KhsaZ=2FYwcjzo3wYCaxUthA=3D=3D?= To: ruby-core@ml.ruby-lang.org X-Entity-ID: u001.I8uzylDtAfgbeCOeLBYDww== Message-ID-Hash: M6TXWC33U35G5QAWGCLRAUAI2OYM5NNS X-Message-ID-Hash: M6TXWC33U35G5QAWGCLRAUAI2OYM5NNS X-MailFrom: bounces+313651-b711-ruby-core=ml.ruby-lang.org@em5188.ruby-lang.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.3 Precedence: list Reply-To: Ruby developers Subject: [ruby-core:117663] [Ruby master Feature#15554] warn/error passing a block to a method which never use a block List-Id: Ruby developers Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: "Dan0042 (Daniel DeLorme) via ruby-core" Cc: "Dan0042 (Daniel DeLorme)" Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Issue #15554 has been updated by Dan0042 (Daniel DeLorme). byroot (Jean Boussier) wrote in #note-53: > @ko1 here's the result (I ran it on the 5 most important sub components) I think it's worth mentioning there's 67 warnings in that output but "only"= 25 uniques. Acceptable for a codebase as big as Rails? In order to understand the false positives I had a look at the "add_bind" w= arnings. And at first I thought the ignored block was actually a bug! It to= ok me half an hour of looking through the code to finally understand what i= t did and why it was ok to ignore the block. So while it's a false positive= , this mirrors my experience in #note-45 that making the arguments more exp= licit would really help understanding of the code. my 2=A2 ---------------------------------------- Feature #15554: warn/error passing a block to a method which never use a bl= ock https://bugs.ruby-lang.org/issues/15554#change-108071 * Author: ko1 (Koichi Sasada) * Status: Closed * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- # Abstract Warn or raise an ArgumentError if block is passed to a method which does no= t use a block. In other words, detect "block user methods" implicitly and only "block user= methods" can accept a block. # Background Sometimes, we pass a block to a method which ignores the passed block accid= entally. ``` def my_open(name) open(name) end # user hopes it works as Kernel#open which invokes a block with opened file. my_open(name){|f| important_work_with f } # but simply ignored... ``` To solve this issue, this feature request propose showing warnings or raisi= ng an exception on such case. Last developer's meeting, matz proposed `&nil` which declares this method n= ever receive a block. It is explicit, but it is tough to add this `&nil` pa= rameter declaration to all of methods (do you want to add it to `def []=3D(= i, e, &nil)`?). (I agree `&nil` is valuable on some situations) # Spec ## Define "use a block" methods We need to define which method accepts a block and which method does not. * (1) method has a block parameter (`&b`) * (2) method body has `yield' * (3) method body has `super` (ZSUPER in internal terminology) or `super(..= .)` * (4) method body has singleton method (optional) (1) and (2) is very clear. I need to explain about (3) and (4). (3). `super` (ZSUPER) passes all parameters as arguments. So there is no su= rprise that which can accept `block`. However `super(...)` also passes a block if no explicit block passing (like= `super(){}` or `super(&b)`) are written. I'm not sure we need to continue this strange specification, but to keep co= mpatibility depending this spec, I add this rule. (4). surprisingly, the following code invoke a block: ``` def foo class << Object.new yield end end foo{ p :ok } #=3D> :ok ``` I'm also not sure we need to keep this spec, but to allow this spec, I adde= d (4) rule. Strictly speaking, it is not required, but we don't keep the link from sing= leton class ISeq to lexical parent iseq now, so I added it. ## Exceptional cases A method called by `super` doesn`t warn warning even if this method doesn't= use a block. The rule (3) can pass blocks easily and there are many methods don`t use a = block. So my patch ignores callings by `super`. ## corner cases There are several cases to use block without (1)-(4) rules. ### `Proc.new/proc/lambda` without a block Now it was deprecated in r66772 (commit:9f1fb0a17febc59356d58cef5e98db61a3c= 03550). Related discussion: [Bug #15539] ### `block_given?` `block_given?` expects block, but I believe we use it with `yield` or a blo= ck parameter. If you know the usecase without them, please tell us. ### `yield` in `eval` We can't know `yield` (or (3), (4) rule) in an `eval` evaluating string at = calling time. ``` def foo eval('yield`) end foo{} # at calling time, # we can't know the method foo can accept a block or not. ``` So I added a warning to use `yield` in `eval` like that: `test.rb:4: warnin= g: use yield in eval will not be supported in Ruby 3.` Workaround is use a block parameter explicitly. ``` def foo &b eval('b.call') end foo{ p :ok } ``` # Implementation Strategy is: * [compile time] introduce `iseq::has_yield` field and check it if the iseq= (or child iseq) contains `yield` (or something) * [calling time] if block is given, check `iseq::has_yield` flag and show w= arning (or raise an exception) https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b On this patch, now it raises an error to make it easy to detect. It is easy to switch to show the warning. # Evaluation and discussion I tried to avoid ruby's tests. https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786 Here is a patch. There are several patterns to avoid warnings. ## tests for `block_given?`, `Proc.new` (and similar) without block Add a dummy block parameter. It is test-specific issue. ## empty `each` Some tests add `each` methods do not `yield`, like: `def each; end`. Maybe test-specific issue, and adding a dummy block parameter. ## Subtyping / duck typing https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/= lib/optparse.rb#L698 This `parse` method doesn't use `yield`, but other sub-type's `parse` metho= ds use. ## `super` with `new` method https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-pat= ch-L61 This method override `Class#new` method and introduce a hook with block (yi= eld a block in this hook code). https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#= L81 In this method, call `super` and it also passing a block. However, called `= initialize` doesn't use a block. ## Change robustness This change reduce robustness for API change. `Delegator` requires to support `__getobj__` for client classes. Now `__getobj__` should accept block but most of `__getobj__` clients do no= t call given block. https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80 This is because of delegator.rb's API change. https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-pat= ch-L86 Nobu says calling block is not required (ignoring a block is no problem) so= it is not a bug for delegator client classes. ## Found issues. ``` [ 2945/20449] Rinda::TestRingServer#test_do_reply =3D 0.00 s 1) Error: Rinda::TestRingServer#test_do_reply: ArgumentError: passing block to the method "with_timeout" (defined at /home= /ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used. /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:635:in `test_do_reply' [ 2946/20449] Rinda::TestRingServer#test_do_reply_local =3D 0.00 s 2) Error: Rinda::TestRingServer#test_do_reply_local: ArgumentError: passing block to the method "with_timeout" (defined at /home= /ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used. /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:657:in `test_do_reply= _local' [10024/20449] TestGemRequestSetGemDependencyAPI#test_platform_mswin =3D 0.0= 1 s 3) Error: TestGemRequestSetGemDependencyAPI#test_platform_mswin: ArgumentError: passing block to the method "util_set_arch" (defined at /hom= e/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used. /home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_depende= ncy_api.rb:655:in `test_platform_mswin' [10025/20449] TestGemRequestSetGemDependencyAPI#test_platforms =3D 0.01 s 4) Error: TestGemRequestSetGemDependencyAPI#test_platforms: ArgumentError: passing block to the method "util_set_arch" (defined at /hom= e/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used. /home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_depende= ncy_api.rb:711:in `test_platforms' ``` These 4 detection show the problem. `with_timeout` method (used in Rinda te= st) and `util_set_arch` method (used in Rubygems test) simply ignore the gi= ven block. So these tests are simply ignored. I reported them. (https://github.com/rubygems/rubygems/issues/2601) ## raise an error or show a warning? At least, Ruby 2.7 should show warning for this kind of violation with `-w`. How about for Ruby3? --=20 https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-c= ore.ml.ruby-lang.org/