<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Alan Snyder" <javalists@cbfiddle.com><br><b>To: </b>"Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"compiler-dev" <compiler-dev@openjdk.org><br><b>Sent: </b>Sunday, December 17, 2023 9:03:14 PM<br><b>Subject: </b>Re: a change in javac behavior<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div>So, that is how things are supposed to work?</div></blockquote><div><br></div><div>Yes,<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br><div>Also, can you explain why javac does not complain about the builder.perform() invocation?</div><div>That variable is declared using the disputed parameter declaration.</div><div>If the parameter type is taken to be Thread.Builder, the call to perform should be rejected.</div></blockquote><div><br></div><div>Hard to say without the whole code but if your original error comes from the same file, it may mask the error at builder.perform(), javac does several passes on the same code.<br></div><div><br data-mce-bogus="1"></div><div>regards,<br data-mce-bogus="1"></div><div>Rémi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br id="lineBreakAtBeginningOfMessage"><div><br><blockquote><div>On Dec 17, 2023, at 9:56 AM, Remi Forax <forax@univ-mlv.fr> wrote:</div><br class="Apple-interchange-newline"><div><div><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt;"><br><br><hr id="zwchr"><div><blockquote style="border-left-width: 2px; border-left-style: solid; border-left-color: rgb(16, 16, 255); margin-left: 5px; padding-left: 5px; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica, Arial, sans-serif; font-size: 12pt;"><b>From: </b>"Alan Snyder" <javalists@cbfiddle.com><br><b>To: </b>"compiler-dev" <compiler-dev@openjdk.org><br><b>Sent: </b>Sunday, December 17, 2023 5:48:15 PM<br><b>Subject: </b>a change in javac behavior<br></blockquote></div><div><blockquote style="border-left-width: 2px; border-left-style: solid; border-left-color: rgb(16, 16, 255); margin-left: 5px; padding-left: 5px; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica, Arial, sans-serif; font-size: 12pt;">I’m experiencing a change in behavior compiling a particular file.<br><div>The compiler is trying to match an invocation to one of two constructors for a static class defined in the same file.</div><br><div>The second constructor has a parameter of type Builder. In the past, this was interpreted as my Builder class, which is imported into this file.</div><div>That matches the invocation.</div><br><div>Now, however, the constructor parameter type is interpreted as java.lang.Thread.Builder, presumably because the static class extends Thread.</div><div>That causes a mismatch to be reported.</div><br><div>This interpretation appears to be limited to the resolution of the constructor invocation. Within the constructor, I do not get an error when the parameter</div><div>is used as an instance of my Builder class.</div><br><div>This happens in JDK 20, JDK 21, and the latest build of JDK 22.</div><div>It does not happen in JDK 17.</div></blockquote><br><div>I believe this is not a behavior change, you are experiencing the "comb" behavior, where javac will first start to match members declared inside the class hierarchy before trying to match other members.<br></div><div>Here is the classical example<br></div><div>class Foo {<br></div><div>  String name;<br></div><br><div>  void setName(String name) {<br></div><div>    this.name = name;<br></div><div>  }<br></div><br><div>  public void execute() {<br></div><div>    new Thread() {<br></div><div>      public void run() {<br></div><div>        setName("foo");<br></div><div>      }<br></div><div>    }.start();<br></div><div>  }  <br></div><div>}<br></div><br><div>where the method setName() inside execute() calls Thread.setName() instead of Foo.setName().<br></div><br><div>You code compiles with JDK 17 because Thread.Builder was introduced in 21 (19 as preview).<br></div><br><div>If you want to avoid those kind of issues, prefer delegation to inheritance.<br></div><br><blockquote style="border-left-width: 2px; border-left-style: solid; border-left-color: rgb(16, 16, 255); margin-left: 5px; padding-left: 5px; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica, Arial, sans-serif; font-size: 12pt;"><br><div>The error message:</div><br><div><div>    [javac]     constructor Worker.Worker(@org.jetbrains.annotations.NotNull String,@org.jetbrains.annotations.NotNull SeverityLevel,@org.jetbrains.annotations.NotNull java.lang.Thread.Builder,@org.jetbrains.annotations.Nullable TaskStatusListener,@org.jetbrains.annotations.NotNull SimpleTaskReceiver<BuildResult>) is not applicable</div><div>    [javac]       (argument mismatch; @org.jetbrains.annotations.NotNull com.cbfiddle.releases.Builder cannot be converted to @org.jetbrains.annotations.NotNull java.lang.Thread.Builder)</div><br></div><br><div>The constructor:</div><br><div><div style="background-color: rgb(255, 255, 255); color: rgb(74, 92, 110);"><pre style="font-family: Menlo, monospace; font-size: 9pt;"><span style="color: rgb(133, 107, 70);">public </span><span style="color: rgb(167, 95, 0);">Worker</span>(<span style="color: rgb(184, 185, 111);">@NotNull </span><span style="color: rgb(73, 84, 94);">String </span><span style="color: rgb(81, 81, 81);">taskName</span><span style="color: rgb(102, 79, 61);">,<br></span><span style="color: rgb(184, 185, 111);">@NotNull </span><span style="color: rgb(73, 84, 94);">SeverityLevel </span><span style="color: rgb(81, 81, 81);">level</span><span style="color: rgb(102, 79, 61);">,<br></span><span style="color: rgb(184, 185, 111);">@NotNull </span><span style="color: rgb(81, 81, 81);">Builder builder</span><span style="color: rgb(102, 79, 61);">,<br></span><span style="color: rgb(184, 185, 111);">@Nullable </span><span style="color: rgb(81, 81, 81);">TaskStatusListener tsl</span><span style="color: rgb(102, 79, 61);">,<br></span><span style="color: rgb(184, 185, 111);">@NotNull </span><span style="color: rgb(81, 81, 81);">SimpleTaskReceiver</span><<span style="color: rgb(73, 84, 94);">BuildResult</span>> <span style="color: rgb(81, 81, 81);">r</span>)<br>{<br>    <span style="color: rgb(133, 107, 70);">this</span>.<span style="color: rgb(99, 82, 107);">taskName </span>= <span style="color: rgb(81, 81, 81);">taskName</span><span style="color: rgb(96, 76, 61);">;<br></span><span style="color: rgb(133, 107, 70);">this</span>.<span style="color: rgb(99, 82, 107);">level </span>= <span style="color: rgb(81, 81, 81);">level</span><span style="color: rgb(96, 76, 61);">;<br></span><span style="color: rgb(133, 107, 70);">this</span>.<span style="color: rgb(99, 82, 107);">r </span>= <span style="color: rgb(81, 81, 81);">r</span><span style="color: rgb(96, 76, 61);">;<br></span><span style="color: rgb(133, 107, 70);">this</span>.<span style="color: rgb(99, 82, 107);">bl </span>= createBuildListener(<span style="color: rgb(81, 81, 81);">tsl</span>)<span style="color: rgb(96, 76, 61);">;<br></span><span style="color: rgb(133, 107, 70);">this</span>.<span style="color: rgb(99, 82, 107);">op </span>= () -> <span style="color: rgb(179, 141, 196);">builder</span>.perform(<span style="color: rgb(99, 82, 107);">bl</span>)<span style="color: rgb(96, 76, 61);">;<br></span><span style="color: rgb(96, 76, 61);"><br></span>setPriority(<span style="color: rgb(73, 84, 94);">Thread</span>.<span style="color: rgb(134, 109, 143); font-style: italic;">MIN_PRIORITY</span>)<span style="color: rgb(96, 76, 61);">;<br></span>}<br></pre></div></div></blockquote><br><div>regards,<br></div><div>Rémi<br></div></div></div></div></div></blockquote></div><br></blockquote></div></div></body></html>