<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>"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 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;">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><div><br></div><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 data-mce-bogus="1"></div><div>Here is the classical example<br data-mce-bogus="1"></div><div>class Foo {<br data-mce-bogus="1"></div><div>  String name;<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>  void setName(String name) {<br data-mce-bogus="1"></div><div>    this.name = name;<br data-mce-bogus="1"></div><div>  }<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>  public void execute() {<br></div><div>    new Thread() {<br></div><div>      public void run() {<br data-mce-bogus="1"></div><div>        setName("foo");<br data-mce-bogus="1"></div><div>      }<br data-mce-bogus="1"></div><div>    }.start();<br data-mce-bogus="1"></div><div>  }  <br data-mce-bogus="1"></div><div>}<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>where the method setName() inside execute() calls Thread.setName() instead of Foo.setName().<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>You code compiles with JDK 17 because Thread.Builder was introduced in 21 (19 as preview).<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>If you want to avoid those kind of issues, prefer delegation to inheritance.<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>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><div><br></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></div></div></body></html>