From jan.lahoda at oracle.com Thu Oct 3 09:57:34 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 3 Oct 2019 11:57:34 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API Message-ID: Hi, This is a continuation of Joe's patch from here: https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html APIs associated with preview features are split into two groups: essential and non-essential. These are marked with an JDK-internal annotation, PreviewFeature, and a tag in the javadoc, @preview. The javac follows the PreviewFeature annotation, and produces either warnings or errors for the usages of such APIs. For the @preview tag, there is a taglet in the JDK build that adds the content of the tag into the documentation. The first part of the @preview's text goes into the summary, the second part goes into the detailed description. For build, a tricky problem is that the jdk.compiler module uses the PreviewFeature annotation as well, but that is not in the bootstrap JDK. So, for the intermediate langtools build, the PreviewFeature annotation is copied from java.base. Proposed webrev: http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ Javadoc with the change: http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html See for example: http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html JBS: https://bugs.openjdk.java.net/browse/JDK-8226585 CSR: https://bugs.openjdk.java.net/browse/JDK-8231411 Feedback is welcome! Thanks, Jan From erik.joelsson at oracle.com Thu Oct 3 16:06:00 2019 From: erik.joelsson at oracle.com (Erik Joelsson) Date: Thu, 3 Oct 2019 09:06:00 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: Message-ID: Hello Jan, The build change looks ok, but I would recommend this construct for copying the file instead: $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ ??? FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, \ ??? DEST := $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, \ )) TARGETS += $(COPY_PREVIEW_FEATURES) Then you automatically get all the corner case handling we have implemented over the years for logging, making directories and copying files. Your version is still correct for this case though. /Erik On 2019-10-03 02:57, Jan Lahoda wrote: > Hi, > > This is a continuation of Joe's patch from here: > https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html > > > APIs associated with preview features are split into two groups: > essential and non-essential. These are marked with an JDK-internal > annotation, PreviewFeature, and a tag in the javadoc, @preview. The > javac follows the PreviewFeature annotation, and produces either > warnings or errors for the usages of such APIs. For the @preview tag, > there is a taglet in the JDK build that adds the content of the tag > into the documentation. The first part of the @preview's text goes > into the summary, the second part goes into the detailed description. > > For build, a tricky problem is that the jdk.compiler module uses the > PreviewFeature annotation as well, but that is not in the bootstrap > JDK. So, for the intermediate langtools build, the PreviewFeature > annotation is copied from java.base. > > Proposed webrev: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ > > Javadoc with the change: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html > > See for example: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html > > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html > > > JBS: > https://bugs.openjdk.java.net/browse/JDK-8226585 > > CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 > > Feedback is welcome! > > Thanks, > ??? Jan From joe.darcy at oracle.com Fri Oct 4 05:08:20 2019 From: joe.darcy at oracle.com (Joe Darcy) Date: Thu, 3 Oct 2019 22:08:20 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: Message-ID: Hi Jan, For future work, consider having a "Preview Methods" tag alongside static, instance, deprecated, etc. Cheers, -Joe On 10/3/2019 2:57 AM, Jan Lahoda wrote: > Hi, > > This is a continuation of Joe's patch from here: > https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html > > > APIs associated with preview features are split into two groups: > essential and non-essential. These are marked with an JDK-internal > annotation, PreviewFeature, and a tag in the javadoc, @preview. The > javac follows the PreviewFeature annotation, and produces either > warnings or errors for the usages of such APIs. For the @preview tag, > there is a taglet in the JDK build that adds the content of the tag > into the documentation. The first part of the @preview's text goes > into the summary, the second part goes into the detailed description. > > For build, a tricky problem is that the jdk.compiler module uses the > PreviewFeature annotation as well, but that is not in the bootstrap > JDK. So, for the intermediate langtools build, the PreviewFeature > annotation is copied from java.base. > > Proposed webrev: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ > > Javadoc with the change: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html > > See for example: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html > > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html > > > JBS: > https://bugs.openjdk.java.net/browse/JDK-8226585 > > CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 > > Feedback is welcome! > > Thanks, > ??? Jan From jan.lahoda at oracle.com Mon Oct 7 10:40:08 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Mon, 7 Oct 2019 12:40:08 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: Message-ID: <78308536-1708-46b9-d657-9babbf55daec@oracle.com> Hi Joe, Thanks for the suggestion, but I don't think we can do it using Taglets - as far as I know, Taglets cannot add tabs to the method listing. We would either need to modify javadoc, or (maybe) have a special doclet for JDK documentation. Jan On 04. 10. 19 7:08, Joe Darcy wrote: > Hi Jan, > > For future work, consider having a "Preview Methods" tag alongside > static, instance, deprecated, etc. > > Cheers, > > -Joe > > On 10/3/2019 2:57 AM, Jan Lahoda wrote: >> Hi, >> >> This is a continuation of Joe's patch from here: >> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >> >> >> APIs associated with preview features are split into two groups: >> essential and non-essential. These are marked with an JDK-internal >> annotation, PreviewFeature, and a tag in the javadoc, @preview. The >> javac follows the PreviewFeature annotation, and produces either >> warnings or errors for the usages of such APIs. For the @preview tag, >> there is a taglet in the JDK build that adds the content of the tag >> into the documentation. The first part of the @preview's text goes >> into the summary, the second part goes into the detailed description. >> >> For build, a tricky problem is that the jdk.compiler module uses the >> PreviewFeature annotation as well, but that is not in the bootstrap >> JDK. So, for the intermediate langtools build, the PreviewFeature >> annotation is copied from java.base. >> >> Proposed webrev: >> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >> >> Javadoc with the change: >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >> >> See for example: >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >> >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >> >> >> JBS: >> https://bugs.openjdk.java.net/browse/JDK-8226585 >> >> CSR: >> https://bugs.openjdk.java.net/browse/JDK-8231411 >> >> Feedback is welcome! >> >> Thanks, >> ??? Jan From vicente.romero at oracle.com Mon Oct 7 20:59:03 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 7 Oct 2019 16:59:03 -0400 Subject: FYI, proposed javax.lang.model changes for records Message-ID: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> Hi, We have recently made an update of the javax.lang.model implementation for records [1]. The key difference with the previous implementation is that we have made javax.lang.model.element.RecordComponentElement, a top level element in the model, a direct subinterface of j.l.m.e.Element. Previously it was extending j.l.m.e.VariableElement. Doing this seemingly minor change has implied a cascade of changes several existing APIs plus the addition of several new ones: new visitors, new scanners, etc. A specdiff of the changes comprised in this iteration can be seen at [2]. As a baseline I have also provided a specdiff of all the changes done in javax.lang.model for records at [3]. This last diff is a comparison between current JDK14 implementation and our proposal for records, Thanks, Vicente [1] https://hg.openjdk.java.net/amber/amber/rev/cf64ea74503e [2] http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/diff_initial_and_current_approach/specdiff.01/java.compiler/module-summary.html [3]http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/specdiff.00/java.compiler/module-summary.html From maurizio.cimadamore at oracle.com Mon Oct 7 22:51:42 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 7 Oct 2019 23:51:42 +0100 Subject: FYI, proposed javax.lang.model changes for records In-Reply-To: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> References: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> Message-ID: Hi Vicente, looking at the ElementKind construct, it is very nice to see that we have now a nice 1-1 mapping between: - Record/Record_Component - Enum/Enum_Constant That said, from an API perspective, while both enums and records are TypeElement (so we're consistent there), there's nothing in the API to model enum constants directly, while now we do have a way to model record components. I think this asymmetry should be rectified, eventually, but I do not think this is a fault of the record API - I believe in reality what I'd wish is for enums to be more exposed in the element API, rather than being presented as a special kind of field (which is, I think, what happens now). Moreover, there's no way to ask a TypeElement representing an 'enum' questions like: give me all your constants. As for sealing, I echo here what was said offline by Jon, which I think was a good point that should not get lost: at the source level we now have new modifiers, such as 'non-sealed'. While javac supports them, we haven't worked out a story for these yet in the source reflection API. In a way, one could say that the changes you have there are enough: after all, you can see that a class has been marked as 'non-sealed' by the absence of any other modifier there. But this brings out a question of 'how much fidelity' do we expect between source code and the j.l.model API - I believe right now the mapping is a bit fuzzy - that is, e.g. interface fields will probably have { PUBLIC, STATIC } regardless of the way in which they have been declared. In any case, there's a question about what to do w.r.t. 'non-sealed' (and, more generally, with 'non-xyz' modifiers), especially if we expect some of these to be inspectionable by some other tools (see javadoc). Overall, this looks like solid work - and at some point we'll need to have some discussion about the finishing touches discussed above. Maurizio On 07/10/2019 21:59, Vicente Romero wrote: > Hi, > > We have recently made an update of the javax.lang.model implementation > for records [1]. The key difference with the previous implementation > is that we have made javax.lang.model.element.RecordComponentElement, > a top level element in the model, a direct subinterface of > j.l.m.e.Element. Previously it was extending j.l.m.e.VariableElement. > Doing this seemingly minor change has implied a cascade of changes > several existing APIs plus the addition of several new ones: new > visitors, new scanners, etc. A specdiff of the changes comprised in > this iteration can be seen at [2]. As a baseline I have also provided > a specdiff of all the changes done in javax.lang.model for records at > [3]. This last diff is a comparison between current JDK14 > implementation and our proposal for records, > > Thanks, > Vicente > > [1] https://hg.openjdk.java.net/amber/amber/rev/cf64ea74503e > [2] > http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/diff_initial_and_current_approach/specdiff.01/java.compiler/module-summary.html > [3]http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/specdiff.00/java.compiler/module-summary.html > From jonathan.gibbons at oracle.com Tue Oct 8 00:48:31 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 7 Oct 2019 17:48:31 -0700 Subject: FYI, proposed javax.lang.model changes for records In-Reply-To: References: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> Message-ID: <95e9f901-17aa-dd49-a58b-63456156ed22@oracle.com> On 10/7/19 3:51 PM, Maurizio Cimadamore wrote: > Hi Vicente, > looking at the ElementKind construct, it is very nice to see that we > have now a nice 1-1 mapping between: > > - Record/Record_Component > - Enum/Enum_Constant > > That said, from an API perspective, while both enums and records are > TypeElement (so we're consistent there), there's nothing in the API to > model enum constants directly, while now we do have a way to model > record components. > > I think this asymmetry should be rectified, eventually, but I do not > think this is a fault of the record API - I believe in reality what > I'd wish is for enums to be more exposed in the element API, rather > than being presented as a special kind of field (which is, I think, > what happens now). Moreover, there's no way to ask a TypeElement > representing an 'enum' questions like: give me all your constants. > > As for sealing, I echo here what was said offline by Jon, which I > think was a good point that should not get lost: at the source level > we now have new modifiers, such as 'non-sealed'. While javac supports > them, we haven't worked out a story for these yet in the source > reflection API. In a way, one could say that the changes you have > there are enough: after all, you can see that a class has been marked > as 'non-sealed' by the absence of any other modifier there. But this > brings out a question of 'how much fidelity' do we expect between > source code and the j.l.model API - I believe right now the mapping is > a bit fuzzy - that is, e.g. interface fields will probably have { > PUBLIC, STATIC } regardless of the way in which they have been > declared. In any case, there's a question about what to do w.r.t. > 'non-sealed' (and, more generally, with 'non-xyz' modifiers), > especially if we expect some of these to be inspectionable by some > other tools (see javadoc). With regard to non-sealed, at least for javadoc, it's not enough to just look for the absence of "sealed"; you have to look at the supertype to see if it is sealed, and hence whether non-sealed may be necessary.? In other words, we have a tri-valued state here ... 1. "nothing" (standard for almost all declarations) 2. "sealed" (for sealed types) 3. "non-sealed" (for non-sealed subtypes of sealed types) It's not rocket-science for javadoc to do the right thing, but it's not convenient either. -- Jon > > Overall, this looks like solid work - and at some point we'll need to > have some discussion about the finishing touches discussed above. > > Maurizio > > On 07/10/2019 21:59, Vicente Romero wrote: >> Hi, >> >> We have recently made an update of the javax.lang.model >> implementation for records [1]. The key difference with the previous >> implementation is that we have made >> javax.lang.model.element.RecordComponentElement, a top level element >> in the model, a direct subinterface of j.l.m.e.Element. Previously it >> was extending j.l.m.e.VariableElement. Doing this seemingly minor >> change has implied a cascade of changes several existing APIs plus >> the addition of several new ones: new visitors, new scanners, etc. A >> specdiff of the changes comprised in this iteration can be seen at >> [2]. As a baseline I have also provided a specdiff of all the changes >> done in javax.lang.model for records at [3]. This last diff is a >> comparison between current JDK14 implementation and our proposal for >> records, >> >> Thanks, >> Vicente >> >> [1] https://hg.openjdk.java.net/amber/amber/rev/cf64ea74503e >> [2] >> http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/diff_initial_and_current_approach/specdiff.01/java.compiler/module-summary.html >> [3]http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/specdiff.00/java.compiler/module-summary.html >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Tue Oct 8 00:52:34 2019 From: joe.darcy at oracle.com (Joe Darcy) Date: Mon, 7 Oct 2019 17:52:34 -0700 Subject: FYI, proposed javax.lang.model changes for records In-Reply-To: References: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> Message-ID: <0ccf9dc2-928c-88f3-a6c9-2af4d3247265@oracle.com> Hello, On 10/7/2019 3:51 PM, Maurizio Cimadamore wrote: > Hi Vicente, > looking at the ElementKind construct, it is very nice to see that we > have now a nice 1-1 mapping between: > > - Record/Record_Component > - Enum/Enum_Constant > > That said, from an API perspective, while both enums and records are > TypeElement (so we're consistent there), there's nothing in the API to > model enum constants directly, while now we do have a way to model > record components. > > I think this asymmetry should be rectified, eventually, but I do not > think this is a fault of the record API - I believe in reality what > I'd wish is for enums to be more exposed in the element API, rather > than being presented as a special kind of field (which is, I think, > what happens now). Moreover, there's no way to ask a TypeElement > representing an 'enum' questions like: give me all your constants. Giving some context on the API design here, back in the original apt modeling API, there was a more specific correspondence between the interface hierarchy and the language concepts. For example, there were interfaces for all of * TypeDeclaration * ClassDeclaration extends TypeDeclaration * EnumDeclaration extends ClassDeclaration (adding getEnumConstants method) * InterfaceDeclaration extends TypeDeclaration * AnnotationTypeDeclaration extends InterfaceDeclaration Based on experience with the apt API, wanting to make the replacement API easier to evolve and easier to be implemented by multiple compilers, we made the javax.lang.model API less specific. For example, all five interfaces above map to javax.lang.model.TypeElement. The flip side is if methods are conceptually hoisted up the interface hierarchy, because several layers of interfaces are combined, more special cases in methods will need to be defined in terms of vacuous results. For example, if javax.lang.model.TypeElement::getSuperClass is called on an interface type, a sentinel "no type" value is returned. Another consequence is that methods analogous to "getEnumConstants" aren't necessarily were you'd look for them. To keep the main modeling interfaces streamlined, secondary functionality was moved over to the javax.lang.model.util.Elements helper interface. There isn't a single method in the current javax.lang.model API for returning the enum constants; filtering on the enclosed objects whose element kind is ENUM_CONSTANT is how I'd recommend coding the functionality in user code and how javac's printing processor isolates the constants. It would also be possible to add a method to return the constants to javax.lang.model.util.Elements. (If default methods were available when JSR 269 was being designed, it is likely we would have made different API trade-offs and included more convenience methods in the main interfaces.) Vicente and I had various off-list discussions about how record components should be represented in javax.lang.model. [1] One possible model is what is proposed here, record components as a new direct subinterface of Element. I don't think it is absolutely necessary to give record components their own modeling interface, but I think it is reasonable to do so given their additional "conceptual size" compared to enum constants. For example, a record component gets mapped into potentially a constructor parameter, a private field, and an accessor method and can host annotations that get copied down accordingly. That is "bigger" than the enum constant mapping of to a static final field. [2] I wouldn't object to a convenience method for getting the enum constants of a type , but I think retrofitting a EnumConstantElement interface would be problematic with respect to behavioral compatibility of existing visitors. One of the main technical differences between javax.lang.model and the older api apt API besides the leaner modeling approach is javax.lang.model tackles the "expression problem" for coping with evolving the language while the apt API was only intended for the Java SE 5.0 iteration of the language. [3] HTH, -Joe [1] The modeling choices include: 1) New top-level RecordComponentElement as a direct subinterface of javax.lang.model.Element with matching kind. 2) New sub-interface of VariableElement; record components distinguished by a new kind. 3) No new interface for record components, reuse VariableElements with a RECORD_COMPONENT kind. It is clearer how to make solutions 1) and 3) work for the visitors, with 1) being the most straightforward if largest footprint on the API. [2] A limitation of the current modeling of enum constants came to my attention in the context of some recent work on an annotation processor to check the declarations of serializable types. If an enum constant is declared using the specialized enum constant syntax which implicitly defines an anonymous class, there is no way through the existing API to access the members of that class. To address this, the API could allow enum constants to have a non-empty list of enclosed elements. However, since this is, to my knowledge, the first time this limitation has come up in about 15 years of using the API, I don't think it is a very urgent problem. [3] See https://en.wikipedia.org/wiki/Expression_problem for history and discussion. The visitUnknown visitor methods and UnknownFooExceptions are the mechanisms to allow well-written annotation processors to be run From vicente.romero at oracle.com Tue Oct 8 02:50:13 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 7 Oct 2019 22:50:13 -0400 Subject: FYI, proposed javax.lang.model changes for records In-Reply-To: References: <747228be-0e31-7098-e61e-17c94033bcd7@oracle.com> Message-ID: <62ae9da3-8082-eba4-b30d-88ec3cf5522d@oracle.com> Hi Maurizio, Thanks for the feedback. Yes I agree we still don't have a great story for non-XX modifiers, we can probably talk about that in the next meeting. On 10/7/19 6:51 PM, Maurizio Cimadamore wrote: > Hi Vicente, > looking at the ElementKind construct, it is very nice to see that we > have now a nice 1-1 mapping between: > > - Record/Record_Component > - Enum/Enum_Constant > > That said, from an API perspective, while both enums and records are > TypeElement (so we're consistent there), there's nothing in the API to > model enum constants directly, while now we do have a way to model > record components. > > I think this asymmetry should be rectified, eventually, but I do not > think this is a fault of the record API - I believe in reality what > I'd wish is for enums to be more exposed in the element API, rather > than being presented as a special kind of field (which is, I think, > what happens now). good point, yes we can leverage the API for enums too > Moreover, there's no way to ask a TypeElement representing an 'enum' > questions like: give me all your constants. > > As for sealing, I echo here what was said offline by Jon, which I > think was a good point that should not get lost: at the source level > we now have new modifiers, such as 'non-sealed'. While javac supports > them, we haven't worked out a story for these yet in the source > reflection API. In a way, one could say that the changes you have > there are enough: after all, you can see that a class has been marked > as 'non-sealed' by the absence of any other modifier there. But this > brings out a question of 'how much fidelity' do we expect between > source code and the j.l.model API - I believe right now the mapping is > a bit fuzzy - that is, e.g. interface fields will probably have { > PUBLIC, STATIC } regardless of the way in which they have been > declared. In any case, there's a question about what to do w.r.t. > 'non-sealed' (and, more generally, with 'non-xyz' modifiers), > especially if we expect some of these to be inspectionable by some > other tools (see javadoc). > > Overall, this looks like solid work - and at some point we'll need to > have some discussion about the finishing touches discussed above. > > Maurizio Thanks, Vicente > > On 07/10/2019 21:59, Vicente Romero wrote: >> Hi, >> >> We have recently made an update of the javax.lang.model >> implementation for records [1]. The key difference with the previous >> implementation is that we have made >> javax.lang.model.element.RecordComponentElement, a top level element >> in the model, a direct subinterface of j.l.m.e.Element. Previously it >> was extending j.l.m.e.VariableElement. Doing this seemingly minor >> change has implied a cascade of changes several existing APIs plus >> the addition of several new ones: new visitors, new scanners, etc. A >> specdiff of the changes comprised in this iteration can be seen at >> [2]. As a baseline I have also provided a specdiff of all the changes >> done in javax.lang.model for records at [3]. This last diff is a >> comparison between current JDK14 implementation and our proposal for >> records, >> >> Thanks, >> Vicente >> >> [1] https://hg.openjdk.java.net/amber/amber/rev/cf64ea74503e >> [2] >> http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/diff_initial_and_current_approach/specdiff.01/java.compiler/module-summary.html >> [3]http://cr.openjdk.java.net/~vromero/amber/records/javax.lang.model/specdiff.00/java.compiler/module-summary.html >> From ronshapiro at google.com Tue Oct 8 08:31:38 2019 From: ronshapiro at google.com (Ron Shapiro) Date: Tue, 8 Oct 2019 11:31:38 +0300 Subject: RFR 8230162: ScopeImpl.remove() has O(N) performance In-Reply-To: References: <635e2298-3bb2-e576-d741-48dcddd132d4@oracle.com> <591e776d-9d9e-261e-9202-ffff4d4e0844@oracle.com> Message-ID: Hi, can someone sponsor/submit (I think that's right terminology) this patch? I don't want it to get lost. Here is the latest webrev for reference: http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ On Mon, Sep 30, 2019 at 7:16 PM Brad Corso wrote: > Friendly ping. > > On Wed, Sep 18, 2019 at 9:55 AM Brad Corso wrote: > >> Hi Jan, >> >> I'm okay with either version so I'll leave that decision up to you. >> >> Let me know if there's anything else you need from me. >> >> Thanks! >> Brad >> >> On Wed, Sep 18, 2019 at 12:38 AM Jan Lahoda >> wrote: >> >>> I've added logging to count how many Entries are created, and there's a >>> little above 500000 instances created for java.base and a little less >>> for java.desktop. So if the Entry would be 8 bytes bigger, it would be >>> about 4MB, which does not sound terrible. So maybe we should go with >>> version .00. >>> >>> Jan >>> >>> On 18. 09. 19 3:10, Brad Corso wrote: >>> > Hi Jan, are you okay moving forward with >>> > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/? >>> > >>> > On Wed, Sep 4, 2019 at 5:15 AM Ron Shapiro >> > > wrote: >>> > >>> > Here's the updated webrev that Brad mentioned in his last message: >>> > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ >>> > >>> > On Wed, Aug 28, 2019 at 2:40 AM Brad Corso >> > > wrote: >>> > >>> > I believe "Do you have any estimates of the increase in >>> size >>> > in typical >>> > usage, due to the extra field in Scope?" (Jon) >>> > >>> > I was seeing noticeably bad performance once the size of the >>> > Entry.sibling linked list reached ~10000, and the max I saw was >>> > ~30000 in a single scope. Given that an additional reference >>> > adds 32/64b, this could add up to 120/240Kb for the cases I >>> saw. >>> > >>> > I'd add, is there a chance to get an improvement in >>> > Scope.remove speed >>> > without making ScopeImpl.Entry bigger (assuming it gets >>> > bigger(?))? One >>> > possibility that occurred to me is that we could try not to >>> > remove the >>> > things from elems, but only mark them as removed. We would >>> > need to do >>> > filtering (and possibly the actual removal) while reading >>> > from the Scope >>> > (in getSymbols), so this is a different kind of trade-off. >>> > >>> > (Overall, I guess the question is whether we are trading >>> > problems with >>> > >>> > Scope.remove speed in some cases for out-of-memory problems >>> > in other cases.) >>> > >>> > Thanks, I've verified your suggestion also gives us the >>> > performance improvements, so this change is okay with me. >>> > >>> > >>> > >>> > On Tue, Aug 27, 2019 at 12:05 AM Jan Lahoda >>> > > wrote: >>> > >>> > On 27. 08. 19 0:06, Brad Corso wrote: >>> > > Sorry, what's the question? >>> > >>> > I believe "Do you have any estimates of the increase in >>> size >>> > in typical >>> > usage, due to the extra field in Scope?" (Jon) >>> > >>> > I'd add, is there a chance to get an improvement in >>> > Scope.remove speed >>> > without making ScopeImpl.Entry bigger (assuming it gets >>> > bigger(?))? One >>> > possibility that occurred to me is that we could try not to >>> > remove the >>> > things from elems, but only mark them as removed. We would >>> > need to do >>> > filtering (and possibly the actual removal) while reading >>> > from the Scope >>> > (in getSymbols), so this is a different kind of trade-off. >>> > >>> > (Overall, I guess the question is whether we are trading >>> > problems with >>> > Scope.remove speed in some cases for out-of-memory problems >>> > in other cases.) >>> > >>> > Jan >>> > >>> > > >>> > > On Mon, Aug 26, 2019 at 1:54 PM Ron Shapiro >>> > >>> > > >> > >> wrote: >>> > > >>> > > Adding Brad back in to the thread since he would >>> know >>> > best >>> > > >>> > > ?????? ??? ??, 26 ????? 2019, 19:40, ??? Jonathan >>> Gibbons >>> > > ?>> > >>> > >> > >>: >>> > > >>> > > >>> > > On 8/26/19 9:12 AM, Ron Shapiro wrote: >>> > > > >>> > > > Note that the patch was prepared by my >>> > coworker, Brad (cc'd). >>> > > I wasn't >>> > > > sure what to do to make sure that he was >>> > attributed correctly. >>> > > >>> > > >>> > > Mention this when you have a sponsor to push the >>> > changeset, so >>> > > that it >>> > > can be marked with "Contributed-By:" >>> > > >>> > > -- Jon >>> > > >>> > >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ronshapiro at google.com Tue Oct 8 08:45:15 2019 From: ronshapiro at google.com (Ron Shapiro) Date: Tue, 8 Oct 2019 11:45:15 +0300 Subject: RFR 8231990: Remove unnecessary else-if branch in Types.union Message-ID: Please review the following tiny patch which was already discussed/review in another thread[0] webrev: http://cr.openjdk.java.net/~ronsh/8231990/webrev.00/ bug: https://bugs.openjdk.java.net/browse/JDK-8231990 The patch was prepared by Brad Corso (cc'ed) - whoever ends up submitting, can you make sure that the authorship is marked correctly? Thanks! [0]: https://mail.openjdk.java.net/pipermail/compiler-dev/2019-September/013679.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From cushon at google.com Tue Oct 8 15:06:34 2019 From: cushon at google.com (Liam Miller-Cushon) Date: Tue, 8 Oct 2019 08:06:34 -0700 Subject: RFR 8230162: ScopeImpl.remove() has O(N) performance In-Reply-To: References: <635e2298-3bb2-e576-d741-48dcddd132d4@oracle.com> <591e776d-9d9e-261e-9202-ffff4d4e0844@oracle.com> Message-ID: I'm happy to help push the patch once it's been reviewed, but I'm not a Reviewer. +Jan Lahoda , does version .00 look OK to you? On Tue, Oct 8, 2019 at 1:34 AM Ron Shapiro wrote: > Hi, can someone sponsor/submit (I think that's right terminology) this > patch? I don't want it to get lost. > > Here is the latest webrev for reference: > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ > > On Mon, Sep 30, 2019 at 7:16 PM Brad Corso wrote: > >> Friendly ping. >> >> On Wed, Sep 18, 2019 at 9:55 AM Brad Corso wrote: >> >>> Hi Jan, >>> >>> I'm okay with either version so I'll leave that decision up to you. >>> >>> Let me know if there's anything else you need from me. >>> >>> Thanks! >>> Brad >>> >>> On Wed, Sep 18, 2019 at 12:38 AM Jan Lahoda >>> wrote: >>> >>>> I've added logging to count how many Entries are created, and there's a >>>> little above 500000 instances created for java.base and a little less >>>> for java.desktop. So if the Entry would be 8 bytes bigger, it would be >>>> about 4MB, which does not sound terrible. So maybe we should go with >>>> version .00. >>>> >>>> Jan >>>> >>>> On 18. 09. 19 3:10, Brad Corso wrote: >>>> > Hi Jan, are you okay moving forward with >>>> > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/? >>>> > >>>> > On Wed, Sep 4, 2019 at 5:15 AM Ron Shapiro >>> > > wrote: >>>> > >>>> > Here's the updated webrev that Brad mentioned in his last message: >>>> > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ >>>> > >>>> > On Wed, Aug 28, 2019 at 2:40 AM Brad Corso >>> > > wrote: >>>> > >>>> > I believe "Do you have any estimates of the increase in >>>> size >>>> > in typical >>>> > usage, due to the extra field in Scope?" (Jon) >>>> > >>>> > I was seeing noticeably bad performance once the size of the >>>> > Entry.sibling linked list reached ~10000, and the max I saw >>>> was >>>> > ~30000 in a single scope. Given that an additional reference >>>> > adds 32/64b, this could add up to 120/240Kb for the cases I >>>> saw. >>>> > >>>> > I'd add, is there a chance to get an improvement in >>>> > Scope.remove speed >>>> > without making ScopeImpl.Entry bigger (assuming it gets >>>> > bigger(?))? One >>>> > possibility that occurred to me is that we could try not >>>> to >>>> > remove the >>>> > things from elems, but only mark them as removed. We would >>>> > need to do >>>> > filtering (and possibly the actual removal) while reading >>>> > from the Scope >>>> > (in getSymbols), so this is a different kind of trade-off. >>>> > >>>> > (Overall, I guess the question is whether we are trading >>>> > problems with >>>> > >>>> > Scope.remove speed in some cases for out-of-memory >>>> problems >>>> > in other cases.) >>>> > >>>> > Thanks, I've verified your suggestion also gives us the >>>> > performance improvements, so this change is okay with me. >>>> > >>>> > >>>> > >>>> > On Tue, Aug 27, 2019 at 12:05 AM Jan Lahoda >>>> > > wrote: >>>> > >>>> > On 27. 08. 19 0:06, Brad Corso wrote: >>>> > > Sorry, what's the question? >>>> > >>>> > I believe "Do you have any estimates of the increase in >>>> size >>>> > in typical >>>> > usage, due to the extra field in Scope?" (Jon) >>>> > >>>> > I'd add, is there a chance to get an improvement in >>>> > Scope.remove speed >>>> > without making ScopeImpl.Entry bigger (assuming it gets >>>> > bigger(?))? One >>>> > possibility that occurred to me is that we could try not >>>> to >>>> > remove the >>>> > things from elems, but only mark them as removed. We would >>>> > need to do >>>> > filtering (and possibly the actual removal) while reading >>>> > from the Scope >>>> > (in getSymbols), so this is a different kind of trade-off. >>>> > >>>> > (Overall, I guess the question is whether we are trading >>>> > problems with >>>> > Scope.remove speed in some cases for out-of-memory >>>> problems >>>> > in other cases.) >>>> > >>>> > Jan >>>> > >>>> > > >>>> > > On Mon, Aug 26, 2019 at 1:54 PM Ron Shapiro >>>> > >>>> > > >>> > >> wrote: >>>> > > >>>> > > Adding Brad back in to the thread since he would >>>> know >>>> > best >>>> > > >>>> > > ?????? ??? ??, 26 ????? 2019, 19:40, ??? Jonathan >>>> Gibbons >>>> > > ?>>> > >>>> > >>> > >>: >>>> > > >>>> > > >>>> > > On 8/26/19 9:12 AM, Ron Shapiro wrote: >>>> > > > >>>> > > > Note that the patch was prepared by my >>>> > coworker, Brad (cc'd). >>>> > > I wasn't >>>> > > > sure what to do to make sure that he was >>>> > attributed correctly. >>>> > > >>>> > > >>>> > > Mention this when you have a sponsor to push >>>> the >>>> > changeset, so >>>> > > that it >>>> > > can be marked with "Contributed-By:" >>>> > > >>>> > > -- Jon >>>> > > >>>> > >>>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Tue Oct 8 15:08:51 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 8 Oct 2019 17:08:51 +0200 Subject: RFR 8230162: ScopeImpl.remove() has O(N) performance In-Reply-To: References: <635e2298-3bb2-e576-d741-48dcddd132d4@oracle.com> <591e776d-9d9e-261e-9202-ffff4d4e0844@oracle.com> Message-ID: <906b9361-54c7-8095-619c-ce676e3401d5@oracle.com> On 08. 10. 19 17:06, Liam Miller-Cushon wrote: > I'm happy to help push the patch once it's been reviewed, but I'm not a > Reviewer. > > +Jan Lahoda , does version .00 look OK to you? I did actually push that: http://hg.openjdk.java.net/jdk/jdk/rev/03165abce4cc Jan > > On Tue, Oct 8, 2019 at 1:34 AM Ron Shapiro > wrote: > > Hi, can someone sponsor/submit (I think that's right terminology) > this patch? I don't want it to get lost. > > Here is the latest webrev for reference: > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ > > On Mon, Sep 30, 2019 at 7:16 PM Brad Corso > wrote: > > Friendly ping. > > On Wed, Sep 18, 2019 at 9:55 AM Brad Corso > wrote: > > Hi Jan, > > I'm okay with either version so I'll leave that decision up > to?you. > > Let me know if there's anything else you?need from me. > > Thanks! > Brad > > On Wed, Sep 18, 2019 at 12:38 AM Jan Lahoda > > wrote: > > I've added logging to count how many Entries are > created, and there's a > little above 500000 instances created for java.base and > a little less > for java.desktop. So if the Entry would be 8 bytes > bigger, it would be > about 4MB, which does not sound terrible. So maybe we > should go with > version .00. > > Jan > > On 18. 09. 19 3:10, Brad Corso wrote: > > Hi Jan, are you okay moving forward with > > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/? > > > > On Wed, Sep 4, 2019 at 5:15 AM Ron Shapiro > > > >> wrote: > > > >? ? ?Here's the updated webrev that Brad mentioned in > his last message: > > http://cr.openjdk.java.net/~ronsh/8230162/webrev.01/ > > > >? ? ?On Wed, Aug 28, 2019 at 2:40 AM Brad Corso > > >? ? ? >> wrote: > > > >? ? ? ? ? ? ?I believe "Do you have any estimates of > the increase in size > >? ? ? ? ? ? ?in typical > >? ? ? ? ? ? ?usage, due to the extra field in Scope?" > (Jon) > > > >? ? ? ? ?I was seeing noticeably bad performance once > the size of the > >? ? ? ? ?Entry.sibling linked list reached ~10000, and > the max I saw was > >? ? ? ? ?~30000 in a single scope. Given that an > additional reference > >? ? ? ? ?adds 32/64b, this could add up to 120/240Kb > for the cases I saw. > > > >? ? ? ? ? ? ?I'd add, is there a chance to get an > improvement in > >? ? ? ? ? ? ?Scope.remove speed > >? ? ? ? ? ? ?without making ScopeImpl.Entry bigger > (assuming it gets > >? ? ? ? ? ? ?bigger(?))? One > >? ? ? ? ? ? ?possibility that occurred to me is that > we could try not to > >? ? ? ? ? ? ?remove the > >? ? ? ? ? ? ?things from elems, but only mark them as > removed. We would > >? ? ? ? ? ? ?need to do > >? ? ? ? ? ? ?filtering (and possibly the actual > removal) while reading > >? ? ? ? ? ? ?from the Scope > >? ? ? ? ? ? ?(in getSymbols), so this is a different > kind of trade-off. > > > >? ? ? ? ? ? ?(Overall, I guess the question is whether > we are trading > >? ? ? ? ? ? ?problems with > > > >? ? ? ? ? ? ?Scope.remove speed in some cases for > out-of-memory problems > >? ? ? ? ? ? ?in other cases.) > > > >? ? ? ? ?Thanks, I've verified your suggestion also > gives us the > >? ? ? ? ?performance improvements, so this change is > okay with me. > > > > > > > >? ? ? ? ?On Tue, Aug 27, 2019 at 12:05 AM Jan Lahoda > >? ? ? ? ? > >> wrote: > > > >? ? ? ? ? ? ?On 27. 08. 19 0:06, Brad Corso wrote: > >? ? ? ? ? ? ? > Sorry, what's the question? > > > >? ? ? ? ? ? ?I believe "Do you have any estimates of > the increase in size > >? ? ? ? ? ? ?in typical > >? ? ? ? ? ? ?usage, due to the extra field in Scope?" > (Jon) > > > >? ? ? ? ? ? ?I'd add, is there a chance to get an > improvement in > >? ? ? ? ? ? ?Scope.remove speed > >? ? ? ? ? ? ?without making ScopeImpl.Entry bigger > (assuming it gets > >? ? ? ? ? ? ?bigger(?))? One > >? ? ? ? ? ? ?possibility that occurred to me is that > we could try not to > >? ? ? ? ? ? ?remove the > >? ? ? ? ? ? ?things from elems, but only mark them as > removed. We would > >? ? ? ? ? ? ?need to do > >? ? ? ? ? ? ?filtering (and possibly the actual > removal) while reading > >? ? ? ? ? ? ?from the Scope > >? ? ? ? ? ? ?(in getSymbols), so this is a different > kind of trade-off. > > > >? ? ? ? ? ? ?(Overall, I guess the question is whether > we are trading > >? ? ? ? ? ? ?problems with > >? ? ? ? ? ? ?Scope.remove speed in some cases for > out-of-memory problems > >? ? ? ? ? ? ?in other cases.) > > > >? ? ? ? ? ? ?Jan > > > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? > On Mon, Aug 26, 2019 at 1:54 PM Ron > Shapiro > >? ? ? ? ? ? ? > > > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >>> wrote: > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ?Adding Brad back in to the thread > since he would know > >? ? ? ? ? ? ?best > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ??????? ??? ??, 26 ????? 2019, > 19:40, ??? Jonathan Gibbons > >? ? ? ? ? ? ? >? ? ?? > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? > >? ? ? ? ? ? ? >>>: > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ? ? ?On 8/26/19 9:12 AM, Ron > Shapiro wrote: > >? ? ? ? ? ? ? >? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ? ? ? > Note that the patch was > prepared by my > >? ? ? ? ? ? ?coworker, Brad (cc'd). > >? ? ? ? ? ? ? >? ? ? ? ?I wasn't > >? ? ? ? ? ? ? >? ? ? ? ? > sure what to do to make > sure that he was > >? ? ? ? ? ? ?attributed correctly. > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ? ? ?Mention this when you have a > sponsor to push the > >? ? ? ? ? ? ?changeset, so > >? ? ? ? ? ? ? >? ? ? ? ?that it > >? ? ? ? ? ? ? >? ? ? ? ?can be marked with > "Contributed-By:" > >? ? ? ? ? ? ? > > >? ? ? ? ? ? ? >? ? ? ? ?-- Jon > >? ? ? ? ? ? ? > > > > From cushon at google.com Tue Oct 8 15:10:25 2019 From: cushon at google.com (Liam Miller-Cushon) Date: Tue, 8 Oct 2019 08:10:25 -0700 Subject: RFR 8230162: ScopeImpl.remove() has O(N) performance In-Reply-To: <906b9361-54c7-8095-619c-ce676e3401d5@oracle.com> References: <635e2298-3bb2-e576-d741-48dcddd132d4@oracle.com> <591e776d-9d9e-261e-9202-ffff4d4e0844@oracle.com> <906b9361-54c7-8095-619c-ce676e3401d5@oracle.com> Message-ID: On Tue, Oct 8, 2019 at 8:09 AM Jan Lahoda wrote: > I did actually push that: > http://hg.openjdk.java.net/jdk/jdk/rev/03165abce4cc Ah, great. Thanks! -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Tue Oct 8 15:27:10 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 8 Oct 2019 17:27:10 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: Message-ID: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> Thanks for the new code Erik! A new webrev/patch that includes this better way of copying is here: http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ Any feedback is welcome! Thanks, Jan On 03. 10. 19 18:06, Erik Joelsson wrote: > Hello Jan, > > The build change looks ok, but I would recommend this construct for > copying the file instead: > > $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ > ??? FILES := > $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, \ > ??? DEST := > $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, > \ > )) > > TARGETS += $(COPY_PREVIEW_FEATURES) > > Then you automatically get all the corner case handling we have > implemented over the years for logging, making directories and copying > files. Your version is still correct for this case though. > > /Erik > > On 2019-10-03 02:57, Jan Lahoda wrote: >> Hi, >> >> This is a continuation of Joe's patch from here: >> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >> >> >> APIs associated with preview features are split into two groups: >> essential and non-essential. These are marked with an JDK-internal >> annotation, PreviewFeature, and a tag in the javadoc, @preview. The >> javac follows the PreviewFeature annotation, and produces either >> warnings or errors for the usages of such APIs. For the @preview tag, >> there is a taglet in the JDK build that adds the content of the tag >> into the documentation. The first part of the @preview's text goes >> into the summary, the second part goes into the detailed description. >> >> For build, a tricky problem is that the jdk.compiler module uses the >> PreviewFeature annotation as well, but that is not in the bootstrap >> JDK. So, for the intermediate langtools build, the PreviewFeature >> annotation is copied from java.base. >> >> Proposed webrev: >> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >> >> Javadoc with the change: >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >> >> See for example: >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >> >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >> >> >> JBS: >> https://bugs.openjdk.java.net/browse/JDK-8226585 >> >> CSR: >> https://bugs.openjdk.java.net/browse/JDK-8231411 >> >> Feedback is welcome! >> >> Thanks, >> ??? Jan From erik.joelsson at oracle.com Tue Oct 8 16:04:17 2019 From: erik.joelsson at oracle.com (Erik Joelsson) Date: Tue, 8 Oct 2019 09:04:17 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> Message-ID: Build changes look good. /Erik On 2019-10-08 08:27, Jan Lahoda wrote: > Thanks for the new code Erik! > > A new webrev/patch that includes this better way of copying is here: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ > > Any feedback is welcome! > > Thanks, > ??? Jan > > On 03. 10. 19 18:06, Erik Joelsson wrote: >> Hello Jan, >> >> The build change looks ok, but I would recommend this construct for >> copying the file instead: >> >> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >> ???? FILES := >> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >> \ >> ???? DEST := >> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >> \ >> )) >> >> TARGETS += $(COPY_PREVIEW_FEATURES) >> >> Then you automatically get all the corner case handling we have >> implemented over the years for logging, making directories and >> copying files. Your version is still correct for this case though. >> >> /Erik >> >> On 2019-10-03 02:57, Jan Lahoda wrote: >>> Hi, >>> >>> This is a continuation of Joe's patch from here: >>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>> >>> >>> APIs associated with preview features are split into two groups: >>> essential and non-essential. These are marked with an JDK-internal >>> annotation, PreviewFeature, and a tag in the javadoc, @preview. The >>> javac follows the PreviewFeature annotation, and produces either >>> warnings or errors for the usages of such APIs. For the @preview >>> tag, there is a taglet in the JDK build that adds the content of the >>> tag into the documentation. The first part of the @preview's text >>> goes into the summary, the second part goes into the detailed >>> description. >>> >>> For build, a tricky problem is that the jdk.compiler module uses the >>> PreviewFeature annotation as well, but that is not in the bootstrap >>> JDK. So, for the intermediate langtools build, the PreviewFeature >>> annotation is copied from java.base. >>> >>> Proposed webrev: >>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>> >>> Javadoc with the change: >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>> >>> See for example: >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>> >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>> >>> >>> JBS: >>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>> >>> CSR: >>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>> >>> Feedback is welcome! >>> >>> Thanks, >>> ??? Jan From magnus.ihse.bursie at oracle.com Wed Oct 9 08:42:56 2019 From: magnus.ihse.bursie at oracle.com (Magnus Ihse Bursie) Date: Wed, 9 Oct 2019 10:42:56 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> Message-ID: <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> I can?t see how the compilation is dependent on the copy being finished. Since Erik contributed this it will probably be correct :) but I?d appreciate an explanation on how this dependency is guaranteed. Or maybe I?m misunderstanding what this is supposed to do? /Magnus > 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : > > Thanks for the new code Erik! > > A new webrev/patch that includes this better way of copying is here: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ > > Any feedback is welcome! > > Thanks, > Jan > >> On 03. 10. 19 18:06, Erik Joelsson wrote: >> Hello Jan, >> The build change looks ok, but I would recommend this construct for copying the file instead: >> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >> FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, \ >> DEST := $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, \ >> )) >> TARGETS += $(COPY_PREVIEW_FEATURES) >> Then you automatically get all the corner case handling we have implemented over the years for logging, making directories and copying files. Your version is still correct for this case though. >> /Erik >>> On 2019-10-03 02:57, Jan Lahoda wrote: >>> Hi, >>> >>> This is a continuation of Joe's patch from here: >>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>> >>> APIs associated with preview features are split into two groups: essential and non-essential. These are marked with an JDK-internal annotation, PreviewFeature, and a tag in the javadoc, @preview. The javac follows the PreviewFeature annotation, and produces either warnings or errors for the usages of such APIs. For the @preview tag, there is a taglet in the JDK build that adds the content of the tag into the documentation. The first part of the @preview's text goes into the summary, the second part goes into the detailed description. >>> >>> For build, a tricky problem is that the jdk.compiler module uses the PreviewFeature annotation as well, but that is not in the bootstrap JDK. So, for the intermediate langtools build, the PreviewFeature annotation is copied from java.base. >>> >>> Proposed webrev: >>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>> >>> Javadoc with the change: >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>> >>> See for example: >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>> >>> JBS: >>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>> >>> CSR: >>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>> >>> Feedback is welcome! >>> >>> Thanks, >>> Jan From maurizio.cimadamore at oracle.com Wed Oct 9 09:23:47 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 9 Oct 2019 10:23:47 +0100 Subject: RFR 8231990: Remove unnecessary else-if branch in Types.union In-Reply-To: References: Message-ID: <515c3f54-52e8-55f7-0aaf-72d84088bde2@oracle.com> Looks good - do you need somebody on our side to push this, or will Liam take care of it? Cheers Maurizio On 08/10/2019 09:45, Ron Shapiro wrote: > Please review the following tiny patch which was already > discussed/review in another thread[0] > > webrev: http://cr.openjdk.java.net/~ronsh/8231990/webrev.00/ > bug: https://bugs.openjdk.java.net/browse/JDK-8231990 > > The patch was prepared by Brad Corso (cc'ed) - whoever ends up > submitting, can you make sure that the authorship is marked correctly? > Thanks! > > [0]: > https://mail.openjdk.java.net/pipermail/compiler-dev/2019-September/013679.html From erik.joelsson at oracle.com Wed Oct 9 15:41:22 2019 From: erik.joelsson at oracle.com (Erik Joelsson) Date: Wed, 9 Oct 2019 08:41:22 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> Message-ID: Oh, you are absolutely correct, the dependency is missing. We need something like this inside "define SetupInterimModule": $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) /Erik On 2019-10-09 01:42, Magnus Ihse Bursie wrote: > I can?t see how the compilation is dependent on the copy being finished. Since Erik contributed this it will probably be correct :) but I?d appreciate an explanation on how this dependency is guaranteed. > > Or maybe I?m misunderstanding what this is supposed to do? > > /Magnus > >> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >> >> Thanks for the new code Erik! >> >> A new webrev/patch that includes this better way of copying is here: >> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >> >> Any feedback is welcome! >> >> Thanks, >> Jan >> >>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>> Hello Jan, >>> The build change looks ok, but I would recommend this construct for copying the file instead: >>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>> FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, \ >>> DEST := $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, \ >>> )) >>> TARGETS += $(COPY_PREVIEW_FEATURES) >>> Then you automatically get all the corner case handling we have implemented over the years for logging, making directories and copying files. Your version is still correct for this case though. >>> /Erik >>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>> Hi, >>>> >>>> This is a continuation of Joe's patch from here: >>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>>> >>>> APIs associated with preview features are split into two groups: essential and non-essential. These are marked with an JDK-internal annotation, PreviewFeature, and a tag in the javadoc, @preview. The javac follows the PreviewFeature annotation, and produces either warnings or errors for the usages of such APIs. For the @preview tag, there is a taglet in the JDK build that adds the content of the tag into the documentation. The first part of the @preview's text goes into the summary, the second part goes into the detailed description. >>>> >>>> For build, a tricky problem is that the jdk.compiler module uses the PreviewFeature annotation as well, but that is not in the bootstrap JDK. So, for the intermediate langtools build, the PreviewFeature annotation is copied from java.base. >>>> >>>> Proposed webrev: >>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>> >>>> Javadoc with the change: >>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>> >>>> See for example: >>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>>> >>>> JBS: >>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>> >>>> CSR: >>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>> >>>> Feedback is welcome! >>>> >>>> Thanks, >>>> Jan From cushon at google.com Wed Oct 9 17:46:25 2019 From: cushon at google.com (Liam Miller-Cushon) Date: Wed, 9 Oct 2019 10:46:25 -0700 Subject: RFR 8231990: Remove unnecessary else-if branch in Types.union In-Reply-To: <515c3f54-52e8-55f7-0aaf-72d84088bde2@oracle.com> References: <515c3f54-52e8-55f7-0aaf-72d84088bde2@oracle.com> Message-ID: On Wed, Oct 9, 2019 at 2:26 AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Looks good - do you need somebody on our side to push this, or will Liam > take care of it? > I can take care of it, thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Wed Oct 9 19:35:27 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 9 Oct 2019 20:35:27 +0100 Subject: RFR 8231990: Remove unnecessary else-if branch in Types.union In-Reply-To: References: <515c3f54-52e8-55f7-0aaf-72d84088bde2@oracle.com> Message-ID: <8883071b-422f-9f14-ccf5-65f7f059cdd8@oracle.com> Thanks! Maurizio On 09/10/2019 18:46, Liam Miller-Cushon wrote: > On Wed, Oct 9, 2019 at 2:26 AM Maurizio Cimadamore > > wrote: > > Looks good - do you need somebody on our side to push this, or > will Liam > take care of it? > > > I can take care of it, thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Thu Oct 10 12:12:59 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 10 Oct 2019 14:12:59 +0200 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof Message-ID: Hi, As part of the effort to prepare JEP 305: Pattern Matching for instanceof (Preview) for Propose to Target, I would like to ask for a code review for the corresponding javac changes. The webrev is here: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ The patch applies on top of: https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html The current spec the patch is striving to implements is here: http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html As far as I know, there is one (significant) open issue in the spec, and that is whether non-reifiable types should be allowed in "instanceof ". Currently (AFAIK), the spec does not allow non-reifiable types in the type test pattern in instanceof, and the javac implementation should be consistent with the spec. Should the spec change, the corresponding update to the javac code should have a very limited impact. I'll be preparing a CSR for this change in the coming days. The JBS issue for this code change is: https://bugs.openjdk.java.net/browse/JDK-8231826 Any feedback is welcome! Thanks! Jan From maurizio.cimadamore at oracle.com Thu Oct 10 15:33:51 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 10 Oct 2019 16:33:51 +0100 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: References: Message-ID: Hi Jan, the code looks generally very clean, kudos. Some general comments: * looking at the spec, it seems like both "instanceof T" and "instanceof T t" are cases of type test patterns. I guess I'm fine with the implementation doing what it always did in terms of plain "instanceof T", but I'm worried about the intersection between this and e.g. the tree API - InstanceofTree::getPattern returns null in cases like "instanceof T"; now, I know I know that we're speaking about a JDK specific API, but I think this issue reveals some modelling issues in the way we treat instanceof, and I'm worried that some of these issues might pop up in the future. I'd prefer to either rectify the spec so that plain 'instanceof T' is not a pattern matching instanceof, or rectify javac so that these tests are internally also represented with patterns (at the expense of some extra allocation, perhaps). * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" flag is to be able to distinguish between regular 'expression-wide' bindings, and bindings which 'leaked' outside a statement (e.g. an if statement). And the reason you need to distinguish between these is that you don't want Check::checkUnique to flag duplicate errors between regular 'expression-wide' bindings, which are reported elsewhere (MatchBindingsComputer). But this is also, more crucially, used in TransPattern, where the 'isPreserved' flag is used to control whether a variable decl for the binding variable should be 'lifted' to the enclosing statement context or not. Is my understanding correct here? * The idea behind TransPatterns seems to be: when we process a statement, or an expression, we attempt to add all declaration for the bindings that are used inside the statements/expression upfront. If we are processing a statement, then we surround the results in a block; e.g. if (obj instanceof Foo f) { ? ... } becomes { ?? Foo f$; ?? if (let Object temp = obj in (obj instanceof Foo && (f$ = (Foo)temp) == temp) { ????? ... } If we are processing an expression, we instead generate a LetExpr, e.g. boolean b = obj instanceof Foo t && t.equals(foo); becomes: boolean b = let Foo f$ = null in ((let Object temp = obj in (obj instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) So, sometimes the hoisted var is a real var decl in a block, other times is a var decl inside a let expression. In these cases we have to generate an initializer, to set the value (which might be used later). On top of that, instanceof generates its own letExpr to cache the target of the test (to avoid double computation). It also seems to me that the code handles cases where the binding variable is not used, neither hoisted - e.g. boolean field = obj instanceof Foo t; In this case we generate a plain instanceof w/o the init (because the 't' variable hasn't been hoisted anywhere). Finally, we use the 'isPreserved()' flag to ensure that variables are hoisted correctly - for instance, if something is to be preserved (and the enclosing context allows for it) we push things in the enclosing context instead. Am I getting the correct picture here? It would be nice to have more javadoc spread around to help the reader understand what's the rationale and show some snippet of generated code. * Flow, I wonder if, like you had created SnippetAliveAnalyzer, creating a SnippetBreakAnalyzer would help you avoid the breaksOut[0] trick (that could become a field in the child visitor) Other than that, it looks very good. Maurizio On 10/10/2019 13:12, Jan Lahoda wrote: > Hi, > > As part of the effort to prepare JEP 305: Pattern Matching for > instanceof (Preview) for Propose to Target, I would like to ask for a > code review for the corresponding javac changes. > > The webrev is here: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ > > The patch applies on top of: > https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html > > > The current spec the patch is striving to implements is here: > http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html > > > As far as I know, there is one (significant) open issue in the spec, > and that is whether non-reifiable types should be allowed in > "instanceof ". Currently (AFAIK), the spec does not > allow non-reifiable types in the type test pattern in instanceof, and > the javac implementation should be consistent with the spec. Should > the spec change, the corresponding update to the javac code should > have a very limited impact. > > I'll be preparing a CSR for this change in the coming days. > > The JBS issue for this code change is: > https://bugs.openjdk.java.net/browse/JDK-8231826 > > Any feedback is welcome! > > Thanks! > ??? Jan From brian.goetz at oracle.com Thu Oct 10 15:48:14 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 10 Oct 2019 11:48:14 -0400 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: References: Message-ID: <69FA64DB-1032-4B59-9759-FCC2E0036734@oracle.com> >>> As far as I know, there is one (significant) open issue in the spec, and that is whether non-reifiable types should be allowed in "instanceof ". Currently (AFAIK), the spec does not allow non-reifiable types in the type test pattern in instanceof, and the javac implementation should be consistent with the spec. Should the spec change, the corresponding update to the javac code should have a very limited impact. To be clear, do we treat `instanceof T` and `instanceof T t` differently, or do we disallow non-reifiable types in both places? If the latter, I am fine to say that this is an enhancement that can come in later phases of PM. The former is a little more worrisome, because I would expect users to be confused by an asymmetric treatment. > * looking at the spec, it seems like both "instanceof T" and "instanceof T t" are cases of type test patterns. This is true, though I suspect that ultimately we?ll have to refine the spec somewhat. When we get to patterns in switch, or nested patterns, I think having `T` be a pattern will lead to amibiguties with constant patterns, and we?ll end up making the grammar a little more complicated in order to clean this up. But, for now, the spec treats them the same, and there?s some good in that too. From maurizio.cimadamore at oracle.com Thu Oct 10 15:54:21 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 10 Oct 2019 16:54:21 +0100 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: Message-ID: The javac changes looks good. I guess I would have preferred to move the check for preview from Check to Preview, and also create a tighter integration between PreviewFeature.Feature and javac's Feature enum, so that we could generate tight error messages, but I guess we can also do that as a followup. Maurizio On 03/10/2019 10:57, Jan Lahoda wrote: > Hi, > > This is a continuation of Joe's patch from here: > https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html > > > APIs associated with preview features are split into two groups: > essential and non-essential. These are marked with an JDK-internal > annotation, PreviewFeature, and a tag in the javadoc, @preview. The > javac follows the PreviewFeature annotation, and produces either > warnings or errors for the usages of such APIs. For the @preview tag, > there is a taglet in the JDK build that adds the content of the tag > into the documentation. The first part of the @preview's text goes > into the summary, the second part goes into the detailed description. > > For build, a tricky problem is that the jdk.compiler module uses the > PreviewFeature annotation as well, but that is not in the bootstrap > JDK. So, for the intermediate langtools build, the PreviewFeature > annotation is copied from java.base. > > Proposed webrev: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ > > Javadoc with the change: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html > > See for example: > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html > > http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html > > > JBS: > https://bugs.openjdk.java.net/browse/JDK-8226585 > > CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 > > Feedback is welcome! > > Thanks, > ??? Jan From jan.lahoda at oracle.com Thu Oct 10 19:07:47 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 10 Oct 2019 21:07:47 +0200 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: <69FA64DB-1032-4B59-9759-FCC2E0036734@oracle.com> References: <69FA64DB-1032-4B59-9759-FCC2E0036734@oracle.com> Message-ID: <85857f70-d473-ecd1-a2c3-4593833ffd8c@oracle.com> On 10. 10. 19 17:48, Brian Goetz wrote: >>>> As far as I know, there is one (significant) open issue in the spec, and that is whether non-reifiable types should be allowed in "instanceof ". Currently (AFAIK), the spec does not allow non-reifiable types in the type test pattern in instanceof, and the javac implementation should be consistent with the spec. Should the spec change, the corresponding update to the javac code should have a very limited impact. > > To be clear, do we treat `instanceof T` and `instanceof T t` differently, or do we disallow non-reifiable types in both places? If the latter, I am fine to say that this is an enhancement that can come in later phases of PM. The former is a little more worrisome, because I would expect users to be confused by an asymmetric treatment. I believe the current spec treats them consistently, and without a change from the original state, i.e. non-reifiable types are prohibited for both ordinary instanceof and pattern matching instanceof. The javac patch/behavior should be consistent with that(*). Jan (*) The behavior of javac using the patch submitted herein should be consistent with the spec. The patterns-stage-1 branch in the amber repo is not (at least not yet). That branch is missing quite a few recent updates that are in the patch submitted here, as many of them depend on the new preview feature API handling. The branch should be ignored for now. > > >> * looking at the spec, it seems like both "instanceof T" and "instanceof T t" are cases of type test patterns. > > This is true, though I suspect that ultimately we?ll have to refine the spec somewhat. When we get to patterns in switch, or nested patterns, I think having `T` be a pattern will lead to amibiguties with constant patterns, and we?ll end up making the grammar a little more complicated in order to clean this up. But, for now, the spec treats them the same, and there?s some good in that too. > > From jai.forums2013 at gmail.com Fri Oct 11 14:26:00 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Fri, 11 Oct 2019 19:56:00 +0530 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause Message-ID: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> In recent versions of JDK (I think after JDK 8), the com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a java.nio.file.InvalidPathException in certain cases when the classpath entry it is parsing isn't a valid one. This is because of its usage of the java.nio.file.Path APIs, specifically https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. The throws clause of this FSInfo#getJarClassPath API lists IOException, so this method is now throwing an exception which isn't listed in its throws clause. As a result, callers, like the com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 are no longer able to catch this exception and log it and move on. Instead it gets propagated all the way back to the top level callers, thus breaking applications which are trying to compile java files programmatically. Would this be considered a bug? If so, I can create a JBS issue and provide a patch (and will try a jtreg test case too) for review. Although these classes are internal and not public API, the calling code is actually using public APIs (which internally end up calling these APIs). Like here https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. For a lengthy discussion/context - please read the comments in this issue https://github.com/quarkusio/quarkus/issues/3592 -Jaikiran From david.lloyd at redhat.com Fri Oct 11 14:30:44 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Fri, 11 Oct 2019 09:30:44 -0500 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> Message-ID: In the Quarkus issue, the class path entry is actually valid. But the FSInfo class appears to fail to account for the fact that class-path entries in a JAR are specified as relative URLs, not as file paths, so passing the string directly into getPath() is incorrect. At the very least the string would have to be URL decoded. On Fri, Oct 11, 2019 at 9:27 AM Jaikiran Pai wrote: > > In recent versions of JDK (I think after JDK 8), the > com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a > java.nio.file.InvalidPathException in certain cases when the classpath > entry it is parsing isn't a valid one. This is because of its usage of > the java.nio.file.Path APIs, specifically > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. > > The throws clause of this FSInfo#getJarClassPath API lists IOException, > so this method is now throwing an exception which isn't listed in its > throws clause. As a result, callers, like the > com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 > are no longer able to catch this exception and log it and move on. > Instead it gets propagated all the way back to the top level callers, > thus breaking applications which are trying to compile java files > programmatically. > > Would this be considered a bug? If so, I can create a JBS issue and > provide a patch (and will try a jtreg test case too) for review. > > Although these classes are internal and not public API, the calling code > is actually using public APIs (which internally end up calling these > APIs). Like here > https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. > > For a lengthy discussion/context - please read the comments in this > issue https://github.com/quarkusio/quarkus/issues/3592 > > -Jaikiran > > > -- - DML From jonathan.gibbons at oracle.com Fri Oct 11 14:50:56 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Fri, 11 Oct 2019 07:50:56 -0700 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> Message-ID: <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> Jaikiran, Not catching InvalidPathException is a bug and an unforeseen consequence of converting the file manager from using java.io.File to java.nio.file.Path. -- Jon On 10/11/19 7:26 AM, Jaikiran Pai wrote: > In recent versions of JDK (I think after JDK 8), the > com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a > java.nio.file.InvalidPathException in certain cases when the classpath > entry it is parsing isn't a valid one. This is because of its usage of > the java.nio.file.Path APIs, specifically > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. > > The throws clause of this FSInfo#getJarClassPath API lists IOException, > so this method is now throwing an exception which isn't listed in its > throws clause. As a result, callers, like the > com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 > are no longer able to catch this exception and log it and move on. > Instead it gets propagated all the way back to the top level callers, > thus breaking applications which are trying to compile java files > programmatically. > > Would this be considered a bug? If so, I can create a JBS issue and > provide a patch (and will try a jtreg test case too) for review. > > Although these classes are internal and not public API, the calling code > is actually using public APIs (which internally end up calling these > APIs). Like here > https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. > > For a lengthy discussion/context - please read the comments in this > issue https://github.com/quarkusio/quarkus/issues/3592 > > -Jaikiran > > > From jai.forums2013 at gmail.com Sat Oct 12 05:51:33 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Sat, 12 Oct 2019 11:21:33 +0530 Subject: RFR: JDK-8232170: FSInfo#getJarClassPath throws an exception not declared in its throws clause Message-ID: <49aa84d1-5b5a-3f65-55dc-7e2f575e338f@gmail.com> Can I please get a review and a sponsor for a fix for JDK-8232170[1]? I have the patch available as a webrev at [2]? The patch only deals with catching the java.nio.file.Path usage related exceptions and then rethrows them as IOException. The original discussion is available at [3]. In that discussion, David had mentioned that the existing usage of java.nio.file.Path may not be the right thing to do and might need changes. This patch does not address it since that change I think will need more broader discussion and review. The patch also contains a jtreg test to reproduce this issue and verify the fix. [1] https://bugs.openjdk.java.net/browse/JDK-8232170 [2] http://cr.openjdk.java.net/~jpai/webrev/8232170/1/webrev/ [3] http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013753.html -Jaikiran From jai.forums2013 at gmail.com Sat Oct 12 11:33:32 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Sat, 12 Oct 2019 17:03:32 +0530 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> Message-ID: <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> Thank you Jon. I've created https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR thread with the patch. -Jaikiran On 11/10/19 8:20 PM, Jonathan Gibbons wrote: > Jaikiran, > > Not catching InvalidPathException is a bug and an unforeseen > consequence of converting the file manager from using java.io.File > to java.nio.file.Path. > > -- Jon > > On 10/11/19 7:26 AM, Jaikiran Pai wrote: >> In recent versions of JDK (I think after JDK 8), the >> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >> java.nio.file.InvalidPathException in certain cases when the classpath >> entry it is parsing isn't a valid one. This is because of its usage of >> the java.nio.file.Path APIs, specifically >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >> >> >> The throws clause of this FSInfo#getJarClassPath API lists IOException, >> so this method is now throwing an exception which isn't listed in its >> throws clause. As a result, callers, like the >> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >> >> are no longer able to catch this exception and log it and move on. >> Instead it gets propagated all the way back to the top level callers, >> thus breaking applications which are trying to compile java files >> programmatically. >> >> Would this be considered a bug? If so, I can create a JBS issue and >> provide a patch (and will try a jtreg test case too) for review. >> >> Although these classes are internal and not public API, the calling code >> is actually using public APIs (which internally end up calling these >> APIs). Like here >> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >> >> >> For a lengthy discussion/context - please read the comments in this >> issue https://github.com/quarkusio/quarkus/issues/3592 >> >> -Jaikiran >> >> >> From jonathan.gibbons at oracle.com Sun Oct 13 20:00:20 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Sun, 13 Oct 2019 13:00:20 -0700 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> Message-ID: Jaikiran, A slightly simpler patch with the same effective functionality would be to use a single try-catch block with a multi-catch 111 for (StringTokenizer st = new StringTokenizer(path); 112 st.hasMoreTokens(); ) { 113 String elt = st.nextToken(); 114 Path f = null; 115 try { 116 f = FileSystems.getDefault().getPath(elt); 121 if (!f.isAbsolute() && parent != null) 122 f = parent.resolve(f).toAbsolutePath(); 123 } catch (InvalidPathException | IOError e) { 124 throw new IOException(e); 125 } 126 list.add(f); 127 } 128 -- Jon On 10/12/19 4:33 AM, Jaikiran Pai wrote: > Thank you Jon. I've created > https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR > thread with the patch. > > -Jaikiran > > On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >> Jaikiran, >> >> Not catching InvalidPathException is a bug and an unforeseen >> consequence of converting the file manager from using java.io.File >> to java.nio.file.Path. >> >> -- Jon >> >> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >>> In recent versions of JDK (I think after JDK 8), the >>> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >>> java.nio.file.InvalidPathException in certain cases when the classpath >>> entry it is parsing isn't a valid one. This is because of its usage of >>> the java.nio.file.Path APIs, specifically >>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >>> >>> >>> The throws clause of this FSInfo#getJarClassPath API lists IOException, >>> so this method is now throwing an exception which isn't listed in its >>> throws clause. As a result, callers, like the >>> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >>> >>> are no longer able to catch this exception and log it and move on. >>> Instead it gets propagated all the way back to the top level callers, >>> thus breaking applications which are trying to compile java files >>> programmatically. >>> >>> Would this be considered a bug? If so, I can create a JBS issue and >>> provide a patch (and will try a jtreg test case too) for review. >>> >>> Although these classes are internal and not public API, the calling code >>> is actually using public APIs (which internally end up calling these >>> APIs). Like here >>> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >>> >>> >>> For a lengthy discussion/context - please read the comments in this >>> issue https://github.com/quarkusio/quarkus/issues/3592 >>> >>> -Jaikiran >>> >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From jonathan.gibbons at oracle.com Sun Oct 13 20:04:20 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Sun, 13 Oct 2019 13:04:20 -0700 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> Message-ID: <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> Or, ... 111 for (StringTokenizer st = new StringTokenizer(path); 112 st.hasMoreTokens(); ) { 113 String elt = st.nextToken(); 115 try { 116 Path f = FileSystems.getDefault().getPath(elt); 121 if (!f.isAbsolute() && parent != null) 122 f = parent.resolve(f).toAbsolutePath(); 126 list.add(f); 123 } catch (InvalidPathException | IOError e) { 124 throw new IOException(e); 125 } 127 } -- Jon On 10/13/19 1:00 PM, Jonathan Gibbons wrote: > > Jaikiran, > > A slightly simpler patch with the same effective functionality would > be to use a single try-catch block with a multi-catch > > 111 for (StringTokenizer st = new StringTokenizer(path); > 112 st.hasMoreTokens(); ) { > 113 String elt = st.nextToken(); > 114 Path f = null; > 115 try { > 116 f = FileSystems.getDefault().getPath(elt); > 121 if (!f.isAbsolute() && parent != null) > 122 f = parent.resolve(f).toAbsolutePath(); > 123 } catch (InvalidPathException | IOError e) { > 124 throw new IOException(e); > 125 } > 126 list.add(f); > 127 } > 128 > -- Jon > > On 10/12/19 4:33 AM, Jaikiran Pai wrote: >> Thank you Jon. I've created >> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR >> thread with the patch. >> >> -Jaikiran >> >> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >>> Jaikiran, >>> >>> Not catching InvalidPathException is a bug and an unforeseen >>> consequence of converting the file manager from using java.io.File >>> to java.nio.file.Path. >>> >>> -- Jon >>> >>> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >>>> In recent versions of JDK (I think after JDK 8), the >>>> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >>>> java.nio.file.InvalidPathException in certain cases when the classpath >>>> entry it is parsing isn't a valid one. This is because of its usage of >>>> the java.nio.file.Path APIs, specifically >>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >>>> >>>> >>>> The throws clause of this FSInfo#getJarClassPath API lists IOException, >>>> so this method is now throwing an exception which isn't listed in its >>>> throws clause. As a result, callers, like the >>>> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >>>> >>>> are no longer able to catch this exception and log it and move on. >>>> Instead it gets propagated all the way back to the top level callers, >>>> thus breaking applications which are trying to compile java files >>>> programmatically. >>>> >>>> Would this be considered a bug? If so, I can create a JBS issue and >>>> provide a patch (and will try a jtreg test case too) for review. >>>> >>>> Although these classes are internal and not public API, the calling code >>>> is actually using public APIs (which internally end up calling these >>>> APIs). Like here >>>> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >>>> >>>> >>>> For a lengthy discussion/context - please read the comments in this >>>> issuehttps://github.com/quarkusio/quarkus/issues/3592 >>>> >>>> -Jaikiran >>>> >>>> >>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From jai.forums2013 at gmail.com Mon Oct 14 01:54:17 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Mon, 14 Oct 2019 07:24:17 +0530 Subject: RFR: JDK-8232170: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <49aa84d1-5b5a-3f65-55dc-7e2f575e338f@gmail.com> References: <49aa84d1-5b5a-3f65-55dc-7e2f575e338f@gmail.com> Message-ID: Based on Jon's suggestion, I've updated the webrev to include a change in the try/catch block. The updated webrev is now available for review at http://cr.openjdk.java.net/~jpai/webrev/8232170/2/webrev/ -Jaikiran On 12/10/19 11:21 AM, Jaikiran Pai wrote: > Can I please get a review and a sponsor for a fix for JDK-8232170[1]? I > have the patch available as a webrev at [2]? > > The patch only deals with catching the java.nio.file.Path usage related > exceptions and then rethrows them as IOException. The original > discussion is available at [3]. In that discussion, David had mentioned > that the existing usage of java.nio.file.Path may not be the right thing > to do and might need changes. This patch does not address it since that > change I think will need more broader discussion and review. > > The patch also contains a jtreg test to reproduce this issue and verify > the fix. > > [1] https://bugs.openjdk.java.net/browse/JDK-8232170 > > [2] http://cr.openjdk.java.net/~jpai/webrev/8232170/1/webrev/ > > [3] > http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013753.html > > -Jaikiran > > From jai.forums2013 at gmail.com Mon Oct 14 01:55:38 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Mon, 14 Oct 2019 07:25:38 +0530 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> Message-ID: <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> Hello Jon, Thank you for the review. I have taken your inputs and updated the patch to include this change. I have uploaded that patch as a webrev, in the RFR thread. -Jaikiran On 14/10/19 1:34 AM, Jonathan Gibbons wrote: > > Or, ... > > 111 for (StringTokenizer st = new StringTokenizer(path); > 112 st.hasMoreTokens(); ) { > 113 String elt = st.nextToken(); > 115 try { > 116 Path f = FileSystems.getDefault().getPath(elt); > 121 if (!f.isAbsolute() && parent != null) > 122 f = parent.resolve(f).toAbsolutePath(); > 126 list.add(f); > ?123 } catch (InvalidPathException | IOError e) { > 124 throw new IOException(e); > 125 } > 127 } > > -- Jon > > > On 10/13/19 1:00 PM, Jonathan Gibbons wrote: >> >> Jaikiran, >> >> A slightly simpler patch with the same effective functionality would >> be to use a single try-catch block with a multi-catch >> >> 111 for (StringTokenizer st = new StringTokenizer(path); >> 112 st.hasMoreTokens(); ) { >> 113 String elt = st.nextToken(); >> 114 Path f = null; >> 115 try { >> 116 f = FileSystems.getDefault().getPath(elt); >> 121 if (!f.isAbsolute() && parent != null) >> 122 f = parent.resolve(f).toAbsolutePath(); >> 123 } catch (InvalidPathException | IOError e) { >> 124 throw new IOException(e); >> 125 } >> 126 list.add(f); >> 127 } >> 128 >> -- Jon >> >> On 10/12/19 4:33 AM, Jaikiran Pai wrote: >>> Thank you Jon. I've created >>> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR >>> thread with the patch. >>> >>> -Jaikiran >>> >>> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >>>> Jaikiran, >>>> >>>> Not catching InvalidPathException is a bug and an unforeseen >>>> consequence of converting the file manager from using java.io.File >>>> to java.nio.file.Path. >>>> >>>> -- Jon >>>> >>>> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >>>>> In recent versions of JDK (I think after JDK 8), the >>>>> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >>>>> java.nio.file.InvalidPathException in certain cases when the classpath >>>>> entry it is parsing isn't a valid one. This is because of its usage of >>>>> the java.nio.file.Path APIs, specifically >>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >>>>> >>>>> >>>>> The throws clause of this FSInfo#getJarClassPath API lists IOException, >>>>> so this method is now throwing an exception which isn't listed in its >>>>> throws clause. As a result, callers, like the >>>>> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >>>>> >>>>> are no longer able to catch this exception and log it and move on. >>>>> Instead it gets propagated all the way back to the top level callers, >>>>> thus breaking applications which are trying to compile java files >>>>> programmatically. >>>>> >>>>> Would this be considered a bug? If so, I can create a JBS issue and >>>>> provide a patch (and will try a jtreg test case too) for review. >>>>> >>>>> Although these classes are internal and not public API, the calling code >>>>> is actually using public APIs (which internally end up calling these >>>>> APIs). Like here >>>>> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >>>>> >>>>> >>>>> For a lengthy discussion/context - please read the comments in this >>>>> issue https://github.com/quarkusio/quarkus/issues/3592 >>>>> >>>>> -Jaikiran >>>>> >>>>> >>>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From jonathan.gibbons at oracle.com Mon Oct 14 14:24:18 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 14 Oct 2019 07:24:18 -0700 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> Message-ID: <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> Jaikiran, I'll take a look and sponsor for you. -- Jon On 10/13/19 6:55 PM, Jaikiran Pai wrote: > > Hello Jon, > > Thank you for the review. I have taken your inputs and updated the > patch to include this change. I have uploaded that patch as a webrev, > in the RFR thread. > > -Jaikiran > > On 14/10/19 1:34 AM, Jonathan Gibbons wrote: >> >> Or, ... >> >> 111 for (StringTokenizer st = new StringTokenizer(path); >> 112 st.hasMoreTokens(); ) { >> 113 String elt = st.nextToken(); >> 115 try { >> 116 Path f = FileSystems.getDefault().getPath(elt); >> 121 if (!f.isAbsolute() && parent != null) >> 122 f = parent.resolve(f).toAbsolutePath(); >> 126 list.add(f); >> 123 } catch (InvalidPathException | IOError e) { >> 124 throw new IOException(e); >> 125 } >> 127 } >> >> -- Jon >> >> >> On 10/13/19 1:00 PM, Jonathan Gibbons wrote: >>> >>> Jaikiran, >>> >>> A slightly simpler patch with the same effective functionality would >>> be to use a single try-catch block with a multi-catch >>> >>> 111 for (StringTokenizer st = new StringTokenizer(path); >>> 112 st.hasMoreTokens(); ) { >>> 113 String elt = st.nextToken(); >>> 114 Path f = null; >>> 115 try { >>> 116 f = FileSystems.getDefault().getPath(elt); >>> 121 if (!f.isAbsolute() && parent != null) >>> 122 f = parent.resolve(f).toAbsolutePath(); >>> 123 } catch (InvalidPathException | IOError e) { >>> 124 throw new IOException(e); >>> 125 } >>> 126 list.add(f); >>> 127 } >>> 128 >>> -- Jon >>> >>> On 10/12/19 4:33 AM, Jaikiran Pai wrote: >>>> Thank you Jon. I've created >>>> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR >>>> thread with the patch. >>>> >>>> -Jaikiran >>>> >>>> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >>>>> Jaikiran, >>>>> >>>>> Not catching InvalidPathException is a bug and an unforeseen >>>>> consequence of converting the file manager from using java.io.File >>>>> to java.nio.file.Path. >>>>> >>>>> -- Jon >>>>> >>>>> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >>>>>> In recent versions of JDK (I think after JDK 8), the >>>>>> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >>>>>> java.nio.file.InvalidPathException in certain cases when the classpath >>>>>> entry it is parsing isn't a valid one. This is because of its usage of >>>>>> the java.nio.file.Path APIs, specifically >>>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >>>>>> >>>>>> >>>>>> The throws clause of this FSInfo#getJarClassPath API lists IOException, >>>>>> so this method is now throwing an exception which isn't listed in its >>>>>> throws clause. As a result, callers, like the >>>>>> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >>>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >>>>>> >>>>>> are no longer able to catch this exception and log it and move on. >>>>>> Instead it gets propagated all the way back to the top level callers, >>>>>> thus breaking applications which are trying to compile java files >>>>>> programmatically. >>>>>> >>>>>> Would this be considered a bug? If so, I can create a JBS issue and >>>>>> provide a patch (and will try a jtreg test case too) for review. >>>>>> >>>>>> Although these classes are internal and not public API, the calling code >>>>>> is actually using public APIs (which internally end up calling these >>>>>> APIs). Like here >>>>>> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >>>>>> >>>>>> >>>>>> For a lengthy discussion/context - please read the comments in this >>>>>> issuehttps://github.com/quarkusio/quarkus/issues/3592 >>>>>> >>>>>> -Jaikiran >>>>>> >>>>>> >>>>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.lloyd at redhat.com Mon Oct 14 14:54:50 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Mon, 14 Oct 2019 09:54:50 -0500 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> Message-ID: I'm concerned that this doesn't actually solve the underlying problem of having `Class-Path` entries which are valid per the JAR file specification (i.e. they are relative URLs) but which are invalid paths (due to URL encoding for example, or due to a leading drive letter on a Windows absolute path). On Mon, Oct 14, 2019 at 9:36 AM Jonathan Gibbons wrote: > > Jaikiran, > > I'll take a look and sponsor for you. > > -- Jon > > On 10/13/19 6:55 PM, Jaikiran Pai wrote: > > Hello Jon, > > Thank you for the review. I have taken your inputs and updated the patch to include this change. I have uploaded that patch as a webrev, in the RFR thread. > > -Jaikiran > > On 14/10/19 1:34 AM, Jonathan Gibbons wrote: > > Or, ... > > 111 for (StringTokenizer st = new StringTokenizer(path); > 112 st.hasMoreTokens(); ) { > 113 String elt = st.nextToken(); > 115 try { > 116 Path f = FileSystems.getDefault().getPath(elt); > 121 if (!f.isAbsolute() && parent != null) > 122 f = parent.resolve(f).toAbsolutePath(); > 126 list.add(f); > 123 } catch (InvalidPathException | IOError e) { > 124 throw new IOException(e); > 125 } > 127 } > > -- Jon > > > On 10/13/19 1:00 PM, Jonathan Gibbons wrote: > > Jaikiran, > > A slightly simpler patch with the same effective functionality would be to use a single try-catch block with a multi-catch > > 111 for (StringTokenizer st = new StringTokenizer(path); > 112 st.hasMoreTokens(); ) { > 113 String elt = st.nextToken(); > 114 Path f = null; > 115 try { > 116 f = FileSystems.getDefault().getPath(elt); > 121 if (!f.isAbsolute() && parent != null) > 122 f = parent.resolve(f).toAbsolutePath(); > 123 } catch (InvalidPathException | IOError e) { > 124 throw new IOException(e); > 125 } > 126 list.add(f); > 127 } > 128 > > -- Jon > > On 10/12/19 4:33 AM, Jaikiran Pai wrote: > > Thank you Jon. I've created > https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR > thread with the patch. > > -Jaikiran > > On 11/10/19 8:20 PM, Jonathan Gibbons wrote: > > Jaikiran, > > Not catching InvalidPathException is a bug and an unforeseen > consequence of converting the file manager from using java.io.File > to java.nio.file.Path. > > -- Jon > > On 10/11/19 7:26 AM, Jaikiran Pai wrote: > > In recent versions of JDK (I think after JDK 8), the > com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a > java.nio.file.InvalidPathException in certain cases when the classpath > entry it is parsing isn't a valid one. This is because of its usage of > the java.nio.file.Path APIs, specifically > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. > > > The throws clause of this FSInfo#getJarClassPath API lists IOException, > so this method is now throwing an exception which isn't listed in its > throws clause. As a result, callers, like the > com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) > https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 > > are no longer able to catch this exception and log it and move on. > Instead it gets propagated all the way back to the top level callers, > thus breaking applications which are trying to compile java files > programmatically. > > Would this be considered a bug? If so, I can create a JBS issue and > provide a patch (and will try a jtreg test case too) for review. > > Although these classes are internal and not public API, the calling code > is actually using public APIs (which internally end up calling these > APIs). Like here > https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. > > > For a lengthy discussion/context - please read the comments in this > issue https://github.com/quarkusio/quarkus/issues/3592 > > -Jaikiran > > > -- - DML From jonathan.gibbons at oracle.com Mon Oct 14 16:10:13 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 14 Oct 2019 09:10:13 -0700 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> Message-ID: <337057ef-bf0f-f8ea-d2c1-9c87a776abae@oracle.com> David, That may be a valid concern, which can be investigated, but that is not the focus of this change, which is to avoid the regression of unexpected/undocumented exceptions being thrown from the method. -- Jon On 10/14/19 7:54 AM, David Lloyd wrote: > I'm concerned that this doesn't actually solve the underlying problem > of having `Class-Path` entries which are valid per the JAR file > specification (i.e. they are relative URLs) but which are invalid > paths (due to URL encoding for example, or due to a leading drive > letter on a Windows absolute path). > > On Mon, Oct 14, 2019 at 9:36 AM Jonathan Gibbons > wrote: >> Jaikiran, >> >> I'll take a look and sponsor for you. >> >> -- Jon >> >> On 10/13/19 6:55 PM, Jaikiran Pai wrote: >> >> Hello Jon, >> >> Thank you for the review. I have taken your inputs and updated the patch to include this change. I have uploaded that patch as a webrev, in the RFR thread. >> >> -Jaikiran >> >> On 14/10/19 1:34 AM, Jonathan Gibbons wrote: >> >> Or, ... >> >> 111 for (StringTokenizer st = new StringTokenizer(path); >> 112 st.hasMoreTokens(); ) { >> 113 String elt = st.nextToken(); >> 115 try { >> 116 Path f = FileSystems.getDefault().getPath(elt); >> 121 if (!f.isAbsolute() && parent != null) >> 122 f = parent.resolve(f).toAbsolutePath(); >> 126 list.add(f); >> 123 } catch (InvalidPathException | IOError e) { >> 124 throw new IOException(e); >> 125 } >> 127 } >> >> -- Jon >> >> >> On 10/13/19 1:00 PM, Jonathan Gibbons wrote: >> >> Jaikiran, >> >> A slightly simpler patch with the same effective functionality would be to use a single try-catch block with a multi-catch >> >> 111 for (StringTokenizer st = new StringTokenizer(path); >> 112 st.hasMoreTokens(); ) { >> 113 String elt = st.nextToken(); >> 114 Path f = null; >> 115 try { >> 116 f = FileSystems.getDefault().getPath(elt); >> 121 if (!f.isAbsolute() && parent != null) >> 122 f = parent.resolve(f).toAbsolutePath(); >> 123 } catch (InvalidPathException | IOError e) { >> 124 throw new IOException(e); >> 125 } >> 126 list.add(f); >> 127 } >> 128 >> >> -- Jon >> >> On 10/12/19 4:33 AM, Jaikiran Pai wrote: >> >> Thank you Jon. I've created >> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR >> thread with the patch. >> >> -Jaikiran >> >> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >> >> Jaikiran, >> >> Not catching InvalidPathException is a bug and an unforeseen >> consequence of converting the file manager from using java.io.File >> to java.nio.file.Path. >> >> -- Jon >> >> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >> >> In recent versions of JDK (I think after JDK 8), the >> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >> java.nio.file.InvalidPathException in certain cases when the classpath >> entry it is parsing isn't a valid one. This is because of its usage of >> the java.nio.file.Path APIs, specifically >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >> >> >> The throws clause of this FSInfo#getJarClassPath API lists IOException, >> so this method is now throwing an exception which isn't listed in its >> throws clause. As a result, callers, like the >> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >> >> are no longer able to catch this exception and log it and move on. >> Instead it gets propagated all the way back to the top level callers, >> thus breaking applications which are trying to compile java files >> programmatically. >> >> Would this be considered a bug? If so, I can create a JBS issue and >> provide a patch (and will try a jtreg test case too) for review. >> >> Although these classes are internal and not public API, the calling code >> is actually using public APIs (which internally end up calling these >> APIs). Like here >> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >> >> >> For a lengthy discussion/context - please read the comments in this >> issue https://github.com/quarkusio/quarkus/issues/3592 >> >> -Jaikiran >> >> >> > From david.lloyd at redhat.com Mon Oct 14 16:19:32 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Mon, 14 Oct 2019 11:19:32 -0500 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <337057ef-bf0f-f8ea-d2c1-9c87a776abae@oracle.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> <337057ef-bf0f-f8ea-d2c1-9c87a776abae@oracle.com> Message-ID: The original bug - the one for which this email thread was begun - was the URI issue, and the exception issue was merely a side-effect of that change. But very well: I'll start a new thread for it. On Mon, Oct 14, 2019 at 11:14 AM Jonathan Gibbons wrote: > > David, > > That may be a valid concern, which can be investigated, but that is > not the focus of this change, which is to avoid the regression of > unexpected/undocumented exceptions being thrown from the method. > > -- Jon > > On 10/14/19 7:54 AM, David Lloyd wrote: > > I'm concerned that this doesn't actually solve the underlying problem > > of having `Class-Path` entries which are valid per the JAR file > > specification (i.e. they are relative URLs) but which are invalid > > paths (due to URL encoding for example, or due to a leading drive > > letter on a Windows absolute path). > > > > On Mon, Oct 14, 2019 at 9:36 AM Jonathan Gibbons > > wrote: > >> Jaikiran, > >> > >> I'll take a look and sponsor for you. > >> > >> -- Jon > >> > >> On 10/13/19 6:55 PM, Jaikiran Pai wrote: > >> > >> Hello Jon, > >> > >> Thank you for the review. I have taken your inputs and updated the patch to include this change. I have uploaded that patch as a webrev, in the RFR thread. > >> > >> -Jaikiran > >> > >> On 14/10/19 1:34 AM, Jonathan Gibbons wrote: > >> > >> Or, ... > >> > >> 111 for (StringTokenizer st = new StringTokenizer(path); > >> 112 st.hasMoreTokens(); ) { > >> 113 String elt = st.nextToken(); > >> 115 try { > >> 116 Path f = FileSystems.getDefault().getPath(elt); > >> 121 if (!f.isAbsolute() && parent != null) > >> 122 f = parent.resolve(f).toAbsolutePath(); > >> 126 list.add(f); > >> 123 } catch (InvalidPathException | IOError e) { > >> 124 throw new IOException(e); > >> 125 } > >> 127 } > >> > >> -- Jon > >> > >> > >> On 10/13/19 1:00 PM, Jonathan Gibbons wrote: > >> > >> Jaikiran, > >> > >> A slightly simpler patch with the same effective functionality would be to use a single try-catch block with a multi-catch > >> > >> 111 for (StringTokenizer st = new StringTokenizer(path); > >> 112 st.hasMoreTokens(); ) { > >> 113 String elt = st.nextToken(); > >> 114 Path f = null; > >> 115 try { > >> 116 f = FileSystems.getDefault().getPath(elt); > >> 121 if (!f.isAbsolute() && parent != null) > >> 122 f = parent.resolve(f).toAbsolutePath(); > >> 123 } catch (InvalidPathException | IOError e) { > >> 124 throw new IOException(e); > >> 125 } > >> 126 list.add(f); > >> 127 } > >> 128 > >> > >> -- Jon > >> > >> On 10/12/19 4:33 AM, Jaikiran Pai wrote: > >> > >> Thank you Jon. I've created > >> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR > >> thread with the patch. > >> > >> -Jaikiran > >> > >> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: > >> > >> Jaikiran, > >> > >> Not catching InvalidPathException is a bug and an unforeseen > >> consequence of converting the file manager from using java.io.File > >> to java.nio.file.Path. > >> > >> -- Jon > >> > >> On 10/11/19 7:26 AM, Jaikiran Pai wrote: > >> > >> In recent versions of JDK (I think after JDK 8), the > >> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a > >> java.nio.file.InvalidPathException in certain cases when the classpath > >> entry it is parsing isn't a valid one. This is because of its usage of > >> the java.nio.file.Path APIs, specifically > >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. > >> > >> > >> The throws clause of this FSInfo#getJarClassPath API lists IOException, > >> so this method is now throwing an exception which isn't listed in its > >> throws clause. As a result, callers, like the > >> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) > >> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 > >> > >> are no longer able to catch this exception and log it and move on. > >> Instead it gets propagated all the way back to the top level callers, > >> thus breaking applications which are trying to compile java files > >> programmatically. > >> > >> Would this be considered a bug? If so, I can create a JBS issue and > >> provide a patch (and will try a jtreg test case too) for review. > >> > >> Although these classes are internal and not public API, the calling code > >> is actually using public APIs (which internally end up calling these > >> APIs). Like here > >> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. > >> > >> > >> For a lengthy discussion/context - please read the comments in this > >> issue https://github.com/quarkusio/quarkus/issues/3592 > >> > >> -Jaikiran > >> > >> > >> > > -- - DML From david.lloyd at redhat.com Mon Oct 14 16:43:12 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Mon, 14 Oct 2019 11:43:12 -0500 Subject: FSInfo#getJarClassPath does not comply with the JAR specification Message-ID: The JAR specification specifies that the `Class-Path` attribute is a space-separated sequence of relative URLs. A relative URL is defined ([2], [3]) as a hierarchical URI with no scheme component. Relative URLs resemble file paths. However they differ in some important ways: for example, a relative URL is URL-encoded, whereas a file path is not, causing problems when dealing with paths that have embedded spaces (among other things). Relative URLs representing absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. Note (since this is a point of frequent confusion) that a relative URL can have an absolute path. AFAIK neither of these cases work correctly when javac interacts with a JAR that contains a `Class-Path` attribute. The current FSInfo code, as noted in the recent thread entitled `FSInfo#getJarClassPath throws an exception not declared in its throws clause`, reads the class path attribute value with code that uses FileSystems.getDefault().getPath(xxx) on each class path element [4]. The correct behavior would be to wrap each item in a `java.net.URI`. If the syntax is invalid, report an error or skip the element. Then determine if the URI is absolute; if it is, report an error or skip the element. Finally, query the Path API to look up the file by URI using Path.of(uri) or similar, reporting an error or skipping the element if there's a problem. The less-elegant solution would be to manually URL-decode the string, and (on windows) manually check to see if there's a drive letter, removing the leading slash if there is one. However I would consider this to be more likely to be bug-prone. This problem is the underlying cause of at least one Quarkus bug [5], where the issue was discussed in depth. [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 [5] https://github.com/quarkusio/quarkus/issues/3592 -- - DML From jonathan.gibbons at oracle.com Mon Oct 14 17:59:54 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 14 Oct 2019 10:59:54 -0700 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: Message-ID: David, Thank you for the detailed write-up of the issue. -- Jon On 10/14/19 9:43 AM, David Lloyd wrote: > The JAR specification specifies that the `Class-Path` attribute is a > space-separated sequence of relative URLs. A relative URL is defined > ([2], [3]) as a hierarchical URI with no scheme component. > > Relative URLs resemble file paths. However they differ in some > important ways: for example, a relative URL is URL-encoded, whereas a > file path is not, causing problems when dealing with paths that have > embedded spaces (among other things). Relative URLs representing > absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the > corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. > > Note (since this is a point of frequent confusion) that a relative URL > can have an absolute path. > > AFAIK neither of these cases work correctly when javac interacts with > a JAR that contains a `Class-Path` attribute. > > The current FSInfo code, as noted in the recent thread entitled > `FSInfo#getJarClassPath throws an exception not declared in its throws > clause`, reads the class path attribute value with code that uses > FileSystems.getDefault().getPath(xxx) on each class path element [4]. > > The correct behavior would be to wrap each item in a `java.net.URI`. > If the syntax is invalid, report an error or skip the element. Then > determine if the URI is absolute; if it is, report an error or skip > the element. Finally, query the Path API to look up the file by URI > using Path.of(uri) or similar, reporting an error or skipping the > element if there's a problem. > > The less-elegant solution would be to manually URL-decode the string, > and (on windows) manually check to see if there's a drive letter, > removing the leading slash if there is one. However I would consider > this to be more likely to be bug-prone. > > This problem is the underlying cause of at least one Quarkus bug [5], > where the issue was discussed in depth. > > [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute > [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 > [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html > [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 > [5] https://github.com/quarkusio/quarkus/issues/3592 > From jan.lahoda at oracle.com Tue Oct 15 09:46:35 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 15 Oct 2019 11:46:35 +0200 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: References: Message-ID: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> Hi, I've updated the patch with the Flow changes and with additional comments in TransPatterns here: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ diff from previous: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ An additional patch (that would apply on top of this one) which makes all instanceof instances to be modelled as instanceof : http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ Some more comment inline. On 10. 10. 19 17:33, Maurizio Cimadamore wrote: > Hi Jan, > the code looks generally very clean, kudos. > > Some general comments: > > * looking at the spec, it seems like both "instanceof T" and "instanceof > T t" are cases of type test patterns. I guess I'm fine with the > implementation doing what it always did in terms of plain "instanceof > T", but I'm worried about the intersection between this and e.g. the > tree API - InstanceofTree::getPattern returns null in cases like > "instanceof T"; now, I know I know that we're speaking about a JDK > specific API, but I think this issue reveals some modelling issues in > the way we treat instanceof, and I'm worried that some of these issues > might pop up in the future. I'd prefer to either rectify the spec so > that plain 'instanceof T' is not a pattern matching instanceof, or > rectify javac so that these tests are internally also represented with > patterns (at the expense of some extra allocation, perhaps). > > * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" flag > is to be able to distinguish between regular 'expression-wide' bindings, > and bindings which 'leaked' outside a statement (e.g. an if statement). > And the reason you need to distinguish between these is that you don't > want Check::checkUnique to flag duplicate errors between regular > 'expression-wide' bindings, which are reported elsewhere > (MatchBindingsComputer). But this is also, more crucially, used in > TransPattern, where the 'isPreserved' flag is used to control whether a > variable decl for the binding variable should be 'lifted' to the > enclosing statement context or not. Is my understanding correct here? Yes, the primary intent is to mark variables that need to be hoisted to the parent of the current statement. > > * The idea behind TransPatterns seems to be: when we process a > statement, or an expression, we attempt to add all declaration for the > bindings that are used inside the statements/expression upfront. If we > are processing a statement, then we surround the results in a block; e.g. > > if (obj instanceof Foo f) { > ? ... > } > > becomes > > { > ?? Foo f$; > ?? if (let Object temp = obj in (obj instanceof Foo && (f$ = (Foo)temp) > == temp) { > ????? ... > } > > If we are processing an expression, we instead generate a LetExpr, e.g. > > boolean b = obj instanceof Foo t && t.equals(foo); > > becomes: > > boolean b = let Foo f$ = null in ((let Object temp = obj in (obj > instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) > > So, sometimes the hoisted var is a real var decl in a block, other times > is a var decl inside a let expression. In these cases we have to > generate an initializer, to set the value (which might be used later). The hoisted vars do not have an initializer (they used to have one, but it is both unnecessary and was masking out bugs, so I have removed it). But I see I've forgot the initializer code commented out in TransPatterns, removed in the updated version to avoid confusion. > On top of that, instanceof generates its own letExpr to cache the target > of the test (to avoid double computation). > > It also seems to me that the code handles cases where the binding > variable is not used, neither hoisted - e.g. > > boolean field = obj instanceof Foo t; > > In this case we generate a plain instanceof w/o the init (because the > 't' variable hasn't been hoisted anywhere). > > Finally, we use the 'isPreserved()' flag to ensure that variables are > hoisted correctly - for instance, if something is to be preserved (and > the enclosing context allows for it) we push things in the enclosing > context instead. > > Am I getting the correct picture here? Yes, I think it is correct. > > It would be nice to have more javadoc spread around to help the reader > understand what's the rationale and show some snippet of generated code. > > * Flow, I wonder if, like you had created SnippetAliveAnalyzer, creating > a SnippetBreakAnalyzer would help you avoid the breaksOut[0] trick (that > could become a field in the child visitor) I tried to do these two in the updated patch. Thanks for the comments! Jan > > > Other than that, it looks very good. > > Maurizio > > On 10/10/2019 13:12, Jan Lahoda wrote: >> Hi, >> >> As part of the effort to prepare JEP 305: Pattern Matching for >> instanceof (Preview) for Propose to Target, I would like to ask for a >> code review for the corresponding javac changes. >> >> The webrev is here: >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >> >> The patch applies on top of: >> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >> >> >> The current spec the patch is striving to implements is here: >> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >> >> >> As far as I know, there is one (significant) open issue in the spec, >> and that is whether non-reifiable types should be allowed in >> "instanceof ". Currently (AFAIK), the spec does not >> allow non-reifiable types in the type test pattern in instanceof, and >> the javac implementation should be consistent with the spec. Should >> the spec change, the corresponding update to the javac code should >> have a very limited impact. >> >> I'll be preparing a CSR for this change in the coming days. >> >> The JBS issue for this code change is: >> https://bugs.openjdk.java.net/browse/JDK-8231826 >> >> Any feedback is welcome! >> >> Thanks! >> ??? Jan From maurizio.cimadamore at oracle.com Tue Oct 15 11:59:12 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 15 Oct 2019 12:59:12 +0100 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> References: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> Message-ID: <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> Hi, the flow changes look good - I think the TransPattern documentation should contain less text and more code snippet examples which show what the generated code looks like (as I've tried to do in my email, and as you've done for visitTypeTest). In other words, what is missing here is "the big picture" which shows what are the main ideas behind the translation strategy. Specific example: decorateExpression: + //if there are binding variables defined and used only in this expression, + //which are not confined to a specific sub-expression, + //a let expression is created which replaces the statement, and + //the binding variables are hoisted into this let expression: This kind of illustrates my point: * "if there are binding variables defined and used only in this expression, which are not confined to a specific sub-expression" is very convoluted, and will be almost meaningless when we pick up this code again in 6 months * "a let expression is created which replaces the statement" - statement? Probably cut and paste error Thanks Maurizio On 15/10/2019 10:46, Jan Lahoda wrote: > Hi, > > I've updated the patch with the Flow changes and with additional > comments in TransPatterns here: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ > diff from previous: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ > > An additional patch (that would apply on top of this one) which makes > all instanceof instances to be modelled as instanceof : > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ > > Some more comment inline. > > On 10. 10. 19 17:33, Maurizio Cimadamore wrote: >> Hi Jan, >> the code looks generally very clean, kudos. >> >> Some general comments: >> >> * looking at the spec, it seems like both "instanceof T" and >> "instanceof T t" are cases of type test patterns. I guess I'm fine >> with the implementation doing what it always did in terms of plain >> "instanceof T", but I'm worried about the intersection between this >> and e.g. the tree API - InstanceofTree::getPattern returns null in >> cases like "instanceof T"; now, I know I know that we're speaking >> about a JDK specific API, but I think this issue reveals some >> modelling issues in the way we treat instanceof, and I'm worried that >> some of these issues might pop up in the future. I'd prefer to either >> rectify the spec so that plain 'instanceof T' is not a pattern >> matching instanceof, or rectify javac so that these tests are >> internally also represented with patterns (at the expense of some >> extra allocation, perhaps). >> >> * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" >> flag is to be able to distinguish between regular 'expression-wide' >> bindings, and bindings which 'leaked' outside a statement (e.g. an if >> statement). And the reason you need to distinguish between these is >> that you don't want Check::checkUnique to flag duplicate errors >> between regular 'expression-wide' bindings, which are reported >> elsewhere (MatchBindingsComputer). But this is also, more crucially, >> used in TransPattern, where the 'isPreserved' flag is used to control >> whether a variable decl for the binding variable should be 'lifted' >> to the enclosing statement context or not. Is my understanding >> correct here? > > Yes, the primary intent is to mark variables that need to be hoisted > to the parent of the current statement. > >> >> * The idea behind TransPatterns seems to be: when we process a >> statement, or an expression, we attempt to add all declaration for >> the bindings that are used inside the statements/expression upfront. >> If we are processing a statement, then we surround the results in a >> block; e.g. >> >> if (obj instanceof Foo f) { >> ?? ... >> } >> >> becomes >> >> { >> ??? Foo f$; >> ??? if (let Object temp = obj in (obj instanceof Foo && (f$ = >> (Foo)temp) == temp) { >> ?????? ... >> } >> >> If we are processing an expression, we instead generate a LetExpr, e.g. >> >> boolean b = obj instanceof Foo t && t.equals(foo); >> >> becomes: >> >> boolean b = let Foo f$ = null in ((let Object temp = obj in (obj >> instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) >> >> So, sometimes the hoisted var is a real var decl in a block, other >> times is a var decl inside a let expression. In these cases we have >> to generate an initializer, to set the value (which might be used >> later). > > The hoisted vars do not have an initializer (they used to have one, > but it is both unnecessary and was masking out bugs, so I have removed > it). But I see I've forgot the initializer code commented out in > TransPatterns, removed in the updated version to avoid confusion. > >> On top of that, instanceof generates its own letExpr to cache the >> target of the test (to avoid double computation). >> >> It also seems to me that the code handles cases where the binding >> variable is not used, neither hoisted - e.g. >> >> boolean field = obj instanceof Foo t; >> >> In this case we generate a plain instanceof w/o the init (because the >> 't' variable hasn't been hoisted anywhere). >> >> Finally, we use the 'isPreserved()' flag to ensure that variables are >> hoisted correctly - for instance, if something is to be preserved >> (and the enclosing context allows for it) we push things in the >> enclosing context instead. >> >> Am I getting the correct picture here? > > Yes, I think it is correct. > >> >> It would be nice to have more javadoc spread around to help the >> reader understand what's the rationale and show some snippet of >> generated code. >> >> * Flow, I wonder if, like you had created SnippetAliveAnalyzer, >> creating a SnippetBreakAnalyzer would help you avoid the breaksOut[0] >> trick (that could become a field in the child visitor) > > I tried to do these two in the updated patch. > > Thanks for the comments! > > Jan > >> >> >> Other than that, it looks very good. >> >> Maurizio >> >> On 10/10/2019 13:12, Jan Lahoda wrote: >>> Hi, >>> >>> As part of the effort to prepare JEP 305: Pattern Matching for >>> instanceof (Preview) for Propose to Target, I would like to ask for >>> a code review for the corresponding javac changes. >>> >>> The webrev is here: >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >>> >>> The patch applies on top of: >>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >>> >>> >>> The current spec the patch is striving to implements is here: >>> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >>> >>> >>> As far as I know, there is one (significant) open issue in the spec, >>> and that is whether non-reifiable types should be allowed in >>> "instanceof ". Currently (AFAIK), the spec does >>> not allow non-reifiable types in the type test pattern in >>> instanceof, and the javac implementation should be consistent with >>> the spec. Should the spec change, the corresponding update to the >>> javac code should have a very limited impact. >>> >>> I'll be preparing a CSR for this change in the coming days. >>> >>> The JBS issue for this code change is: >>> https://bugs.openjdk.java.net/browse/JDK-8231826 >>> >>> Any feedback is welcome! >>> >>> Thanks! >>> ??? Jan -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Tue Oct 15 12:56:23 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 15 Oct 2019 14:56:23 +0200 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> References: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> Message-ID: <8821e763-d28b-8648-c8c9-1f3531fcf3a8@oracle.com> Would this be better? Full patch: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.02/ Diff from previous: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.01-02/ Thanks, Jan On 15. 10. 19 13:59, Maurizio Cimadamore wrote: > Hi, > the flow changes look good - I think the TransPattern documentation > should contain less text and more code snippet examples which show what > the generated code looks like (as I've tried to do in my email, and as > you've done for visitTypeTest). In other words, what is missing here is > "the big picture" which shows what are the main ideas behind the > translation strategy. > > Specific example: decorateExpression: > > + //if there are binding variables defined and used only in this expression, > + //which are not confined to a specific sub-expression, > + //a let expression is created which replaces the statement, and > + //the binding variables are hoisted into this let expression: > > > This kind of illustrates my point: > > * "if there are binding variables defined and used only in this > expression, which are not confined to a specific sub-expression" is very > convoluted, and will be almost meaningless when we pick up this code > again in 6 months > * "a let expression is created which replaces the statement" - > statement? Probably cut and paste error > > Thanks > Maurizio > > On 15/10/2019 10:46, Jan Lahoda wrote: >> Hi, >> >> I've updated the patch with the Flow changes and with additional >> comments in TransPatterns here: >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ >> diff from previous: >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ >> >> An additional patch (that would apply on top of this one) which makes >> all instanceof instances to be modelled as instanceof : >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ >> >> Some more comment inline. >> >> On 10. 10. 19 17:33, Maurizio Cimadamore wrote: >>> Hi Jan, >>> the code looks generally very clean, kudos. >>> >>> Some general comments: >>> >>> * looking at the spec, it seems like both "instanceof T" and >>> "instanceof T t" are cases of type test patterns. I guess I'm fine >>> with the implementation doing what it always did in terms of plain >>> "instanceof T", but I'm worried about the intersection between this >>> and e.g. the tree API - InstanceofTree::getPattern returns null in >>> cases like "instanceof T"; now, I know I know that we're speaking >>> about a JDK specific API, but I think this issue reveals some >>> modelling issues in the way we treat instanceof, and I'm worried that >>> some of these issues might pop up in the future. I'd prefer to either >>> rectify the spec so that plain 'instanceof T' is not a pattern >>> matching instanceof, or rectify javac so that these tests are >>> internally also represented with patterns (at the expense of some >>> extra allocation, perhaps). >>> >>> * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" >>> flag is to be able to distinguish between regular 'expression-wide' >>> bindings, and bindings which 'leaked' outside a statement (e.g. an if >>> statement). And the reason you need to distinguish between these is >>> that you don't want Check::checkUnique to flag duplicate errors >>> between regular 'expression-wide' bindings, which are reported >>> elsewhere (MatchBindingsComputer). But this is also, more crucially, >>> used in TransPattern, where the 'isPreserved' flag is used to control >>> whether a variable decl for the binding variable should be 'lifted' >>> to the enclosing statement context or not. Is my understanding >>> correct here? >> >> Yes, the primary intent is to mark variables that need to be hoisted >> to the parent of the current statement. >> >>> >>> * The idea behind TransPatterns seems to be: when we process a >>> statement, or an expression, we attempt to add all declaration for >>> the bindings that are used inside the statements/expression upfront. >>> If we are processing a statement, then we surround the results in a >>> block; e.g. >>> >>> if (obj instanceof Foo f) { >>> ?? ... >>> } >>> >>> becomes >>> >>> { >>> ??? Foo f$; >>> ??? if (let Object temp = obj in (obj instanceof Foo && (f$ = >>> (Foo)temp) == temp) { >>> ?????? ... >>> } >>> >>> If we are processing an expression, we instead generate a LetExpr, e.g. >>> >>> boolean b = obj instanceof Foo t && t.equals(foo); >>> >>> becomes: >>> >>> boolean b = let Foo f$ = null in ((let Object temp = obj in (obj >>> instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) >>> >>> So, sometimes the hoisted var is a real var decl in a block, other >>> times is a var decl inside a let expression. In these cases we have >>> to generate an initializer, to set the value (which might be used >>> later). >> >> The hoisted vars do not have an initializer (they used to have one, >> but it is both unnecessary and was masking out bugs, so I have removed >> it). But I see I've forgot the initializer code commented out in >> TransPatterns, removed in the updated version to avoid confusion. >> >>> On top of that, instanceof generates its own letExpr to cache the >>> target of the test (to avoid double computation). >>> >>> It also seems to me that the code handles cases where the binding >>> variable is not used, neither hoisted - e.g. >>> >>> boolean field = obj instanceof Foo t; >>> >>> In this case we generate a plain instanceof w/o the init (because the >>> 't' variable hasn't been hoisted anywhere). >>> >>> Finally, we use the 'isPreserved()' flag to ensure that variables are >>> hoisted correctly - for instance, if something is to be preserved >>> (and the enclosing context allows for it) we push things in the >>> enclosing context instead. >>> >>> Am I getting the correct picture here? >> >> Yes, I think it is correct. >> >>> >>> It would be nice to have more javadoc spread around to help the >>> reader understand what's the rationale and show some snippet of >>> generated code. >>> >>> * Flow, I wonder if, like you had created SnippetAliveAnalyzer, >>> creating a SnippetBreakAnalyzer would help you avoid the breaksOut[0] >>> trick (that could become a field in the child visitor) >> >> I tried to do these two in the updated patch. >> >> Thanks for the comments! >> >> Jan >> >>> >>> >>> Other than that, it looks very good. >>> >>> Maurizio >>> >>> On 10/10/2019 13:12, Jan Lahoda wrote: >>>> Hi, >>>> >>>> As part of the effort to prepare JEP 305: Pattern Matching for >>>> instanceof (Preview) for Propose to Target, I would like to ask for >>>> a code review for the corresponding javac changes. >>>> >>>> The webrev is here: >>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >>>> >>>> The patch applies on top of: >>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >>>> >>>> >>>> The current spec the patch is striving to implements is here: >>>> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >>>> >>>> >>>> As far as I know, there is one (significant) open issue in the spec, >>>> and that is whether non-reifiable types should be allowed in >>>> "instanceof ". Currently (AFAIK), the spec does >>>> not allow non-reifiable types in the type test pattern in >>>> instanceof, and the javac implementation should be consistent with >>>> the spec. Should the spec change, the corresponding update to the >>>> javac code should have a very limited impact. >>>> >>>> I'll be preparing a CSR for this change in the coming days. >>>> >>>> The JBS issue for this code change is: >>>> https://bugs.openjdk.java.net/browse/JDK-8231826 >>>> >>>> Any feedback is welcome! >>>> >>>> Thanks! >>>> ??? Jan From maurizio.cimadamore at oracle.com Tue Oct 15 13:02:19 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 15 Oct 2019 14:02:19 +0100 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: <8821e763-d28b-8648-c8c9-1f3531fcf3a8@oracle.com> References: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> <8821e763-d28b-8648-c8c9-1f3531fcf3a8@oracle.com> Message-ID: Yep - that would be more helpful (at least to me) Thanks Maurizio On 15/10/2019 13:56, Jan Lahoda wrote: > Would this be better? > > Full patch: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.02/ > > Diff from previous: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.01-02/ > > Thanks, > ??? Jan > > On 15. 10. 19 13:59, Maurizio Cimadamore wrote: >> Hi, >> the flow changes look good - I think the TransPattern documentation >> should contain less text and more code snippet examples which show >> what the generated code looks like (as I've tried to do in my email, >> and as you've done for visitTypeTest). In other words, what is >> missing here is "the big picture" which shows what are the main ideas >> behind the translation strategy. >> >> Specific example: decorateExpression: >> >> + //if there are binding variables defined and used only in this >> expression, >> + //which are not confined to a specific sub-expression, >> + //a let expression is created which replaces the statement, and >> + //the binding variables are hoisted into this let expression: >> >> >> This kind of illustrates my point: >> >> * "if there are binding variables defined and used only in this >> expression, which are not confined to a specific sub-expression" is >> very convoluted, and will be almost meaningless when we pick up this >> code again in 6 months >> * "a let expression is created which replaces the statement" - >> statement? Probably cut and paste error >> >> Thanks >> Maurizio >> >> On 15/10/2019 10:46, Jan Lahoda wrote: >>> Hi, >>> >>> I've updated the patch with the Flow changes and with additional >>> comments in TransPatterns here: >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ >>> diff from previous: >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ >>> >>> An additional patch (that would apply on top of this one) which >>> makes all instanceof instances to be modelled as instanceof : >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ >>> >>> Some more comment inline. >>> >>> On 10. 10. 19 17:33, Maurizio Cimadamore wrote: >>>> Hi Jan, >>>> the code looks generally very clean, kudos. >>>> >>>> Some general comments: >>>> >>>> * looking at the spec, it seems like both "instanceof T" and >>>> "instanceof T t" are cases of type test patterns. I guess I'm fine >>>> with the implementation doing what it always did in terms of plain >>>> "instanceof T", but I'm worried about the intersection between this >>>> and e.g. the tree API - InstanceofTree::getPattern returns null in >>>> cases like "instanceof T"; now, I know I know that we're speaking >>>> about a JDK specific API, but I think this issue reveals some >>>> modelling issues in the way we treat instanceof, and I'm worried >>>> that some of these issues might pop up in the future. I'd prefer to >>>> either rectify the spec so that plain 'instanceof T' is not a >>>> pattern matching instanceof, or rectify javac so that these tests >>>> are internally also represented with patterns (at the expense of >>>> some extra allocation, perhaps). >>>> >>>> * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" >>>> flag is to be able to distinguish between regular 'expression-wide' >>>> bindings, and bindings which 'leaked' outside a statement (e.g. an >>>> if statement). And the reason you need to distinguish between these >>>> is that you don't want Check::checkUnique to flag duplicate errors >>>> between regular 'expression-wide' bindings, which are reported >>>> elsewhere (MatchBindingsComputer). But this is also, more >>>> crucially, used in TransPattern, where the 'isPreserved' flag is >>>> used to control whether a variable decl for the binding variable >>>> should be 'lifted' to the enclosing statement context or not. Is my >>>> understanding correct here? >>> >>> Yes, the primary intent is to mark variables that need to be hoisted >>> to the parent of the current statement. >>> >>>> >>>> * The idea behind TransPatterns seems to be: when we process a >>>> statement, or an expression, we attempt to add all declaration for >>>> the bindings that are used inside the statements/expression >>>> upfront. If we are processing a statement, then we surround the >>>> results in a block; e.g. >>>> >>>> if (obj instanceof Foo f) { >>>> ?? ... >>>> } >>>> >>>> becomes >>>> >>>> { >>>> ??? Foo f$; >>>> ??? if (let Object temp = obj in (obj instanceof Foo && (f$ = >>>> (Foo)temp) == temp) { >>>> ?????? ... >>>> } >>>> >>>> If we are processing an expression, we instead generate a LetExpr, >>>> e.g. >>>> >>>> boolean b = obj instanceof Foo t && t.equals(foo); >>>> >>>> becomes: >>>> >>>> boolean b = let Foo f$ = null in ((let Object temp = obj in (obj >>>> instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) >>>> >>>> So, sometimes the hoisted var is a real var decl in a block, other >>>> times is a var decl inside a let expression. In these cases we have >>>> to generate an initializer, to set the value (which might be used >>>> later). >>> >>> The hoisted vars do not have an initializer (they used to have one, >>> but it is both unnecessary and was masking out bugs, so I have >>> removed it). But I see I've forgot the initializer code commented >>> out in TransPatterns, removed in the updated version to avoid >>> confusion. >>> >>>> On top of that, instanceof generates its own letExpr to cache the >>>> target of the test (to avoid double computation). >>>> >>>> It also seems to me that the code handles cases where the binding >>>> variable is not used, neither hoisted - e.g. >>>> >>>> boolean field = obj instanceof Foo t; >>>> >>>> In this case we generate a plain instanceof w/o the init (because >>>> the 't' variable hasn't been hoisted anywhere). >>>> >>>> Finally, we use the 'isPreserved()' flag to ensure that variables >>>> are hoisted correctly - for instance, if something is to be >>>> preserved (and the enclosing context allows for it) we push things >>>> in the enclosing context instead. >>>> >>>> Am I getting the correct picture here? >>> >>> Yes, I think it is correct. >>> >>>> >>>> It would be nice to have more javadoc spread around to help the >>>> reader understand what's the rationale and show some snippet of >>>> generated code. >>>> >>>> * Flow, I wonder if, like you had created SnippetAliveAnalyzer, >>>> creating a SnippetBreakAnalyzer would help you avoid the >>>> breaksOut[0] trick (that could become a field in the child visitor) >>> >>> I tried to do these two in the updated patch. >>> >>> Thanks for the comments! >>> >>> Jan >>> >>>> >>>> >>>> Other than that, it looks very good. >>>> >>>> Maurizio >>>> >>>> On 10/10/2019 13:12, Jan Lahoda wrote: >>>>> Hi, >>>>> >>>>> As part of the effort to prepare JEP 305: Pattern Matching for >>>>> instanceof (Preview) for Propose to Target, I would like to ask >>>>> for a code review for the corresponding javac changes. >>>>> >>>>> The webrev is here: >>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >>>>> >>>>> The patch applies on top of: >>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >>>>> >>>>> >>>>> The current spec the patch is striving to implements is here: >>>>> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >>>>> >>>>> >>>>> As far as I know, there is one (significant) open issue in the >>>>> spec, and that is whether non-reifiable types should be allowed in >>>>> "instanceof ". Currently (AFAIK), the spec does >>>>> not allow non-reifiable types in the type test pattern in >>>>> instanceof, and the javac implementation should be consistent with >>>>> the spec. Should the spec change, the corresponding update to the >>>>> javac code should have a very limited impact. >>>>> >>>>> I'll be preparing a CSR for this change in the coming days. >>>>> >>>>> The JBS issue for this code change is: >>>>> https://bugs.openjdk.java.net/browse/JDK-8231826 >>>>> >>>>> Any feedback is welcome! >>>>> >>>>> Thanks! >>>>> ??? Jan From jan.lahoda at oracle.com Wed Oct 16 12:50:56 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Wed, 16 Oct 2019 14:50:56 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> Message-ID: <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> Hi, An updated patch is here: http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ Changes in the update: -added the dependency into the makefiles -loosened the handling of essential preview APIs when --enable-preview and @SuppressWarnings is applied - there is no warning for the essential APIs (as there is no warning in such a case for non-essential APIs). This is per the discussion in the CSR: https://bugs.openjdk.java.net/browse/JDK-8231411 Any comments/feedback on this? Thanks! Jan On 09. 10. 19 17:41, Erik Joelsson wrote: > Oh, you are absolutely correct, the dependency is missing. > > We need something like this inside "define SetupInterimModule": > > $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) > > /Erik > > On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >> I can?t see how the compilation is dependent on the copy being >> finished. Since Erik contributed this it will probably be correct :) >> but I?d appreciate an explanation on how this dependency is guaranteed. >> >> Or maybe I?m misunderstanding what this is supposed to do? >> >> /Magnus >> >>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>> >>> Thanks for the new code Erik! >>> >>> A new webrev/patch that includes this better way of copying is here: >>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>> >>> Any feedback is welcome! >>> >>> Thanks, >>> ??? Jan >>> >>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>> Hello Jan, >>>> The build change looks ok, but I would recommend this construct for >>>> copying the file instead: >>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>> ???? FILES := >>>> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >>>> \ >>>> ???? DEST := >>>> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >>>> \ >>>> )) >>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>> Then you automatically get all the corner case handling we have >>>> implemented over the years for logging, making directories and >>>> copying files. Your version is still correct for this case though. >>>> /Erik >>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>> Hi, >>>>> >>>>> This is a continuation of Joe's patch from here: >>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>>>> >>>>> >>>>> APIs associated with preview features are split into two groups: >>>>> essential and non-essential. These are marked with an JDK-internal >>>>> annotation, PreviewFeature, and a tag in the javadoc, @preview. The >>>>> javac follows the PreviewFeature annotation, and produces either >>>>> warnings or errors for the usages of such APIs. For the @preview >>>>> tag, there is a taglet in the JDK build that adds the content of >>>>> the tag into the documentation. The first part of the @preview's >>>>> text goes into the summary, the second part goes into the detailed >>>>> description. >>>>> >>>>> For build, a tricky problem is that the jdk.compiler module uses >>>>> the PreviewFeature annotation as well, but that is not in the >>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>> PreviewFeature annotation is copied from java.base. >>>>> >>>>> Proposed webrev: >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>> >>>>> Javadoc with the change: >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>> >>>>> See for example: >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>>>> >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>>>> >>>>> >>>>> JBS: >>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>> >>>>> CSR: >>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>> >>>>> Feedback is welcome! >>>>> >>>>> Thanks, >>>>> ???? Jan From erik.joelsson at oracle.com Wed Oct 16 12:55:12 2019 From: erik.joelsson at oracle.com (Erik Joelsson) Date: Wed, 16 Oct 2019 05:55:12 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> Message-ID: Build change looks good now. /Erik On 2019-10-16 05:50, Jan Lahoda wrote: > Hi, > > An updated patch is here: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ > > Changes in the update: > -added the dependency into the makefiles > -loosened the handling of essential preview APIs when --enable-preview > and @SuppressWarnings is applied - there is no warning for the > essential APIs (as there is no warning in such a case for > non-essential APIs). This is per the discussion in the CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 > > Any comments/feedback on this? > > Thanks! > ??? Jan > > On 09. 10. 19 17:41, Erik Joelsson wrote: >> Oh, you are absolutely correct, the dependency is missing. >> >> We need something like this inside "define SetupInterimModule": >> >> $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) >> >> /Erik >> >> On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >>> I can?t see how the compilation is dependent on the copy being >>> finished. Since Erik contributed this it will probably be correct :) >>> but I?d appreciate an explanation on how this dependency is guaranteed. >>> >>> Or maybe I?m misunderstanding what this is supposed to do? >>> >>> /Magnus >>> >>>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>>> >>>> Thanks for the new code Erik! >>>> >>>> A new webrev/patch that includes this better way of copying is here: >>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>>> >>>> Any feedback is welcome! >>>> >>>> Thanks, >>>> ??? Jan >>>> >>>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>>> Hello Jan, >>>>> The build change looks ok, but I would recommend this construct >>>>> for copying the file instead: >>>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>>> ???? FILES := >>>>> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >>>>> \ >>>>> ???? DEST := >>>>> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >>>>> \ >>>>> )) >>>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>>> Then you automatically get all the corner case handling we have >>>>> implemented over the years for logging, making directories and >>>>> copying files. Your version is still correct for this case though. >>>>> /Erik >>>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>>> Hi, >>>>>> >>>>>> This is a continuation of Joe's patch from here: >>>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>>>>> >>>>>> >>>>>> APIs associated with preview features are split into two groups: >>>>>> essential and non-essential. These are marked with an >>>>>> JDK-internal annotation, PreviewFeature, and a tag in the >>>>>> javadoc, @preview. The javac follows the PreviewFeature >>>>>> annotation, and produces either warnings or errors for the usages >>>>>> of such APIs. For the @preview tag, there is a taglet in the JDK >>>>>> build that adds the content of the tag into the documentation. >>>>>> The first part of the @preview's text goes into the summary, the >>>>>> second part goes into the detailed description. >>>>>> >>>>>> For build, a tricky problem is that the jdk.compiler module uses >>>>>> the PreviewFeature annotation as well, but that is not in the >>>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>>> PreviewFeature annotation is copied from java.base. >>>>>> >>>>>> Proposed webrev: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>>> >>>>>> Javadoc with the change: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>>> >>>>>> See for example: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>>>>> >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>>>>> >>>>>> >>>>>> JBS: >>>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>>> >>>>>> CSR: >>>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>>> >>>>>> Feedback is welcome! >>>>>> >>>>>> Thanks, >>>>>> ???? Jan From alex.buckley at oracle.com Wed Oct 16 17:45:08 2019 From: alex.buckley at oracle.com (Alex Buckley) Date: Wed, 16 Oct 2019 10:45:08 -0700 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> Message-ID: <07d16fc4-42a9-8f6f-992f-3ebc83e3e777@oracle.com> On 10/16/2019 5:50 AM, Jan Lahoda wrote: > -loosened the handling of essential preview APIs when --enable-preview > and @SuppressWarnings is applied - there is no warning for the essential > APIs (as there is no warning in such a case for non-essential APIs). > This is per the discussion in the CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 Thank you for implementing this change so quickly. Per the discussion in the CSR, I have updated JEP 12 to allow suppression in the case above (see http://openjdk.java.net/jeps/12#Relationship-to-Java-SE-APIs / second list / fourth bullet) and also the JLS RFE (JDK-8231433). The interesting takeaway is that use of a preview language feature generates a non-suppressible warning (scan JEP 12 for "This message cannot be turned off") while use of an essential API element associated with a preview language feature generates a suppressible warning. Alex From jai.forums2013 at gmail.com Thu Oct 17 02:30:26 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Thu, 17 Oct 2019 08:00:26 +0530 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: Message-ID: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> One of the reasonsI hadn't done anything related to this in my proposed change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what the actual expected semantics of the Class-Path attribute are. The jar Manifest documentation (which David pointed to) does state the URI is to be relative, but I remember seeing a recent change discussed in one of these mailing lists where absolute (file: scheme based) URIs were supported. I finally found time to look through the JBS and here's that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think whatever change we do here will then have to allow for absolute URI (for file: scheme of local jars too). [1] http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html -Jaikiran On 14/10/19 10:13 PM, David Lloyd wrote: > The JAR specification specifies that the `Class-Path` attribute is a > space-separated sequence of relative URLs. A relative URL is defined > ([2], [3]) as a hierarchical URI with no scheme component. > > Relative URLs resemble file paths. However they differ in some > important ways: for example, a relative URL is URL-encoded, whereas a > file path is not, causing problems when dealing with paths that have > embedded spaces (among other things). Relative URLs representing > absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the > corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. > > Note (since this is a point of frequent confusion) that a relative URL > can have an absolute path. > > AFAIK neither of these cases work correctly when javac interacts with > a JAR that contains a `Class-Path` attribute. > > The current FSInfo code, as noted in the recent thread entitled > `FSInfo#getJarClassPath throws an exception not declared in its throws > clause`, reads the class path attribute value with code that uses > FileSystems.getDefault().getPath(xxx) on each class path element [4]. > > The correct behavior would be to wrap each item in a `java.net.URI`. > If the syntax is invalid, report an error or skip the element. Then > determine if the URI is absolute; if it is, report an error or skip > the element. Finally, query the Path API to look up the file by URI > using Path.of(uri) or similar, reporting an error or skipping the > element if there's a problem. > > The less-elegant solution would be to manually URL-decode the string, > and (on windows) manually check to see if there's a drive letter, > removing the leading slash if there is one. However I would consider > this to be more likely to be bug-prone. > > This problem is the underlying cause of at least one Quarkus bug [5], > where the issue was discussed in depth. > > [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute > [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 > [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html > [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 > [5] https://github.com/quarkusio/quarkus/issues/3592 > From jai.forums2013 at gmail.com Thu Oct 17 02:30:59 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Thu, 17 Oct 2019 08:00:59 +0530 Subject: FSInfo#getJarClassPath throws an exception not declared in its throws clause In-Reply-To: <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> References: <3333ff4b-f0d3-9edb-e9a2-7bed0db91769@gmail.com> <9ec630ed-fe77-a338-ee7b-359b3438cd55@oracle.com> <3e08f66f-f6d5-7194-67ad-c6f427517933@gmail.com> <9cf04562-1ef5-9cb9-9594-73e8a113dcfb@oracle.com> <27f825ab-72d9-5210-bbb5-6d43e6a117ae@gmail.com> <15c6a90c-6db2-d6d2-b804-b66e51a0e6e7@oracle.com> Message-ID: <3f2e09a2-ef35-cb1e-f08f-ca00d699f090@gmail.com> Thank you Jon. -Jaikiran On 14/10/19 7:54 PM, Jonathan Gibbons wrote: > > Jaikiran, > > I'll take a look and sponsor for you. > > -- Jon > > On 10/13/19 6:55 PM, Jaikiran Pai wrote: >> >> Hello Jon, >> >> Thank you for the review. I have taken your inputs and updated the >> patch to include this change. I have uploaded that patch as a webrev, >> in the RFR thread. >> >> -Jaikiran >> >> On 14/10/19 1:34 AM, Jonathan Gibbons wrote: >>> >>> Or, ... >>> >>> 111 for (StringTokenizer st = new StringTokenizer(path); >>> 112 st.hasMoreTokens(); ) { >>> 113 String elt = st.nextToken(); >>> 115 try { >>> 116 Path f = FileSystems.getDefault().getPath(elt); >>> 121 if (!f.isAbsolute() && parent != null) >>> 122 f = parent.resolve(f).toAbsolutePath(); >>> 126 list.add(f); >>> ?123 } catch (InvalidPathException | IOError e) { >>> 124 throw new IOException(e); >>> 125 } >>> 127 } >>> >>> -- Jon >>> >>> >>> On 10/13/19 1:00 PM, Jonathan Gibbons wrote: >>>> >>>> Jaikiran, >>>> >>>> A slightly simpler patch with the same effective functionality >>>> would be to use a single try-catch block with a multi-catch >>>> >>>> 111 for (StringTokenizer st = new StringTokenizer(path); >>>> 112 st.hasMoreTokens(); ) { >>>> 113 String elt = st.nextToken(); >>>> 114 Path f = null; >>>> 115 try { >>>> 116 f = FileSystems.getDefault().getPath(elt); >>>> 121 if (!f.isAbsolute() && parent != null) >>>> 122 f = parent.resolve(f).toAbsolutePath(); >>>> 123 } catch (InvalidPathException | IOError e) { >>>> 124 throw new IOException(e); >>>> 125 } >>>> 126 list.add(f); >>>> 127 } >>>> 128 >>>> -- Jon >>>> >>>> On 10/12/19 4:33 AM, Jaikiran Pai wrote: >>>>> Thank you Jon. I've created >>>>> https://bugs.openjdk.java.net/browse/JDK-8232170 and submitted a RFR >>>>> thread with the patch. >>>>> >>>>> -Jaikiran >>>>> >>>>> On 11/10/19 8:20 PM, Jonathan Gibbons wrote: >>>>>> Jaikiran, >>>>>> >>>>>> Not catching InvalidPathException is a bug and an unforeseen >>>>>> consequence of converting the file manager from using java.io.File >>>>>> to java.nio.file.Path. >>>>>> >>>>>> -- Jon >>>>>> >>>>>> On 10/11/19 7:26 AM, Jaikiran Pai wrote: >>>>>>> In recent versions of JDK (I think after JDK 8), the >>>>>>> com.sun.tools.javac.file.FSInfo#getJarClassPath(...) is throwing a >>>>>>> java.nio.file.InvalidPathException in certain cases when the classpath >>>>>>> entry it is parsing isn't a valid one. This is because of its usage of >>>>>>> the java.nio.file.Path APIs, specifically >>>>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112. >>>>>>> >>>>>>> >>>>>>> The throws clause of this FSInfo#getJarClassPath API lists IOException, >>>>>>> so this method is now throwing an exception which isn't listed in its >>>>>>> throws clause. As a result, callers, like the >>>>>>> com.sun.tools.javac.file.Locations.SearchPath#addJarClassPath(...) >>>>>>> https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java#L425 >>>>>>> >>>>>>> are no longer able to catch this exception and log it and move on. >>>>>>> Instead it gets propagated all the way back to the top level callers, >>>>>>> thus breaking applications which are trying to compile java files >>>>>>> programmatically. >>>>>>> >>>>>>> Would this be considered a bug? If so, I can create a JBS issue and >>>>>>> provide a patch (and will try a jtreg test case too) for review. >>>>>>> >>>>>>> Although these classes are internal and not public API, the calling code >>>>>>> is actually using public APIs (which internally end up calling these >>>>>>> APIs). Like here >>>>>>> https://github.com/quarkusio/quarkus/blob/master/core/devmode/src/main/java/io/quarkus/dev/JavaCompilationProvider.java#L48. >>>>>>> >>>>>>> >>>>>>> For a lengthy discussion/context - please read the comments in this >>>>>>> issue https://github.com/quarkusio/quarkus/issues/3592 >>>>>>> >>>>>>> -Jaikiran >>>>>>> >>>>>>> >>>>>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.lloyd at redhat.com Thu Oct 17 13:04:43 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 17 Oct 2019 08:04:43 -0500 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: It seems reasonable to include the special exception for `file:` absolute URLs. I did file a bug at bugreport but I haven't yet received a notification that the bug was created. If I do, I will post the JIRA # here. On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: > > One of the reasonsI hadn't done anything related to this in my proposed > change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what > the actual expected semantics of the Class-Path attribute are. > > The jar Manifest documentation (which David pointed to) does state the > URI is to be relative, but I remember seeing a recent change discussed > in one of these mailing lists where absolute (file: scheme based) URIs > were supported. I finally found time to look through the JBS and here's > that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think > whatever change we do here will then have to allow for absolute URI (for > file: scheme of local jars too). > > [1] > http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html > > -Jaikiran > > On 14/10/19 10:13 PM, David Lloyd wrote: > > The JAR specification specifies that the `Class-Path` attribute is a > > space-separated sequence of relative URLs. A relative URL is defined > > ([2], [3]) as a hierarchical URI with no scheme component. > > > > Relative URLs resemble file paths. However they differ in some > > important ways: for example, a relative URL is URL-encoded, whereas a > > file path is not, causing problems when dealing with paths that have > > embedded spaces (among other things). Relative URLs representing > > absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the > > corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. > > > > Note (since this is a point of frequent confusion) that a relative URL > > can have an absolute path. > > > > AFAIK neither of these cases work correctly when javac interacts with > > a JAR that contains a `Class-Path` attribute. > > > > The current FSInfo code, as noted in the recent thread entitled > > `FSInfo#getJarClassPath throws an exception not declared in its throws > > clause`, reads the class path attribute value with code that uses > > FileSystems.getDefault().getPath(xxx) on each class path element [4]. > > > > The correct behavior would be to wrap each item in a `java.net.URI`. > > If the syntax is invalid, report an error or skip the element. Then > > determine if the URI is absolute; if it is, report an error or skip > > the element. Finally, query the Path API to look up the file by URI > > using Path.of(uri) or similar, reporting an error or skipping the > > element if there's a problem. > > > > The less-elegant solution would be to manually URL-decode the string, > > and (on windows) manually check to see if there's a drive letter, > > removing the leading slash if there is one. However I would consider > > this to be more likely to be bug-prone. > > > > This problem is the underlying cause of at least one Quarkus bug [5], > > where the issue was discussed in depth. > > > > [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute > > [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 > > [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html > > [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 > > [5] https://github.com/quarkusio/quarkus/issues/3592 > > > -- - DML From jonathan.gibbons at oracle.com Thu Oct 17 14:32:42 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Thu, 17 Oct 2019 07:32:42 -0700 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: Any changes/exceptions should be done in conjunction with updates to specification. -- Jon On 10/17/19 6:04 AM, David Lloyd wrote: > It seems reasonable to include the special exception for `file:` absolute URLs. > > I did file a bug at bugreport but I haven't yet received a > notification that the bug was created. If I do, I will post the JIRA # > here. > > On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: >> One of the reasonsI hadn't done anything related to this in my proposed >> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what >> the actual expected semantics of the Class-Path attribute are. >> >> The jar Manifest documentation (which David pointed to) does state the >> URI is to be relative, but I remember seeing a recent change discussed >> in one of these mailing lists where absolute (file: scheme based) URIs >> were supported. I finally found time to look through the JBS and here's >> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think >> whatever change we do here will then have to allow for absolute URI (for >> file: scheme of local jars too). >> >> [1] >> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html >> >> -Jaikiran >> >> On 14/10/19 10:13 PM, David Lloyd wrote: >>> The JAR specification specifies that the `Class-Path` attribute is a >>> space-separated sequence of relative URLs. A relative URL is defined >>> ([2], [3]) as a hierarchical URI with no scheme component. >>> >>> Relative URLs resemble file paths. However they differ in some >>> important ways: for example, a relative URL is URL-encoded, whereas a >>> file path is not, causing problems when dealing with paths that have >>> embedded spaces (among other things). Relative URLs representing >>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the >>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. >>> >>> Note (since this is a point of frequent confusion) that a relative URL >>> can have an absolute path. >>> >>> AFAIK neither of these cases work correctly when javac interacts with >>> a JAR that contains a `Class-Path` attribute. >>> >>> The current FSInfo code, as noted in the recent thread entitled >>> `FSInfo#getJarClassPath throws an exception not declared in its throws >>> clause`, reads the class path attribute value with code that uses >>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. >>> >>> The correct behavior would be to wrap each item in a `java.net.URI`. >>> If the syntax is invalid, report an error or skip the element. Then >>> determine if the URI is absolute; if it is, report an error or skip >>> the element. Finally, query the Path API to look up the file by URI >>> using Path.of(uri) or similar, reporting an error or skipping the >>> element if there's a problem. >>> >>> The less-elegant solution would be to manually URL-decode the string, >>> and (on windows) manually check to see if there's a drive letter, >>> removing the leading slash if there is one. However I would consider >>> this to be more likely to be bug-prone. >>> >>> This problem is the underlying cause of at least one Quarkus bug [5], >>> where the issue was discussed in depth. >>> >>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute >>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 >>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html >>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 >>> [5] https://github.com/quarkusio/quarkus/issues/3592 >>> > From david.lloyd at redhat.com Thu Oct 17 16:08:49 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 17 Oct 2019 11:08:49 -0500 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: How would you account for JDK-8216401 in this case? Would you say that the specification should have been updated to account for the implementation? On Thu, Oct 17, 2019 at 9:34 AM Jonathan Gibbons wrote: > > Any changes/exceptions should be done in conjunction with updates to > specification. > > -- Jon > > On 10/17/19 6:04 AM, David Lloyd wrote: > > It seems reasonable to include the special exception for `file:` absolute URLs. > > > > I did file a bug at bugreport but I haven't yet received a > > notification that the bug was created. If I do, I will post the JIRA # > > here. > > > > On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: > >> One of the reasonsI hadn't done anything related to this in my proposed > >> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what > >> the actual expected semantics of the Class-Path attribute are. > >> > >> The jar Manifest documentation (which David pointed to) does state the > >> URI is to be relative, but I remember seeing a recent change discussed > >> in one of these mailing lists where absolute (file: scheme based) URIs > >> were supported. I finally found time to look through the JBS and here's > >> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think > >> whatever change we do here will then have to allow for absolute URI (for > >> file: scheme of local jars too). > >> > >> [1] > >> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html > >> > >> -Jaikiran > >> > >> On 14/10/19 10:13 PM, David Lloyd wrote: > >>> The JAR specification specifies that the `Class-Path` attribute is a > >>> space-separated sequence of relative URLs. A relative URL is defined > >>> ([2], [3]) as a hierarchical URI with no scheme component. > >>> > >>> Relative URLs resemble file paths. However they differ in some > >>> important ways: for example, a relative URL is URL-encoded, whereas a > >>> file path is not, causing problems when dealing with paths that have > >>> embedded spaces (among other things). Relative URLs representing > >>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the > >>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. > >>> > >>> Note (since this is a point of frequent confusion) that a relative URL > >>> can have an absolute path. > >>> > >>> AFAIK neither of these cases work correctly when javac interacts with > >>> a JAR that contains a `Class-Path` attribute. > >>> > >>> The current FSInfo code, as noted in the recent thread entitled > >>> `FSInfo#getJarClassPath throws an exception not declared in its throws > >>> clause`, reads the class path attribute value with code that uses > >>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. > >>> > >>> The correct behavior would be to wrap each item in a `java.net.URI`. > >>> If the syntax is invalid, report an error or skip the element. Then > >>> determine if the URI is absolute; if it is, report an error or skip > >>> the element. Finally, query the Path API to look up the file by URI > >>> using Path.of(uri) or similar, reporting an error or skipping the > >>> element if there's a problem. > >>> > >>> The less-elegant solution would be to manually URL-decode the string, > >>> and (on windows) manually check to see if there's a drive letter, > >>> removing the leading slash if there is one. However I would consider > >>> this to be more likely to be bug-prone. > >>> > >>> This problem is the underlying cause of at least one Quarkus bug [5], > >>> where the issue was discussed in depth. > >>> > >>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute > >>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 > >>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html > >>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 > >>> [5] https://github.com/quarkusio/quarkus/issues/3592 > >>> > > -- - DML From vicente.romero at oracle.com Thu Oct 17 19:43:07 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Thu, 17 Oct 2019 15:43:07 -0400 Subject: RFR: JEP 359-Records: javadoc code Message-ID: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> Hi, Please review the javadoc code for JEP 359 (Records), this webrev contains only the javadoc code as we have decided to split the new code in clusters to make the review process easier. Thanks in advance for the feedback, Vicente PS, Jon is the author of this code please keep him in the loop http://cr.openjdk.java.net/~vromero/records.review/javadoc/webrev.00/ From jonathan.gibbons at oracle.com Thu Oct 17 19:45:02 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Thu, 17 Oct 2019 12:45:02 -0700 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> Message-ID: <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> cc: javadoc-dev at openjdk.java.net --Jon On 10/17/2019 12:43 PM, Vicente Romero wrote: > Hi, > > Please review the javadoc code for JEP 359 (Records), this webrev > contains only the javadoc code as we have decided to split the new > code in clusters to make the review process easier. > > Thanks in advance for the feedback, > Vicente > > PS, Jon is the author of this code please keep him in the loop > > http://cr.openjdk.java.net/~vromero/records.review/javadoc/webrev.00/ From maurizio.cimadamore at oracle.com Fri Oct 18 12:05:45 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 18 Oct 2019 13:05:45 +0100 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> Message-ID: <68ee0609-3b98-85ec-97f8-1cc2ced8aa04@oracle.com> Looks good - but I suggest garbage collecting the isEssentialAPI() from the @PreviewFeature annotation, as the new behavior effectively removes any distinctions between the two (unless I miss something). Maurizio On 16/10/2019 13:50, Jan Lahoda wrote: > Hi, > > An updated patch is here: > http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ > > Changes in the update: > -added the dependency into the makefiles > -loosened the handling of essential preview APIs when --enable-preview > and @SuppressWarnings is applied - there is no warning for the > essential APIs (as there is no warning in such a case for > non-essential APIs). This is per the discussion in the CSR: > https://bugs.openjdk.java.net/browse/JDK-8231411 > > Any comments/feedback on this? > > Thanks! > ??? Jan > > On 09. 10. 19 17:41, Erik Joelsson wrote: >> Oh, you are absolutely correct, the dependency is missing. >> >> We need something like this inside "define SetupInterimModule": >> >> $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) >> >> /Erik >> >> On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >>> I can?t see how the compilation is dependent on the copy being >>> finished. Since Erik contributed this it will probably be correct :) >>> but I?d appreciate an explanation on how this dependency is guaranteed. >>> >>> Or maybe I?m misunderstanding what this is supposed to do? >>> >>> /Magnus >>> >>>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>>> >>>> Thanks for the new code Erik! >>>> >>>> A new webrev/patch that includes this better way of copying is here: >>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>>> >>>> Any feedback is welcome! >>>> >>>> Thanks, >>>> ??? Jan >>>> >>>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>>> Hello Jan, >>>>> The build change looks ok, but I would recommend this construct >>>>> for copying the file instead: >>>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>>> ???? FILES := >>>>> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >>>>> \ >>>>> ???? DEST := >>>>> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >>>>> \ >>>>> )) >>>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>>> Then you automatically get all the corner case handling we have >>>>> implemented over the years for logging, making directories and >>>>> copying files. Your version is still correct for this case though. >>>>> /Erik >>>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>>> Hi, >>>>>> >>>>>> This is a continuation of Joe's patch from here: >>>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>>>>> >>>>>> >>>>>> APIs associated with preview features are split into two groups: >>>>>> essential and non-essential. These are marked with an >>>>>> JDK-internal annotation, PreviewFeature, and a tag in the >>>>>> javadoc, @preview. The javac follows the PreviewFeature >>>>>> annotation, and produces either warnings or errors for the usages >>>>>> of such APIs. For the @preview tag, there is a taglet in the JDK >>>>>> build that adds the content of the tag into the documentation. >>>>>> The first part of the @preview's text goes into the summary, the >>>>>> second part goes into the detailed description. >>>>>> >>>>>> For build, a tricky problem is that the jdk.compiler module uses >>>>>> the PreviewFeature annotation as well, but that is not in the >>>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>>> PreviewFeature annotation is copied from java.base. >>>>>> >>>>>> Proposed webrev: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>>> >>>>>> Javadoc with the change: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>>> >>>>>> See for example: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>>>>> >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>>>>> >>>>>> >>>>>> JBS: >>>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>>> >>>>>> CSR: >>>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>>> >>>>>> Feedback is welcome! >>>>>> >>>>>> Thanks, >>>>>> ???? Jan From maurizio.cimadamore at oracle.com Fri Oct 18 12:28:45 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 18 Oct 2019 13:28:45 +0100 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> Message-ID: <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> I went through the javadoc changes and, although I'm no javadoc expert, they seem clean enough, to the point that I could follow the logic quite easily. One high-level gripe which is pointing at a failure of the j.l.model API is the lack of a way to get to the canonical constructor directly; we have this issue both in core reflection and source reflection, and I think we should address that, as both serialization and javadoc has to DYI around that. Maurizio On 17/10/2019 20:45, Jonathan Gibbons wrote: > cc: javadoc-dev at openjdk.java.net > > --Jon > > > On 10/17/2019 12:43 PM, Vicente Romero wrote: >> Hi, >> >> Please review the javadoc code for JEP 359 (Records), this webrev >> contains only the javadoc code as we have decided to split the new >> code in clusters to make the review process easier. >> >> Thanks in advance for the feedback, >> Vicente >> >> PS, Jon is the author of this code please keep him in the loop >> >> http://cr.openjdk.java.net/~vromero/records.review/javadoc/webrev.00/ > From jan.lahoda at oracle.com Fri Oct 18 12:38:07 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Fri, 18 Oct 2019 14:38:07 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <68ee0609-3b98-85ec-97f8-1cc2ced8aa04@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> <68ee0609-3b98-85ec-97f8-1cc2ced8aa04@oracle.com> Message-ID: <6B0AC83B-213C-4B61-A4A3-0771A9DCF68A@oracle.com> 18. ??jna 2019 14:05:45 SEL?, Maurizio Cimadamore napsal: >Looks good - but I suggest garbage collecting the isEssentialAPI() from > >the @PreviewFeature annotation, as the new behavior effectively removes > >any distinctions between the two (unless I miss something). I am afraid there is still a distinction between them - when --enable-preview is not specified, use of essential APIs will lead to a compile time warning, while use of non essential API (reflection, typically) only produces warnings. Jan > >Maurizio > >On 16/10/2019 13:50, Jan Lahoda wrote: >> Hi, >> >> An updated patch is here: >> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ >> >> Changes in the update: >> -added the dependency into the makefiles >> -loosened the handling of essential preview APIs when >--enable-preview >> and @SuppressWarnings is applied - there is no warning for the >> essential APIs (as there is no warning in such a case for >> non-essential APIs). This is per the discussion in the CSR: >> https://bugs.openjdk.java.net/browse/JDK-8231411 >> >> Any comments/feedback on this? >> >> Thanks! >> ??? Jan >> >> On 09. 10. 19 17:41, Erik Joelsson wrote: >>> Oh, you are absolutely correct, the dependency is missing. >>> >>> We need something like this inside "define SetupInterimModule": >>> >>> $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) >>> >>> /Erik >>> >>> On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >>>> I can?t see how the compilation is dependent on the copy being >>>> finished. Since Erik contributed this it will probably be correct >:) >>>> but I?d appreciate an explanation on how this dependency is >guaranteed. >>>> >>>> Or maybe I?m misunderstanding what this is supposed to do? >>>> >>>> /Magnus >>>> >>>>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>>>> >>>>> Thanks for the new code Erik! >>>>> >>>>> A new webrev/patch that includes this better way of copying is >here: >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>>>> >>>>> Any feedback is welcome! >>>>> >>>>> Thanks, >>>>> ??? Jan >>>>> >>>>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>>>> Hello Jan, >>>>>> The build change looks ok, but I would recommend this construct >>>>>> for copying the file instead: >>>>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>>>> ???? FILES := >>>>>> >$(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, > >>>>>> \ >>>>>> ???? DEST := >>>>>> >$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, > >>>>>> \ >>>>>> )) >>>>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>>>> Then you automatically get all the corner case handling we have >>>>>> implemented over the years for logging, making directories and >>>>>> copying files. Your version is still correct for this case >though. >>>>>> /Erik >>>>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>>>> Hi, >>>>>>> >>>>>>> This is a continuation of Joe's patch from here: >>>>>>> >https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html > >>>>>>> >>>>>>> >>>>>>> APIs associated with preview features are split into two groups: > >>>>>>> essential and non-essential. These are marked with an >>>>>>> JDK-internal annotation, PreviewFeature, and a tag in the >>>>>>> javadoc, @preview. The javac follows the PreviewFeature >>>>>>> annotation, and produces either warnings or errors for the >usages >>>>>>> of such APIs. For the @preview tag, there is a taglet in the JDK > >>>>>>> build that adds the content of the tag into the documentation. >>>>>>> The first part of the @preview's text goes into the summary, the > >>>>>>> second part goes into the detailed description. >>>>>>> >>>>>>> For build, a tricky problem is that the jdk.compiler module uses > >>>>>>> the PreviewFeature annotation as well, but that is not in the >>>>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>>>> PreviewFeature annotation is copied from java.base. >>>>>>> >>>>>>> Proposed webrev: >>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>>>> >>>>>>> Javadoc with the change: >>>>>>> >http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>>>> >>>>>>> See for example: >>>>>>> >http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html > >>>>>>> >>>>>>> >http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html > >>>>>>> >>>>>>> >>>>>>> JBS: >>>>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>>>> >>>>>>> CSR: >>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>>>> >>>>>>> Feedback is welcome! >>>>>>> >>>>>>> Thanks, >>>>>>> ???? Jan From maurizio.cimadamore at oracle.com Fri Oct 18 13:08:20 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 18 Oct 2019 14:08:20 +0100 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: <6B0AC83B-213C-4B61-A4A3-0771A9DCF68A@oracle.com> References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> <68ee0609-3b98-85ec-97f8-1cc2ced8aa04@oracle.com> <6B0AC83B-213C-4B61-A4A3-0771A9DCF68A@oracle.com> Message-ID: <214762ca-2826-9304-6eff-d1389b816deb@oracle.com> Sorry, I got the table in the CSR completely mixed up. So, the new behavior only really changes the fact that essential API warnings are now suppressible when using --enable-preview. I now see the relevant difference in Check.java. Looks good Maurizio On 18/10/2019 13:38, Jan Lahoda wrote: > > 18. ??jna 2019 14:05:45 SEL?, Maurizio Cimadamore napsal: >> Looks good - but I suggest garbage collecting the isEssentialAPI() from >> >> the @PreviewFeature annotation, as the new behavior effectively removes >> >> any distinctions between the two (unless I miss something). > I am afraid there is still a distinction between them - when --enable-preview is not specified, use of essential APIs will lead to a compile time warning, while use of non essential API (reflection, typically) only produces warnings. > > Jan > >> Maurizio >> >> On 16/10/2019 13:50, Jan Lahoda wrote: >>> Hi, >>> >>> An updated patch is here: >>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ >>> >>> Changes in the update: >>> -added the dependency into the makefiles >>> -loosened the handling of essential preview APIs when >> --enable-preview >>> and @SuppressWarnings is applied - there is no warning for the >>> essential APIs (as there is no warning in such a case for >>> non-essential APIs). This is per the discussion in the CSR: >>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>> >>> Any comments/feedback on this? >>> >>> Thanks! >>> ??? Jan >>> >>> On 09. 10. 19 17:41, Erik Joelsson wrote: >>>> Oh, you are absolutely correct, the dependency is missing. >>>> >>>> We need something like this inside "define SetupInterimModule": >>>> >>>> $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) >>>> >>>> /Erik >>>> >>>> On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >>>>> I can?t see how the compilation is dependent on the copy being >>>>> finished. Since Erik contributed this it will probably be correct >> :) >>>>> but I?d appreciate an explanation on how this dependency is >> guaranteed. >>>>> Or maybe I?m misunderstanding what this is supposed to do? >>>>> >>>>> /Magnus >>>>> >>>>>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>>>>> >>>>>> Thanks for the new code Erik! >>>>>> >>>>>> A new webrev/patch that includes this better way of copying is >> here: >>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>>>>> >>>>>> Any feedback is welcome! >>>>>> >>>>>> Thanks, >>>>>> ??? Jan >>>>>> >>>>>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>>>>> Hello Jan, >>>>>>> The build change looks ok, but I would recommend this construct >>>>>>> for copying the file instead: >>>>>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>>>>> ???? FILES := >>>>>>> >> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >> >>>>>>> \ >>>>>>> ???? DEST := >>>>>>> >> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >> >>>>>>> \ >>>>>>> )) >>>>>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>>>>> Then you automatically get all the corner case handling we have >>>>>>> implemented over the years for logging, making directories and >>>>>>> copying files. Your version is still correct for this case >> though. >>>>>>> /Erik >>>>>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>>>>> Hi, >>>>>>>> >>>>>>>> This is a continuation of Joe's patch from here: >>>>>>>> >> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >> >>>>>>>> >>>>>>>> APIs associated with preview features are split into two groups: >>>>>>>> essential and non-essential. These are marked with an >>>>>>>> JDK-internal annotation, PreviewFeature, and a tag in the >>>>>>>> javadoc, @preview. The javac follows the PreviewFeature >>>>>>>> annotation, and produces either warnings or errors for the >> usages >>>>>>>> of such APIs. For the @preview tag, there is a taglet in the JDK >>>>>>>> build that adds the content of the tag into the documentation. >>>>>>>> The first part of the @preview's text goes into the summary, the >>>>>>>> second part goes into the detailed description. >>>>>>>> >>>>>>>> For build, a tricky problem is that the jdk.compiler module uses >>>>>>>> the PreviewFeature annotation as well, but that is not in the >>>>>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>>>>> PreviewFeature annotation is copied from java.base. >>>>>>>> >>>>>>>> Proposed webrev: >>>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>>>>> >>>>>>>> Javadoc with the change: >>>>>>>> >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>>>>> See for example: >>>>>>>> >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >> >>>>>>>> >> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >> >>>>>>>> >>>>>>>> JBS: >>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>>>>> >>>>>>>> CSR: >>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>>>>> >>>>>>>> Feedback is welcome! >>>>>>>> >>>>>>>> Thanks, >>>>>>>> ???? Jan From jonathan.gibbons at oracle.com Sat Oct 19 01:16:35 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Fri, 18 Oct 2019 18:16:35 -0700 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> Message-ID: <4161060b-cdca-b290-8697-2852481fdb5f@oracle.com> Generally, for historical reasons I accept, the jx.l.m model API has not been very friendly with helpful utility methods, going for a more minimalist approach, although I sense that is changing, maybe in part because of default methods. With respect to accessing the canonical constructor, I would like to see jx.l.m provide utility methods either for all the derived features of a record (canonical constructor, fields, accessors) or none, depending on the level of convenience desired.? Having a mix of some but not others is just confusing.?? Access to `equals` and `hashCode` can/should be provided by more general methods that need not be specific to records. -- Jon On 10/18/19 5:28 AM, Maurizio Cimadamore wrote: > I went through the javadoc changes and, although I'm no javadoc > expert, they seem clean enough, to the point that I could follow the > logic quite easily. > > One high-level gripe which is pointing at a failure of the j.l.model > API is the lack of a way to get to the canonical constructor directly; > we have this issue both in core reflection and source reflection, and > I think we should address that, as both serialization and javadoc has > to DYI around that. > > Maurizio > > On 17/10/2019 20:45, Jonathan Gibbons wrote: >> cc: javadoc-dev at openjdk.java.net >> >> --Jon >> >> >> On 10/17/2019 12:43 PM, Vicente Romero wrote: >>> Hi, >>> >>> Please review the javadoc code for JEP 359 (Records), this webrev >>> contains only the javadoc code as we have decided to split the new >>> code in clusters to make the review process easier. >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> PS, Jon is the author of this code please keep him in the loop >>> >>> http://cr.openjdk.java.net/~vromero/records.review/javadoc/webrev.00/ >> From vicente.romero at oracle.com Mon Oct 21 12:31:44 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 21 Oct 2019 08:31:44 -0400 Subject: RFR: JEP 359-Records: compiler code Message-ID: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Hi, Please review the compiler code for JEP 359 (Records) [1] Thanks in advance for the feedback, Vicente [1] http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From jan.lahoda at oracle.com Mon Oct 21 13:49:07 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Mon, 21 Oct 2019 15:49:07 +0200 Subject: RFR: JDK-8232684: Make switch expressions final Message-ID: Hi, As part of preparation for proposing JEP 361: Switch Expressions (Standard) to target, I would like to ask for a review of the patch to make switch expression a non-preview feature in javac: http://cr.openjdk.java.net/~jlahoda/8232684/webrev.00/ The patch basically removes the feature from the list of preview features, updates test to this new state (removes --enable-preview from associated tests, and adjusts their expected output), and removes the @PreviewFeature annotation and associated text from the javadoc of the Trees API. I also would like to ask for a review for the CSR associated with that: https://bugs.openjdk.java.net/browse/JDK-8232685 Reviews/comments on either of these would be very welcome! JBS: https://bugs.openjdk.java.net/browse/JDK-8232684 Thanks! Jan From maurizio.cimadamore at oracle.com Mon Oct 21 14:17:20 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2019 15:17:20 +0100 Subject: RFR: JDK-8232684: Make switch expressions final In-Reply-To: References: Message-ID: Looks generally good -? went through the test updates one by one and they look ok, except this: http://cr.openjdk.java.net/~jlahoda/8232684/webrev.00/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java.udiff.html Which you explained to me offline (we need to change this code every time the compiler stops using the @Preview annotation - ugh). Nothing specific to this webrev, so I approve. Maurizio On 21/10/2019 14:49, Jan Lahoda wrote: > Hi, > > As part of preparation for proposing JEP 361: Switch Expressions > (Standard) to target, I would like to ask for a review of the patch to > make switch expression a non-preview feature in javac: > http://cr.openjdk.java.net/~jlahoda/8232684/webrev.00/ > > The patch basically removes the feature from the list of preview > features, updates test to this new state (removes --enable-preview > from associated tests, and adjusts their expected output), and removes > the @PreviewFeature annotation and associated text from the javadoc of > the Trees API. > > I also would like to ask for a review for the CSR associated with that: > https://bugs.openjdk.java.net/browse/JDK-8232685 > > Reviews/comments on either of these would be very welcome! > > JBS: https://bugs.openjdk.java.net/browse/JDK-8232684 > > Thanks! > > Jan From chris.hegarty at oracle.com Mon Oct 21 16:26:30 2019 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Mon, 21 Oct 2019 17:26:30 +0100 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> Message-ID: <016E1A04-93C1-4586-9CC3-6467AC66BB41@oracle.com> > On 18 Oct 2019, at 13:28, Maurizio Cimadamore wrote: > > ... > > One high-level gripe which is pointing at a failure of the j.l.model API is the lack of a way to get to the canonical constructor directly; we have this issue both in core reflection and source reflection, and I think we should address that, as both serialization and javadoc has to DYI around that. Core reflection adds just a couple of primitives for record support: 1) Class::isRecord, and 2) Class::getRecordComponents The getRecordComponents method returns an empty array if the class is not a record or is a record with no components. The not-a-record-class scenario is not ideal, but seems like a reasonable ( given what we have ). If we were to add ( the fingersome ) Class::getRecordCanonicalConsructor, then this method would likely throw an appropriate exception if the class is not a record. If we do this, then maybe the this-class-is-not-a-record behavior of getRecordComponents should be re-examined? I also think that ?record? would likely need to be in the method name too, as I?m not sure that the term ?canonical constructor? will be enough by itself. BTW - I agree that such a method would be useful. It also promotes the notion of the ?canonical constructor?, even more than is already done by java.lang.Record. -Chris. From maurizio.cimadamore at oracle.com Mon Oct 21 18:01:58 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2019 19:01:58 +0100 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Message-ID: <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Hi Vicente, I did a pretty thorough pass on most of the code. I didn't look at tests, and I also didn't look at Lower. Comments below: * Flags.java - VARARGS flag for records components; I wonder, instead of a new flag, can we use the internal VARARGS flag we have for methods, and attach that to the record symbol? That should also lead to more direct code in TypeHelper * Symbol.java - I think the override for 'erasure' is redundant - isn't that the impl from supertype? * Symbol.java (and others) in general this webrev shuld be updated as soon as Jan push the @Preview work, as I see that methods implementing preview API are using the 'deprecate for removal' annotation * Symbol.java - I wonder if accessor list with Pair isn't a premature generalization; we should just add a getter symbol and that's it * Attr.java - I think we might want to leave the door open for a check which forces all constructors of a record to go through the canonical one (depending on where the spec lands) * Check.java - understanding checkpoint: when we see an annotation on a record component, first we check it's one of the kinds which are allowed (if not, error), and, if it's allowed, we add all record component annotations to record component elements, and we also filter away all annotations that have nothing to do with the element in which they appear. If my understanding is correct, I think this logic should be documented more clearly; I found the comment after the "if (isRecordField)" to be a bit obscure. * Enter.java - why are you removing the static flag on records? I don't see anything similar around for enums. * Flow.java - not sure I get the changes to checkInit; typically checkInit is called at the use-site of DA/DU variables. Here it seems you suppress some of the errors emitted for accessing record fields inside the canonical constructor - but I hope that code like this record Foo(int x) { ?? Foo(int x) { ?????? print(this.x); ?? } } Still give errors? If this works correctly, which errors does the 'guard' around the error generation is supposed to protect against? * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used here... * TypeEnter.java - implicit super calls are added in Attr::visitMethod for regular calls; we should do the same for records (or add all in TypeEnter - that is records and class should be consistent) * TypeEnter.java - on finishClass - you are calling memberEnter on record fields, which I think you already did in the new RecordsPhase * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal with _all_ record members (e.g. including accessors), not just some? * TypeEnter.java - checkForSerializationMember should probably be moved to MemberEnter::visitVar, or even to Attr (note that the code for the check is doing a little visit :-)) * TypeEnter.java - again on check timings; while it's ok for the code in here to add new synthetic members, I think it's less ok to add more global error checks (such as make sure that the canonical declaration whose parameter names match the record components in order); these should live in Attr. More generally, I think that we should only check stuff here if we think that the check will add any value to annotation processing. Every other check can be deferred, and take place in a more 'deterministic' part of javac. * TypeEnter.java - I think finishClass should be a bit better at determining as to whether default constructor is needed or not - for instance, this check: if ((sym.flags() & INTERFACE) == 0 && 928 !TreeInfo.hasConstructors(tree.defs)) { Should be generalized to something that works for both classes and records; for classes you need to check if there's no other constructor; for records you need to check if there's no other constructor _with same signature_ as the canonical one. Then you can simplify addRecordMembers and remove the dependency on the boolean 'generatedConstructor' parameter. In other words the code should: 1) check if default/canonical constructor generation is required 2) if so, use the appropriate helper to generate the code 3) at the end, add the remaining record members (under the assumption that the canonical constructor has already been added in (1), if that was missing) *TypeEnter.java - addAccessor can be simplified if we only worry about getters. Again, the checks in here feel more Attr check than MemberEnter checks. *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we create a tree for a member, and then we visit the member tree with memberEnter, just to add it to the scope. I understand that, currently addEnumMembers does the same, but this looks very roundabout; I wonder if there's a way to make all this process a bit simpler - create a symbol and add that to the scope. Or are there important checks in MemberEnter that we would lose? *JCTree.java/TreeMaker.java - I don't think there's any need to store accessors in the field AST; these are only used from TypeEnter, and TypeEnter can do whatever it does by looking at which record components there are in the record class, and add a getter for each. Let's make the code simpler and more direct * ClassReader.java - should we just silently ignore record attributes when not in preview mode - or should we issue classfile errors? * ClassReader.java - what kind of validation should we do on record attributes? Currently javac does nothing. Should we check that we have (i) getters (ii) toString/hashCode/equals implementations and (iii) a canonical constructor (ad fail if we don't) ? At the very least I would add code to _parse_ the attribute, even if we do nothing with it, so that at least we throw a classfile error if the attribute is badly broken * Tokens.java - for "var", "yields" and other context-dependent keywords we never added a token. We just handled that in JavacParser. Why the difference here? I think it's best to stick to current style and maybe fix all of them (assuming that's what we want to do) in a followup cleanup. Actually, after looking at parser, it seems like you already handle that manually, so I just suggest to revert the changed to Tokens * TreeInfo.java - how is 'isCanonicalConstructor' not returning 'true' for all constructors inside a record, as opposed to only return true for the canonical one? * TreeInfo.java - There is some code reuse possible between "recordFieldTypes" and "recordFields" * Names.java - what is 'oldEquals' ? * JavacParser.java - timing of checks; I don't think we should check for illegal record component names in here * JavacParser.java - code can be simplified somewhat by getting rid of accessors in VarDef AST. On 21/10/2019 13:31, Vicente Romero wrote: > Hi, > > Please review the compiler code for JEP 359 (Records) [1] > > Thanks in advance for the feedback, > Vicente > > [1] > http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 20:44:19 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2019 21:44:19 +0100 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> And here are some comments on Lower - findMethodOrFailSilently? doesn't seem to be used anywhere; this should be removed and associated changes in Resolve reverted - findUserDefinedAccessors - this seems to have to do with setting the record component symbol straight - this should happen well before Lower, otherwise I'm not even sure what annotations processor will see? This code should go in TypeEnter, where you already look up for existing accessor. - related; not 100% as to why in visitRecordDef you protect against accessor not being there - which means you need to do a lookup. You need to get to this part of the code where all accessors have been set. Then the code can be simplified. - As pointed out previously, getting rid of the Pair accessor will result in cascading simplification in few methods in Lower too - both the signature generator and the indy machinery are shared between LambdaToMethod and Lower - so we should probably put them somewhere in a common superclass which can be used by the various backend steps - I guess the main translation strategy for record members is to generate an indy - where the runtime gives you back some constant callsite which wraps a method handle with the right signature. If so, some comments should be sprinkled around to clarify that this is indeed the case. - I also guess that the if/else in generateRecordMethod is to avoid generating a tree if an explicit member has been declared by the user - again, correct, but some comments please ;-) Also some comments? on tests: * test/langtools/tools/javac/6402516/CheckLocalElements.java - why the change? * test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java -? why the change from @run to @compile? * test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java - who is using the new target? * diags/** in general, for all new diagnostics added it would be nice to have an html of the output (I have a script for doing that, let me know if you need it) * examples-not-yet - why no test for local records? That should be easy to add (I hope)? * test/langtools/tools/javac/parser/JavacParserTest.java - here I wonder if we should have different messages depending on the version (eg. we don't want to say 'expected records' if compiling with -source 12?) *? test/langtools/tools/javac/tree/JavacTreeScannerTest.java, test/langtools/tools/javac/tree/SourceTreeScannerTest.java, src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java - seems like these probably depend on the accessor pairs being in the AST? * test/langtools/tools/javac/doctree/AccessorsTest.java - not sure about this, does it even belong to this patch? I'd be surprised if DocTree does anything special with accessors? * test/langtools/tools/javac/doctree/AccessorsTest.java - this tests that ElementFilter and getAccessor() agree, but doesn't test that they actually yield the correct result * more generally, certain tests (e.g. signature mismatches, record component names order mismatches, reflection tests, serialization tests) have a certain ad-hoc nature to them - in the sense that they test one record shape or two and that's it. E.g. test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java I'd like to see a more combinatorial-oriented approach to such tests, where at least we tests all primitive types plus a reference type of choice, with varying degrees of arity (and w/, w/o varargs). That's all for now Thanks Maurizio On 21/10/2019 19:01, Maurizio Cimadamore wrote: > Hi Vicente, > I did a pretty thorough pass on most of the code. I didn't look at > tests, and I also didn't look at Lower. Comments below: > > * Flags.java - VARARGS flag for records components; I wonder, instead > of a new flag, can we use the internal VARARGS flag we have for > methods, and attach that to the record symbol? That should also lead > to more direct code in TypeHelper > > * Symbol.java - I think the override for 'erasure' is redundant - > isn't that the impl from supertype? > > * Symbol.java (and others) in general this webrev shuld be updated as > soon as Jan push the @Preview work, as I see that methods implementing > preview API are using the 'deprecate for removal' annotation > > * Symbol.java - I wonder if accessor list with Pair > isn't a premature generalization; we should just add a getter symbol > and that's it > > * Attr.java - I think we might want to leave the door open for a check > which forces all constructors of a record to go through the canonical > one (depending on where the spec lands) > > * Check.java - understanding checkpoint: when we see an annotation on > a record component, first we check it's one of the kinds which are > allowed (if not, error), and, if it's allowed, we add all record > component annotations to record component elements, and we also filter > away all annotations that have nothing to do with the element in which > they appear. If my understanding is correct, I think this logic should > be documented more clearly; I found the comment after the "if > (isRecordField)" to be a bit obscure. > > * Enter.java - why are you removing the static flag on records? I > don't see anything similar around for enums. > > * Flow.java - not sure I get the changes to checkInit; typically > checkInit is called at the use-site of DA/DU variables. Here it seems > you suppress some of the errors emitted for accessing record fields > inside the canonical constructor - but I hope that code like this > > record Foo(int x) { > ?? Foo(int x) { > ?????? print(this.x); > ?? } > } > > Still give errors? If this works correctly, which errors does the > 'guard' around the error generation is supposed to protect against? > > * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used > here... > > * TypeEnter.java - implicit super calls are added in Attr::visitMethod > for regular calls; we should do the same for records (or add all in > TypeEnter - that is records and class should be consistent) > > * TypeEnter.java - on finishClass - you are calling memberEnter on > record fields, which I think you already did in the new RecordsPhase > > * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal > with _all_ record members (e.g. including accessors), not just some? > > * TypeEnter.java - checkForSerializationMember should probably be > moved to MemberEnter::visitVar, or even to Attr (note that the code > for the check is doing a little visit :-)) > > * TypeEnter.java - again on check timings; while it's ok for the code > in here to add new synthetic members, I think it's less ok to add more > global error checks (such as make sure that the canonical declaration > whose parameter names match the record components in order); these > should live in Attr. More generally, I think that we should only check > stuff here if we think that the check will add any value to annotation > processing. Every other check can be deferred, and take place in a > more 'deterministic' part of javac. > > * TypeEnter.java - I think finishClass should be a bit better at > determining as to whether default constructor is needed or not - for > instance, this check: > > if ((sym.flags() & INTERFACE) == 0 && > ?928???????????????? !TreeInfo.hasConstructors(tree.defs)) { > > Should be generalized to something that works for both classes and > records; for classes you need to check if there's no other > constructor; for records you need to check if there's no other > constructor _with same signature_ as the canonical one. Then you can > simplify addRecordMembers and remove the dependency on the boolean > 'generatedConstructor' parameter. In other words the code should: > > 1) check if default/canonical constructor generation is required > 2) if so, use the appropriate helper to generate the code > 3) at the end, add the remaining record members (under the assumption > that the canonical constructor has already been added in (1), if that > was missing) > > *TypeEnter.java - addAccessor can be simplified if we only worry about > getters. Again, the checks in here feel more Attr check than > MemberEnter checks. > > *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we > create a tree for a member, and then we visit the member tree with > memberEnter, just to add it to the scope. I understand that, currently > addEnumMembers does the same, but this looks very roundabout; I wonder > if there's a way to make all this process a bit simpler - create a > symbol and add that to the scope. Or are there important checks in > MemberEnter that we would lose? > > *JCTree.java/TreeMaker.java - I don't think there's any need to store > accessors in the field AST; these are only used from TypeEnter, and > TypeEnter can do whatever it does by looking at which record > components there are in the record class, and add a getter for each. > Let's make the code simpler and more direct > > * ClassReader.java - should we just silently ignore record attributes > when not in preview mode - or should we issue classfile errors? > > * ClassReader.java - what kind of validation should we do on record > attributes? Currently javac does nothing. Should we check that we have > (i) getters (ii) toString/hashCode/equals implementations and (iii) a > canonical constructor (ad fail if we don't) ? At the very least I > would add code to _parse_ the attribute, even if we do nothing with > it, so that at least we throw a classfile error if the attribute is > badly broken > > * Tokens.java - for "var", "yields" and other context-dependent > keywords we never added a token. We just handled that in JavacParser. > Why the difference here? I think it's best to stick to current style > and maybe fix all of them (assuming that's what we want to do) in a > followup cleanup. Actually, after looking at parser, it seems like you > already handle that manually, so I just suggest to revert the changed > to Tokens > > * TreeInfo.java - how is 'isCanonicalConstructor' not returning 'true' > for all constructors inside a record, as opposed to only return true > for the canonical one? > > * TreeInfo.java - There is some code reuse possible between > "recordFieldTypes" and "recordFields" > > * Names.java - what is 'oldEquals' ? > > * JavacParser.java - timing of checks; I don't think we should check > for illegal record component names in here > > * JavacParser.java - code can be simplified somewhat by getting rid of > accessors in VarDef AST. > > > > > > On 21/10/2019 13:31, Vicente Romero wrote: >> Hi, >> >> Please review the compiler code for JEP 359 (Records) [1] >> >> Thanks in advance for the feedback, >> Vicente >> >> [1] >> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From vicente.romero at oracle.com Mon Oct 21 21:10:09 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 21 Oct 2019 17:10:09 -0400 Subject: RFR: JEP 359-Records: reflection code Message-ID: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> Hi, Please review the reflection code for JEP 359 (Records) at [1]. There is a class here that is special [2] this contain the bootstrap methods for equals, hashCode and toString methods in records. Thanks in advance for the feedback, Vicente [1] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/ [2] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java.html From vicente.romero at oracle.com Mon Oct 21 21:20:31 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 21 Oct 2019 17:20:31 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> Message-ID: <81b4e85f-1c7c-7cf1-a52d-d4ee4515fbb5@oracle.com> Hi Maurizio, Thanks a lot for the review, working on your comments, Vicente On 10/21/19 4:44 PM, Maurizio Cimadamore wrote: > And here are some comments on Lower > > - findMethodOrFailSilently? doesn't seem to be used anywhere; this > should be removed and associated changes in Resolve reverted > > - findUserDefinedAccessors - this seems to have to do with setting the > record component symbol straight - this should happen well before > Lower, otherwise I'm not even sure what annotations processor will > see? This code should go in TypeEnter, where you already look up for > existing accessor. > > - related; not 100% as to why in visitRecordDef you protect against > accessor not being there - which means you need to do a lookup. You > need to get to this part of the code where all accessors have been > set. Then the code can be simplified. > > - As pointed out previously, getting rid of the Pair > accessor will result in cascading simplification in few methods in > Lower too > > - both the signature generator and the indy machinery are shared > between LambdaToMethod and Lower - so we should probably put them > somewhere in a common superclass which can be used by the various > backend steps > > - I guess the main translation strategy for record members is to > generate an indy - where the runtime gives you back some constant > callsite which wraps a method handle with the right signature. If so, > some comments should be sprinkled around to clarify that this is > indeed the case. > > - I also guess that the if/else in generateRecordMethod is to avoid > generating a tree if an explicit member has been declared by the user > - again, correct, but some comments please ;-) > > > Also some comments? on tests: > > * test/langtools/tools/javac/6402516/CheckLocalElements.java - why the > change? > > * test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java > -? why the change from @run to @compile? > > * > test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java > - who is using the new target? > > * diags/** in general, for all new diagnostics added it would be nice > to have an html of the output (I have a script for doing that, let me > know if you need it) > > * examples-not-yet - why no test for local records? That should be > easy to add (I hope)? > > * test/langtools/tools/javac/parser/JavacParserTest.java - here I > wonder if we should have different messages depending on the version > (eg. we don't want to say 'expected records' if compiling with -source > 12?) > > *? test/langtools/tools/javac/tree/JavacTreeScannerTest.java, > test/langtools/tools/javac/tree/SourceTreeScannerTest.java, > src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java > - seems like these probably depend on the accessor pairs being in the > AST? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - not sure > about this, does it even belong to this patch? I'd be surprised if > DocTree does anything special with accessors? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - this tests > that ElementFilter and getAccessor() agree, but doesn't test that they > actually yield the correct result > > * more generally, certain tests (e.g. signature mismatches, record > component names order mismatches, reflection tests, serialization > tests) have a certain ad-hoc nature to them - in the sense that they > test one record shape or two and that's it. E.g. > > test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java > > > I'd like to see a more combinatorial-oriented approach to such tests, > where at least we tests all primitive types plus a reference type of > choice, with varying degrees of arity (and w/, w/o varargs). > > > That's all for now > > Thanks > Maurizio > > On 21/10/2019 19:01, Maurizio Cimadamore wrote: >> Hi Vicente, >> I did a pretty thorough pass on most of the code. I didn't look at >> tests, and I also didn't look at Lower. Comments below: >> >> * Flags.java - VARARGS flag for records components; I wonder, instead >> of a new flag, can we use the internal VARARGS flag we have for >> methods, and attach that to the record symbol? That should also lead >> to more direct code in TypeHelper >> >> * Symbol.java - I think the override for 'erasure' is redundant - >> isn't that the impl from supertype? >> >> * Symbol.java (and others) in general this webrev shuld be updated as >> soon as Jan push the @Preview work, as I see that methods >> implementing preview API are using the 'deprecate for removal' >> annotation >> >> * Symbol.java - I wonder if accessor list with Pair >> isn't a premature generalization; we should just add a getter symbol >> and that's it >> >> * Attr.java - I think we might want to leave the door open for a >> check which forces all constructors of a record to go through the >> canonical one (depending on where the spec lands) >> >> * Check.java - understanding checkpoint: when we see an annotation on >> a record component, first we check it's one of the kinds which are >> allowed (if not, error), and, if it's allowed, we add all record >> component annotations to record component elements, and we also >> filter away all annotations that have nothing to do with the element >> in which they appear. If my understanding is correct, I think this >> logic should be documented more clearly; I found the comment after >> the "if (isRecordField)" to be a bit obscure. >> >> * Enter.java - why are you removing the static flag on records? I >> don't see anything similar around for enums. >> >> * Flow.java - not sure I get the changes to checkInit; typically >> checkInit is called at the use-site of DA/DU variables. Here it seems >> you suppress some of the errors emitted for accessing record fields >> inside the canonical constructor - but I hope that code like this >> >> record Foo(int x) { >> ?? Foo(int x) { >> ?????? print(this.x); >> ?? } >> } >> >> Still give errors? If this works correctly, which errors does the >> 'guard' around the error generation is supposed to protect against? >> >> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used >> here... >> >> * TypeEnter.java - implicit super calls are added in >> Attr::visitMethod for regular calls; we should do the same for >> records (or add all in TypeEnter - that is records and class should >> be consistent) >> >> * TypeEnter.java - on finishClass - you are calling memberEnter on >> record fields, which I think you already did in the new RecordsPhase >> >> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >> with _all_ record members (e.g. including accessors), not just some? >> >> * TypeEnter.java - checkForSerializationMember should probably be >> moved to MemberEnter::visitVar, or even to Attr (note that the code >> for the check is doing a little visit :-)) >> >> * TypeEnter.java - again on check timings; while it's ok for the code >> in here to add new synthetic members, I think it's less ok to add >> more global error checks (such as make sure that the canonical >> declaration whose parameter names match the record components in >> order); these should live in Attr. More generally, I think that we >> should only check stuff here if we think that the check will add any >> value to annotation processing. Every other check can be deferred, >> and take place in a more 'deterministic' part of javac. >> >> * TypeEnter.java - I think finishClass should be a bit better at >> determining as to whether default constructor is needed or not - for >> instance, this check: >> >> if ((sym.flags() & INTERFACE) == 0 && >> ?928???????????????? !TreeInfo.hasConstructors(tree.defs)) { >> >> Should be generalized to something that works for both classes and >> records; for classes you need to check if there's no other >> constructor; for records you need to check if there's no other >> constructor _with same signature_ as the canonical one. Then you can >> simplify addRecordMembers and remove the dependency on the boolean >> 'generatedConstructor' parameter. In other words the code should: >> >> 1) check if default/canonical constructor generation is required >> 2) if so, use the appropriate helper to generate the code >> 3) at the end, add the remaining record members (under the assumption >> that the canonical constructor has already been added in (1), if that >> was missing) >> >> *TypeEnter.java - addAccessor can be simplified if we only worry >> about getters. Again, the checks in here feel more Attr check than >> MemberEnter checks. >> >> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >> create a tree for a member, and then we visit the member tree with >> memberEnter, just to add it to the scope. I understand that, >> currently addEnumMembers does the same, but this looks very >> roundabout; I wonder if there's a way to make all this process a bit >> simpler - create a symbol and add that to the scope. Or are there >> important checks in MemberEnter that we would lose? >> >> *JCTree.java/TreeMaker.java - I don't think there's any need to store >> accessors in the field AST; these are only used from TypeEnter, and >> TypeEnter can do whatever it does by looking at which record >> components there are in the record class, and add a getter for each. >> Let's make the code simpler and more direct >> >> * ClassReader.java - should we just silently ignore record attributes >> when not in preview mode - or should we issue classfile errors? >> >> * ClassReader.java - what kind of validation should we do on record >> attributes? Currently javac does nothing. Should we check that we >> have (i) getters (ii) toString/hashCode/equals implementations and >> (iii) a canonical constructor (ad fail if we don't) ? At the very >> least I would add code to _parse_ the attribute, even if we do >> nothing with it, so that at least we throw a classfile error if the >> attribute is badly broken >> >> * Tokens.java - for "var", "yields" and other context-dependent >> keywords we never added a token. We just handled that in JavacParser. >> Why the difference here? I think it's best to stick to current style >> and maybe fix all of them (assuming that's what we want to do) in a >> followup cleanup. Actually, after looking at parser, it seems like >> you already handle that manually, so I just suggest to revert the >> changed to Tokens >> >> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >> 'true' for all constructors inside a record, as opposed to only >> return true for the canonical one? >> >> * TreeInfo.java - There is some code reuse possible between >> "recordFieldTypes" and "recordFields" >> >> * Names.java - what is 'oldEquals' ? >> >> * JavacParser.java - timing of checks; I don't think we should check >> for illegal record component names in here >> >> * JavacParser.java - code can be simplified somewhat by getting rid >> of accessors in VarDef AST. >> >> >> >> >> >> On 21/10/2019 13:31, Vicente Romero wrote: >>> Hi, >>> >>> Please review the compiler code for JEP 359 (Records) [1] >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From forax at univ-mlv.fr Mon Oct 21 22:02:21 2019 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 22 Oct 2019 00:02:21 +0200 (CEST) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> Message-ID: <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> The class ObjectMethods is in the package java.lang.invoke if you take a look to the source but in the package java.lang.runtime if you trust the webrev. It should be in java.lang.invoke so Claes (or someone else) will be able to optimize it later, otherwise if we want to use an internal non public MethodHandle, we will have to rely on a special SharedSecret class. I really dislike the bootstrap protocol: - first it means that you can not have more than 250 fields - the same call works for equals/hashCode and toString, so depending on the methods some arguments are not used or not (names is used only in toString). - theClass and lookup.lookupClass are the same if used from invokedynamic. - the whole "if the methodType is null, then return a MethodHandle instead of the callsite" is a hack that leak to the public interface. - the format 'names' is not the same as the one in the StringConcatFactory and what if the name are not the name of the record components or in wrong order. I propose the following design to fix these issues: All invokedynamic should takes the same constant dynamic as parameters typed as an Object. This object should be an instance of an internal class of ObjectMethods (let say RecordMirror) created or populated by the VM from the Record attribute, from inside the constant dynamic BSM, so there will be only one upcall and one downcall instead of one upcall per getter. This class can store the property names using the StringConcatFactory format and all the getters (the constant method handles). A kick and simple implementation can use Class.getRecordComponents() on the lookup.lookupClass() to populate the instance of RecordMirror. I will be less efficient than calling one native method that fills the RecordMirror instance but this can be optimized later. So the bootstrap method is just: public static Object bootstrap(Lookup lookup, String methodName, TypeDescriptor type, Object recordMirrorObject) The bootstrap can easy validate the recordMirrorObject just by doing a cast to RecordMirror. regards, R?mi ----- Mail original ----- > De: "Vicente Romero" > ?: "amber-dev" , "compiler-dev" > Envoy?: Lundi 21 Octobre 2019 23:10:09 > Objet: RFR: JEP 359-Records: reflection code > Hi, > > Please review the reflection code for JEP 359 (Records) at [1]. There is > a class here that is special [2] this contain the bootstrap methods for > equals, hashCode and toString methods in records. > > Thanks in advance for the feedback, > Vicente > > [1] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/ > [2] > http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java.html From maurizio.cimadamore at oracle.com Mon Oct 21 22:32:04 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2019 23:32:04 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> Message-ID: <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> On 21/10/2019 23:02, Remi Forax wrote: > - the same call works for equals/hashCode and toString, so depending on the methods some arguments are not used or not I too found this a bit odd when looking at the javac code - it took me sometime to figure out what was going on. The question I have here is - is the decision of having a single point a deliberate decision that we think it's going to pay off in the long run? Or was it more a way to quickly bootstrap the javac implementation? If the latter, we should probably revert to one bootstrap per Object method. Maurizio From forax at univ-mlv.fr Mon Oct 21 23:31:01 2019 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 22 Oct 2019 01:31:01 +0200 (CEST) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> Message-ID: <983359174.462351.1571700661292.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: "Remi Forax" , "Vicente Romero" > Cc: "amber-dev" , "compiler-dev" > Envoy?: Mardi 22 Octobre 2019 00:32:04 > Objet: Re: RFR: JEP 359-Records: reflection code > On 21/10/2019 23:02, Remi Forax wrote: >> - the same call works for equals/hashCode and toString, so depending on the >> methods some arguments are not used or not > > I too found this a bit odd when looking at the javac code - it took me > sometime to figure out what was going on. > > The question I have here is - is the decision of having a single point a > deliberate decision that we think it's going to pay off in the long run? > Or was it more a way to quickly bootstrap the javac implementation? If > the latter, we should probably revert to one bootstrap per Object method. Having one bootstrap method makes the code more compact, because the boostrap method descriptor is shared inside the constant pool. But, you still have several boostrap method infos inside the BootstrapMethods attributes because the arguments of each BSM call is different. Having the same constant dynamic constant as argument for all bootstrap method calls allows more sharing. If we want more sharing, we can also make a new kind of constant pool constant to store the record components. It's not straightforward because a constant pool constant has to have a fixed size, so it can not store directly the record components but a constant pool constant can reference an attribute (the Record attribute) just by it's name and no value. With that, the bootstrap method calls will be able to load directly all the info needed to implement equals/hashCode and toString by reifying the record attribute into a RecordDescriptor. > > Maurizio R?mi From vicente.romero at oracle.com Tue Oct 22 02:40:34 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 21 Oct 2019 22:40:34 -0400 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> Message-ID: <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> On 10/21/19 6:32 PM, Maurizio Cimadamore wrote: > > On 21/10/2019 23:02, Remi Forax wrote: >> - the same call works for equals/hashCode and toString, so depending >> on the methods some arguments are not used or not > > I too found this a bit odd when looking at the javac code - it took me > sometime to figure out what was going on. > > The question I have here is - is the decision of having a single point > a deliberate decision that we think it's going to pay off in the long > run? it was a deliberate decision, the first implementation actually had different bootstrap methods but then we got a table with three bootstrap methods per every humble record, so having only one bootstrap method is a space gain. > Or was it more a way to quickly bootstrap the javac implementation? If > the latter, we should probably revert to one bootstrap per Object method. > > Maurizio > Vicente From maurizio.cimadamore at oracle.com Tue Oct 22 07:57:23 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 08:57:23 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> Message-ID: <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> Ok, so the goal is share of CP entries (should be documented somewhere). I think in that case I would at least advocate for replacing the compiler generated string of names with some runtime concatenation using getter names; the concatenation is done at runtime, after all. Currently the code uses 'String::split' in the bootstrap which is not great, e.g. sometimes it inserts additional empty strings in the middle ( e.g. "foo;;bar"), and it's probably as expensive (if not more) as constructing the string from scratch (since it involves regex matching). I note that the bootstrap code protects against lengths mismatches with an 'assert', but the assert will not be run in production code, so there could be some surprising crashes there. If the code is kept this way I suggest at least replacing assert with a runtime exception (throw new AssertionError). E.g. I'm fine with assert keywords when it comes to checking invariants that are under control of the implementation (in which case, you run tests with assertion enabled to shake possible issues); but in this case the invariant depends on what names string the client has passed to the BSM, so I think some real validation is in order here. Maurizio On 22/10/2019 03:40, Vicente Romero wrote: > > > On 10/21/19 6:32 PM, Maurizio Cimadamore wrote: >> >> On 21/10/2019 23:02, Remi Forax wrote: >>> - the same call works for equals/hashCode and toString, so depending >>> on the methods some arguments are not used or not >> >> I too found this a bit odd when looking at the javac code - it took >> me sometime to figure out what was going on. >> >> The question I have here is - is the decision of having a single >> point a deliberate decision that we think it's going to pay off in >> the long run? > > it was a deliberate decision, the first implementation actually had > different bootstrap methods but then we got a table with three > bootstrap methods per every humble record, so having only one > bootstrap method is a space gain. >> Or was it more a way to quickly bootstrap the javac implementation? >> If the latter, we should probably revert to one bootstrap per Object >> method. >> >> Maurizio >> > Vicente From maurizio.cimadamore at oracle.com Tue Oct 22 07:59:07 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 08:59:07 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> Message-ID: <2c61392a-a492-5bfb-06b5-48a517002396@oracle.com> > If the code is kept this way I suggest at least replacing assert with > a runtime exception (throw new AssertionError). E.g. I'm fine with > assert keywords when it comes to checking invariants that are under > control of the implementation (in which case, you run tests with > assertion enabled to shake possible issues); but in this case the > invariant depends on what names string the client has passed to the > BSM, so I think some real validation is in order here. My bad - there is a real validation, in the main BSM code: if (nameList.size() != getterList.size()) 342 throw new IllegalArgumentException("Name list and accessor list do not match"); So, the plain assert is fine in the toString impl. Maurizio > Maurizio > > > On 22/10/2019 03:40, Vicente Romero wrote: >> >> >> On 10/21/19 6:32 PM, Maurizio Cimadamore wrote: >>> >>> On 21/10/2019 23:02, Remi Forax wrote: >>>> - the same call works for equals/hashCode and toString, so >>>> depending on the methods some arguments are not used or not >>> >>> I too found this a bit odd when looking at the javac code - it took >>> me sometime to figure out what was going on. >>> >>> The question I have here is - is the decision of having a single >>> point a deliberate decision that we think it's going to pay off in >>> the long run? >> >> it was a deliberate decision, the first implementation actually had >> different bootstrap methods but then we got a table with three >> bootstrap methods per every humble record, so having only one >> bootstrap method is a space gain. >>> Or was it more a way to quickly bootstrap the javac implementation? >>> If the latter, we should probably revert to one bootstrap per Object >>> method. >>> >>> Maurizio >>> >> Vicente -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Oct 22 08:43:42 2019 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 22 Oct 2019 10:43:42 +0200 (CEST) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> Message-ID: <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: "Vicente Romero" , "Remi Forax" > Cc: "amber-dev" , "compiler-dev" > Envoy?: Mardi 22 Octobre 2019 09:57:23 > Objet: Re: RFR: JEP 359-Records: reflection code > Ok, so the goal is share of CP entries (should be documented somewhere). > > I think in that case I would at least advocate for replacing the > compiler generated string of names with some runtime concatenation using > getter names; the concatenation is done at runtime, after all. Getting the name from a method handle is not that simple. Usually you can't. In this peculiar example you can because you can call revealDirect [1] on the lookup because the same lookup is used to create the getters and calling the BSM. But i still think it's better to do not send any arguments and use getRecordComponents() at runtime or to enable object sharing between the BSM calls to use one constant dynamic as argument and initialize it with the calls to getRecordComponents(). [...] > Maurizio R?mi [1] https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#revealDirect(java.lang.invoke.MethodHandle) > > > On 22/10/2019 03:40, Vicente Romero wrote: >> >> >> On 10/21/19 6:32 PM, Maurizio Cimadamore wrote: >>> >>> On 21/10/2019 23:02, Remi Forax wrote: >>>> - the same call works for equals/hashCode and toString, so depending >>>> on the methods some arguments are not used or not >>> >>> I too found this a bit odd when looking at the javac code - it took >>> me sometime to figure out what was going on. >>> >>> The question I have here is - is the decision of having a single >>> point a deliberate decision that we think it's going to pay off in >>> the long run? >> >> it was a deliberate decision, the first implementation actually had >> different bootstrap methods but then we got a table with three >> bootstrap methods per every humble record, so having only one >> bootstrap method is a space gain. >>> Or was it more a way to quickly bootstrap the javac implementation? >>> If the latter, we should probably revert to one bootstrap per Object >>> method. >>> >>> Maurizio >>> > > Vicente From maurizio.cimadamore at oracle.com Tue Oct 22 08:51:03 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 09:51:03 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> Message-ID: <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> On 22/10/2019 09:43, forax at univ-mlv.fr wrote: > ----- Mail original ----- >> De: "Maurizio Cimadamore" >> ?: "Vicente Romero" , "Remi Forax" >> Cc: "amber-dev" , "compiler-dev" >> Envoy?: Mardi 22 Octobre 2019 09:57:23 >> Objet: Re: RFR: JEP 359-Records: reflection code >> Ok, so the goal is share of CP entries (should be documented somewhere). >> >> I think in that case I would at least advocate for replacing the >> compiler generated string of names with some runtime concatenation using >> getter names; the concatenation is done at runtime, after all. > Getting the name from a method handle is not that simple. > Usually you can't. In this peculiar example you can because you can call revealDirect [1] on the lookup because the same lookup is used to create the getters and calling the BSM. Let me rephrase. We have Class::getRecordComponents; and we have RecordComponent::accessor. What is the need to pass _anything_ to the BSM, other than the record class (e.g. Point.class) AND the method name (e.g. toString) ? The BSM can take the .class, and get the components; from there: - you can easily derive names - you can also easily derive accessor MHs (just a lookup away) I was _not_ advocating for extracting a name from a direct method handle - that seems brittle, given that the compiler implementation might change, eventually. But doubling down on the reflection API seems the right thing to do? Maurizio > > But i still think it's better to do not send any arguments and use getRecordComponents() at runtime or to enable object sharing between the BSM calls to use one constant dynamic as argument and initialize it with the calls to getRecordComponents(). > > [...] > >> Maurizio > R?mi > > [1] https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#revealDirect(java.lang.invoke.MethodHandle) > > >> >> On 22/10/2019 03:40, Vicente Romero wrote: >>> >>> On 10/21/19 6:32 PM, Maurizio Cimadamore wrote: >>>> On 21/10/2019 23:02, Remi Forax wrote: >>>>> - the same call works for equals/hashCode and toString, so depending >>>>> on the methods some arguments are not used or not >>>> I too found this a bit odd when looking at the javac code - it took >>>> me sometime to figure out what was going on. >>>> >>>> The question I have here is - is the decision of having a single >>>> point a deliberate decision that we think it's going to pay off in >>>> the long run? >>> it was a deliberate decision, the first implementation actually had >>> different bootstrap methods but then we got a table with three >>> bootstrap methods per every humble record, so having only one >>> bootstrap method is a space gain. >>>> Or was it more a way to quickly bootstrap the javac implementation? >>>> If the latter, we should probably revert to one bootstrap per Object >>>> method. >>>> >>>> Maurizio >>>> >>> Vicente From magnus.ihse.bursie at oracle.com Tue Oct 22 09:37:35 2019 From: magnus.ihse.bursie at oracle.com (Magnus Ihse Bursie) Date: Tue, 22 Oct 2019 11:37:35 +0200 Subject: RFR: JDK-8226585: Improve javac messages for using a preview API In-Reply-To: References: <85fa1e39-4966-c30a-b609-970caaaa6a4d@oracle.com> <5984363A-8615-42DC-AA11-B3017D2D2372@oracle.com> <875ebdb1-c37b-079c-0416-3a80351c87bb@oracle.com> Message-ID: On 2019-10-16 14:55, Erik Joelsson wrote: > Build change looks good now. I agree. /Magnus > > /Erik > > On 2019-10-16 05:50, Jan Lahoda wrote: >> Hi, >> >> An updated patch is here: >> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.02/ >> >> Changes in the update: >> -added the dependency into the makefiles >> -loosened the handling of essential preview APIs when >> --enable-preview and @SuppressWarnings is applied - there is no >> warning for the essential APIs (as there is no warning in such a case >> for non-essential APIs). This is per the discussion in the CSR: >> https://bugs.openjdk.java.net/browse/JDK-8231411 >> >> Any comments/feedback on this? >> >> Thanks! >> ??? Jan >> >> On 09. 10. 19 17:41, Erik Joelsson wrote: >>> Oh, you are absolutely correct, the dependency is missing. >>> >>> We need something like this inside "define SetupInterimModule": >>> >>> $$(BUILD_$1.interim): $(COPY_PREVIEW_FEATURES) >>> >>> /Erik >>> >>> On 2019-10-09 01:42, Magnus Ihse Bursie wrote: >>>> I can?t see how the compilation is dependent on the copy being >>>> finished. Since Erik contributed this it will probably be correct >>>> :) but I?d appreciate an explanation on how this dependency is >>>> guaranteed. >>>> >>>> Or maybe I?m misunderstanding what this is supposed to do? >>>> >>>> /Magnus >>>> >>>>> 8 okt. 2019 kl. 17:27 skrev Jan Lahoda : >>>>> >>>>> Thanks for the new code Erik! >>>>> >>>>> A new webrev/patch that includes this better way of copying is here: >>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.01/ >>>>> >>>>> Any feedback is welcome! >>>>> >>>>> Thanks, >>>>> ??? Jan >>>>> >>>>>> On 03. 10. 19 18:06, Erik Joelsson wrote: >>>>>> Hello Jan, >>>>>> The build change looks ok, but I would recommend this construct >>>>>> for copying the file instead: >>>>>> $(eval $(call SetupCopyFiles, COPY_PREVIEW_FEATURES, \ >>>>>> ???? FILES := >>>>>> $(TOPDIR)/src/java.base/share/classes/jdk/internal/PreviewFeature.java, >>>>>> \ >>>>>> ???? DEST := >>>>>> $(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim/jdk/internal/PreviewFeature.java, >>>>>> \ >>>>>> )) >>>>>> TARGETS += $(COPY_PREVIEW_FEATURES) >>>>>> Then you automatically get all the corner case handling we have >>>>>> implemented over the years for logging, making directories and >>>>>> copying files. Your version is still correct for this case though. >>>>>> /Erik >>>>>>> On 2019-10-03 02:57, Jan Lahoda wrote: >>>>>>> Hi, >>>>>>> >>>>>>> This is a continuation of Joe's patch from here: >>>>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-June/013498.html >>>>>>> >>>>>>> >>>>>>> APIs associated with preview features are split into two groups: >>>>>>> essential and non-essential. These are marked with an >>>>>>> JDK-internal annotation, PreviewFeature, and a tag in the >>>>>>> javadoc, @preview. The javac follows the PreviewFeature >>>>>>> annotation, and produces either warnings or errors for the >>>>>>> usages of such APIs. For the @preview tag, there is a taglet in >>>>>>> the JDK build that adds the content of the tag into the >>>>>>> documentation. The first part of the @preview's text goes into >>>>>>> the summary, the second part goes into the detailed description. >>>>>>> >>>>>>> For build, a tricky problem is that the jdk.compiler module uses >>>>>>> the PreviewFeature annotation as well, but that is not in the >>>>>>> bootstrap JDK. So, for the intermediate langtools build, the >>>>>>> PreviewFeature annotation is copied from java.base. >>>>>>> >>>>>>> Proposed webrev: >>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/webrev.00/ >>>>>>> >>>>>>> Javadoc with the change: >>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/index.html >>>>>>> >>>>>>> See for example: >>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/java.base/java/lang/String.html >>>>>>> >>>>>>> http://cr.openjdk.java.net/~jlahoda/8226585/docs.00/api/jdk.compiler/com/sun/source/tree/CaseTree.html >>>>>>> >>>>>>> >>>>>>> JBS: >>>>>>> https://bugs.openjdk.java.net/browse/JDK-8226585 >>>>>>> >>>>>>> CSR: >>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231411 >>>>>>> >>>>>>> Feedback is welcome! >>>>>>> >>>>>>> Thanks, >>>>>>> ???? Jan From chris.hegarty at oracle.com Tue Oct 22 09:41:28 2019 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 22 Oct 2019 10:41:28 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> Message-ID: > On 22 Oct 2019, at 09:51, Maurizio Cimadamore wrote: > > .. > > Let me rephrase. We have Class::getRecordComponents; and we have RecordComponent::accessor. > > What is the need to pass _anything_ to the BSM, other than the record class (e.g. Point.class) AND the method name (e.g. toString) ? > > The BSM can take the .class, and get the components; from there: > > - you can easily derive names > - you can also easily derive accessor MHs (just a lookup away) > > I was _not_ advocating for extracting a name from a direct method handle - that seems brittle, given that the compiler implementation might change, eventually. But doubling down on the reflection API seems the right thing to do? A quick change shows that this simplifies the code a lot ( since there is less arg checking ) http://cr.openjdk.java.net/~chegar/records/ObjectMethods.00/ Q: the TypeDescriptor arg can be used for linking a dynamic constant. Is this still needed? -Chris. -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Oct 22 10:01:47 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 11:01:47 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> Message-ID: <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> Thinking more, I think the fundamental reason as to why the bootstrap method leaves me not 100% convinced is that, on the one hand, ObjectMethods tries hard to be a _general_ helper class, offering a bootstrap method to compute equals/hashCode/toString on _all_ classes, not just records. And, I think, it is because of that generality that the bootstrap method receives a bunch of getter method handles - so that e.g. other language implementation can still use these methods on regular POJOs. But, if this is meant to be a general building block, then I don't understand e.g. why we are unifying all the signatures. If a client wants hashCode, I think it is kind of a design flaw that (i) there's no such BSM with that name (the BSM is just called "bootstrap") and (ii) that there still a requirement to pass a 'name list', which is ignored by the BSM. So, the _general_ building block case seems to push for one BSM per Object method, whereas the record translation use case seems to push towards a single unified BSM. I think we can actually have our cake and eat it too: 1) ObjectMethods could expose several BSMs - one for each Object method, with the _right_ static argument list and names, to make it easy for clients to find them. Of course, for generality, these methods should be expressed in terms of MethodHandle[], since we can't rely on the class being a record 2) We coud add a j.l.Record.bootstrap, which, using core reflection could extract the required ingredients, before delegating to the _right_ BSM in ObjectMethods (e.g. the MH list and the names list) This way we get the best of both worlds: sharp BSMs for clients that just want to implement object methods (which also works on things that are not records); unified BSM which act as a record translation target. Maurizio On 22/10/2019 10:41, Chris Hegarty wrote: > > >> On 22 Oct 2019, at 09:51, Maurizio Cimadamore >> > > wrote: >> >> .. >> >> Let me rephrase. We have Class::getRecordComponents; and we have >> RecordComponent::accessor. >> >> What is the need to pass _anything_ to the BSM, other than the record >> class (e.g. Point.class) AND the method name (e.g. toString) ? >> >> The BSM can take the .class, and get the components; from there: >> >> - you can easily derive names >> - you can also easily derive accessor MHs (just a lookup away) >> >> I was _not_ advocating for extracting a name from a direct method >> handle - that seems brittle, given that the compiler implementation >> might change, eventually. But doubling down on the reflection API >> seems the right thing to do? > > A quick change shows that this simplifies the code a lot ( since there > is less arg checking ) > > http://cr.openjdk.java.net/~chegar/records/ObjectMethods.00/ > > Q: the TypeDescriptor arg can be used for linking a dynamic constant. > Is this still needed? > > -Chris. -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan.reich.maker.of.eye at googlemail.com Tue Oct 22 11:11:22 2019 From: stefan.reich.maker.of.eye at googlemail.com (Stefan Reich) Date: Tue, 22 Oct 2019 13:11:22 +0200 Subject: Possible compiler bug Message-ID: Hi, ok, the class relationships in this example are bit convoluted (I have them for a reason in the original source code), but I still don't see why it would fail to compile. import java.util.Map; class Referenced { } class Base { class Inner { Map map; void bla() { Referenced r = map.get(0); } } } class Derived extends Base { class Inner extends Base.Inner { void bla() { Referenced r = map.get(0); } } } The error message is: Referenced.java:20: error: incompatible types: Object cannot be converted to Referenced Referenced r = map.get(0); Why does the map suddenly lose its type parameters? Many greetings, Stefan -- Stefan Reich BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Oct 22 11:16:16 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 12:16:16 +0100 Subject: Possible compiler bug In-Reply-To: References: Message-ID: The problem is that Derived.Inner extends Base.Inner - which is a raw type. Because of that, Derived.Inner does not inherit 'map' with type Map as you expect, but instead it inherits it raw (Map). Hence the error. To fix, you need to replace the extends clause of Derived.Inner to say? "extends Base.Inner" Maurizio On 22/10/2019 12:11, Stefan Reich wrote: > Hi, ok, the class relationships in this example are bit convoluted (I > have them for a reason in the original source code), but I still don't > see why it would fail to compile. > import java.util.Map; > > class Referenced { > } > > class Base { > > class Inner { > Mapmap; > > void bla() { > Referenced r =map.get(0); > } > } > } > > class Derivedextends Base { > class Innerextends Base.Inner { > void bla() { > Referenced r =map.get(0); > } > } > } > The error message is: > > Referenced.java:20: error: incompatible types: Object cannot be > converted to Referenced > ? ? ? ? ? ? Referenced r = map.get(0); > > Why does the map suddenly?lose its type parameters? > > Many greetings, > Stefan > > -- > Stefan Reich > BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan.reich.maker.of.eye at googlemail.com Tue Oct 22 11:18:47 2019 From: stefan.reich.maker.of.eye at googlemail.com (Stefan Reich) Date: Tue, 22 Oct 2019 13:18:47 +0200 Subject: Possible compiler bug In-Reply-To: References: Message-ID: Hmm... so you're saying all the fields in a base class lose their type parameters when I inherit from the raw base class? That's quite surprising actually. On Tue, 22 Oct 2019 at 13:16, Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > The problem is that Derived.Inner extends Base.Inner - which is a raw type. > > Because of that, Derived.Inner does not inherit 'map' with type > Map as you expect, but instead it inherits it raw > (Map). Hence the error. > > To fix, you need to replace the extends clause of Derived.Inner to say > "extends Base.Inner" > > Maurizio > On 22/10/2019 12:11, Stefan Reich wrote: > > Hi, ok, the class relationships in this example are bit convoluted (I have > them for a reason in the original source code), but I still don't see why > it would fail to compile. > > import java.util.Map; > class Referenced { > } > class Base { > > class Inner { > Map map; > > void bla() { > Referenced r = map.get(0); > } > } > } > class Derived extends Base { > class Inner extends Base.Inner { > void bla() { > Referenced r = map.get(0); > } > } > } > > The error message is: > > Referenced.java:20: error: incompatible types: Object cannot be converted > to Referenced > Referenced r = map.get(0); > > Why does the map suddenly lose its type parameters? > > Many greetings, > Stefan > > -- > Stefan Reich > BotCompany.de // Java-based operating systems > > -- Stefan Reich BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan.reich.maker.of.eye at googlemail.com Tue Oct 22 11:19:55 2019 From: stefan.reich.maker.of.eye at googlemail.com (Stefan Reich) Date: Tue, 22 Oct 2019 13:19:55 +0200 Subject: Possible compiler bug In-Reply-To: References: Message-ID: I was confused because the map's type parameters have nothing to do with either the base, derived or enclosing classes. Be that as it may, your fix works. Thanks! On Tue, 22 Oct 2019 at 13:18, Stefan Reich < stefan.reich.maker.of.eye at googlemail.com> wrote: > Hmm... so you're saying all the fields in a base class lose their type > parameters when I inherit from the raw base class? That's quite surprising > actually. > > On Tue, 22 Oct 2019 at 13:16, Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> The problem is that Derived.Inner extends Base.Inner - which is a raw >> type. >> >> Because of that, Derived.Inner does not inherit 'map' with type >> Map as you expect, but instead it inherits it raw >> (Map). Hence the error. >> >> To fix, you need to replace the extends clause of Derived.Inner to say >> "extends Base.Inner" >> >> Maurizio >> On 22/10/2019 12:11, Stefan Reich wrote: >> >> Hi, ok, the class relationships in this example are bit convoluted (I >> have them for a reason in the original source code), but I still don't see >> why it would fail to compile. >> >> import java.util.Map; >> class Referenced { >> } >> class Base { >> >> class Inner { >> Map map; >> >> void bla() { >> Referenced r = map.get(0); >> } >> } >> } >> class Derived extends Base { >> class Inner extends Base.Inner { >> void bla() { >> Referenced r = map.get(0); >> } >> } >> } >> >> The error message is: >> >> Referenced.java:20: error: incompatible types: Object cannot be converted >> to Referenced >> Referenced r = map.get(0); >> >> Why does the map suddenly lose its type parameters? >> >> Many greetings, >> Stefan >> >> -- >> Stefan Reich >> BotCompany.de // Java-based operating systems >> >> > > -- > Stefan Reich > BotCompany.de // Java-based operating systems > -- Stefan Reich BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Oct 22 11:25:48 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 12:25:48 +0100 Subject: Possible compiler bug In-Reply-To: References: Message-ID: <985137c5-a09e-6dfb-bd38-4320db9b6a35@oracle.com> This is what is specified in the JLS 4. (raw types): https://docs.oracle.com/javase/specs/jls/se13/html/jls-4.html#jls-4.8 More specifically, the combinations of these two bullets: " The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of the parameterizations of the generic type. The type of a constructor (?8.8), instance method (?8.4, ?9.4), or non-static field (?8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C. " Lead to the behavior you observed. I agree that the behavior is surprising, and this has been pointed out in the past. The existing rules are designed to prevent issues when a member of the superclass refer to some of the type variable (if the subclass is raw, the type parameters might be missing!). In cases such as yours, this rule works against you - in the sense that there's no reason to erase the type of 'map' since it doesn't refer to any type variable of Base. But that said, we looked at this issue several times in the past and come away with a feeling that determining in which case the compiler should erase vs. should _not_ erase is trickier than it seems in the general case. Maurizio On 22/10/2019 12:19, Stefan Reich wrote: > I was confused because the map's type parameters have nothing to do > with either the base, derived or enclosing classes. > > Be that as it may, your fix works. Thanks! > > On Tue, 22 Oct 2019 at 13:18, Stefan Reich > > wrote: > > Hmm... so you're saying all the fields in a base class lose their > type parameters when I inherit from the raw base class? That's > quite surprising actually. > > On Tue, 22 Oct 2019 at 13:16, Maurizio Cimadamore > > wrote: > > The problem is that Derived.Inner extends Base.Inner - which > is a raw type. > > Because of that, Derived.Inner does not inherit 'map' with > type Map as you expect, but instead it > inherits it raw (Map). Hence the error. > > To fix, you need to replace the extends clause of > Derived.Inner to say? "extends Base.Inner" > > Maurizio > > On 22/10/2019 12:11, Stefan Reich wrote: >> Hi, ok, the class relationships in this example are bit >> convoluted (I have them for a reason in the original source >> code), but I still don't see why it would fail to compile. >> import java.util.Map; >> >> class Referenced { >> } >> >> class Base { >> >> class Inner { >> Mapmap; >> >> void bla() { >> Referenced r =map.get(0); >> } >> } >> } >> >> class Derivedextends Base { >> class Innerextends Base.Inner { >> void bla() { >> Referenced r =map.get(0); >> } >> } >> } >> The error message is: >> >> Referenced.java:20: error: incompatible types: Object cannot >> be converted to Referenced >> ? ? ? ? ? ? Referenced r = map.get(0); >> >> Why does the map suddenly?lose its type parameters? >> >> Many greetings, >> Stefan >> >> -- >> Stefan Reich >> BotCompany.de // Java-based operating systems > > > > -- > Stefan Reich > BotCompany.de // Java-based operating systems > > > > -- > Stefan Reich > BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan.reich.maker.of.eye at googlemail.com Tue Oct 22 11:26:40 2019 From: stefan.reich.maker.of.eye at googlemail.com (Stefan Reich) Date: Tue, 22 Oct 2019 13:26:40 +0200 Subject: Possible compiler bug In-Reply-To: <985137c5-a09e-6dfb-bd38-4320db9b6a35@oracle.com> References: <985137c5-a09e-6dfb-bd38-4320db9b6a35@oracle.com> Message-ID: I understand, thanks On Tue, 22 Oct 2019 at 13:25, Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > This is what is specified in the JLS 4. (raw types): > > https://docs.oracle.com/javase/specs/jls/se13/html/jls-4.html#jls-4.8 > > More specifically, the combinations of these two bullets: > > " > The superclasses (respectively, superinterfaces) of a raw type are the > erasures of the superclasses (superinterfaces) of any of the > parameterizations of the generic type. > > The type of a constructor (?8.8), instance method (?8.4, ?9.4), or > non-static field (?8.3) of a raw type C that is not inherited from its > superclasses or superinterfaces is the raw type that corresponds to the > erasure of its type in the generic declaration corresponding to C. > " > > Lead to the behavior you observed. > > I agree that the behavior is surprising, and this has been pointed out in > the past. The existing rules are designed to prevent issues when a member > of the superclass refer to some of the type variable (if the subclass is > raw, the type parameters might be missing!). In cases such as yours, this > rule works against you - in the sense that there's no reason to erase the > type of 'map' since it doesn't refer to any type variable of Base. But that > said, we looked at this issue several times in the past and come away with > a feeling that determining in which case the compiler should erase vs. > should _not_ erase is trickier than it seems in the general case. > > Maurizio > > > On 22/10/2019 12:19, Stefan Reich wrote: > > I was confused because the map's type parameters have nothing to do with > either the base, derived or enclosing classes. > > Be that as it may, your fix works. Thanks! > > On Tue, 22 Oct 2019 at 13:18, Stefan Reich < > stefan.reich.maker.of.eye at googlemail.com> wrote: > >> Hmm... so you're saying all the fields in a base class lose their type >> parameters when I inherit from the raw base class? That's quite surprising >> actually. >> >> On Tue, 22 Oct 2019 at 13:16, Maurizio Cimadamore < >> maurizio.cimadamore at oracle.com> wrote: >> >>> The problem is that Derived.Inner extends Base.Inner - which is a raw >>> type. >>> >>> Because of that, Derived.Inner does not inherit 'map' with type >>> Map as you expect, but instead it inherits it raw >>> (Map). Hence the error. >>> >>> To fix, you need to replace the extends clause of Derived.Inner to say >>> "extends Base.Inner" >>> >>> Maurizio >>> On 22/10/2019 12:11, Stefan Reich wrote: >>> >>> Hi, ok, the class relationships in this example are bit convoluted (I >>> have them for a reason in the original source code), but I still don't see >>> why it would fail to compile. >>> >>> import java.util.Map; >>> class Referenced { >>> } >>> class Base { >>> >>> class Inner { >>> Map map; >>> >>> void bla() { >>> Referenced r = map.get(0); >>> } >>> } >>> } >>> class Derived extends Base { >>> class Inner extends Base.Inner { >>> void bla() { >>> Referenced r = map.get(0); >>> } >>> } >>> } >>> >>> The error message is: >>> >>> Referenced.java:20: error: incompatible types: Object cannot be >>> converted to Referenced >>> Referenced r = map.get(0); >>> >>> Why does the map suddenly lose its type parameters? >>> >>> Many greetings, >>> Stefan >>> >>> -- >>> Stefan Reich >>> BotCompany.de // Java-based operating systems >>> >>> >> >> -- >> Stefan Reich >> BotCompany.de // Java-based operating systems >> > > > -- > Stefan Reich > BotCompany.de // Java-based operating systems > > -- Stefan Reich BotCompany.de // Java-based operating systems -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.hegarty at oracle.com Tue Oct 22 12:44:14 2019 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 22 Oct 2019 13:44:14 +0100 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> Message-ID: > On 21 Oct 2019, at 22:10, Vicente Romero wrote: > > Hi, > > Please review the reflection code for JEP 359 (Records) at [1]. There is a class here that is special [2] this contain the bootstrap methods for equals, hashCode and toString methods in records. > > Thanks in advance for the feedback, > Vicente > > [1] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/ A few minor comments to get out of the way: 1) missing license header, and 2) missing @since javadoc tag Pushed to the records branch: https://hg.openjdk.java.net/amber/amber/rev/31b6ebe43579 -Chris. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Tue Oct 22 15:21:19 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 22 Oct 2019 17:21:19 +0200 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> Message-ID: <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Hi, In addition to Maurizio's comments, a few more comments: -for tests, "--enable-preview -source 14" is used on many places. This will cause issues when JDK 15 is started (and --enable-preview -source 14 will be replaced with --enable-preview -source 15). On all places where that is possible, "--enable-preview -source ${jdk.version}" should be used, or a programmatic equivalent. -for code like this: ---$ cat R.java public record R(int i) {} --- compiling without --enable-preview: --- $ javac R.java /tmp/R.java:1: error: class, interface, or enum expected public record R(int i) {} ^ 1 error --- it would be nice if we could provide some helpful note that to get support for records, --enable-preview needs to be used. It may not be possible to embed that into the error esp. for nested records, but at least a warning. Just so that the user would get a hint what they are doing wrong if records don't work for them. -in Flags, it would be nice to document on which Symbols given flag may appear. That would be useful in order to partition the Flags into separate Symbol-kind specific sub-sets. -in Lower, there is method "recordVars, which looks at the superclasses of a record, to see if these have a state component - is a record superclass of a record allowed? (I thought it isn't.) -there seem to be commented debugs in Check, like: + //System.out.println("at Check.validateAnnotation: flags: " + Flags.toString(s.flags_field) + ", declaration tree " + declarationTree); Ideally, these would be removed -in: test/langtools/tools/javac/launcher/SourceLauncherTest.javathere are changes like: - file + ":1: error: class, interface, or enum expected\n" + + file + ":1: error: class, interface, enum expected\n" + are these intentional? These seem suspicious to me. -in: test/langtools/tools/javac/processing/model/element/TestRecord.java and: test/langtools/tools/javac/processing/model/element/TestRecordDesugar.java there is @bug 8888888 - that seems like a placeholder number. Thanks, Jan On 21. 10. 19 22:44, Maurizio Cimadamore wrote: > And here are some comments on Lower > > - findMethodOrFailSilently? doesn't seem to be used anywhere; this > should be removed and associated changes in Resolve reverted > > - findUserDefinedAccessors - this seems to have to do with setting the > record component symbol straight - this should happen well before Lower, > otherwise I'm not even sure what annotations processor will see? This > code should go in TypeEnter, where you already look up for existing > accessor. > > - related; not 100% as to why in visitRecordDef you protect against > accessor not being there - which means you need to do a lookup. You need > to get to this part of the code where all accessors have been set. Then > the code can be simplified. > > - As pointed out previously, getting rid of the Pair > accessor will result in cascading simplification in few methods in Lower > too > > - both the signature generator and the indy machinery are shared between > LambdaToMethod and Lower - so we should probably put them somewhere in a > common superclass which can be used by the various backend steps > > - I guess the main translation strategy for record members is to > generate an indy - where the runtime gives you back some constant > callsite which wraps a method handle with the right signature. If so, > some comments should be sprinkled around to clarify that this is indeed > the case. > > - I also guess that the if/else in generateRecordMethod is to avoid > generating a tree if an explicit member has been declared by the user - > again, correct, but some comments please ;-) > > > Also some comments? on tests: > > * test/langtools/tools/javac/6402516/CheckLocalElements.java - why the > change? > > * test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java - > why the change from @run to @compile? > > * > test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java > - who is using the new target? > > * diags/** in general, for all new diagnostics added it would be nice to > have an html of the output (I have a script for doing that, let me know > if you need it) > > * examples-not-yet - why no test for local records? That should be easy > to add (I hope)? > > * test/langtools/tools/javac/parser/JavacParserTest.java - here I wonder > if we should have different messages depending on the version (eg. we > don't want to say 'expected records' if compiling with -source 12?) > > *? test/langtools/tools/javac/tree/JavacTreeScannerTest.java, > test/langtools/tools/javac/tree/SourceTreeScannerTest.java, > src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java - > seems like these probably depend on the accessor pairs being in the AST? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - not sure about > this, does it even belong to this patch? I'd be surprised if DocTree > does anything special with accessors? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - this tests > that ElementFilter and getAccessor() agree, but doesn't test that they > actually yield the correct result > > * more generally, certain tests (e.g. signature mismatches, record > component names order mismatches, reflection tests, serialization tests) > have a certain ad-hoc nature to them - in the sense that they test one > record shape or two and that's it. E.g. > > test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java > > > I'd like to see a more combinatorial-oriented approach to such tests, > where at least we tests all primitive types plus a reference type of > choice, with varying degrees of arity (and w/, w/o varargs). > > > That's all for now > > Thanks > Maurizio > > On 21/10/2019 19:01, Maurizio Cimadamore wrote: >> Hi Vicente, >> I did a pretty thorough pass on most of the code. I didn't look at >> tests, and I also didn't look at Lower. Comments below: >> >> * Flags.java - VARARGS flag for records components; I wonder, instead >> of a new flag, can we use the internal VARARGS flag we have for >> methods, and attach that to the record symbol? That should also lead >> to more direct code in TypeHelper >> >> * Symbol.java - I think the override for 'erasure' is redundant - >> isn't that the impl from supertype? >> >> * Symbol.java (and others) in general this webrev shuld be updated as >> soon as Jan push the @Preview work, as I see that methods implementing >> preview API are using the 'deprecate for removal' annotation >> >> * Symbol.java - I wonder if accessor list with Pair >> isn't a premature generalization; we should just add a getter symbol >> and that's it >> >> * Attr.java - I think we might want to leave the door open for a check >> which forces all constructors of a record to go through the canonical >> one (depending on where the spec lands) >> >> * Check.java - understanding checkpoint: when we see an annotation on >> a record component, first we check it's one of the kinds which are >> allowed (if not, error), and, if it's allowed, we add all record >> component annotations to record component elements, and we also filter >> away all annotations that have nothing to do with the element in which >> they appear. If my understanding is correct, I think this logic should >> be documented more clearly; I found the comment after the "if >> (isRecordField)" to be a bit obscure. >> >> * Enter.java - why are you removing the static flag on records? I >> don't see anything similar around for enums. >> >> * Flow.java - not sure I get the changes to checkInit; typically >> checkInit is called at the use-site of DA/DU variables. Here it seems >> you suppress some of the errors emitted for accessing record fields >> inside the canonical constructor - but I hope that code like this >> >> record Foo(int x) { >> ?? Foo(int x) { >> ?????? print(this.x); >> ?? } >> } >> >> Still give errors? If this works correctly, which errors does the >> 'guard' around the error generation is supposed to protect against? >> >> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used >> here... >> >> * TypeEnter.java - implicit super calls are added in Attr::visitMethod >> for regular calls; we should do the same for records (or add all in >> TypeEnter - that is records and class should be consistent) >> >> * TypeEnter.java - on finishClass - you are calling memberEnter on >> record fields, which I think you already did in the new RecordsPhase >> >> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >> with _all_ record members (e.g. including accessors), not just some? >> >> * TypeEnter.java - checkForSerializationMember should probably be >> moved to MemberEnter::visitVar, or even to Attr (note that the code >> for the check is doing a little visit :-)) >> >> * TypeEnter.java - again on check timings; while it's ok for the code >> in here to add new synthetic members, I think it's less ok to add more >> global error checks (such as make sure that the canonical declaration >> whose parameter names match the record components in order); these >> should live in Attr. More generally, I think that we should only check >> stuff here if we think that the check will add any value to annotation >> processing. Every other check can be deferred, and take place in a >> more 'deterministic' part of javac. >> >> * TypeEnter.java - I think finishClass should be a bit better at >> determining as to whether default constructor is needed or not - for >> instance, this check: >> >> if ((sym.flags() & INTERFACE) == 0 && >> ?928???????????????? !TreeInfo.hasConstructors(tree.defs)) { >> >> Should be generalized to something that works for both classes and >> records; for classes you need to check if there's no other >> constructor; for records you need to check if there's no other >> constructor _with same signature_ as the canonical one. Then you can >> simplify addRecordMembers and remove the dependency on the boolean >> 'generatedConstructor' parameter. In other words the code should: >> >> 1) check if default/canonical constructor generation is required >> 2) if so, use the appropriate helper to generate the code >> 3) at the end, add the remaining record members (under the assumption >> that the canonical constructor has already been added in (1), if that >> was missing) >> >> *TypeEnter.java - addAccessor can be simplified if we only worry about >> getters. Again, the checks in here feel more Attr check than >> MemberEnter checks. >> >> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >> create a tree for a member, and then we visit the member tree with >> memberEnter, just to add it to the scope. I understand that, currently >> addEnumMembers does the same, but this looks very roundabout; I wonder >> if there's a way to make all this process a bit simpler - create a >> symbol and add that to the scope. Or are there important checks in >> MemberEnter that we would lose? >> >> *JCTree.java/TreeMaker.java - I don't think there's any need to store >> accessors in the field AST; these are only used from TypeEnter, and >> TypeEnter can do whatever it does by looking at which record >> components there are in the record class, and add a getter for each. >> Let's make the code simpler and more direct >> >> * ClassReader.java - should we just silently ignore record attributes >> when not in preview mode - or should we issue classfile errors? >> >> * ClassReader.java - what kind of validation should we do on record >> attributes? Currently javac does nothing. Should we check that we have >> (i) getters (ii) toString/hashCode/equals implementations and (iii) a >> canonical constructor (ad fail if we don't) ? At the very least I >> would add code to _parse_ the attribute, even if we do nothing with >> it, so that at least we throw a classfile error if the attribute is >> badly broken >> >> * Tokens.java - for "var", "yields" and other context-dependent >> keywords we never added a token. We just handled that in JavacParser. >> Why the difference here? I think it's best to stick to current style >> and maybe fix all of them (assuming that's what we want to do) in a >> followup cleanup. Actually, after looking at parser, it seems like you >> already handle that manually, so I just suggest to revert the changed >> to Tokens >> >> * TreeInfo.java - how is 'isCanonicalConstructor' not returning 'true' >> for all constructors inside a record, as opposed to only return true >> for the canonical one? >> >> * TreeInfo.java - There is some code reuse possible between >> "recordFieldTypes" and "recordFields" >> >> * Names.java - what is 'oldEquals' ? >> >> * JavacParser.java - timing of checks; I don't think we should check >> for illegal record component names in here >> >> * JavacParser.java - code can be simplified somewhat by getting rid of >> accessors in VarDef AST. >> >> >> >> >> >> On 21/10/2019 13:31, Vicente Romero wrote: >>> Hi, >>> >>> Please review the compiler code for JEP 359 (Records) [1] >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From jan.lahoda at oracle.com Tue Oct 22 15:27:26 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 22 Oct 2019 17:27:26 +0200 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: References: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> <8821e763-d28b-8648-c8c9-1f3531fcf3a8@oracle.com> Message-ID: <2f4419d4-f3b5-40d6-9a18-7f8e8537b4f7@oracle.com> Hi, A new draft of the pattern matching for instanceof has been published here: https://mail.openjdk.java.net/pipermail/amber-dev/2019-October/004962.html A significant change in this draft is that safe(*) reifiable types are allowed in instanceof of. And updated version of the pattern matching patch for javac which supports this change is here: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.03/ A diff from the previous revision: http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.02-03/ (*) reifiable types are allowed if (for "expr instanceof type"), "expr" can be cast to "type" without unchecked warnings. Does this make sense? Thanks, Jan On 15. 10. 19 15:02, Maurizio Cimadamore wrote: > Yep - that would be more helpful (at least to me) > > Thanks > Maurizio > > On 15/10/2019 13:56, Jan Lahoda wrote: >> Would this be better? >> >> Full patch: >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.02/ >> >> Diff from previous: >> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.01-02/ >> >> Thanks, >> ??? Jan >> >> On 15. 10. 19 13:59, Maurizio Cimadamore wrote: >>> Hi, >>> the flow changes look good - I think the TransPattern documentation >>> should contain less text and more code snippet examples which show >>> what the generated code looks like (as I've tried to do in my email, >>> and as you've done for visitTypeTest). In other words, what is >>> missing here is "the big picture" which shows what are the main ideas >>> behind the translation strategy. >>> >>> Specific example: decorateExpression: >>> >>> + //if there are binding variables defined and used only in this >>> expression, >>> + //which are not confined to a specific sub-expression, >>> + //a let expression is created which replaces the statement, and >>> + //the binding variables are hoisted into this let expression: >>> >>> >>> This kind of illustrates my point: >>> >>> * "if there are binding variables defined and used only in this >>> expression, which are not confined to a specific sub-expression" is >>> very convoluted, and will be almost meaningless when we pick up this >>> code again in 6 months >>> * "a let expression is created which replaces the statement" - >>> statement? Probably cut and paste error >>> >>> Thanks >>> Maurizio >>> >>> On 15/10/2019 10:46, Jan Lahoda wrote: >>>> Hi, >>>> >>>> I've updated the patch with the Flow changes and with additional >>>> comments in TransPatterns here: >>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ >>>> diff from previous: >>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ >>>> >>>> An additional patch (that would apply on top of this one) which >>>> makes all instanceof instances to be modelled as instanceof : >>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ >>>> >>>> Some more comment inline. >>>> >>>> On 10. 10. 19 17:33, Maurizio Cimadamore wrote: >>>>> Hi Jan, >>>>> the code looks generally very clean, kudos. >>>>> >>>>> Some general comments: >>>>> >>>>> * looking at the spec, it seems like both "instanceof T" and >>>>> "instanceof T t" are cases of type test patterns. I guess I'm fine >>>>> with the implementation doing what it always did in terms of plain >>>>> "instanceof T", but I'm worried about the intersection between this >>>>> and e.g. the tree API - InstanceofTree::getPattern returns null in >>>>> cases like "instanceof T"; now, I know I know that we're speaking >>>>> about a JDK specific API, but I think this issue reveals some >>>>> modelling issues in the way we treat instanceof, and I'm worried >>>>> that some of these issues might pop up in the future. I'd prefer to >>>>> either rectify the spec so that plain 'instanceof T' is not a >>>>> pattern matching instanceof, or rectify javac so that these tests >>>>> are internally also represented with patterns (at the expense of >>>>> some extra allocation, perhaps). >>>>> >>>>> * If I'm not mistaken the only use for the "MATCH_BINDING_TO_OUTER" >>>>> flag is to be able to distinguish between regular 'expression-wide' >>>>> bindings, and bindings which 'leaked' outside a statement (e.g. an >>>>> if statement). And the reason you need to distinguish between these >>>>> is that you don't want Check::checkUnique to flag duplicate errors >>>>> between regular 'expression-wide' bindings, which are reported >>>>> elsewhere (MatchBindingsComputer). But this is also, more >>>>> crucially, used in TransPattern, where the 'isPreserved' flag is >>>>> used to control whether a variable decl for the binding variable >>>>> should be 'lifted' to the enclosing statement context or not. Is my >>>>> understanding correct here? >>>> >>>> Yes, the primary intent is to mark variables that need to be hoisted >>>> to the parent of the current statement. >>>> >>>>> >>>>> * The idea behind TransPatterns seems to be: when we process a >>>>> statement, or an expression, we attempt to add all declaration for >>>>> the bindings that are used inside the statements/expression >>>>> upfront. If we are processing a statement, then we surround the >>>>> results in a block; e.g. >>>>> >>>>> if (obj instanceof Foo f) { >>>>> ?? ... >>>>> } >>>>> >>>>> becomes >>>>> >>>>> { >>>>> ??? Foo f$; >>>>> ??? if (let Object temp = obj in (obj instanceof Foo && (f$ = >>>>> (Foo)temp) == temp) { >>>>> ?????? ... >>>>> } >>>>> >>>>> If we are processing an expression, we instead generate a LetExpr, >>>>> e.g. >>>>> >>>>> boolean b = obj instanceof Foo t && t.equals(foo); >>>>> >>>>> becomes: >>>>> >>>>> boolean b = let Foo f$ = null in ((let Object temp = obj in (obj >>>>> instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) >>>>> >>>>> So, sometimes the hoisted var is a real var decl in a block, other >>>>> times is a var decl inside a let expression. In these cases we have >>>>> to generate an initializer, to set the value (which might be used >>>>> later). >>>> >>>> The hoisted vars do not have an initializer (they used to have one, >>>> but it is both unnecessary and was masking out bugs, so I have >>>> removed it). But I see I've forgot the initializer code commented >>>> out in TransPatterns, removed in the updated version to avoid >>>> confusion. >>>> >>>>> On top of that, instanceof generates its own letExpr to cache the >>>>> target of the test (to avoid double computation). >>>>> >>>>> It also seems to me that the code handles cases where the binding >>>>> variable is not used, neither hoisted - e.g. >>>>> >>>>> boolean field = obj instanceof Foo t; >>>>> >>>>> In this case we generate a plain instanceof w/o the init (because >>>>> the 't' variable hasn't been hoisted anywhere). >>>>> >>>>> Finally, we use the 'isPreserved()' flag to ensure that variables >>>>> are hoisted correctly - for instance, if something is to be >>>>> preserved (and the enclosing context allows for it) we push things >>>>> in the enclosing context instead. >>>>> >>>>> Am I getting the correct picture here? >>>> >>>> Yes, I think it is correct. >>>> >>>>> >>>>> It would be nice to have more javadoc spread around to help the >>>>> reader understand what's the rationale and show some snippet of >>>>> generated code. >>>>> >>>>> * Flow, I wonder if, like you had created SnippetAliveAnalyzer, >>>>> creating a SnippetBreakAnalyzer would help you avoid the >>>>> breaksOut[0] trick (that could become a field in the child visitor) >>>> >>>> I tried to do these two in the updated patch. >>>> >>>> Thanks for the comments! >>>> >>>> Jan >>>> >>>>> >>>>> >>>>> Other than that, it looks very good. >>>>> >>>>> Maurizio >>>>> >>>>> On 10/10/2019 13:12, Jan Lahoda wrote: >>>>>> Hi, >>>>>> >>>>>> As part of the effort to prepare JEP 305: Pattern Matching for >>>>>> instanceof (Preview) for Propose to Target, I would like to ask >>>>>> for a code review for the corresponding javac changes. >>>>>> >>>>>> The webrev is here: >>>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >>>>>> >>>>>> The patch applies on top of: >>>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >>>>>> >>>>>> >>>>>> The current spec the patch is striving to implements is here: >>>>>> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >>>>>> >>>>>> >>>>>> As far as I know, there is one (significant) open issue in the >>>>>> spec, and that is whether non-reifiable types should be allowed in >>>>>> "instanceof ". Currently (AFAIK), the spec does >>>>>> not allow non-reifiable types in the type test pattern in >>>>>> instanceof, and the javac implementation should be consistent with >>>>>> the spec. Should the spec change, the corresponding update to the >>>>>> javac code should have a very limited impact. >>>>>> >>>>>> I'll be preparing a CSR for this change in the coming days. >>>>>> >>>>>> The JBS issue for this code change is: >>>>>> https://bugs.openjdk.java.net/browse/JDK-8231826 >>>>>> >>>>>> Any feedback is welcome! >>>>>> >>>>>> Thanks! >>>>>> ??? Jan From maurizio.cimadamore at oracle.com Tue Oct 22 16:20:14 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 17:20:14 +0100 Subject: RFR: JDK-8231826: Implement javac changes for pattern matching for instanceof In-Reply-To: <2f4419d4-f3b5-40d6-9a18-7f8e8537b4f7@oracle.com> References: <82fed943-bd28-f0ae-fe9c-645d1f3160c6@oracle.com> <9b6820ff-9a93-31cb-0b51-367d8337fa7f@oracle.com> <8821e763-d28b-8648-c8c9-1f3531fcf3a8@oracle.com> <2f4419d4-f3b5-40d6-9a18-7f8e8537b4f7@oracle.com> Message-ID: Looks good Maurizio On 22/10/2019 16:27, Jan Lahoda wrote: > Hi, > > A new draft of the pattern matching for instanceof has been published > here: > https://mail.openjdk.java.net/pipermail/amber-dev/2019-October/004962.html > > > A significant change in this draft is that safe(*) reifiable types are > allowed in instanceof of. And updated version of the pattern matching > patch for javac which supports this change is here: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.03/ > > A diff from the previous revision: > http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.02-03/ > > (*) reifiable types are allowed if (for "expr instanceof type"), > "expr" can be cast to "type" without unchecked warnings. > > Does this make sense? > > Thanks, > ??? Jan > > On 15. 10. 19 15:02, Maurizio Cimadamore wrote: >> Yep - that would be more helpful (at least to me) >> >> Thanks >> Maurizio >> >> On 15/10/2019 13:56, Jan Lahoda wrote: >>> Would this be better? >>> >>> Full patch: >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.02/ >>> >>> Diff from previous: >>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.01-02/ >>> >>> Thanks, >>> ??? Jan >>> >>> On 15. 10. 19 13:59, Maurizio Cimadamore wrote: >>>> Hi, >>>> the flow changes look good - I think the TransPattern documentation >>>> should contain less text and more code snippet examples which show >>>> what the generated code looks like (as I've tried to do in my >>>> email, and as you've done for visitTypeTest). In other words, what >>>> is missing here is "the big picture" which shows what are the main >>>> ideas behind the translation strategy. >>>> >>>> Specific example: decorateExpression: >>>> >>>> + //if there are binding variables defined and used only in this >>>> expression, >>>> + //which are not confined to a specific sub-expression, >>>> + //a let expression is created which replaces the statement, and >>>> + //the binding variables are hoisted into this let expression: >>>> >>>> >>>> This kind of illustrates my point: >>>> >>>> * "if there are binding variables defined and used only in this >>>> expression, which are not confined to a specific sub-expression" is >>>> very convoluted, and will be almost meaningless when we pick up >>>> this code again in 6 months >>>> * "a let expression is created which replaces the statement" - >>>> statement? Probably cut and paste error >>>> >>>> Thanks >>>> Maurizio >>>> >>>> On 15/10/2019 10:46, Jan Lahoda wrote: >>>>> Hi, >>>>> >>>>> I've updated the patch with the Flow changes and with additional >>>>> comments in TransPatterns here: >>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01/ >>>>> diff from previous: >>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.delta.00-01/ >>>>> >>>>> An additional patch (that would apply on top of this one) which >>>>> makes all instanceof instances to be modelled as instanceof >>>>> : >>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.01.unify.instanceof/ >>>>> >>>>> >>>>> Some more comment inline. >>>>> >>>>> On 10. 10. 19 17:33, Maurizio Cimadamore wrote: >>>>>> Hi Jan, >>>>>> the code looks generally very clean, kudos. >>>>>> >>>>>> Some general comments: >>>>>> >>>>>> * looking at the spec, it seems like both "instanceof T" and >>>>>> "instanceof T t" are cases of type test patterns. I guess I'm >>>>>> fine with the implementation doing what it always did in terms of >>>>>> plain "instanceof T", but I'm worried about the intersection >>>>>> between this and e.g. the tree API - InstanceofTree::getPattern >>>>>> returns null in cases like "instanceof T"; now, I know I know >>>>>> that we're speaking about a JDK specific API, but I think this >>>>>> issue reveals some modelling issues in the way we treat >>>>>> instanceof, and I'm worried that some of these issues might pop >>>>>> up in the future. I'd prefer to either rectify the spec so that >>>>>> plain 'instanceof T' is not a pattern matching instanceof, or >>>>>> rectify javac so that these tests are internally also represented >>>>>> with patterns (at the expense of some extra allocation, perhaps). >>>>>> >>>>>> * If I'm not mistaken the only use for the >>>>>> "MATCH_BINDING_TO_OUTER" flag is to be able to distinguish >>>>>> between regular 'expression-wide' bindings, and bindings which >>>>>> 'leaked' outside a statement (e.g. an if statement). And the >>>>>> reason you need to distinguish between these is that you don't >>>>>> want Check::checkUnique to flag duplicate errors between regular >>>>>> 'expression-wide' bindings, which are reported elsewhere >>>>>> (MatchBindingsComputer). But this is also, more crucially, used >>>>>> in TransPattern, where the 'isPreserved' flag is used to control >>>>>> whether a variable decl for the binding variable should be >>>>>> 'lifted' to the enclosing statement context or not. Is my >>>>>> understanding correct here? >>>>> >>>>> Yes, the primary intent is to mark variables that need to be >>>>> hoisted to the parent of the current statement. >>>>> >>>>>> >>>>>> * The idea behind TransPatterns seems to be: when we process a >>>>>> statement, or an expression, we attempt to add all declaration >>>>>> for the bindings that are used inside the statements/expression >>>>>> upfront. If we are processing a statement, then we surround the >>>>>> results in a block; e.g. >>>>>> >>>>>> if (obj instanceof Foo f) { >>>>>> ?? ... >>>>>> } >>>>>> >>>>>> becomes >>>>>> >>>>>> { >>>>>> ??? Foo f$; >>>>>> ??? if (let Object temp = obj in (obj instanceof Foo && (f$ = >>>>>> (Foo)temp) == temp) { >>>>>> ?????? ... >>>>>> } >>>>>> >>>>>> If we are processing an expression, we instead generate a >>>>>> LetExpr, e.g. >>>>>> >>>>>> boolean b = obj instanceof Foo t && t.equals(foo); >>>>>> >>>>>> becomes: >>>>>> >>>>>> boolean b = let Foo f$ = null in ((let Object temp = obj in (obj >>>>>> instanceof Foo && (f$ = (Foo)temp) == temp) && f$.equals(foo)) >>>>>> >>>>>> So, sometimes the hoisted var is a real var decl in a block, >>>>>> other times is a var decl inside a let expression. In these cases >>>>>> we have to generate an initializer, to set the value (which might >>>>>> be used later). >>>>> >>>>> The hoisted vars do not have an initializer (they used to have >>>>> one, but it is both unnecessary and was masking out bugs, so I >>>>> have removed it). But I see I've forgot the initializer code >>>>> commented out in TransPatterns, removed in the updated version to >>>>> avoid confusion. >>>>> >>>>>> On top of that, instanceof generates its own letExpr to cache the >>>>>> target of the test (to avoid double computation). >>>>>> >>>>>> It also seems to me that the code handles cases where the binding >>>>>> variable is not used, neither hoisted - e.g. >>>>>> >>>>>> boolean field = obj instanceof Foo t; >>>>>> >>>>>> In this case we generate a plain instanceof w/o the init (because >>>>>> the 't' variable hasn't been hoisted anywhere). >>>>>> >>>>>> Finally, we use the 'isPreserved()' flag to ensure that variables >>>>>> are hoisted correctly - for instance, if something is to be >>>>>> preserved (and the enclosing context allows for it) we push >>>>>> things in the enclosing context instead. >>>>>> >>>>>> Am I getting the correct picture here? >>>>> >>>>> Yes, I think it is correct. >>>>> >>>>>> >>>>>> It would be nice to have more javadoc spread around to help the >>>>>> reader understand what's the rationale and show some snippet of >>>>>> generated code. >>>>>> >>>>>> * Flow, I wonder if, like you had created SnippetAliveAnalyzer, >>>>>> creating a SnippetBreakAnalyzer would help you avoid the >>>>>> breaksOut[0] trick (that could become a field in the child visitor) >>>>> >>>>> I tried to do these two in the updated patch. >>>>> >>>>> Thanks for the comments! >>>>> >>>>> Jan >>>>> >>>>>> >>>>>> >>>>>> Other than that, it looks very good. >>>>>> >>>>>> Maurizio >>>>>> >>>>>> On 10/10/2019 13:12, Jan Lahoda wrote: >>>>>>> Hi, >>>>>>> >>>>>>> As part of the effort to prepare JEP 305: Pattern Matching for >>>>>>> instanceof (Preview) for Propose to Target, I would like to ask >>>>>>> for a code review for the corresponding javac changes. >>>>>>> >>>>>>> The webrev is here: >>>>>>> http://cr.openjdk.java.net/~jlahoda/8231826/webrev.00/ >>>>>>> >>>>>>> The patch applies on top of: >>>>>>> https://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013727.html >>>>>>> >>>>>>> >>>>>>> The current spec the patch is striving to implements is here: >>>>>>> http://cr.openjdk.java.net/~gbierman/jep305/jep305-20190918/specs/patterns-instanceof-jls.html >>>>>>> >>>>>>> >>>>>>> As far as I know, there is one (significant) open issue in the >>>>>>> spec, and that is whether non-reifiable types should be allowed >>>>>>> in "instanceof ". Currently (AFAIK), the spec >>>>>>> does not allow non-reifiable types in the type test pattern in >>>>>>> instanceof, and the javac implementation should be consistent >>>>>>> with the spec. Should the spec change, the corresponding update >>>>>>> to the javac code should have a very limited impact. >>>>>>> >>>>>>> I'll be preparing a CSR for this change in the coming days. >>>>>>> >>>>>>> The JBS issue for this code change is: >>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231826 >>>>>>> >>>>>>> Any feedback is welcome! >>>>>>> >>>>>>> Thanks! >>>>>>> ??? Jan From brian.goetz at oracle.com Tue Oct 22 16:26:56 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 Oct 2019 12:26:56 -0400 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> Message-ID: > The class ObjectMethods is in the package java.lang.invoke if you take a look to the source but in the package java.lang.runtime if you trust the webrev. > > It should be in java.lang.invoke so Claes (or someone else) will be able to optimize it later, otherwise if we want to use an internal non public MethodHandle, > we will have to rely on a special SharedSecret class. No. Going forward, _all_ language-support runtime is moving to java.lang.runtime. We got where we are today honestly, first by putting LambdaMetafactory there, and then string concat, but going forward, JLI is not the place for the language support runtime, and we need to reverse this trend. JLI is for the java.lang.invoke implementation. We?re in the process of disentangling the dependence of LMF and string concat on JLI internals. > I propose the following design to fix these issues: > All invokedynamic should takes the same constant dynamic as parameters typed as an Object. > This object should be an instance of an internal class of ObjectMethods (let say RecordMirror) created or populated by the VM from the Record attribute, from inside the constant dynamic BSM, so there will be only one upcall and one downcall instead of one upcall per getter. I think you?re suggesting something like: interface ObjectMethodsMirror { int numParams(); String paramName(int n); MethodHandle paramAccessor(int n); } or something similar? And then some code to derive such a thing from a record? I don?t intrinsically object to this approach, but I?m also not entirely convinced. Don?t forget, this is not just for records. Value types, and other language compilers that have similar mechanisms, may want to use this as well, so anything with ?record? in the name is likely wrong. > This class can store the property names using the StringConcatFactory format and all the getters (the constant method handles). Aligning the name format is reasonable. > So the bootstrap method is just: > public static Object bootstrap(Lookup lookup, String methodName, TypeDescriptor type, Object recordMirrorObject) BZZT, you used the R-word :) If w?ere going this way, I would much prefer to use an interface. Then we need a condy bootstrap to serve up the mirror ? the sensible version of which, hmm, looks a lot like the current bootstrap?. From forax at univ-mlv.fr Tue Oct 22 16:28:57 2019 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 22 Oct 2019 18:28:57 +0200 (CEST) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> Message-ID: <1949854612.811379.1571761737354.JavaMail.zimbra@u-pem.fr> Maurizio, This seems a good idea to separate the API in (1) and (2). I think the BSM of (1) should return a MethodHandle instead of a CallSite and don't have a be real BSM but an API method that can be called by a BSM (see below). There is still an issue with (2). As i understand you will have to extract the ingredients each time you call the BSM, so once for each toString/equals/hashCode instead of once for all of them. To be able to share the extraction of the ingredients, the simplest way is to have a contstant dynamic that create an instance of the class that will contains the ingredient (i wonder if there is a bonus point to use a record class for that :) ) so the ingredients are extracted once and stored in an opaque object in the constant pool then each invokedynamic call inside toString/equals/hashCode can take that object as their argument. And for the trick to return a constant method handle because in the future maybe we will be able to use a MethodHandle instead of a ConstantCallSite + a MethodHandle, the BSM (2) should have a relaxed signature (return an Object) but the implementation doesn't have to support that now and when we will need it, it believe the best way to do that will be to document that in the future this BSM may return a MethodHandle instead of a CallSite so user code should be ready to deal with that. R?mi > De: "Maurizio Cimadamore" > ?: "Chris Hegarty" > Cc: "Remi Forax" , "amber-dev" , > "compiler-dev" > Envoy?: Mardi 22 Octobre 2019 12:01:47 > Objet: Re: RFR: JEP 359-Records: reflection code > Thinking more, > I think the fundamental reason as to why the bootstrap method leaves me not 100% > convinced is that, on the one hand, ObjectMethods tries hard to be a _general_ > helper class, offering a bootstrap method to compute equals/hashCode/toString > on _all_ classes, not just records. And, I think, it is because of that > generality that the bootstrap method receives a bunch of getter method handles > - so that e.g. other language implementation can still use these methods on > regular POJOs. > But, if this is meant to be a general building block, then I don't understand > e.g. why we are unifying all the signatures. If a client wants hashCode, I > think it is kind of a design flaw that (i) there's no such BSM with that name > (the BSM is just called "bootstrap") and (ii) that there still a requirement to > pass a 'name list', which is ignored by the BSM. > So, the _general_ building block case seems to push for one BSM per Object > method, whereas the record translation use case seems to push towards a single > unified BSM. > I think we can actually have our cake and eat it too: > 1) ObjectMethods could expose several BSMs - one for each Object method, with > the _right_ static argument list and names, to make it easy for clients to find > them. Of course, for generality, these methods should be expressed in terms of > MethodHandle[], since we can't rely on the class being a record > 2) We coud add a j.l.Record.bootstrap, which, using core reflection could > extract the required ingredients, before delegating to the _right_ BSM in > ObjectMethods (e.g. the MH list and the names list) > This way we get the best of both worlds: sharp BSMs for clients that just want > to implement object methods (which also works on things that are not records); > unified BSM which act as a record translation target. > Maurizio > On 22/10/2019 10:41, Chris Hegarty wrote: >>> On 22 Oct 2019, at 09:51, Maurizio Cimadamore < [ >>> mailto:maurizio.cimadamore at oracle.com | maurizio.cimadamore at oracle.com ] > >>> wrote: >>> .. >>> Let me rephrase. We have Class::getRecordComponents; and we have >>> RecordComponent::accessor. >>> What is the need to pass _anything_ to the BSM, other than the record class >>> (e.g. Point.class) AND the method name (e.g. toString) ? >>> The BSM can take the .class, and get the components; from there: >>> - you can easily derive names >>> - you can also easily derive accessor MHs (just a lookup away) >>> I was _not_ advocating for extracting a name from a direct method handle - that >>> seems brittle, given that the compiler implementation might change, eventually. >>> But doubling down on the reflection API seems the right thing to do? >> A quick change shows that this simplifies the code a lot ( since there is less >> arg checking ) >> [ http://cr.openjdk.java.net/~chegar/records/ObjectMethods.00/ | >> http://cr.openjdk.java.net/~chegar/records/ObjectMethods.00/ ] >> Q: the TypeDescriptor arg can be used for linking a dynamic constant. Is this >> still needed? >> -Chris. -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Oct 22 16:34:13 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 Oct 2019 12:34:13 -0400 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1385583467.451521.1571695341077.JavaMail.zimbra@u-pem.fr> <60453a78-b284-19cd-4b11-c5db07c50b6b@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> Message-ID: <26F16E3F-E993-4FFF-8084-3DF32B8D68C6@oracle.com> I think there?s something in between ?specific to records? and ?general building block?. It definitely, 100% was intended to NOT be specific to records. But, it is still not general, in the sense that no human user will ever call this API. So it is (or should be) optimized for what makes sense from a runtime performance / class file impact perspective. 100% of the clients of this API will be compilers and frameworks. It may well be used by Javac for value types, and could be used by other language compilers as well. So that?s the target profile we?re aiming at. > On Oct 22, 2019, at 6:01 AM, Maurizio Cimadamore wrote: > > But, if this is meant to be a general building block, then I don't understand e.g. why we are unifying all the signatures. If a client wants hashCode, I think it is kind of a design flaw that (i) there's no such BSM with that name (the BSM is just called "bootstrap") and (ii) that there still a requirement to pass a 'name list', which is ignored by the BSM. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Oct 22 16:48:00 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 Oct 2019 12:48:00 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Message-ID: This doesn?t work when you invoke the tests through `make run-test`, which is why I used the explicit 14. > On Oct 22, 2019, at 11:21 AM, Jan Lahoda wrote: > > -for tests, "--enable-preview -source 14" is used on many places. This will cause issues when JDK 15 is started (and --enable-preview -source 14 will be replaced with --enable-preview -source 15). On all places where that is possible, "--enable-preview -source ${jdk.version}" should be used, or a programmatic equivalent. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Tue Oct 22 17:27:11 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Tue, 22 Oct 2019 19:27:11 +0200 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Message-ID: <6da6b929-0492-4ef6-319d-f90d023c8ba4@oracle.com> On 22. 10. 19 18:48, Brian Goetz wrote: > This doesn?t work when you invoke the tests through `make run-test`, > which is why I used the explicit 14. Maybe it does not work for the "jdk" tests (due to https://bugs.openjdk.java.net/browse/JDK-8219408), but we use -source ${jdk.version} is langtools tests extensively. Jan > >> On Oct 22, 2019, at 11:21 AM, Jan Lahoda > > wrote: >> >> -for tests, "--enable-preview -source 14" is used on many places. This >> will cause issues when JDK 15 is started (and --enable-preview -source >> 14 will be replaced with --enable-preview -source 15). On all places >> where that is possible, "--enable-preview -source ${jdk.version}" >> should be used, or a programmatic equivalent. > From jonathan.gibbons at oracle.com Tue Oct 22 17:25:41 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Tue, 22 Oct 2019 10:25:41 -0700 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Message-ID: Brian, What doesn't work with "make run-test"??? Are you saying there's a problem with "--enable-preview -source ${jdk.version}", or with the general methodology of specifying --enable-preview and -source? If there's an issue with the jtreg support for ${jdk.version}, I guess I'd like to know. -- Jon On 10/22/19 9:48 AM, Brian Goetz wrote: > This doesn?t work when you invoke the tests through `make run-test`, which is why I used the explicit 14. > >> On Oct 22, 2019, at 11:21 AM, Jan Lahoda wrote: >> >> -for tests, "--enable-preview -source 14" is used on many places. This will cause issues when JDK 15 is started (and --enable-preview -source 14 will be replaced with --enable-preview -source 15). On all places where that is possible, "--enable-preview -source ${jdk.version}" should be used, or a programmatic equivalent. From brian.goetz at oracle.com Tue Oct 22 17:30:51 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 Oct 2019 13:30:51 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Message-ID: <8ACBD981-359A-4212-8598-A9A428817DF2@oracle.com> Yes, I found these tests to fail when running make run-test TEST=?jtreg:/path/to/tests? It was barfing on ?unrecognized source version?, which I took to mean the variable wasn?t being expanded. > On Oct 22, 2019, at 1:25 PM, Jonathan Gibbons wrote: > > Brian, > > What doesn't work with "make run-test"? Are you saying there's a problem with "--enable-preview -source ${jdk.version}", or with the general methodology of specifying --enable-preview and -source? > > If there's an issue with the jtreg support for ${jdk.version}, I guess I'd like to know. > > -- Jon > > On 10/22/19 9:48 AM, Brian Goetz wrote: >> This doesn?t work when you invoke the tests through `make run-test`, which is why I used the explicit 14. >> >>> On Oct 22, 2019, at 11:21 AM, Jan Lahoda wrote: >>> >>> -for tests, "--enable-preview -source 14" is used on many places. This will cause issues when JDK 15 is started (and --enable-preview -source 14 will be replaced with --enable-preview -source 15). On all places where that is possible, "--enable-preview -source ${jdk.version}" should be used, or a programmatic equivalent. From jonathan.gibbons at oracle.com Tue Oct 22 17:48:28 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Tue, 22 Oct 2019 10:48:28 -0700 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <8ACBD981-359A-4212-8598-A9A428817DF2@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> <8ACBD981-359A-4212-8598-A9A428817DF2@oracle.com> Message-ID: <331dbf13-d2a5-ac48-2ad8-5c2deca44fc7@oracle.com> Yes, thanks; I followed up on the JBS issue in Jan's comment. I see that the substitution feature is disabled in the jdk repo. I'll work with Igor et al to see if we can get the feature enabled there.? For what it's worth, it's not specifically related to "make run-test". -- Jon On 10/22/19 10:30 AM, Brian Goetz wrote: > Yes, I found these tests to fail when running > make run-test TEST=?jtreg:/path/to/tests? > > It was barfing on ?unrecognized source version?, which I took to mean the variable wasn?t being expanded. > >> On Oct 22, 2019, at 1:25 PM, Jonathan Gibbons wrote: >> >> Brian, >> >> What doesn't work with "make run-test"? Are you saying there's a problem with "--enable-preview -source ${jdk.version}", or with the general methodology of specifying --enable-preview and -source? >> >> If there's an issue with the jtreg support for ${jdk.version}, I guess I'd like to know. >> >> -- Jon >> >> On 10/22/19 9:48 AM, Brian Goetz wrote: >>> This doesn?t work when you invoke the tests through `make run-test`, which is why I used the explicit 14. >>> >>>> On Oct 22, 2019, at 11:21 AM, Jan Lahoda wrote: >>>> >>>> -for tests, "--enable-preview -source 14" is used on many places. This will cause issues when JDK 15 is started (and --enable-preview -source 14 will be replaced with --enable-preview -source 15). On all places where that is possible, "--enable-preview -source ${jdk.version}" should be used, or a programmatic equivalent. From forax at univ-mlv.fr Tue Oct 22 18:39:54 2019 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 22 Oct 2019 20:39:54 +0200 (CEST) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <26F16E3F-E993-4FFF-8084-3DF32B8D68C6@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <1b2d8725-1203-bcc8-8c1f-0902683e300c@oracle.com> <7d32c089-2887-ca8e-a56d-51c97b1d79ef@oracle.com> <1495460856.584807.1571733822969.JavaMail.zimbra@u-pem.fr> <0290bcd0-f2a2-083a-0fff-29cd80df8a31@oracle.com> <07953f08-579e-9490-4c94-82c2949aa17c@oracle.com> <26F16E3F-E993-4FFF-8084-3DF32B8D68C6@oracle.com> Message-ID: <1703176468.832852.1571769594984.JavaMail.zimbra@u-pem.fr> > De: "Brian Goetz" > ?: "Maurizio Cimadamore" > Cc: "amber-dev" , "compiler-dev" > , "Chris Hegarty" > Envoy?: Mardi 22 Octobre 2019 18:34:13 > Objet: Re: RFR: JEP 359-Records: reflection code > I think there?s something in between ?specific to records? and ?general building > block?. > It definitely, 100% was intended to NOT be specific to records. But, it is still > not general, in the sense that no human user will ever call this API. So it is > (or should be) optimized for what makes sense from a runtime performance / > class file impact perspective. 100% of the clients of this API will be > compilers and frameworks. It may well be used by Javac for value types, and > could be used by other language compilers as well. So that?s the target profile > we?re aiming at. With my language runtime dev hat, the way to find the getters is language dependent, so it makes sense to have an API with 3 entrypoints which is based on getters for equals/hashCode or getters + string format for toString but for records but at the same time from the class format perspective it makes little sense to send the getters for a record so it's better to use another entry point. I like Maurizio's idea to separate the API in: - 3 reusable entry points: defaultObjectEquals(getters), defaultObjectHashCode(getters), defaultObjectToString(getters + stringconcat format) that are public method handles that returns MethodHandle - 1 boostrap method for records recordObjectMethodsBootstrap(Lookup lookup, String methodName, MethodType type) that uses reflection to create the getters and delegate to the methods above For inline types, we will add a new boostrap method inlineObjectMethodsBootstrap that may use different parameters. For other languages, unlike the lambdaMetaFactory that spins bytecode so restrict which kind of method refs can be used, here all methods defaultObject*() are directly reusable so a language like Groovy which is bean based can use the Introspector to find all the properties and then use methods defaultObject*(). My idea of using a constant dynamic in the middle is an optimization that can be done later because records are released has a preview feature we can still change the bytecode encoding in the next release. R?mi >> On Oct 22, 2019, at 6:01 AM, Maurizio Cimadamore < [ >> mailto:maurizio.cimadamore at oracle.com | maurizio.cimadamore at oracle.com ] > >> wrote: >> But, if this is meant to be a general building block, then I don't understand >> e.g. why we are unifying all the signatures. If a client wants hashCode, I >> think it is kind of a design flaw that (i) there's no such BSM with that name >> (the BSM is just called "bootstrap") and (ii) that there still a requirement to >> pass a 'name list', which is ignored by the BSM. -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Oct 22 22:29:09 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 Oct 2019 23:29:09 +0100 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <4f0ee8fc-22bc-7ff9-7af6-88e9e436b583@oracle.com> <434628a6-90c9-f77e-3231-e68082f8b791@oracle.com> Message-ID: Answering to myself here: On 18/10/2019 13:28, Maurizio Cimadamore wrote: > > > One high-level gripe which is pointing at a failure of the j.l.model > API is the lack of a way to get to the canonical constructor directly; > we have this issue both in core reflection and source reflection, and > I think we should address that, as both serialization and javadoc has > to DYI around that. We discussed more about this offline today and we concluded that, for the time being, this is a non-issue, both for core reflection and for source reflection. These API are traditionally 'lumpy' meaning that e.g. records and classes have the same representation (e.g. j.l.Class and j.l.model.TypeElement). So, adding an extra method like 'getCanonicalConstructor' feels yet of another of those arguable API moves where we add a method X which only makes sense if the predicate Y yields true. Moving forward we will have better ways to deal with lumpy APIs like these (see pattern matching) - in the meantime, we think it's better to leave this alone and avoid excessive pollution of the reflective APIs. Of course, should this ever become an usability pain point, we can always add helper methods later, as the records feature exits its preview period. Cheers Maurizio > > Maurizio > > On 17/10/2019 20:45, Jonathan Gibbons wrote: >> cc: javadoc-dev at openjdk.java.net >> >> --Jon >> >> >> On 10/17/2019 12:43 PM, Vicente Romero wrote: >>> Hi, >>> >>> Please review the javadoc code for JEP 359 (Records), this webrev >>> contains only the javadoc code as we have decided to split the new >>> code in clusters to make the review process easier. >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> PS, Jon is the author of this code please keep him in the loop >>> >>> http://cr.openjdk.java.net/~vromero/records.review/javadoc/webrev.00/ >> From david.lloyd at redhat.com Wed Oct 23 14:07:17 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Wed, 23 Oct 2019 09:07:17 -0500 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: The bug ID never showed up for this. Is this not acknowledged as a bug? And have you had any more thoughts about the specification's take on `file` URLs? On Thu, Oct 17, 2019 at 11:08 AM David Lloyd wrote: > > How would you account for JDK-8216401 in this case? Would you say > that the specification should have been updated to account for the > implementation? > > On Thu, Oct 17, 2019 at 9:34 AM Jonathan Gibbons > wrote: > > > > Any changes/exceptions should be done in conjunction with updates to > > specification. > > > > -- Jon > > > > On 10/17/19 6:04 AM, David Lloyd wrote: > > > It seems reasonable to include the special exception for `file:` absolute URLs. > > > > > > I did file a bug at bugreport but I haven't yet received a > > > notification that the bug was created. If I do, I will post the JIRA # > > > here. > > > > > > On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: > > >> One of the reasonsI hadn't done anything related to this in my proposed > > >> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what > > >> the actual expected semantics of the Class-Path attribute are. > > >> > > >> The jar Manifest documentation (which David pointed to) does state the > > >> URI is to be relative, but I remember seeing a recent change discussed > > >> in one of these mailing lists where absolute (file: scheme based) URIs > > >> were supported. I finally found time to look through the JBS and here's > > >> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think > > >> whatever change we do here will then have to allow for absolute URI (for > > >> file: scheme of local jars too). > > >> > > >> [1] > > >> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html > > >> > > >> -Jaikiran > > >> > > >> On 14/10/19 10:13 PM, David Lloyd wrote: > > >>> The JAR specification specifies that the `Class-Path` attribute is a > > >>> space-separated sequence of relative URLs. A relative URL is defined > > >>> ([2], [3]) as a hierarchical URI with no scheme component. > > >>> > > >>> Relative URLs resemble file paths. However they differ in some > > >>> important ways: for example, a relative URL is URL-encoded, whereas a > > >>> file path is not, causing problems when dealing with paths that have > > >>> embedded spaces (among other things). Relative URLs representing > > >>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the > > >>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. > > >>> > > >>> Note (since this is a point of frequent confusion) that a relative URL > > >>> can have an absolute path. > > >>> > > >>> AFAIK neither of these cases work correctly when javac interacts with > > >>> a JAR that contains a `Class-Path` attribute. > > >>> > > >>> The current FSInfo code, as noted in the recent thread entitled > > >>> `FSInfo#getJarClassPath throws an exception not declared in its throws > > >>> clause`, reads the class path attribute value with code that uses > > >>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. > > >>> > > >>> The correct behavior would be to wrap each item in a `java.net.URI`. > > >>> If the syntax is invalid, report an error or skip the element. Then > > >>> determine if the URI is absolute; if it is, report an error or skip > > >>> the element. Finally, query the Path API to look up the file by URI > > >>> using Path.of(uri) or similar, reporting an error or skipping the > > >>> element if there's a problem. > > >>> > > >>> The less-elegant solution would be to manually URL-decode the string, > > >>> and (on windows) manually check to see if there's a drive letter, > > >>> removing the leading slash if there is one. However I would consider > > >>> this to be more likely to be bug-prone. > > >>> > > >>> This problem is the underlying cause of at least one Quarkus bug [5], > > >>> where the issue was discussed in depth. > > >>> > > >>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute > > >>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 > > >>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html > > >>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 > > >>> [5] https://github.com/quarkusio/quarkus/issues/3592 > > >>> > > > > > > > -- > - DML -- - DML From jonathan.gibbons at oracle.com Wed Oct 23 14:29:45 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Wed, 23 Oct 2019 07:29:45 -0700 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: <96da2269-5664-9275-1bbd-f37b8f0f7ce8@oracle.com> Hi David, I haven't looked at this again recently.?? I know there was an email discussion a while back when the code for URLClassLoader was updated, and I want to go back and review that thread. In general, your comments about the FSInfo code are compelling, and should be addressed. At that time, we should examine this related issue about file: URLs.? And yes, the implementation should be in accordance with the specification, and vice versa. -- Jon On 10/23/19 7:07 AM, David Lloyd wrote: > The bug ID never showed up for this. Is this not acknowledged as a > bug? And have you had any more thoughts about the specification's > take on `file` URLs? > > On Thu, Oct 17, 2019 at 11:08 AM David Lloyd wrote: >> How would you account for JDK-8216401 in this case? Would you say >> that the specification should have been updated to account for the >> implementation? >> >> On Thu, Oct 17, 2019 at 9:34 AM Jonathan Gibbons >> wrote: >>> Any changes/exceptions should be done in conjunction with updates to >>> specification. >>> >>> -- Jon >>> >>> On 10/17/19 6:04 AM, David Lloyd wrote: >>>> It seems reasonable to include the special exception for `file:` absolute URLs. >>>> >>>> I did file a bug at bugreport but I haven't yet received a >>>> notification that the bug was created. If I do, I will post the JIRA # >>>> here. >>>> >>>> On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: >>>>> One of the reasonsI hadn't done anything related to this in my proposed >>>>> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what >>>>> the actual expected semantics of the Class-Path attribute are. >>>>> >>>>> The jar Manifest documentation (which David pointed to) does state the >>>>> URI is to be relative, but I remember seeing a recent change discussed >>>>> in one of these mailing lists where absolute (file: scheme based) URIs >>>>> were supported. I finally found time to look through the JBS and here's >>>>> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think >>>>> whatever change we do here will then have to allow for absolute URI (for >>>>> file: scheme of local jars too). >>>>> >>>>> [1] >>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html >>>>> >>>>> -Jaikiran >>>>> >>>>> On 14/10/19 10:13 PM, David Lloyd wrote: >>>>>> The JAR specification specifies that the `Class-Path` attribute is a >>>>>> space-separated sequence of relative URLs. A relative URL is defined >>>>>> ([2], [3]) as a hierarchical URI with no scheme component. >>>>>> >>>>>> Relative URLs resemble file paths. However they differ in some >>>>>> important ways: for example, a relative URL is URL-encoded, whereas a >>>>>> file path is not, causing problems when dealing with paths that have >>>>>> embedded spaces (among other things). Relative URLs representing >>>>>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the >>>>>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. >>>>>> >>>>>> Note (since this is a point of frequent confusion) that a relative URL >>>>>> can have an absolute path. >>>>>> >>>>>> AFAIK neither of these cases work correctly when javac interacts with >>>>>> a JAR that contains a `Class-Path` attribute. >>>>>> >>>>>> The current FSInfo code, as noted in the recent thread entitled >>>>>> `FSInfo#getJarClassPath throws an exception not declared in its throws >>>>>> clause`, reads the class path attribute value with code that uses >>>>>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. >>>>>> >>>>>> The correct behavior would be to wrap each item in a `java.net.URI`. >>>>>> If the syntax is invalid, report an error or skip the element. Then >>>>>> determine if the URI is absolute; if it is, report an error or skip >>>>>> the element. Finally, query the Path API to look up the file by URI >>>>>> using Path.of(uri) or similar, reporting an error or skipping the >>>>>> element if there's a problem. >>>>>> >>>>>> The less-elegant solution would be to manually URL-decode the string, >>>>>> and (on windows) manually check to see if there's a drive letter, >>>>>> removing the leading slash if there is one. However I would consider >>>>>> this to be more likely to be bug-prone. >>>>>> >>>>>> This problem is the underlying cause of at least one Quarkus bug [5], >>>>>> where the issue was discussed in depth. >>>>>> >>>>>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute >>>>>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 >>>>>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html >>>>>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 >>>>>> [5] https://github.com/quarkusio/quarkus/issues/3592 >>>>>> >> >> >> -- >> - DML > > From jai.forums2013 at gmail.com Thu Oct 24 05:07:51 2019 From: jai.forums2013 at gmail.com (Jaikiran Pai) Date: Thu, 24 Oct 2019 10:37:51 +0530 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> Message-ID: <4bc6d096-0e4a-748b-cfd3-94a40194bcfe@gmail.com> Hello David, On 23/10/19 7:37 PM, David Lloyd wrote: > The bug ID never showed up for this. Given that there seems to be an acknowledgment, in this thread, that this current behaviour needs review, I took the liberty to file a bug in JBS https://bugs.openjdk.java.net/browse/JDK-8232925 -Jaikiran > Is this not acknowledged as a > bug? And have you had any more thoughts about the specification's > take on `file` URLs? > > On Thu, Oct 17, 2019 at 11:08 AM David Lloyd wrote: >> How would you account for JDK-8216401 in this case? Would you say >> that the specification should have been updated to account for the >> implementation? >> >> On Thu, Oct 17, 2019 at 9:34 AM Jonathan Gibbons >> wrote: >>> Any changes/exceptions should be done in conjunction with updates to >>> specification. >>> >>> -- Jon >>> >>> On 10/17/19 6:04 AM, David Lloyd wrote: >>>> It seems reasonable to include the special exception for `file:` absolute URLs. >>>> >>>> I did file a bug at bugreport but I haven't yet received a >>>> notification that the bug was created. If I do, I will post the JIRA # >>>> here. >>>> >>>> On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: >>>>> One of the reasonsI hadn't done anything related to this in my proposed >>>>> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what >>>>> the actual expected semantics of the Class-Path attribute are. >>>>> >>>>> The jar Manifest documentation (which David pointed to) does state the >>>>> URI is to be relative, but I remember seeing a recent change discussed >>>>> in one of these mailing lists where absolute (file: scheme based) URIs >>>>> were supported. I finally found time to look through the JBS and here's >>>>> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think >>>>> whatever change we do here will then have to allow for absolute URI (for >>>>> file: scheme of local jars too). >>>>> >>>>> [1] >>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html >>>>> >>>>> -Jaikiran >>>>> >>>>> On 14/10/19 10:13 PM, David Lloyd wrote: >>>>>> The JAR specification specifies that the `Class-Path` attribute is a >>>>>> space-separated sequence of relative URLs. A relative URL is defined >>>>>> ([2], [3]) as a hierarchical URI with no scheme component. >>>>>> >>>>>> Relative URLs resemble file paths. However they differ in some >>>>>> important ways: for example, a relative URL is URL-encoded, whereas a >>>>>> file path is not, causing problems when dealing with paths that have >>>>>> embedded spaces (among other things). Relative URLs representing >>>>>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the >>>>>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. >>>>>> >>>>>> Note (since this is a point of frequent confusion) that a relative URL >>>>>> can have an absolute path. >>>>>> >>>>>> AFAIK neither of these cases work correctly when javac interacts with >>>>>> a JAR that contains a `Class-Path` attribute. >>>>>> >>>>>> The current FSInfo code, as noted in the recent thread entitled >>>>>> `FSInfo#getJarClassPath throws an exception not declared in its throws >>>>>> clause`, reads the class path attribute value with code that uses >>>>>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. >>>>>> >>>>>> The correct behavior would be to wrap each item in a `java.net.URI`. >>>>>> If the syntax is invalid, report an error or skip the element. Then >>>>>> determine if the URI is absolute; if it is, report an error or skip >>>>>> the element. Finally, query the Path API to look up the file by URI >>>>>> using Path.of(uri) or similar, reporting an error or skipping the >>>>>> element if there's a problem. >>>>>> >>>>>> The less-elegant solution would be to manually URL-decode the string, >>>>>> and (on windows) manually check to see if there's a drive letter, >>>>>> removing the leading slash if there is one. However I would consider >>>>>> this to be more likely to be bug-prone. >>>>>> >>>>>> This problem is the underlying cause of at least one Quarkus bug [5], >>>>>> where the issue was discussed in depth. >>>>>> >>>>>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute >>>>>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 >>>>>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html >>>>>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 >>>>>> [5] https://github.com/quarkusio/quarkus/issues/3592 >>>>>> >> >> >> -- >> - DML > > From jonathan.gibbons at oracle.com Thu Oct 24 06:02:06 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Wed, 23 Oct 2019 23:02:06 -0700 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: <4bc6d096-0e4a-748b-cfd3-94a40194bcfe@gmail.com> References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> <4bc6d096-0e4a-748b-cfd3-94a40194bcfe@gmail.com> Message-ID: <107114c4-d8f0-9a1d-28a7-f483055d6437@oracle.com> Generally, I think that the handling of Class-Path in javac, the handling in URLClassLoader [1], and the specification should somehow all be brought into alignment. -- Jon [1] and any other usages in core-libs On 10/23/19 10:07 PM, Jaikiran Pai wrote: > Hello David, > > On 23/10/19 7:37 PM, David Lloyd wrote: >> The bug ID never showed up for this. > Given that there seems to be an acknowledgment, in this thread, that > this current behaviour needs review, I took the liberty to file a bug in > JBS https://bugs.openjdk.java.net/browse/JDK-8232925 > > -Jaikiran > > >> Is this not acknowledged as a >> bug? And have you had any more thoughts about the specification's >> take on `file` URLs? >> >> On Thu, Oct 17, 2019 at 11:08 AM David Lloyd wrote: >>> How would you account for JDK-8216401 in this case? Would you say >>> that the specification should have been updated to account for the >>> implementation? >>> >>> On Thu, Oct 17, 2019 at 9:34 AM Jonathan Gibbons >>> wrote: >>>> Any changes/exceptions should be done in conjunction with updates to >>>> specification. >>>> >>>> -- Jon >>>> >>>> On 10/17/19 6:04 AM, David Lloyd wrote: >>>>> It seems reasonable to include the special exception for `file:` absolute URLs. >>>>> >>>>> I did file a bug at bugreport but I haven't yet received a >>>>> notification that the bug was created. If I do, I will post the JIRA # >>>>> here. >>>>> >>>>> On Wed, Oct 16, 2019 at 9:33 PM Jaikiran Pai wrote: >>>>>> One of the reasonsI hadn't done anything related to this in my proposed >>>>>> change to FSInfo#getJarClassPath patch[1] was because I wasn't sure what >>>>>> the actual expected semantics of the Class-Path attribute are. >>>>>> >>>>>> The jar Manifest documentation (which David pointed to) does state the >>>>>> URI is to be relative, but I remember seeing a recent change discussed >>>>>> in one of these mailing lists where absolute (file: scheme based) URIs >>>>>> were supported. I finally found time to look through the JBS and here's >>>>>> that issue https://bugs.openjdk.java.net/browse/JDK-8216401. So I think >>>>>> whatever change we do here will then have to allow for absolute URI (for >>>>>> file: scheme of local jars too). >>>>>> >>>>>> [1] >>>>>> http://mail.openjdk.java.net/pipermail/compiler-dev/2019-October/013760.html >>>>>> >>>>>> -Jaikiran >>>>>> >>>>>> On 14/10/19 10:13 PM, David Lloyd wrote: >>>>>>> The JAR specification specifies that the `Class-Path` attribute is a >>>>>>> space-separated sequence of relative URLs. A relative URL is defined >>>>>>> ([2], [3]) as a hierarchical URI with no scheme component. >>>>>>> >>>>>>> Relative URLs resemble file paths. However they differ in some >>>>>>> important ways: for example, a relative URL is URL-encoded, whereas a >>>>>>> file path is not, causing problems when dealing with paths that have >>>>>>> embedded spaces (among other things). Relative URLs representing >>>>>>> absolute paths on Windows have a form like `/C:/Foo/Bar`, whereas the >>>>>>> corresponding file path would be `C:/Foo/Bar` or `C:\Foo\Bar`. >>>>>>> >>>>>>> Note (since this is a point of frequent confusion) that a relative URL >>>>>>> can have an absolute path. >>>>>>> >>>>>>> AFAIK neither of these cases work correctly when javac interacts with >>>>>>> a JAR that contains a `Class-Path` attribute. >>>>>>> >>>>>>> The current FSInfo code, as noted in the recent thread entitled >>>>>>> `FSInfo#getJarClassPath throws an exception not declared in its throws >>>>>>> clause`, reads the class path attribute value with code that uses >>>>>>> FileSystems.getDefault().getPath(xxx) on each class path element [4]. >>>>>>> >>>>>>> The correct behavior would be to wrap each item in a `java.net.URI`. >>>>>>> If the syntax is invalid, report an error or skip the element. Then >>>>>>> determine if the URI is absolute; if it is, report an error or skip >>>>>>> the element. Finally, query the Path API to look up the file by URI >>>>>>> using Path.of(uri) or similar, reporting an error or skipping the >>>>>>> element if there's a problem. >>>>>>> >>>>>>> The less-elegant solution would be to manually URL-decode the string, >>>>>>> and (on windows) manually check to see if there's a drive letter, >>>>>>> removing the leading slash if there is one. However I would consider >>>>>>> this to be more likely to be bug-prone. >>>>>>> >>>>>>> This problem is the underlying cause of at least one Quarkus bug [5], >>>>>>> where the issue was discussed in depth. >>>>>>> >>>>>>> [1] https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#class-path-attribute >>>>>>> [2] RFC 3986 ? 4.2 - https://tools.ietf.org/html/rfc3986#section-4.2 >>>>>>> [3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URI.html >>>>>>> [4] https://github.com/openjdk/jdk/blob/4ad3d82c76936a8927ed8a505689a3683144ad98/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java#L112 >>>>>>> [5] https://github.com/quarkusio/quarkus/issues/3592 >>>>>>> >>> >>> -- >>> - DML >> From david.lloyd at redhat.com Thu Oct 24 14:34:07 2019 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 24 Oct 2019 09:34:07 -0500 Subject: FSInfo#getJarClassPath does not comply with the JAR specification In-Reply-To: <4bc6d096-0e4a-748b-cfd3-94a40194bcfe@gmail.com> References: <47cb8963-3b3f-89a5-d71d-65b5346373f2@gmail.com> <4bc6d096-0e4a-748b-cfd3-94a40194bcfe@gmail.com> Message-ID: On Thu, Oct 24, 2019 at 12:08 AM Jaikiran Pai wrote: > > Hello David, > > On 23/10/19 7:37 PM, David Lloyd wrote: > > The bug ID never showed up for this. > > Given that there seems to be an acknowledgment, in this thread, that > this current behaviour needs review, I took the liberty to file a bug in > JBS https://bugs.openjdk.java.net/browse/JDK-8232925 Thanks. I received an email last night though that the web bug was pushed through to https://bugs.openjdk.java.net/browse/JDK-8232945 so I guess now there's a duplicate. Yours has better formatting though so maybe close the other. :) -- - DML From brian.goetz at oracle.com Fri Oct 25 21:04:24 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 25 Oct 2019 17:04:24 -0400 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> Message-ID: <9f1e7585-1754-afd2-21f4-bdd1931936bf@oracle.com> Spec in Class.java: ?- Various {@code RecordComponent} should be {@link RecordComponent}. ?- Rather than say "if this class was declared as a record in the source code", instead say "is a record class", since record classes are a term defined by the JLS. ?- For isRecord/getRecordComponents, should include "@jls 8.10" link RecordComponent.java: ?- Add @jls 8.10 link ?- "Returns the name of the component represented by this record component." -> "Returns the name of this record component."? and similar in other methods.? Since RC models a record component, its clear enough what is meant. ?- For getGenericSignature, there should be a link back to @jls or @jvms that describes the format of the signature string. ?- Doesn't getAnnotation() need some spec, or an {@inheritDoc}? From vicente.romero at oracle.com Sat Oct 26 19:55:06 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Sat, 26 Oct 2019 15:55:06 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: Hi Maurizio, Thanks again for the comments I have published another iteration at [1]. I focused on this iteration more on the implemenation than on the tests to first have an agreement on the implementation, timing, etc. Some comments inlined below. [1] http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: > > Hi Vicente, > I did a pretty thorough pass on most of the code. I didn't look at > tests, and I also didn't look at Lower. Comments below: > > * Flags.java - VARARGS flag for records components; I wonder, instead > of a new flag, can we use the internal VARARGS flag we have for > methods, and attach that to the record symbol? That should also lead > to more direct code in TypeHelper > removed > * Symbol.java - I think the override for 'erasure' is redundant - > isn't that the impl from supertype? > yep, removed too > * Symbol.java - I wonder if accessor list with Pair > isn't a premature generalization; we should just add a getter symbol > and that's it agreed, done > * Attr.java - I think we might want to leave the door open for a check > which forces all constructors of a record to go through the canonical > one (depending on where the spec lands) > implemented in this iteration > * Check.java - understanding checkpoint: when we see an annotation on > a record component, first we check it's one of the kinds which are > allowed (if not, error), and, if it's allowed, we add all record > component annotations to record component elements, and we also filter > away all annotations that have nothing to do with the element in which > they appear. If my understanding is correct, I think this logic should > be documented more clearly; I found the comment after the "if > (isRecordField)" to be a bit obscure. > yes that's the idea, annotations that are originally applied to record components are pushed down to all generated elements in TypeEnter, and then in Check the ones that are off-site are removed > > * Enter.java - why are you removing the static flag on records? I > don't see anything similar around for enums. > the static flag is added to all records but if the record is a top level class, it is not needed, that's why that code is there > * Flow.java - not sure I get the changes to checkInit; typically > checkInit is called at the use-site of DA/DU variables. Here it seems > you suppress some of the errors emitted for accessing record fields > inside the canonical constructor - but I hope that code like this > > record Foo(int x) { > ?? Foo(int x) { > ?????? print(this.x); > ?? } > } > > Still give errors? > yes it gives an error > > If this works correctly, which errors does the 'guard' around the > error generation is supposed to protect against? > checkInit it not used only for what you mentioned above but also, see AssignAnalyzer::visitMethodDef, to check if an initial constructor, as the canonical constructor is in records, have initialized all the fields. The guard is there to don't issue an error if a canonical constructor hasn't initialized some fields, as the compiler will generate code to initialize those fields later in Lower > > * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used > here... > removed > > * TypeEnter.java - implicit super calls are added in Attr::visitMethod > for regular calls; we should do the same for records (or add all in > TypeEnter - that is records and class should be consistent) > right we should be consistent, I have moved that code to Attr > * TypeEnter.java - on finishClass - you are calling memberEnter on > record fields, which I think you already did in the new RecordsPhase > nope, what I'm doing there is invoking MemberEnter to enter the members that hasn't been entered so far. Anyway that code changed a bit because I'm entering the constructors now at RecordPhase too but I have changed the code a bit to make more clear what is happening. > * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal > with _all_ record members (e.g. including accessors), not just some? > yep changed that too > > * TypeEnter.java - checkForSerializationMember should probably be > moved to MemberEnter::visitVar, or even to Attr (note that the code > for the check is doing a little visit :-)) > moved to Attr > > * TypeEnter.java - again on check timings; while it's ok for the code > in here to add new synthetic members, I think it's less ok to add more > global error checks (such as make sure that the canonical declaration > whose parameter names match the record components in order); these > should live in Attr. More generally, I think that we should only check > stuff here if we think that the check will add any value to annotation > processing. Every other check can be deferred, and take place in a > more 'deterministic' part of javac. > moved to Attr > * TypeEnter.java - I think finishClass should be a bit better at > determining as to whether default constructor is needed or not - for > instance, this check: > > if ((sym.flags() & INTERFACE) == 0 && > 928 !TreeInfo.hasConstructors(tree.defs)) { > > Should be generalized to something that works for both classes and > records; for classes you need to check if there's no other > constructor; for records you need to check if there's no other > constructor _with same signature_ as the canonical one. Then you can > simplify addRecordMembers and remove the dependency on the boolean > 'generatedConstructor' parameter. In other words the code should: > > 1) check if default/canonical constructor generation is required > 2) if so, use the appropriate helper to generate the code > 3) at the end, add the remaining record members (under the assumption > that the canonical constructor has already been added in (1), if that > was missing) > done, in order to do that I had to enter constructors at the RecordPhase, as mentioned earlier. > > *TypeEnter.java - addAccessor can be simplified if we only worry about > getters. Again, the checks in here feel more Attr check than > MemberEnter checks. > agreed, done > *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we > create a tree for a member, and then we visit the member tree with > memberEnter, just to add it to the scope. I understand that, currently > addEnumMembers does the same, but this looks very roundabout; I wonder > if there's a way to make all this process a bit simpler - create a > symbol and add that to the scope. Or are there important checks in > MemberEnter that we would lose? > yes there are several checks we would lose, plus we would lose consistency, but I tried to do that and several things fell apart, we need to enter not only the generated method, also it's parameters etc, which is what MemberEnter is doing. > *JCTree.java/TreeMaker.java - I don't think there's any need to store > accessors in the field AST; these are only used from TypeEnter, and > TypeEnter can do whatever it does by looking at which record > components there are in the record class, and add a getter for each. > Let's make the code simpler and more direct > yep removed > > * ClassReader.java - should we just silently ignore record attributes > when not in preview mode - or should we issue classfile errors? > > * ClassReader.java - what kind of validation should we do on record > attributes? Currently javac does nothing. Should we check that we have > (i) getters (ii) toString/hashCode/equals implementations and (iii) a > canonical constructor (ad fail if we don't) ? At the very least I > would add code to _parse_ the attribute, even if we do nothing with > it, so that at least we throw a classfile error if the attribute is > badly broken > on ClassReader, we can discuss what to do in a language meeting, I don't have any strong preference > > * Tokens.java - for "var", "yields" and other context-dependent > keywords we never added a token. We just handled that in JavacParser. > Why the difference here? I think it's best to stick to current style > and maybe fix all of them (assuming that's what we want to do) in a > followup cleanup. Actually, after looking at parser, it seems like you > already handle that manually, so I just suggest to revert the changed > to Tokens > I added the token to add it as a parameter to an error message, but I removed the token and now I'm passing a string > * TreeInfo.java - how is 'isCanonicalConstructor' not returning 'true' > for all constructors inside a record, as opposed to only return true > for the canonical one? > I have added a comment to clarify what this method is doing > > * TreeInfo.java - There is some code reuse possible between > "recordFieldTypes" and "recordFields" > yep done > > * Names.java - what is 'oldEquals' ? > removed, old code > > * JavacParser.java - timing of checks; I don't think we should check > for illegal record component names in here > removed from there > > * JavacParser.java - code can be simplified somewhat by getting rid of > accessors in VarDef AST. > done Thanks again for taking the time to do this long review, will answer the other mails separately Vicente > > > > > On 21/10/2019 13:31, Vicente Romero wrote: >> Hi, >> >> Please review the compiler code for JEP 359 (Records) [1] >> >> Thanks in advance for the feedback, >> Vicente >> >> [1] >> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Sat Oct 26 20:11:46 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Sat, 26 Oct 2019 16:11:46 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> Message-ID: Hi Maurizio, On 10/21/19 4:44 PM, Maurizio Cimadamore wrote: > And here are some comments on Lower > > - findMethodOrFailSilently? doesn't seem to be used anywhere; this > should be removed and associated changes in Resolve reverted done > > - findUserDefinedAccessors - this seems to have to do with setting the > record component symbol straight - this should happen well before > Lower, otherwise I'm not even sure what annotations processor will > see? This code should go in TypeEnter, where you already look up for > existing accessor. yep removed. This was to set only user defined accessors which were not set in TypeEnter as opposed to compiler generated ones. But now all accessors are set in TypeEnter regardless of origin and so this code was removed > > - related; not 100% as to why in visitRecordDef you protect against > accessor not being there - which means you need to do a lookup. You > need to get to this part of the code where all accessors have been > set. Then the code can be simplified. yep, I have simplified that code > > - As pointed out previously, getting rid of the Pair > accessor will result in cascading simplification in few methods in > Lower too yep agreed > > - both the signature generator and the indy machinery are shared > between LambdaToMethod and Lower - so we should probably put them > somewhere in a common superclass which can be used by the various > backend steps I will do that later, yes > > - I guess the main translation strategy for record members is to > generate an indy - where the runtime gives you back some constant > callsite which wraps a method handle with the right signature. If so, > some comments should be sprinkled around to clarify that this is > indeed the case. yes that's the case, I have added some comments > > - I also guess that the if/else in generateRecordMethod is to avoid > generating a tree if an explicit member has been declared by the user > - again, correct, but some comments please ;-) yep I have added some comments there too > > > Also some comments? on tests: > > * test/langtools/tools/javac/6402516/CheckLocalElements.java - why the > change? > > * test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java > -? why the change from @run to @compile? > > * > test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java > - who is using the new target? > > * diags/** in general, for all new diagnostics added it would be nice > to have an html of the output (I have a script for doing that, let me > know if you need it) > > * examples-not-yet - why no test for local records? That should be > easy to add (I hope)? > > * test/langtools/tools/javac/parser/JavacParserTest.java - here I > wonder if we should have different messages depending on the version > (eg. we don't want to say 'expected records' if compiling with -source > 12?) > > *? test/langtools/tools/javac/tree/JavacTreeScannerTest.java, > test/langtools/tools/javac/tree/SourceTreeScannerTest.java, > src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java > - seems like these probably depend on the accessor pairs being in the > AST? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - not sure > about this, does it even belong to this patch? I'd be surprised if > DocTree does anything special with accessors? > > * test/langtools/tools/javac/doctree/AccessorsTest.java - this tests > that ElementFilter and getAccessor() agree, but doesn't test that they > actually yield the correct result > > * more generally, certain tests (e.g. signature mismatches, record > component names order mismatches, reflection tests, serialization > tests) have a certain ad-hoc nature to them - in the sense that they > test one record shape or two and that's it. E.g. > > test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java > > > I'd like to see a more combinatorial-oriented approach to such tests, > where at least we tests all primitive types plus a reference type of > choice, with varying degrees of arity (and w/, w/o varargs). I have modified some tests in this iteration but I still have to revisit some of them. > > > That's all for now > > Thanks > Maurizio Thanks, Vicente > > On 21/10/2019 19:01, Maurizio Cimadamore wrote: >> Hi Vicente, >> I did a pretty thorough pass on most of the code. I didn't look at >> tests, and I also didn't look at Lower. Comments below: >> >> * Flags.java - VARARGS flag for records components; I wonder, instead >> of a new flag, can we use the internal VARARGS flag we have for >> methods, and attach that to the record symbol? That should also lead >> to more direct code in TypeHelper >> >> * Symbol.java - I think the override for 'erasure' is redundant - >> isn't that the impl from supertype? >> >> * Symbol.java (and others) in general this webrev shuld be updated as >> soon as Jan push the @Preview work, as I see that methods >> implementing preview API are using the 'deprecate for removal' >> annotation >> >> * Symbol.java - I wonder if accessor list with Pair >> isn't a premature generalization; we should just add a getter symbol >> and that's it >> >> * Attr.java - I think we might want to leave the door open for a >> check which forces all constructors of a record to go through the >> canonical one (depending on where the spec lands) >> >> * Check.java - understanding checkpoint: when we see an annotation on >> a record component, first we check it's one of the kinds which are >> allowed (if not, error), and, if it's allowed, we add all record >> component annotations to record component elements, and we also >> filter away all annotations that have nothing to do with the element >> in which they appear. If my understanding is correct, I think this >> logic should be documented more clearly; I found the comment after >> the "if (isRecordField)" to be a bit obscure. >> >> * Enter.java - why are you removing the static flag on records? I >> don't see anything similar around for enums. >> >> * Flow.java - not sure I get the changes to checkInit; typically >> checkInit is called at the use-site of DA/DU variables. Here it seems >> you suppress some of the errors emitted for accessing record fields >> inside the canonical constructor - but I hope that code like this >> >> record Foo(int x) { >> ?? Foo(int x) { >> ?????? print(this.x); >> ?? } >> } >> >> Still give errors? If this works correctly, which errors does the >> 'guard' around the error generation is supposed to protect against? >> >> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used >> here... >> >> * TypeEnter.java - implicit super calls are added in >> Attr::visitMethod for regular calls; we should do the same for >> records (or add all in TypeEnter - that is records and class should >> be consistent) >> >> * TypeEnter.java - on finishClass - you are calling memberEnter on >> record fields, which I think you already did in the new RecordsPhase >> >> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >> with _all_ record members (e.g. including accessors), not just some? >> >> * TypeEnter.java - checkForSerializationMember should probably be >> moved to MemberEnter::visitVar, or even to Attr (note that the code >> for the check is doing a little visit :-)) >> >> * TypeEnter.java - again on check timings; while it's ok for the code >> in here to add new synthetic members, I think it's less ok to add >> more global error checks (such as make sure that the canonical >> declaration whose parameter names match the record components in >> order); these should live in Attr. More generally, I think that we >> should only check stuff here if we think that the check will add any >> value to annotation processing. Every other check can be deferred, >> and take place in a more 'deterministic' part of javac. >> >> * TypeEnter.java - I think finishClass should be a bit better at >> determining as to whether default constructor is needed or not - for >> instance, this check: >> >> if ((sym.flags() & INTERFACE) == 0 && >> ?928???????????????? !TreeInfo.hasConstructors(tree.defs)) { >> >> Should be generalized to something that works for both classes and >> records; for classes you need to check if there's no other >> constructor; for records you need to check if there's no other >> constructor _with same signature_ as the canonical one. Then you can >> simplify addRecordMembers and remove the dependency on the boolean >> 'generatedConstructor' parameter. In other words the code should: >> >> 1) check if default/canonical constructor generation is required >> 2) if so, use the appropriate helper to generate the code >> 3) at the end, add the remaining record members (under the assumption >> that the canonical constructor has already been added in (1), if that >> was missing) >> >> *TypeEnter.java - addAccessor can be simplified if we only worry >> about getters. Again, the checks in here feel more Attr check than >> MemberEnter checks. >> >> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >> create a tree for a member, and then we visit the member tree with >> memberEnter, just to add it to the scope. I understand that, >> currently addEnumMembers does the same, but this looks very >> roundabout; I wonder if there's a way to make all this process a bit >> simpler - create a symbol and add that to the scope. Or are there >> important checks in MemberEnter that we would lose? >> >> *JCTree.java/TreeMaker.java - I don't think there's any need to store >> accessors in the field AST; these are only used from TypeEnter, and >> TypeEnter can do whatever it does by looking at which record >> components there are in the record class, and add a getter for each. >> Let's make the code simpler and more direct >> >> * ClassReader.java - should we just silently ignore record attributes >> when not in preview mode - or should we issue classfile errors? >> >> * ClassReader.java - what kind of validation should we do on record >> attributes? Currently javac does nothing. Should we check that we >> have (i) getters (ii) toString/hashCode/equals implementations and >> (iii) a canonical constructor (ad fail if we don't) ? At the very >> least I would add code to _parse_ the attribute, even if we do >> nothing with it, so that at least we throw a classfile error if the >> attribute is badly broken >> >> * Tokens.java - for "var", "yields" and other context-dependent >> keywords we never added a token. We just handled that in JavacParser. >> Why the difference here? I think it's best to stick to current style >> and maybe fix all of them (assuming that's what we want to do) in a >> followup cleanup. Actually, after looking at parser, it seems like >> you already handle that manually, so I just suggest to revert the >> changed to Tokens >> >> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >> 'true' for all constructors inside a record, as opposed to only >> return true for the canonical one? >> >> * TreeInfo.java - There is some code reuse possible between >> "recordFieldTypes" and "recordFields" >> >> * Names.java - what is 'oldEquals' ? >> >> * JavacParser.java - timing of checks; I don't think we should check >> for illegal record component names in here >> >> * JavacParser.java - code can be simplified somewhat by getting rid >> of accessors in VarDef AST. >> >> >> >> >> >> On 21/10/2019 13:31, Vicente Romero wrote: >>> Hi, >>> >>> Please review the compiler code for JEP 359 (Records) [1] >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From vicente.romero at oracle.com Sat Oct 26 20:14:07 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Sat, 26 Oct 2019 16:14:07 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: I forgot to mention that I have added javax.lang.model code to this iteration that wasn't part of the first iteration. I was planning to publish it as part of a different review but I realized that there was some code affected, tests, API implementation etc, which belonged to the compiler code. So I added that code in this iteration, Thanks, Vicente On 10/26/19 3:55 PM, Vicente Romero wrote: > Hi Maurizio, > > Thanks again for the comments I have published another iteration at > [1]. I focused on this iteration more on the implemenation than on the > tests to first have an agreement on the implementation, timing, etc. > Some comments inlined below. > > [1] http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ > > On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >> >> Hi Vicente, >> I did a pretty thorough pass on most of the code. I didn't look at >> tests, and I also didn't look at Lower. Comments below: >> >> * Flags.java - VARARGS flag for records components; I wonder, instead >> of a new flag, can we use the internal VARARGS flag we have for >> methods, and attach that to the record symbol? That should also lead >> to more direct code in TypeHelper >> > removed > >> * Symbol.java - I think the override for 'erasure' is redundant - >> isn't that the impl from supertype? >> > yep, removed too > >> * Symbol.java - I wonder if accessor list with Pair >> isn't a premature generalization; we should just add a getter symbol >> and that's it > > agreed, done > >> * Attr.java - I think we might want to leave the door open for a >> check which forces all constructors of a record to go through the >> canonical one (depending on where the spec lands) >> > implemented in this iteration > >> * Check.java - understanding checkpoint: when we see an annotation on >> a record component, first we check it's one of the kinds which are >> allowed (if not, error), and, if it's allowed, we add all record >> component annotations to record component elements, and we also >> filter away all annotations that have nothing to do with the element >> in which they appear. If my understanding is correct, I think this >> logic should be documented more clearly; I found the comment after >> the "if (isRecordField)" to be a bit obscure. >> > yes that's the idea, annotations that are originally applied to record > components are pushed down to all generated elements in TypeEnter, and > then in Check the ones that are off-site are removed >> >> * Enter.java - why are you removing the static flag on records? I >> don't see anything similar around for enums. >> > > the static flag is added to all records but if the record is a top > level class, it is not needed, that's why that code is there > >> * Flow.java - not sure I get the changes to checkInit; typically >> checkInit is called at the use-site of DA/DU variables. Here it seems >> you suppress some of the errors emitted for accessing record fields >> inside the canonical constructor - but I hope that code like this >> >> record Foo(int x) { >> ?? Foo(int x) { >> ?????? print(this.x); >> ?? } >> } >> >> Still give errors? >> > > yes it gives an error >> >> If this works correctly, which errors does the 'guard' around the >> error generation is supposed to protect against? >> > > checkInit it not used only for what you mentioned above but also, see > AssignAnalyzer::visitMethodDef, to check if an initial constructor, as > the canonical constructor is in records, have initialized all the > fields. The guard is there to don't issue an error if a canonical > constructor hasn't initialized some fields, as the compiler will > generate code to initialize those fields later in Lower >> >> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only used >> here... >> > removed >> >> * TypeEnter.java - implicit super calls are added in >> Attr::visitMethod for regular calls; we should do the same for >> records (or add all in TypeEnter - that is records and class should >> be consistent) >> > > right we should be consistent, I have moved that code to Attr > >> * TypeEnter.java - on finishClass - you are calling memberEnter on >> record fields, which I think you already did in the new RecordsPhase >> > > nope, what I'm doing there is invoking MemberEnter to enter the > members that hasn't been entered so far. Anyway that code changed a > bit because I'm entering the constructors now at RecordPhase too but I > have changed the code a bit to make more clear what is happening. > >> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >> with _all_ record members (e.g. including accessors), not just some? >> > yep changed that too >> >> * TypeEnter.java - checkForSerializationMember should probably be >> moved to MemberEnter::visitVar, or even to Attr (note that the code >> for the check is doing a little visit :-)) >> > moved to Attr >> >> * TypeEnter.java - again on check timings; while it's ok for the code >> in here to add new synthetic members, I think it's less ok to add >> more global error checks (such as make sure that the canonical >> declaration whose parameter names match the record components in >> order); these should live in Attr. More generally, I think that we >> should only check stuff here if we think that the check will add any >> value to annotation processing. Every other check can be deferred, >> and take place in a more 'deterministic' part of javac. >> > > moved to Attr > >> * TypeEnter.java - I think finishClass should be a bit better at >> determining as to whether default constructor is needed or not - for >> instance, this check: >> >> if ((sym.flags() & INTERFACE) == 0 && >> 928 !TreeInfo.hasConstructors(tree.defs)) { >> >> Should be generalized to something that works for both classes and >> records; for classes you need to check if there's no other >> constructor; for records you need to check if there's no other >> constructor _with same signature_ as the canonical one. Then you can >> simplify addRecordMembers and remove the dependency on the boolean >> 'generatedConstructor' parameter. In other words the code should: >> >> 1) check if default/canonical constructor generation is required >> 2) if so, use the appropriate helper to generate the code >> 3) at the end, add the remaining record members (under the assumption >> that the canonical constructor has already been added in (1), if that >> was missing) >> > > done, in order to do that I had to enter constructors at the > RecordPhase, as mentioned earlier. >> >> *TypeEnter.java - addAccessor can be simplified if we only worry >> about getters. Again, the checks in here feel more Attr check than >> MemberEnter checks. >> > agreed, done > >> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >> create a tree for a member, and then we visit the member tree with >> memberEnter, just to add it to the scope. I understand that, >> currently addEnumMembers does the same, but this looks very >> roundabout; I wonder if there's a way to make all this process a bit >> simpler - create a symbol and add that to the scope. Or are there >> important checks in MemberEnter that we would lose? >> > > yes there are several checks we would lose, plus we would lose > consistency, but I tried to do that and several things fell apart, we > need to enter not only the generated method, also it's parameters etc, > which is what MemberEnter is doing. > >> *JCTree.java/TreeMaker.java - I don't think there's any need to store >> accessors in the field AST; these are only used from TypeEnter, and >> TypeEnter can do whatever it does by looking at which record >> components there are in the record class, and add a getter for each. >> Let's make the code simpler and more direct >> > yep removed >> >> * ClassReader.java - should we just silently ignore record attributes >> when not in preview mode - or should we issue classfile errors? >> >> * ClassReader.java - what kind of validation should we do on record >> attributes? Currently javac does nothing. Should we check that we >> have (i) getters (ii) toString/hashCode/equals implementations and >> (iii) a canonical constructor (ad fail if we don't) ? At the very >> least I would add code to _parse_ the attribute, even if we do >> nothing with it, so that at least we throw a classfile error if the >> attribute is badly broken >> > on ClassReader, we can discuss what to do in a language meeting, I > don't have any strong preference >> >> * Tokens.java - for "var", "yields" and other context-dependent >> keywords we never added a token. We just handled that in JavacParser. >> Why the difference here? I think it's best to stick to current style >> and maybe fix all of them (assuming that's what we want to do) in a >> followup cleanup. Actually, after looking at parser, it seems like >> you already handle that manually, so I just suggest to revert the >> changed to Tokens >> > > I added the token to add it as a parameter to an error message, but I > removed the token and now I'm passing a string > >> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >> 'true' for all constructors inside a record, as opposed to only >> return true for the canonical one? >> > I have added a comment to clarify what this method is doing >> >> * TreeInfo.java - There is some code reuse possible between >> "recordFieldTypes" and "recordFields" >> > yep done >> >> * Names.java - what is 'oldEquals' ? >> > removed, old code >> >> * JavacParser.java - timing of checks; I don't think we should check >> for illegal record component names in here >> > removed from there >> >> * JavacParser.java - code can be simplified somewhat by getting rid >> of accessors in VarDef AST. >> > > done > > Thanks again for taking the time to do this long review, will answer > the other mails separately > > Vicente >> >> >> >> >> On 21/10/2019 13:31, Vicente Romero wrote: >>> Hi, >>> >>> Please review the compiler code for JEP 359 (Records) [1] >>> >>> Thanks in advance for the feedback, >>> Vicente >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Sun Oct 27 01:24:21 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Sat, 26 Oct 2019 21:24:21 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <0ebde608-4fd2-c0ee-f8d6-e33aa662eabf@oracle.com> <4d312903-7d01-3055-aff1-6c4e19866b71@oracle.com> Message-ID: <14abd2fb-5040-86b9-2d2c-ab571a2ccf7b@oracle.com> Hi Jan, On 10/22/19 11:21 AM, Jan Lahoda wrote: > Hi, > > In addition to Maurizio's comments, a few more comments: > -for tests, "--enable-preview -source 14" is used on many places. This > will cause issues when JDK 15 is started (and --enable-preview -source > 14 will be replaced with --enable-preview -source 15). On all places > where that is possible, "--enable-preview -source ${jdk.version}" > should be used, or a programmatic equivalent. done > -for code like this: > ---$ cat R.java > public record R(int i) {} > --- > compiling without --enable-preview: > --- $ javac R.java > /tmp/R.java:1: error: class, interface, or enum expected > public record R(int i) {} > ?????? ^ > 1 error > --- > it would be nice if we could provide some helpful note that to get > support for records, --enable-preview needs to be used. It may not be > possible to embed that into the error esp. for nested records, but at > least a warning. Just so that the user would get a hint what they are > doing wrong if records don't work for them. I will check similar code in other preview projects, > -in Flags, it would be nice to document on which Symbols given flag > may appear. That would be useful in order to partition the Flags into > separate Symbol-kind specific sub-sets. done > -in Lower, there is method "recordVars, which looks at the > superclasses of a record, to see if these have a state component - is > a record superclass of a record allowed? (I thought it isn't.) I removed that method > -there seem to be commented debugs in Check, like: > +??????? //System.out.println("at Check.validateAnnotation: flags: " + > Flags.toString(s.flags_field) + ", declaration tree " + declarationTree); > > Ideally, these would be removed done > -in: > test/langtools/tools/javac/launcher/SourceLauncherTest.javathere are > changes like: > -??????????? file + ":1: error: class, interface, or enum expected\n" + > +??????????? file + ":1: error: class, interface, enum expected\n" + > > are these intentional? These seem suspicious to me. right, fixed > > -in: > test/langtools/tools/javac/processing/model/element/TestRecord.java > and: > test/langtools/tools/javac/processing/model/element/TestRecordDesugar.java > > > there is @bug 8888888 - that seems like a placeholder number. yep removed > > Thanks, > ???? Jan Thanks for the review, Vicente PS, current iteration: http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ > > > On 21. 10. 19 22:44, Maurizio Cimadamore wrote: >> And here are some comments on Lower >> >> - findMethodOrFailSilently? doesn't seem to be used anywhere; this >> should be removed and associated changes in Resolve reverted >> >> - findUserDefinedAccessors - this seems to have to do with setting >> the record component symbol straight - this should happen well before >> Lower, otherwise I'm not even sure what annotations processor will >> see? This code should go in TypeEnter, where you already look up for >> existing accessor. >> >> - related; not 100% as to why in visitRecordDef you protect against >> accessor not being there - which means you need to do a lookup. You >> need to get to this part of the code where all accessors have been >> set. Then the code can be simplified. >> >> - As pointed out previously, getting rid of the Pair >> accessor will result in cascading simplification in few methods in >> Lower too >> >> - both the signature generator and the indy machinery are shared >> between LambdaToMethod and Lower - so we should probably put them >> somewhere in a common superclass which can be used by the various >> backend steps >> >> - I guess the main translation strategy for record members is to >> generate an indy - where the runtime gives you back some constant >> callsite which wraps a method handle with the right signature. If so, >> some comments should be sprinkled around to clarify that this is >> indeed the case. >> >> - I also guess that the if/else in generateRecordMethod is to avoid >> generating a tree if an explicit member has been declared by the user >> - again, correct, but some comments please ;-) >> >> >> Also some comments? on tests: >> >> * test/langtools/tools/javac/6402516/CheckLocalElements.java - why >> the change? >> >> * test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java >> - why the change from @run to @compile? >> >> * >> test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java >> - who is using the new target? >> >> * diags/** in general, for all new diagnostics added it would be nice >> to have an html of the output (I have a script for doing that, let me >> know if you need it) >> >> * examples-not-yet - why no test for local records? That should be >> easy to add (I hope)? >> >> * test/langtools/tools/javac/parser/JavacParserTest.java - here I >> wonder if we should have different messages depending on the version >> (eg. we don't want to say 'expected records' if compiling with >> -source 12?) >> >> *? test/langtools/tools/javac/tree/JavacTreeScannerTest.java, >> test/langtools/tools/javac/tree/SourceTreeScannerTest.java, >> src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java >> - seems like these probably depend on the accessor pairs being in the >> AST? >> >> * test/langtools/tools/javac/doctree/AccessorsTest.java - not sure >> about this, does it even belong to this patch? I'd be surprised if >> DocTree does anything special with accessors? >> >> * test/langtools/tools/javac/doctree/AccessorsTest.java - this tests >> that ElementFilter and getAccessor() agree, but doesn't test that >> they actually yield the correct result >> >> * more generally, certain tests (e.g. signature mismatches, record >> component names order mismatches, reflection tests, serialization >> tests) have a certain ad-hoc nature to them - in the sense that they >> test one record shape or two and that's it. E.g. >> >> test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java >> >> >> I'd like to see a more combinatorial-oriented approach to such tests, >> where at least we tests all primitive types plus a reference type of >> choice, with varying degrees of arity (and w/, w/o varargs). >> >> >> That's all for now >> >> Thanks >> Maurizio >> >> On 21/10/2019 19:01, Maurizio Cimadamore wrote: >>> Hi Vicente, >>> I did a pretty thorough pass on most of the code. I didn't look at >>> tests, and I also didn't look at Lower. Comments below: >>> >>> * Flags.java - VARARGS flag for records components; I wonder, >>> instead of a new flag, can we use the internal VARARGS flag we have >>> for methods, and attach that to the record symbol? That should also >>> lead to more direct code in TypeHelper >>> >>> * Symbol.java - I think the override for 'erasure' is redundant - >>> isn't that the impl from supertype? >>> >>> * Symbol.java (and others) in general this webrev shuld be updated >>> as soon as Jan push the @Preview work, as I see that methods >>> implementing preview API are using the 'deprecate for removal' >>> annotation >>> >>> * Symbol.java - I wonder if accessor list with Pair >>> isn't a premature generalization; we should just add a getter symbol >>> and that's it >>> >>> * Attr.java - I think we might want to leave the door open for a >>> check which forces all constructors of a record to go through the >>> canonical one (depending on where the spec lands) >>> >>> * Check.java - understanding checkpoint: when we see an annotation >>> on a record component, first we check it's one of the kinds which >>> are allowed (if not, error), and, if it's allowed, we add all record >>> component annotations to record component elements, and we also >>> filter away all annotations that have nothing to do with the element >>> in which they appear. If my understanding is correct, I think this >>> logic should be documented more clearly; I found the comment after >>> the "if (isRecordField)" to be a bit obscure. >>> >>> * Enter.java - why are you removing the static flag on records? I >>> don't see anything similar around for enums. >>> >>> * Flow.java - not sure I get the changes to checkInit; typically >>> checkInit is called at the use-site of DA/DU variables. Here it >>> seems you suppress some of the errors emitted for accessing record >>> fields inside the canonical constructor - but I hope that code like >>> this >>> >>> record Foo(int x) { >>> ?? Foo(int x) { >>> ?????? print(this.x); >>> ?? } >>> } >>> >>> Still give errors? If this works correctly, which errors does the >>> 'guard' around the error generation is supposed to protect against? >>> >>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>> used here... >>> >>> * TypeEnter.java - implicit super calls are added in >>> Attr::visitMethod for regular calls; we should do the same for >>> records (or add all in TypeEnter - that is records and class should >>> be consistent) >>> >>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>> record fields, which I think you already did in the new RecordsPhase >>> >>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >>> with _all_ record members (e.g. including accessors), not just some? >>> >>> * TypeEnter.java - checkForSerializationMember should probably be >>> moved to MemberEnter::visitVar, or even to Attr (note that the code >>> for the check is doing a little visit :-)) >>> >>> * TypeEnter.java - again on check timings; while it's ok for the >>> code in here to add new synthetic members, I think it's less ok to >>> add more global error checks (such as make sure that the canonical >>> declaration whose parameter names match the record components in >>> order); these should live in Attr. More generally, I think that we >>> should only check stuff here if we think that the check will add any >>> value to annotation processing. Every other check can be deferred, >>> and take place in a more 'deterministic' part of javac. >>> >>> * TypeEnter.java - I think finishClass should be a bit better at >>> determining as to whether default constructor is needed or not - for >>> instance, this check: >>> >>> if ((sym.flags() & INTERFACE) == 0 && >>> ?928???????????????? !TreeInfo.hasConstructors(tree.defs)) { >>> >>> Should be generalized to something that works for both classes and >>> records; for classes you need to check if there's no other >>> constructor; for records you need to check if there's no other >>> constructor _with same signature_ as the canonical one. Then you can >>> simplify addRecordMembers and remove the dependency on the boolean >>> 'generatedConstructor' parameter. In other words the code should: >>> >>> 1) check if default/canonical constructor generation is required >>> 2) if so, use the appropriate helper to generate the code >>> 3) at the end, add the remaining record members (under the >>> assumption that the canonical constructor has already been added in >>> (1), if that was missing) >>> >>> *TypeEnter.java - addAccessor can be simplified if we only worry >>> about getters. Again, the checks in here feel more Attr check than >>> MemberEnter checks. >>> >>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>> create a tree for a member, and then we visit the member tree with >>> memberEnter, just to add it to the scope. I understand that, >>> currently addEnumMembers does the same, but this looks very >>> roundabout; I wonder if there's a way to make all this process a bit >>> simpler - create a symbol and add that to the scope. Or are there >>> important checks in MemberEnter that we would lose? >>> >>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>> store accessors in the field AST; these are only used from >>> TypeEnter, and TypeEnter can do whatever it does by looking at which >>> record components there are in the record class, and add a getter >>> for each. Let's make the code simpler and more direct >>> >>> * ClassReader.java - should we just silently ignore record >>> attributes when not in preview mode - or should we issue classfile >>> errors? >>> >>> * ClassReader.java - what kind of validation should we do on record >>> attributes? Currently javac does nothing. Should we check that we >>> have (i) getters (ii) toString/hashCode/equals implementations and >>> (iii) a canonical constructor (ad fail if we don't) ? At the very >>> least I would add code to _parse_ the attribute, even if we do >>> nothing with it, so that at least we throw a classfile error if the >>> attribute is badly broken >>> >>> * Tokens.java - for "var", "yields" and other context-dependent >>> keywords we never added a token. We just handled that in >>> JavacParser. Why the difference here? I think it's best to stick to >>> current style and maybe fix all of them (assuming that's what we >>> want to do) in a followup cleanup. Actually, after looking at >>> parser, it seems like you already handle that manually, so I just >>> suggest to revert the changed to Tokens >>> >>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>> 'true' for all constructors inside a record, as opposed to only >>> return true for the canonical one? >>> >>> * TreeInfo.java - There is some code reuse possible between >>> "recordFieldTypes" and "recordFields" >>> >>> * Names.java - what is 'oldEquals' ? >>> >>> * JavacParser.java - timing of checks; I don't think we should check >>> for illegal record component names in here >>> >>> * JavacParser.java - code can be simplified somewhat by getting rid >>> of accessors in VarDef AST. >>> >>> >>> >>> >>> >>> On 21/10/2019 13:31, Vicente Romero wrote: >>>> Hi, >>>> >>>> Please review the compiler code for JEP 359 (Records) [1] >>>> >>>> Thanks in advance for the feedback, >>>> Vicente >>>> >>>> [1] >>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From maurizio.cimadamore at oracle.com Sun Oct 27 22:09:04 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Sun, 27 Oct 2019 22:09:04 +0000 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: Hi Vicente, looks a lot better, thanks. Some comments: Attr.java - Errors.FirstStatementMustBeCallToCanonical - not sure about this message , but in general, all we require is that a constructor delegates to another constructor - it can also be something other than the canonical - e.g contsructor1 -> constructor2 -> canonical Attr.java - the above situation seems to also affect some other code in Attr - where you actually check that the invoked constructor in 'this' has same signature of the canonical constructor. I think these checks should be removed - the important thing is that the canonical will be called _somehow_ - but can also be call indirectly - at least this was my understanding Attr.java - not sure about the tree.sym.isRecord in the visitMethod - it seems like the same flag is used for both record (class) and canonical constructor? I'm ok with sharing the flag, but the method name looks a bit confusing when applied to a method symbol. I suggest putting 'isRecord' inside ClassSymbol, and 'isCanonicalRecordConstructor' on MethodSymbol, so that client code cannot make mistakes. Attr.java/TypeEnter.java - overall, the checks here look nice, and they 'blend' in with existing code nicely, I think. Well done! Enter.java - I guess my question here on records and treatment with STATIC is a general question as to why isn't the code doing the same thing for records and enums - aren't the rules similar? (e.g. enums must be static, etc)? Enums are not set STATIC by default in javac parser, and that is, I think the difference here. What pushed you in this direction? TypeEnter.java: I suggest renaming "getCanonicalInitDecl" to "getCanonicalConstructorDecl" TypeEnter.java - it seems like the result of getCanonicalInitDecl is always given the RECORD flag - but later on (in Lower) I saw a comment which says that only auto-generated symbols have the RECORD flag set. Which one is it? TypeEnter.java - I think the isUnchecked methods are a leftover from previous code - now they seem to be in Attr.java (btw, I think we must have those checks somewhere else in javac, look in Check::isUnchecked) Names.java - I think this bunch of fields is also no longer used? + public final Name where; + public final Name non; + public final Name ofLazyProjection; + I have not checked the j.l.m API. Thanks Maurizio On 26/10/2019 21:14, Vicente Romero wrote: > I forgot to mention that I have added javax.lang.model code to this > iteration that wasn't part of the first iteration. I was planning to > publish it as part of a different review but I realized that there was > some code affected, tests, API implementation etc, which belonged to > the compiler code. So I added that code in this iteration, > > Thanks, > Vicente > > On 10/26/19 3:55 PM, Vicente Romero wrote: >> Hi Maurizio, >> >> Thanks again for the comments I have published another iteration at >> [1]. I focused on this iteration more on the implemenation than on >> the tests to first have an agreement on the implementation, timing, >> etc. Some comments inlined below. >> >> [1] >> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ >> >> On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >>> >>> Hi Vicente, >>> I did a pretty thorough pass on most of the code. I didn't look at >>> tests, and I also didn't look at Lower. Comments below: >>> >>> * Flags.java - VARARGS flag for records components; I wonder, >>> instead of a new flag, can we use the internal VARARGS flag we have >>> for methods, and attach that to the record symbol? That should also >>> lead to more direct code in TypeHelper >>> >> removed >> >>> * Symbol.java - I think the override for 'erasure' is redundant - >>> isn't that the impl from supertype? >>> >> yep, removed too >> >>> * Symbol.java - I wonder if accessor list with Pair >>> isn't a premature generalization; we should just add a getter symbol >>> and that's it >> >> agreed, done >> >>> * Attr.java - I think we might want to leave the door open for a >>> check which forces all constructors of a record to go through the >>> canonical one (depending on where the spec lands) >>> >> implemented in this iteration >> >>> * Check.java - understanding checkpoint: when we see an annotation >>> on a record component, first we check it's one of the kinds which >>> are allowed (if not, error), and, if it's allowed, we add all record >>> component annotations to record component elements, and we also >>> filter away all annotations that have nothing to do with the element >>> in which they appear. If my understanding is correct, I think this >>> logic should be documented more clearly; I found the comment after >>> the "if (isRecordField)" to be a bit obscure. >>> >> yes that's the idea, annotations that are originally applied to >> record components are pushed down to all generated elements in >> TypeEnter, and then in Check the ones that are off-site are removed >>> >>> * Enter.java - why are you removing the static flag on records? I >>> don't see anything similar around for enums. >>> >> >> the static flag is added to all records but if the record is a top >> level class, it is not needed, that's why that code is there >> >>> * Flow.java - not sure I get the changes to checkInit; typically >>> checkInit is called at the use-site of DA/DU variables. Here it >>> seems you suppress some of the errors emitted for accessing record >>> fields inside the canonical constructor - but I hope that code like this >>> >>> record Foo(int x) { >>> ?? Foo(int x) { >>> ?????? print(this.x); >>> ?? } >>> } >>> >>> Still give errors? >>> >> >> yes it gives an error >>> >>> If this works correctly, which errors does the 'guard' around the >>> error generation is supposed to protect against? >>> >> >> checkInit it not used only for what you mentioned above but also, see >> AssignAnalyzer::visitMethodDef, to check if an initial constructor, >> as the canonical constructor is in records, have initialized all the >> fields. The guard is there to don't issue an error if a canonical >> constructor hasn't initialized some fields, as the compiler will >> generate code to initialize those fields later in Lower >>> >>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>> used here... >>> >> removed >>> >>> * TypeEnter.java - implicit super calls are added in >>> Attr::visitMethod for regular calls; we should do the same for >>> records (or add all in TypeEnter - that is records and class should >>> be consistent) >>> >> >> right we should be consistent, I have moved that code to Attr >> >>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>> record fields, which I think you already did in the new RecordsPhase >>> >> >> nope, what I'm doing there is invoking MemberEnter to enter the >> members that hasn't been entered so far. Anyway that code changed a >> bit because I'm entering the constructors now at RecordPhase too but >> I have changed the code a bit to make more clear what is happening. >> >>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >>> with _all_ record members (e.g. including accessors), not just some? >>> >> yep changed that too >>> >>> * TypeEnter.java - checkForSerializationMember should probably be >>> moved to MemberEnter::visitVar, or even to Attr (note that the code >>> for the check is doing a little visit :-)) >>> >> moved to Attr >>> >>> * TypeEnter.java - again on check timings; while it's ok for the >>> code in here to add new synthetic members, I think it's less ok to >>> add more global error checks (such as make sure that the canonical >>> declaration whose parameter names match the record components in >>> order); these should live in Attr. More generally, I think that we >>> should only check stuff here if we think that the check will add any >>> value to annotation processing. Every other check can be deferred, >>> and take place in a more 'deterministic' part of javac. >>> >> >> moved to Attr >> >>> * TypeEnter.java - I think finishClass should be a bit better at >>> determining as to whether default constructor is needed or not - for >>> instance, this check: >>> >>> if ((sym.flags() & INTERFACE) == 0 && >>> 928 !TreeInfo.hasConstructors(tree.defs)) { >>> >>> Should be generalized to something that works for both classes and >>> records; for classes you need to check if there's no other >>> constructor; for records you need to check if there's no other >>> constructor _with same signature_ as the canonical one. Then you can >>> simplify addRecordMembers and remove the dependency on the boolean >>> 'generatedConstructor' parameter. In other words the code should: >>> >>> 1) check if default/canonical constructor generation is required >>> 2) if so, use the appropriate helper to generate the code >>> 3) at the end, add the remaining record members (under the >>> assumption that the canonical constructor has already been added in >>> (1), if that was missing) >>> >> >> done, in order to do that I had to enter constructors at the >> RecordPhase, as mentioned earlier. >>> >>> *TypeEnter.java - addAccessor can be simplified if we only worry >>> about getters. Again, the checks in here feel more Attr check than >>> MemberEnter checks. >>> >> agreed, done >> >>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>> create a tree for a member, and then we visit the member tree with >>> memberEnter, just to add it to the scope. I understand that, >>> currently addEnumMembers does the same, but this looks very >>> roundabout; I wonder if there's a way to make all this process a bit >>> simpler - create a symbol and add that to the scope. Or are there >>> important checks in MemberEnter that we would lose? >>> >> >> yes there are several checks we would lose, plus we would lose >> consistency, but I tried to do that and several things fell apart, we >> need to enter not only the generated method, also it's parameters >> etc, which is what MemberEnter is doing. >> >>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>> store accessors in the field AST; these are only used from >>> TypeEnter, and TypeEnter can do whatever it does by looking at which >>> record components there are in the record class, and add a getter >>> for each. Let's make the code simpler and more direct >>> >> yep removed >>> >>> * ClassReader.java - should we just silently ignore record >>> attributes when not in preview mode - or should we issue classfile >>> errors? >>> >>> * ClassReader.java - what kind of validation should we do on record >>> attributes? Currently javac does nothing. Should we check that we >>> have (i) getters (ii) toString/hashCode/equals implementations and >>> (iii) a canonical constructor (ad fail if we don't) ? At the very >>> least I would add code to _parse_ the attribute, even if we do >>> nothing with it, so that at least we throw a classfile error if the >>> attribute is badly broken >>> >> on ClassReader, we can discuss what to do in a language meeting, I >> don't have any strong preference >>> >>> * Tokens.java - for "var", "yields" and other context-dependent >>> keywords we never added a token. We just handled that in >>> JavacParser. Why the difference here? I think it's best to stick to >>> current style and maybe fix all of them (assuming that's what we >>> want to do) in a followup cleanup. Actually, after looking at >>> parser, it seems like you already handle that manually, so I just >>> suggest to revert the changed to Tokens >>> >> >> I added the token to add it as a parameter to an error message, but I >> removed the token and now I'm passing a string >> >>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>> 'true' for all constructors inside a record, as opposed to only >>> return true for the canonical one? >>> >> I have added a comment to clarify what this method is doing >>> >>> * TreeInfo.java - There is some code reuse possible between >>> "recordFieldTypes" and "recordFields" >>> >> yep done >>> >>> * Names.java - what is 'oldEquals' ? >>> >> removed, old code >>> >>> * JavacParser.java - timing of checks; I don't think we should check >>> for illegal record component names in here >>> >> removed from there >>> >>> * JavacParser.java - code can be simplified somewhat by getting rid >>> of accessors in VarDef AST. >>> >> >> done >> >> Thanks again for taking the time to do this long review, will answer >> the other mails separately >> >> Vicente >>> >>> >>> >>> >>> On 21/10/2019 13:31, Vicente Romero wrote: >>>> Hi, >>>> >>>> Please review the compiler code for JEP 359 (Records) [1] >>>> >>>> Thanks in advance for the feedback, >>>> Vicente >>>> >>>> [1] >>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Sun Oct 27 22:33:19 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Sun, 27 Oct 2019 22:33:19 +0000 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: <415e23ea-8414-5964-3d5a-66a7e33cb8e8@oracle.com> Also some comments on error messages (some feedback from Alex/Jon would also be appreciated here; error messages are also crucial to convey important bits of the programming model, so I think we should try to get them right): +compiler.err.record.cant.declare.duplicate.fields=\ + records cannot declare components with the same name + I think this should be less record specific - it's just a duplicate declaration - so we should issue same error as with method/field duplicate decl? compiler.err.record.cant.declare.field.modifiers=\ + record components can not have modifiers "can not" -> "cannot" +compiler.err.record.fields.must.be.in.header=\ + instance fields in a record must be declared in the header Should it say that fields should be in the header, or should it say that a record cannot declare fields? Invalid field declaration in record (consider replacing field with record component) Or something like that. +compiler.err.canonical.constructor.must.be.public=\ + canonical constructor must be public I think I'd prefer to qualify "canonical _record_ constructor" + +compiler.err.canonical.with.name.mismatch=\ + constructor with same signature as canonical does not match by parameter names This is a tricky one. Perhaps let's try to simplify: "Invalid parameter names in record constructor" (parameter names must match the names of the declared record components) Or something similar. +compiler.err.accessor.return.type.doesnt.match=\ + type returned by the accessor is not the same as the type of the corresponding record component\n\ + required: {0}\n\ + found: {1}\n\ + Again, maybe this can be simpler: "Unexpected type in record accessor + required: {0}\n\ + found: {1}\n\ " +compiler.err.illegal.record.component.name=\ + record {0}, declares an illegal record component name: {1} Better to flip the sentence around? Illegal record component name {1} (record components cannot have same name as Object methods, ...) Maybe the first line could be enough, but if we could list the names that are 'reserved' that could be good too, assuming we can find a nice way to do that) +compiler.err.invalid.supertype.record=\ + no class can explicitly extend java.lang.Record -> "Cannot extend j.l.Record" +compiler.err.canonical.cant.have.return.statement=\ + canonical constructor can not have return statements "can not" -> "cannot" Maurizio On 27/10/2019 22:09, Maurizio Cimadamore wrote: > > Hi Vicente, looks a lot better, thanks. > > Some comments: > > Attr.java - Errors.FirstStatementMustBeCallToCanonical - not sure > about this message , but in general, all we require is that a > constructor delegates to another constructor - it can also be > something other than the canonical - e.g contsructor1 -> constructor2 > -> canonical > > Attr.java - the above situation seems to also affect some other code > in Attr - where you actually check that the invoked constructor in > 'this' has same signature of the canonical constructor. I think these > checks should be removed - the important thing is that the canonical > will be called _somehow_ - but can also be call indirectly - at least > this was my understanding > > Attr.java - not sure about the tree.sym.isRecord in the visitMethod - > it seems like the same flag is used for both record (class) and > canonical constructor? I'm ok with sharing the flag, but the method > name looks a bit confusing when applied to a method symbol. I suggest > putting 'isRecord' inside ClassSymbol, and > 'isCanonicalRecordConstructor' on MethodSymbol, so that client code > cannot make mistakes. > > Attr.java/TypeEnter.java - overall, the checks here look nice, and > they 'blend' in with existing code nicely, I think. Well done! > > Enter.java - I guess my question here on records and treatment with > STATIC is a general question as to why isn't the code doing the same > thing for records and enums - aren't the rules similar? (e.g. enums > must be static, etc)? Enums are not set STATIC by default in javac > parser, and that is, I think the difference here. What pushed you in > this direction? > > TypeEnter.java: I suggest renaming "getCanonicalInitDecl" to > "getCanonicalConstructorDecl" > > TypeEnter.java - it seems like the result of getCanonicalInitDecl is > always given the RECORD flag - but later on (in Lower) I saw a comment > which says that only auto-generated symbols have the RECORD flag set. > Which one is it? > > TypeEnter.java - I think the isUnchecked methods are a leftover from > previous code - now they seem to be in Attr.java (btw, I think we must > have those checks somewhere else in javac, look in Check::isUnchecked) > > Names.java - I think this bunch of fields is also no longer used? > > + public final Name where; > + public final Name non; > + public final Name ofLazyProjection; > + > > > I have not checked the j.l.m API. > > Thanks > Maurizio > > > > > On 26/10/2019 21:14, Vicente Romero wrote: >> I forgot to mention that I have added javax.lang.model code to this >> iteration that wasn't part of the first iteration. I was planning to >> publish it as part of a different review but I realized that there >> was some code affected, tests, API implementation etc, which belonged >> to the compiler code. So I added that code in this iteration, >> >> Thanks, >> Vicente >> >> On 10/26/19 3:55 PM, Vicente Romero wrote: >>> Hi Maurizio, >>> >>> Thanks again for the comments I have published another iteration at >>> [1]. I focused on this iteration more on the implemenation than on >>> the tests to first have an agreement on the implementation, timing, >>> etc. Some comments inlined below. >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ >>> >>> On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >>>> >>>> Hi Vicente, >>>> I did a pretty thorough pass on most of the code. I didn't look at >>>> tests, and I also didn't look at Lower. Comments below: >>>> >>>> * Flags.java - VARARGS flag for records components; I wonder, >>>> instead of a new flag, can we use the internal VARARGS flag we have >>>> for methods, and attach that to the record symbol? That should also >>>> lead to more direct code in TypeHelper >>>> >>> removed >>> >>>> * Symbol.java - I think the override for 'erasure' is redundant - >>>> isn't that the impl from supertype? >>>> >>> yep, removed too >>> >>>> * Symbol.java - I wonder if accessor list with Pair >>>> isn't a premature generalization; we should just add a getter >>>> symbol and that's it >>> >>> agreed, done >>> >>>> * Attr.java - I think we might want to leave the door open for a >>>> check which forces all constructors of a record to go through the >>>> canonical one (depending on where the spec lands) >>>> >>> implemented in this iteration >>> >>>> * Check.java - understanding checkpoint: when we see an annotation >>>> on a record component, first we check it's one of the kinds which >>>> are allowed (if not, error), and, if it's allowed, we add all >>>> record component annotations to record component elements, and we >>>> also filter away all annotations that have nothing to do with the >>>> element in which they appear. If my understanding is correct, I >>>> think this logic should be documented more clearly; I found the >>>> comment after the "if (isRecordField)" to be a bit obscure. >>>> >>> yes that's the idea, annotations that are originally applied to >>> record components are pushed down to all generated elements in >>> TypeEnter, and then in Check the ones that are off-site are removed >>>> >>>> * Enter.java - why are you removing the static flag on records? I >>>> don't see anything similar around for enums. >>>> >>> >>> the static flag is added to all records but if the record is a top >>> level class, it is not needed, that's why that code is there >>> >>>> * Flow.java - not sure I get the changes to checkInit; typically >>>> checkInit is called at the use-site of DA/DU variables. Here it >>>> seems you suppress some of the errors emitted for accessing record >>>> fields inside the canonical constructor - but I hope that code like >>>> this >>>> >>>> record Foo(int x) { >>>> ?? Foo(int x) { >>>> ?????? print(this.x); >>>> ?? } >>>> } >>>> >>>> Still give errors? >>>> >>> >>> yes it gives an error >>>> >>>> If this works correctly, which errors does the 'guard' around the >>>> error generation is supposed to protect against? >>>> >>> >>> checkInit it not used only for what you mentioned above but also, >>> see AssignAnalyzer::visitMethodDef, to check if an initial >>> constructor, as the canonical constructor is in records, have >>> initialized all the fields. The guard is there to don't issue an >>> error if a canonical constructor hasn't initialized some fields, as >>> the compiler will generate code to initialize those fields later in >>> Lower >>>> >>>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>>> used here... >>>> >>> removed >>>> >>>> * TypeEnter.java - implicit super calls are added in >>>> Attr::visitMethod for regular calls; we should do the same for >>>> records (or add all in TypeEnter - that is records and class should >>>> be consistent) >>>> >>> >>> right we should be consistent, I have moved that code to Attr >>> >>>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>>> record fields, which I think you already did in the new RecordsPhase >>>> >>> >>> nope, what I'm doing there is invoking MemberEnter to enter the >>> members that hasn't been entered so far. Anyway that code changed a >>> bit because I'm entering the constructors now at RecordPhase too but >>> I have changed the code a bit to make more clear what is happening. >>> >>>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >>>> with _all_ record members (e.g. including accessors), not just some? >>>> >>> yep changed that too >>>> >>>> * TypeEnter.java - checkForSerializationMember should probably be >>>> moved to MemberEnter::visitVar, or even to Attr (note that the code >>>> for the check is doing a little visit :-)) >>>> >>> moved to Attr >>>> >>>> * TypeEnter.java - again on check timings; while it's ok for the >>>> code in here to add new synthetic members, I think it's less ok to >>>> add more global error checks (such as make sure that the canonical >>>> declaration whose parameter names match the record components in >>>> order); these should live in Attr. More generally, I think that we >>>> should only check stuff here if we think that the check will add >>>> any value to annotation processing. Every other check can be >>>> deferred, and take place in a more 'deterministic' part of javac. >>>> >>> >>> moved to Attr >>> >>>> * TypeEnter.java - I think finishClass should be a bit better at >>>> determining as to whether default constructor is needed or not - >>>> for instance, this check: >>>> >>>> if ((sym.flags() & INTERFACE) == 0 && >>>> 928 !TreeInfo.hasConstructors(tree.defs)) { >>>> >>>> Should be generalized to something that works for both classes and >>>> records; for classes you need to check if there's no other >>>> constructor; for records you need to check if there's no other >>>> constructor _with same signature_ as the canonical one. Then you >>>> can simplify addRecordMembers and remove the dependency on the >>>> boolean 'generatedConstructor' parameter. In other words the code >>>> should: >>>> >>>> 1) check if default/canonical constructor generation is required >>>> 2) if so, use the appropriate helper to generate the code >>>> 3) at the end, add the remaining record members (under the >>>> assumption that the canonical constructor has already been added in >>>> (1), if that was missing) >>>> >>> >>> done, in order to do that I had to enter constructors at the >>> RecordPhase, as mentioned earlier. >>>> >>>> *TypeEnter.java - addAccessor can be simplified if we only worry >>>> about getters. Again, the checks in here feel more Attr check than >>>> MemberEnter checks. >>>> >>> agreed, done >>> >>>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>>> create a tree for a member, and then we visit the member tree with >>>> memberEnter, just to add it to the scope. I understand that, >>>> currently addEnumMembers does the same, but this looks very >>>> roundabout; I wonder if there's a way to make all this process a >>>> bit simpler - create a symbol and add that to the scope. Or are >>>> there important checks in MemberEnter that we would lose? >>>> >>> >>> yes there are several checks we would lose, plus we would lose >>> consistency, but I tried to do that and several things fell apart, >>> we need to enter not only the generated method, also it's parameters >>> etc, which is what MemberEnter is doing. >>> >>>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>>> store accessors in the field AST; these are only used from >>>> TypeEnter, and TypeEnter can do whatever it does by looking at >>>> which record components there are in the record class, and add a >>>> getter for each. Let's make the code simpler and more direct >>>> >>> yep removed >>>> >>>> * ClassReader.java - should we just silently ignore record >>>> attributes when not in preview mode - or should we issue classfile >>>> errors? >>>> >>>> * ClassReader.java - what kind of validation should we do on record >>>> attributes? Currently javac does nothing. Should we check that we >>>> have (i) getters (ii) toString/hashCode/equals implementations and >>>> (iii) a canonical constructor (ad fail if we don't) ? At the very >>>> least I would add code to _parse_ the attribute, even if we do >>>> nothing with it, so that at least we throw a classfile error if the >>>> attribute is badly broken >>>> >>> on ClassReader, we can discuss what to do in a language meeting, I >>> don't have any strong preference >>>> >>>> * Tokens.java - for "var", "yields" and other context-dependent >>>> keywords we never added a token. We just handled that in >>>> JavacParser. Why the difference here? I think it's best to stick to >>>> current style and maybe fix all of them (assuming that's what we >>>> want to do) in a followup cleanup. Actually, after looking at >>>> parser, it seems like you already handle that manually, so I just >>>> suggest to revert the changed to Tokens >>>> >>> >>> I added the token to add it as a parameter to an error message, but >>> I removed the token and now I'm passing a string >>> >>>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>>> 'true' for all constructors inside a record, as opposed to only >>>> return true for the canonical one? >>>> >>> I have added a comment to clarify what this method is doing >>>> >>>> * TreeInfo.java - There is some code reuse possible between >>>> "recordFieldTypes" and "recordFields" >>>> >>> yep done >>>> >>>> * Names.java - what is 'oldEquals' ? >>>> >>> removed, old code >>>> >>>> * JavacParser.java - timing of checks; I don't think we should >>>> check for illegal record component names in here >>>> >>> removed from there >>>> >>>> * JavacParser.java - code can be simplified somewhat by getting rid >>>> of accessors in VarDef AST. >>>> >>> >>> done >>> >>> Thanks again for taking the time to do this long review, will answer >>> the other mails separately >>> >>> Vicente >>>> >>>> >>>> >>>> >>>> On 21/10/2019 13:31, Vicente Romero wrote: >>>>> Hi, >>>>> >>>>> Please review the compiler code for JEP 359 (Records) [1] >>>>> >>>>> Thanks in advance for the feedback, >>>>> Vicente >>>>> >>>>> [1] >>>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ >>>>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Sun Oct 27 23:41:22 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Sun, 27 Oct 2019 19:41:22 -0400 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <9f1e7585-1754-afd2-21f4-bdd1931936bf@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <9f1e7585-1754-afd2-21f4-bdd1931936bf@oracle.com> Message-ID: <65316668-fc7c-e887-52be-2d098d4eb0a2@oracle.com> Hi Brian, Thanks for your comments. I have published another review iteration [1]. Some comments inlined below. On 10/25/19 5:04 PM, Brian Goetz wrote: > Spec in Class.java: > > ?- Various {@code RecordComponent} should be {@link RecordComponent}. we could do that but the current approach is consistent with what we are doing in similar APIs like Class::getDeclaredFields() > ?- Rather than say "if this class was declared as a record in the > source code", instead say "is a record class", since record classes > are a term defined by the JLS. fixed > ?- For isRecord/getRecordComponents, should include "@jls 8.10" link done > > RecordComponent.java: > > ?- Add @jls 8.10 link > ?- "Returns the name of the component represented by this record > component." -> "Returns the name of this record component." and > similar in other methods.? Since RC models a record component, its > clear enough what is meant. done, the javadoc was following the same approach as in java.lang.reflect.Field > ?- For getGenericSignature, there should be a link back to @jls or > @jvms that describes the format of the signature string. done, added @jvms 4.7.9.1 Signatures > ?- Doesn't getAnnotation() need some spec, or an {@inheritDoc}? yep done Thanks, Vicente [1] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.01/ From srikanth.adayapalam at oracle.com Mon Oct 28 09:10:35 2019 From: srikanth.adayapalam at oracle.com (Srikanth) Date: Mon, 28 Oct 2019 14:40:35 +0530 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Message-ID: Hi Vicente, I plan to make one more separate pass over annotation handling later this week, in the mean time, here are several comments. I omitted anything already called out by Maurizio or Jan. HTH, Thanks Srikanth (1) Flags.java: Is there a reason for choosing the flags for RECORD to be 1L<<61, leaving 1<<59 and 1<<60 as holes ?? (2) javadoc for flag RECORD inconsistent with the // comment (one mentions methods the other does not) (3) MemberRecordClassFlags LocalRecordFlags - naming inconsistent; former should be MemberRecordFlags ? (4) com.sun.tools.javac.parser.JavacParser#isRestrictedRecordTypeName appears unused (5) (Ignorable) Field `names' is changed from private to protected because it needs to be referenced in ReplParser I guess. This could have been worked around by reaching to token.name().table.names.record instead. (6) Javac allows a top level record to be static - is this intentional ? Top levels classes may not be. This code compiles: static public record X(int x, int y) { } (7) Local records cannot be explicitly tagged final. (Likewise annotations will be rejected) public class X { ??? public static void main(String [] args) { ??????? final record X(int x, int y) {? // <<-- does not compile ??????? } ??? } } (8) if (isRecordToken() && ??????????? (peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) || ???????????? peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) { ??????????? JCModifiers mods = modifiersOpt(); ??????????? dc = token.comment(CommentStyle.JAVADOC); ??????????? return List.of(recordDeclaration(mods, dc)); ??????? } The call to modifiersOpt - is this misplaced ? We have already seen `record' and the peek is signalling an IDENTIFIER ?? (The default is moved out of the switch - it took me a while to recognize that the semantics are unaffected. So this appears fine) (9) I was surprised to see the emission of Errors.RecordCantBeAbstract in com.sun.tools.javac.parser.JavacParser#recordDeclaration. I would have expected this check inside com.sun.tools.javac.comp.Check#checkFlags See that this latter place is where abstract enums are complained against. (10) List defs = List.nil(); inside JavacParser#recordDeclaration is a redundant initialization. (11) Likewise I was surprised to see Errors.RecordCantDeclareDuplicateFields being emitted in com.sun.tools.javac.parser.JavacParser#recordDeclaration. I would have expected this to be emitted in com.sun.tools.javac.comp.Check#checkUnique (12) Compact constructor trees are modified in in com.sun.tools.javac.parser.JavacParser#recordDeclaration to become elaborated tree - I thought this practice of modifying parse trees in the early stages is frowned upon ?? (Other parse tree transformations also happen here) (13) com.sun.tools.javac.parser.JavacParser#formalParameter() is unused ?? (14) Check.java: Seems import java.util.stream.Collectors; is unused (15) Symbol.java: several unused imports seem to have crept in. import com.sun.tools.javac.util.Name; import com.sun.tools.javac.code.MissingInfoHandler; import com.sun.tools.javac.code.Symbol; import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP; import com.sun.tools.javac.code.Type; (16) The various isXXX methods differ in how they access the flags_field. Some use flags() while others use flags_field. I think it is better to use flags() as it will trigger completion (as it should ??) In any case the difference seems gratuitous (17) Does com.sun.tools.javac.code.Symbol.MethodSymbol#isDynamic serve a purpose - seems to be identical to super implementation ?? (18) Attr: Errors.MethodMustBePublic emission code could use the new Symbol.isPublic() (100 lines below we do use the new method) (19) Attr.isUnchecked() the new methods are mirror images of the Check.isUnchecked methods ? Is there a reason for the duplication ?? (20) Javadoc of com.sun.tools.javac.comp.Attr#checkFirstConstructorStat does not document all parameters (21) I didn't quite understand what we do this in MemberEnter for: ??? else if (v.owner.kind == MTH || (v.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.MANDATED | Flags.RECORD)) != 0) { ??????????? enclScope.enter(v); ??????? } On 21/10/19 6:01 PM, Vicente Romero wrote: > Hi, > > Please review the compiler code for JEP 359 (Records) [1] > > Thanks in advance for the feedback, > Vicente > > [1] > http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ From vicente.romero at oracle.com Mon Oct 28 21:37:33 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 28 Oct 2019 17:37:33 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> Message-ID: <067e32b4-4d07-73f2-73d6-21a57c70c420@oracle.com> Hi Maurizio, Thanks for the comments On 10/27/19 6:09 PM, Maurizio Cimadamore wrote: > > Hi Vicente, looks a lot better, thanks. > > Some comments: > > Attr.java - Errors.FirstStatementMustBeCallToCanonical - not sure > about this message , but in general, all we require is that a > constructor delegates to another constructor - it can also be > something other than the canonical - e.g contsructor1 -> constructor2 > -> canonical > this is what the current spec for records mandates: 8.10.4 Record Constructor Declarations ... "If a record type R declares constructors other the canonical constructor, then they must satisfy both of the following: The constructor body must start with an explicit constructor invocation of the canonical constructor for the record type R." > Attr.java - the above situation seems to also affect some other code > in Attr - where you actually check that the invoked constructor in > 'this' has same signature of the canonical constructor. I think these > checks should be removed - the important thing is that the canonical > will be called _somehow_ - but can also be call indirectly - at least > this was my understanding > ditto > Attr.java - not sure about the tree.sym.isRecord in the visitMethod - > it seems like the same flag is used for both record (class) and > canonical constructor? I'm ok with sharing the flag, but the method > name looks a bit confusing when applied to a method symbol. I suggest > putting 'isRecord' inside ClassSymbol, and > 'isCanonicalRecordConstructor' on MethodSymbol, so that client code > cannot make mistakes. > I can do that if you are pretty strong about this but if we go for it those methods you are proposing will be almost useless as it is more straight forward to just do a bitwise and with the flag rather than having to cast symbols to have access to the particular flavor of the method, worst than that we would have to check if the owner of a method is actually a class before doing the cast, in preparation of local methods. What about renaming the method to: hasRecordFlagSet or similar. Or I can just remove the method and do the old faithful bitwise. > Attr.java/TypeEnter.java - overall, the checks here look nice, and > they 'blend' in with existing code nicely, I think. Well done! > cool, after shaking the box and all the pieces found their place! :) > Enter.java - I guess my question here on records and treatment with > STATIC is a general question as to why isn't the code doing the same > thing for records and enums - aren't the rules similar? (e.g. enums > must be static, etc)? Enums are not set STATIC by default in javac > parser, and that is, I think the difference here. What pushed you in > this direction? > I have updated the code to do the same we do for enums, I just found my approach simpler, but it is true that is less consistent > TypeEnter.java: I suggest renaming "getCanonicalInitDecl" to > "getCanonicalConstructorDecl" > > TypeEnter.java - it seems like the result of getCanonicalInitDecl is > always given the RECORD flag - but later on (in Lower) I saw a comment > which says that only auto-generated symbols have the RECORD flag set. > Which one is it? > the comment in Lower refers to accessors only, I will document all the cases that uses the RECORD flag, as we are running low of flags entry I have reused this one for several different uses but you have a point that it could be tricky to understand when it is used and why > TypeEnter.java - I think the isUnchecked methods are a leftover from > previous code - now they seem to be in Attr.java (btw, I think we must > have those checks somewhere else in javac, look in Check::isUnchecked) > yep I removed them from both, there was a spec change now neither accessors nor canonical constructor can have a throws clause > > Names.java - I think this bunch of fields is also no longer used? > > + public final Name where; > + public final Name non; > + public final Name ofLazyProjection; > + > > yep thanks, removed > I have not checked the j.l.m API. > > Thanks > Maurizio > Thanks, Vicente PS, I will be sending a new iteration soon > > > > On 26/10/2019 21:14, Vicente Romero wrote: >> I forgot to mention that I have added javax.lang.model code to this >> iteration that wasn't part of the first iteration. I was planning to >> publish it as part of a different review but I realized that there >> was some code affected, tests, API implementation etc, which belonged >> to the compiler code. So I added that code in this iteration, >> >> Thanks, >> Vicente >> >> On 10/26/19 3:55 PM, Vicente Romero wrote: >>> Hi Maurizio, >>> >>> Thanks again for the comments I have published another iteration at >>> [1]. I focused on this iteration more on the implemenation than on >>> the tests to first have an agreement on the implementation, timing, >>> etc. Some comments inlined below. >>> >>> [1] >>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ >>> >>> On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >>>> >>>> Hi Vicente, >>>> I did a pretty thorough pass on most of the code. I didn't look at >>>> tests, and I also didn't look at Lower. Comments below: >>>> >>>> * Flags.java - VARARGS flag for records components; I wonder, >>>> instead of a new flag, can we use the internal VARARGS flag we have >>>> for methods, and attach that to the record symbol? That should also >>>> lead to more direct code in TypeHelper >>>> >>> removed >>> >>>> * Symbol.java - I think the override for 'erasure' is redundant - >>>> isn't that the impl from supertype? >>>> >>> yep, removed too >>> >>>> * Symbol.java - I wonder if accessor list with Pair >>>> isn't a premature generalization; we should just add a getter >>>> symbol and that's it >>> >>> agreed, done >>> >>>> * Attr.java - I think we might want to leave the door open for a >>>> check which forces all constructors of a record to go through the >>>> canonical one (depending on where the spec lands) >>>> >>> implemented in this iteration >>> >>>> * Check.java - understanding checkpoint: when we see an annotation >>>> on a record component, first we check it's one of the kinds which >>>> are allowed (if not, error), and, if it's allowed, we add all >>>> record component annotations to record component elements, and we >>>> also filter away all annotations that have nothing to do with the >>>> element in which they appear. If my understanding is correct, I >>>> think this logic should be documented more clearly; I found the >>>> comment after the "if (isRecordField)" to be a bit obscure. >>>> >>> yes that's the idea, annotations that are originally applied to >>> record components are pushed down to all generated elements in >>> TypeEnter, and then in Check the ones that are off-site are removed >>>> >>>> * Enter.java - why are you removing the static flag on records? I >>>> don't see anything similar around for enums. >>>> >>> >>> the static flag is added to all records but if the record is a top >>> level class, it is not needed, that's why that code is there >>> >>>> * Flow.java - not sure I get the changes to checkInit; typically >>>> checkInit is called at the use-site of DA/DU variables. Here it >>>> seems you suppress some of the errors emitted for accessing record >>>> fields inside the canonical constructor - but I hope that code like >>>> this >>>> >>>> record Foo(int x) { >>>> ?? Foo(int x) { >>>> ?????? print(this.x); >>>> ?? } >>>> } >>>> >>>> Still give errors? >>>> >>> >>> yes it gives an error >>>> >>>> If this works correctly, which errors does the 'guard' around the >>>> error generation is supposed to protect against? >>>> >>> >>> checkInit it not used only for what you mentioned above but also, >>> see AssignAnalyzer::visitMethodDef, to check if an initial >>> constructor, as the canonical constructor is in records, have >>> initialized all the fields. The guard is there to don't issue an >>> error if a canonical constructor hasn't initialized some fields, as >>> the compiler will generate code to initialize those fields later in >>> Lower >>>> >>>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>>> used here... >>>> >>> removed >>>> >>>> * TypeEnter.java - implicit super calls are added in >>>> Attr::visitMethod for regular calls; we should do the same for >>>> records (or add all in TypeEnter - that is records and class should >>>> be consistent) >>>> >>> >>> right we should be consistent, I have moved that code to Attr >>> >>>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>>> record fields, which I think you already did in the new RecordsPhase >>>> >>> >>> nope, what I'm doing there is invoking MemberEnter to enter the >>> members that hasn't been entered so far. Anyway that code changed a >>> bit because I'm entering the constructors now at RecordPhase too but >>> I have changed the code a bit to make more clear what is happening. >>> >>>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should deal >>>> with _all_ record members (e.g. including accessors), not just some? >>>> >>> yep changed that too >>>> >>>> * TypeEnter.java - checkForSerializationMember should probably be >>>> moved to MemberEnter::visitVar, or even to Attr (note that the code >>>> for the check is doing a little visit :-)) >>>> >>> moved to Attr >>>> >>>> * TypeEnter.java - again on check timings; while it's ok for the >>>> code in here to add new synthetic members, I think it's less ok to >>>> add more global error checks (such as make sure that the canonical >>>> declaration whose parameter names match the record components in >>>> order); these should live in Attr. More generally, I think that we >>>> should only check stuff here if we think that the check will add >>>> any value to annotation processing. Every other check can be >>>> deferred, and take place in a more 'deterministic' part of javac. >>>> >>> >>> moved to Attr >>> >>>> * TypeEnter.java - I think finishClass should be a bit better at >>>> determining as to whether default constructor is needed or not - >>>> for instance, this check: >>>> >>>> if ((sym.flags() & INTERFACE) == 0 && >>>> 928 !TreeInfo.hasConstructors(tree.defs)) { >>>> >>>> Should be generalized to something that works for both classes and >>>> records; for classes you need to check if there's no other >>>> constructor; for records you need to check if there's no other >>>> constructor _with same signature_ as the canonical one. Then you >>>> can simplify addRecordMembers and remove the dependency on the >>>> boolean 'generatedConstructor' parameter. In other words the code >>>> should: >>>> >>>> 1) check if default/canonical constructor generation is required >>>> 2) if so, use the appropriate helper to generate the code >>>> 3) at the end, add the remaining record members (under the >>>> assumption that the canonical constructor has already been added in >>>> (1), if that was missing) >>>> >>> >>> done, in order to do that I had to enter constructors at the >>> RecordPhase, as mentioned earlier. >>>> >>>> *TypeEnter.java - addAccessor can be simplified if we only worry >>>> about getters. Again, the checks in here feel more Attr check than >>>> MemberEnter checks. >>>> >>> agreed, done >>> >>>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>>> create a tree for a member, and then we visit the member tree with >>>> memberEnter, just to add it to the scope. I understand that, >>>> currently addEnumMembers does the same, but this looks very >>>> roundabout; I wonder if there's a way to make all this process a >>>> bit simpler - create a symbol and add that to the scope. Or are >>>> there important checks in MemberEnter that we would lose? >>>> >>> >>> yes there are several checks we would lose, plus we would lose >>> consistency, but I tried to do that and several things fell apart, >>> we need to enter not only the generated method, also it's parameters >>> etc, which is what MemberEnter is doing. >>> >>>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>>> store accessors in the field AST; these are only used from >>>> TypeEnter, and TypeEnter can do whatever it does by looking at >>>> which record components there are in the record class, and add a >>>> getter for each. Let's make the code simpler and more direct >>>> >>> yep removed >>>> >>>> * ClassReader.java - should we just silently ignore record >>>> attributes when not in preview mode - or should we issue classfile >>>> errors? >>>> >>>> * ClassReader.java - what kind of validation should we do on record >>>> attributes? Currently javac does nothing. Should we check that we >>>> have (i) getters (ii) toString/hashCode/equals implementations and >>>> (iii) a canonical constructor (ad fail if we don't) ? At the very >>>> least I would add code to _parse_ the attribute, even if we do >>>> nothing with it, so that at least we throw a classfile error if the >>>> attribute is badly broken >>>> >>> on ClassReader, we can discuss what to do in a language meeting, I >>> don't have any strong preference >>>> >>>> * Tokens.java - for "var", "yields" and other context-dependent >>>> keywords we never added a token. We just handled that in >>>> JavacParser. Why the difference here? I think it's best to stick to >>>> current style and maybe fix all of them (assuming that's what we >>>> want to do) in a followup cleanup. Actually, after looking at >>>> parser, it seems like you already handle that manually, so I just >>>> suggest to revert the changed to Tokens >>>> >>> >>> I added the token to add it as a parameter to an error message, but >>> I removed the token and now I'm passing a string >>> >>>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>>> 'true' for all constructors inside a record, as opposed to only >>>> return true for the canonical one? >>>> >>> I have added a comment to clarify what this method is doing >>>> >>>> * TreeInfo.java - There is some code reuse possible between >>>> "recordFieldTypes" and "recordFields" >>>> >>> yep done >>>> >>>> * Names.java - what is 'oldEquals' ? >>>> >>> removed, old code >>>> >>>> * JavacParser.java - timing of checks; I don't think we should >>>> check for illegal record component names in here >>>> >>> removed from there >>>> >>>> * JavacParser.java - code can be simplified somewhat by getting rid >>>> of accessors in VarDef AST. >>>> >>> >>> done >>> >>> Thanks again for taking the time to do this long review, will answer >>> the other mails separately >>> >>> Vicente >>>> >>>> >>>> >>>> >>>> On 21/10/2019 13:31, Vicente Romero wrote: >>>>> Hi, >>>>> >>>>> Please review the compiler code for JEP 359 (Records) [1] >>>>> >>>>> Thanks in advance for the feedback, >>>>> Vicente >>>>> >>>>> [1] >>>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ >>>>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Mon Oct 28 22:48:19 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 28 Oct 2019 18:48:19 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <415e23ea-8414-5964-3d5a-66a7e33cb8e8@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <415e23ea-8414-5964-3d5a-66a7e33cb8e8@oracle.com> Message-ID: <1ae03b10-ec1d-4714-264b-138209e3bdc3@oracle.com> Hi Maurizio, I have uploaded another iteration [1], some comments inlined below. On 10/27/19 6:33 PM, Maurizio Cimadamore wrote: > > Also some comments on error messages (some feedback from Alex/Jon > would also be appreciated here; error messages are also crucial to > convey important bits of the programming model, so I think we should > try to get them right): > > +compiler.err.record.cant.declare.duplicate.fields=\ > + records cannot declare components with the same name > + > > I think this should be less record specific - it's just a duplicate > declaration - so we should issue same error as with method/field > duplicate decl? not sure what to do here, there are several error messages about duplicated elements that are also pretty specific, see for modules, annotations etc. > > compiler.err.record.cant.declare.field.modifiers=\ > + record components can not have modifiers > "can not" -> "cannot" done > > +compiler.err.record.fields.must.be.in.header=\ > + instance fields in a record must be declared in the header > Should it say that fields should be in the header, or should it say > that a record cannot declare fields? yep fixed > > Invalid field declaration in record > (consider replacing field with record component) > > Or something like that. > > +compiler.err.canonical.constructor.must.be.public=\ > + canonical constructor must be public > I think I'd prefer to qualify "canonical _record_ constructor" done > + > +compiler.err.canonical.with.name.mismatch=\ > + constructor with same signature as canonical does not match by > parameter names > This is a tricky one. Perhaps let's try to simplify: > > "Invalid parameter names in record constructor" > (parameter names must match the names of the declared record components) done > > Or something similar. > > +compiler.err.accessor.return.type.doesnt.match=\ > + type returned by the accessor is not the same as the type of the > corresponding record component\n\ > + required: {0}\n\ > + found: {1}\n\ > + > > Again, maybe this can be simpler: > > "Unexpected type in record accessor > + required: {0}\n\ > + found: {1}\n\ > " > yep agreed > +compiler.err.illegal.record.component.name=\ > + record {0}, declares an illegal record component name: {1} > > > Better to flip the sentence around? > > Illegal record component name {1} > (record components cannot have same name as Object methods, ...) > > Maybe the first line could be enough, but if we could list the names > that are 'reserved' that could be good too, assuming we can find a > nice way to do that)\\ > I would say lets let only the first part: "Illegal record component name {1}" because there are other serialization related methods and fields that cant be used as component names. Listing all the possible sources would be muddy business I think. > +compiler.err.invalid.supertype.record=\ > + no class can explicitly extend java.lang.Record > > -> "Cannot extend j.l.Record" > done > > > +compiler.err.canonical.cant.have.return.statement=\ > + canonical constructor can not have return statements > > "can not" -> "cannot" > fixed > > > Maurizio > Thanks, Vicente [1] http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.02/ > On 27/10/2019 22:09, Maurizio Cimadamore wrote: >> >> Hi Vicente, looks a lot better, thanks. >> >> Some comments: >> >> Attr.java - Errors.FirstStatementMustBeCallToCanonical - not sure >> about this message , but in general, all we require is that a >> constructor delegates to another constructor - it can also be >> something other than the canonical - e.g contsructor1 -> constructor2 >> -> canonical >> >> Attr.java - the above situation seems to also affect some other code >> in Attr - where you actually check that the invoked constructor in >> 'this' has same signature of the canonical constructor. I think these >> checks should be removed - the important thing is that the canonical >> will be called _somehow_ - but can also be call indirectly - at least >> this was my understanding >> >> Attr.java - not sure about the tree.sym.isRecord in the visitMethod - >> it seems like the same flag is used for both record (class) and >> canonical constructor? I'm ok with sharing the flag, but the method >> name looks a bit confusing when applied to a method symbol. I suggest >> putting 'isRecord' inside ClassSymbol, and >> 'isCanonicalRecordConstructor' on MethodSymbol, so that client code >> cannot make mistakes. >> >> Attr.java/TypeEnter.java - overall, the checks here look nice, and >> they 'blend' in with existing code nicely, I think. Well done! >> >> Enter.java - I guess my question here on records and treatment with >> STATIC is a general question as to why isn't the code doing the same >> thing for records and enums - aren't the rules similar? (e.g. enums >> must be static, etc)? Enums are not set STATIC by default in javac >> parser, and that is, I think the difference here. What pushed you in >> this direction? >> >> TypeEnter.java: I suggest renaming "getCanonicalInitDecl" to >> "getCanonicalConstructorDecl" >> >> TypeEnter.java - it seems like the result of getCanonicalInitDecl is >> always given the RECORD flag - but later on (in Lower) I saw a >> comment which says that only auto-generated symbols have the RECORD >> flag set. Which one is it? >> >> TypeEnter.java - I think the isUnchecked methods are a leftover from >> previous code - now they seem to be in Attr.java (btw, I think we >> must have those checks somewhere else in javac, look in >> Check::isUnchecked) >> >> Names.java - I think this bunch of fields is also no longer used? >> >> + public final Name where; >> + public final Name non; >> + public final Name ofLazyProjection; >> + >> >> >> I have not checked the j.l.m API. >> >> Thanks >> Maurizio >> >> >> >> >> On 26/10/2019 21:14, Vicente Romero wrote: >>> I forgot to mention that I have added javax.lang.model code to this >>> iteration that wasn't part of the first iteration. I was planning to >>> publish it as part of a different review but I realized that there >>> was some code affected, tests, API implementation etc, which >>> belonged to the compiler code. So I added that code in this iteration, >>> >>> Thanks, >>> Vicente >>> >>> On 10/26/19 3:55 PM, Vicente Romero wrote: >>>> Hi Maurizio, >>>> >>>> Thanks again for the comments I have published another iteration at >>>> [1]. I focused on this iteration more on the implemenation than on >>>> the tests to first have an agreement on the implementation, timing, >>>> etc. Some comments inlined below. >>>> >>>> [1] >>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ >>>> >>>> On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >>>>> >>>>> Hi Vicente, >>>>> I did a pretty thorough pass on most of the code. I didn't look at >>>>> tests, and I also didn't look at Lower. Comments below: >>>>> >>>>> * Flags.java - VARARGS flag for records components; I wonder, >>>>> instead of a new flag, can we use the internal VARARGS flag we >>>>> have for methods, and attach that to the record symbol? That >>>>> should also lead to more direct code in TypeHelper >>>>> >>>> removed >>>> >>>>> * Symbol.java - I think the override for 'erasure' is redundant - >>>>> isn't that the impl from supertype? >>>>> >>>> yep, removed too >>>> >>>>> * Symbol.java - I wonder if accessor list with Pair >>>>> isn't a premature generalization; we should just add a getter >>>>> symbol and that's it >>>> >>>> agreed, done >>>> >>>>> * Attr.java - I think we might want to leave the door open for a >>>>> check which forces all constructors of a record to go through the >>>>> canonical one (depending on where the spec lands) >>>>> >>>> implemented in this iteration >>>> >>>>> * Check.java - understanding checkpoint: when we see an annotation >>>>> on a record component, first we check it's one of the kinds which >>>>> are allowed (if not, error), and, if it's allowed, we add all >>>>> record component annotations to record component elements, and we >>>>> also filter away all annotations that have nothing to do with the >>>>> element in which they appear. If my understanding is correct, I >>>>> think this logic should be documented more clearly; I found the >>>>> comment after the "if (isRecordField)" to be a bit obscure. >>>>> >>>> yes that's the idea, annotations that are originally applied to >>>> record components are pushed down to all generated elements in >>>> TypeEnter, and then in Check the ones that are off-site are removed >>>>> >>>>> * Enter.java - why are you removing the static flag on records? I >>>>> don't see anything similar around for enums. >>>>> >>>> >>>> the static flag is added to all records but if the record is a top >>>> level class, it is not needed, that's why that code is there >>>> >>>>> * Flow.java - not sure I get the changes to checkInit; typically >>>>> checkInit is called at the use-site of DA/DU variables. Here it >>>>> seems you suppress some of the errors emitted for accessing record >>>>> fields inside the canonical constructor - but I hope that code >>>>> like this >>>>> >>>>> record Foo(int x) { >>>>> ?? Foo(int x) { >>>>> ?????? print(this.x); >>>>> ?? } >>>>> } >>>>> >>>>> Still give errors? >>>>> >>>> >>>> yes it gives an error >>>>> >>>>> If this works correctly, which errors does the 'guard' around the >>>>> error generation is supposed to protect against? >>>>> >>>> >>>> checkInit it not used only for what you mentioned above but also, >>>> see AssignAnalyzer::visitMethodDef, to check if an initial >>>> constructor, as the canonical constructor is in records, have >>>> initialized all the fields. The guard is there to don't issue an >>>> error if a canonical constructor hasn't initialized some fields, as >>>> the compiler will generate code to initialize those fields later in >>>> Lower >>>>> >>>>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>>>> used here... >>>>> >>>> removed >>>>> >>>>> * TypeEnter.java - implicit super calls are added in >>>>> Attr::visitMethod for regular calls; we should do the same for >>>>> records (or add all in TypeEnter - that is records and class >>>>> should be consistent) >>>>> >>>> >>>> right we should be consistent, I have moved that code to Attr >>>> >>>>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>>>> record fields, which I think you already did in the new RecordsPhase >>>>> >>>> >>>> nope, what I'm doing there is invoking MemberEnter to enter the >>>> members that hasn't been entered so far. Anyway that code changed a >>>> bit because I'm entering the constructors now at RecordPhase too >>>> but I have changed the code a bit to make more clear what is happening. >>>> >>>>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should >>>>> deal with _all_ record members (e.g. including accessors), not >>>>> just some? >>>>> >>>> yep changed that too >>>>> >>>>> * TypeEnter.java - checkForSerializationMember should probably be >>>>> moved to MemberEnter::visitVar, or even to Attr (note that the >>>>> code for the check is doing a little visit :-)) >>>>> >>>> moved to Attr >>>>> >>>>> * TypeEnter.java - again on check timings; while it's ok for the >>>>> code in here to add new synthetic members, I think it's less ok to >>>>> add more global error checks (such as make sure that the canonical >>>>> declaration whose parameter names match the record components in >>>>> order); these should live in Attr. More generally, I think that we >>>>> should only check stuff here if we think that the check will add >>>>> any value to annotation processing. Every other check can be >>>>> deferred, and take place in a more 'deterministic' part of javac. >>>>> >>>> >>>> moved to Attr >>>> >>>>> * TypeEnter.java - I think finishClass should be a bit better at >>>>> determining as to whether default constructor is needed or not - >>>>> for instance, this check: >>>>> >>>>> if ((sym.flags() & INTERFACE) == 0 && >>>>> 928 !TreeInfo.hasConstructors(tree.defs)) { >>>>> >>>>> Should be generalized to something that works for both classes and >>>>> records; for classes you need to check if there's no other >>>>> constructor; for records you need to check if there's no other >>>>> constructor _with same signature_ as the canonical one. Then you >>>>> can simplify addRecordMembers and remove the dependency on the >>>>> boolean 'generatedConstructor' parameter. In other words the code >>>>> should: >>>>> >>>>> 1) check if default/canonical constructor generation is required >>>>> 2) if so, use the appropriate helper to generate the code >>>>> 3) at the end, add the remaining record members (under the >>>>> assumption that the canonical constructor has already been added >>>>> in (1), if that was missing) >>>>> >>>> >>>> done, in order to do that I had to enter constructors at the >>>> RecordPhase, as mentioned earlier. >>>>> >>>>> *TypeEnter.java - addAccessor can be simplified if we only worry >>>>> about getters. Again, the checks in here feel more Attr check than >>>>> MemberEnter checks. >>>>> >>>> agreed, done >>>> >>>>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>>>> create a tree for a member, and then we visit the member tree with >>>>> memberEnter, just to add it to the scope. I understand that, >>>>> currently addEnumMembers does the same, but this looks very >>>>> roundabout; I wonder if there's a way to make all this process a >>>>> bit simpler - create a symbol and add that to the scope. Or are >>>>> there important checks in MemberEnter that we would lose? >>>>> >>>> >>>> yes there are several checks we would lose, plus we would lose >>>> consistency, but I tried to do that and several things fell apart, >>>> we need to enter not only the generated method, also it's >>>> parameters etc, which is what MemberEnter is doing. >>>> >>>>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>>>> store accessors in the field AST; these are only used from >>>>> TypeEnter, and TypeEnter can do whatever it does by looking at >>>>> which record components there are in the record class, and add a >>>>> getter for each. Let's make the code simpler and more direct >>>>> >>>> yep removed >>>>> >>>>> * ClassReader.java - should we just silently ignore record >>>>> attributes when not in preview mode - or should we issue classfile >>>>> errors? >>>>> >>>>> * ClassReader.java - what kind of validation should we do on >>>>> record attributes? Currently javac does nothing. Should we check >>>>> that we have (i) getters (ii) toString/hashCode/equals >>>>> implementations and (iii) a canonical constructor (ad fail if we >>>>> don't) ? At the very least I would add code to _parse_ the >>>>> attribute, even if we do nothing with it, so that at least we >>>>> throw a classfile error if the attribute is badly broken >>>>> >>>> on ClassReader, we can discuss what to do in a language meeting, I >>>> don't have any strong preference >>>>> >>>>> * Tokens.java - for "var", "yields" and other context-dependent >>>>> keywords we never added a token. We just handled that in >>>>> JavacParser. Why the difference here? I think it's best to stick >>>>> to current style and maybe fix all of them (assuming that's what >>>>> we want to do) in a followup cleanup. Actually, after looking at >>>>> parser, it seems like you already handle that manually, so I just >>>>> suggest to revert the changed to Tokens >>>>> >>>> >>>> I added the token to add it as a parameter to an error message, but >>>> I removed the token and now I'm passing a string >>>> >>>>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>>>> 'true' for all constructors inside a record, as opposed to only >>>>> return true for the canonical one? >>>>> >>>> I have added a comment to clarify what this method is doing >>>>> >>>>> * TreeInfo.java - There is some code reuse possible between >>>>> "recordFieldTypes" and "recordFields" >>>>> >>>> yep done >>>>> >>>>> * Names.java - what is 'oldEquals' ? >>>>> >>>> removed, old code >>>>> >>>>> * JavacParser.java - timing of checks; I don't think we should >>>>> check for illegal record component names in here >>>>> >>>> removed from there >>>>> >>>>> * JavacParser.java - code can be simplified somewhat by getting >>>>> rid of accessors in VarDef AST. >>>>> >>>> >>>> done >>>> >>>> Thanks again for taking the time to do this long review, will >>>> answer the other mails separately >>>> >>>> Vicente >>>>> >>>>> >>>>> >>>>> >>>>> On 21/10/2019 13:31, Vicente Romero wrote: >>>>>> Hi, >>>>>> >>>>>> Please review the compiler code for JEP 359 (Records) [1] >>>>>> >>>>>> Thanks in advance for the feedback, >>>>>> Vicente >>>>>> >>>>>> [1] >>>>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ >>>>>> >>>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.hegarty at oracle.com Tue Oct 29 13:49:58 2019 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 29 Oct 2019 13:49:58 +0000 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> Message-ID: <3E0419C6-8EB5-4988-AC6C-D35B2A3BA6E0@oracle.com> > On 21 Oct 2019, at 22:10, Vicente Romero wrote: > > ... > [1] http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.00/ java.lang.reflect.RecordComponent 1) The `toGenericString` method is specified to include the access modifiers of the ?record component, always private and final?. Well, clearly these modifiers are related to the field that backs the record component. Is this class modelling the record components ( as in the record descriptor ), or the private final fields that back those components? If the former, then maybe the access modifiers should be dropped from the string representation. 2) I think that `RecordComponent::toString` should be added and specified ( in a similar way to that of Field or Method, without the generic type information ) -Chris. P.S. I?m happy to push changes for the above, once there is agreement. From joe.darcy at oracle.com Tue Oct 29 16:58:51 2019 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 29 Oct 2019 09:58:51 -0700 Subject: JDK 14 RFR of JDK-8233096: Update javax.lang.model for switch expressions Message-ID: <0ba28fbc-6036-2b58-b579-ab3687b939cf@oracle.com> Hello, After switch expressions are added as a full non-preview feature (JDK-8232684), portions of javax.lang.model should be updated accordingly, including the description of SourceVersion.RELEASE_14. Please review the changes for this: ??? http://cr.openjdk.java.net/~darcy/8233096.0/ Thanks, -Joe From jonathan.gibbons at oracle.com Tue Oct 29 17:09:35 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Tue, 29 Oct 2019 10:09:35 -0700 Subject: JDK 14 RFR of JDK-8233096: Update javax.lang.model for switch expressions In-Reply-To: <0ba28fbc-6036-2b58-b579-ab3687b939cf@oracle.com> References: <0ba28fbc-6036-2b58-b579-ab3687b939cf@oracle.com> Message-ID: Although not modified, is this line in the test as intended? 137 throw new RuntimeException("Unexpected " + message + "-ness of _ on " + version); The reference to "_" seems unexpected. -- Jon On 10/29/19 9:58 AM, Joe Darcy wrote: > Hello, > > After switch expressions are added as a full non-preview feature > (JDK-8232684), portions of javax.lang.model should be updated > accordingly, including the description of SourceVersion.RELEASE_14. > > Please review the changes for this: > > ??? http://cr.openjdk.java.net/~darcy/8233096.0/ > > Thanks, > > -Joe > -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Tue Oct 29 18:28:41 2019 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 29 Oct 2019 11:28:41 -0700 Subject: JDK 14 RFR of JDK-8233096: Update javax.lang.model for switch expressions In-Reply-To: References: <0ba28fbc-6036-2b58-b579-ab3687b939cf@oracle.com> Message-ID: On 10/29/2019 10:09 AM, Jonathan Gibbons wrote: > > Although not modified, is this line in the test as intended? > > 137 throw new RuntimeException("Unexpected " + message + "-ness of _ on " + version); > The reference to "_" seems unexpected. Yeah; I noticed that too. It would clearly be more informative to print out the input causing the failure. Code review feedback could overcome my activation energy to do the small necessary refactoring ;-) -Joe > > -- Jon > > On 10/29/19 9:58 AM, Joe Darcy wrote: >> Hello, >> >> After switch expressions are added as a full non-preview feature >> (JDK-8232684), portions of javax.lang.model should be updated >> accordingly, including the description of SourceVersion.RELEASE_14. >> >> Please review the changes for this: >> >> http://cr.openjdk.java.net/~darcy/8233096.0/ >> >> Thanks, >> >> -Joe >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Wed Oct 30 01:24:38 2019 From: joe.darcy at oracle.com (Joe Darcy) Date: Tue, 29 Oct 2019 18:24:38 -0700 Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <65316668-fc7c-e887-52be-2d098d4eb0a2@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <9f1e7585-1754-afd2-21f4-bdd1931936bf@oracle.com> <65316668-fc7c-e887-52be-2d098d4eb0a2@oracle.com> Message-ID: <48bbd0e4-7b46-f916-5ca9-8ee4d84305e6@oracle.com> Hello, A few comments on the 01 iteration: For Class.isRecord, I suggest explicitly stating that java.lang.Record is *not* a record. It would be reasonable for ElementType to make some reference to the special annotation-handling rules for records. For the equals method operating on floating-point values, Double.compare/Float.compare comparing the result against 0 are likely to do what one wants more so than ==. I see the ObjectMethods implementation already does this. For ObjectMethods, note that void.class is regarded by core reflection as being a primitive class and should likely be treated specially. It seems odd their isn't a better return type than Object for the bootstrap method. Should the invokedynamic and dynamic constant cases be handled by the same method? I recommend some more descriptive parameter names: ??? @param theClass???? the class hosting the components => ??? @param hostClass At least in isolation, I don't think it is clear how the lookup object is used. Cheers, -Joe On 10/27/2019 4:41 PM, Vicente Romero wrote: > Hi Brian, > > Thanks for your comments. I have published another review iteration > [1]. Some comments inlined below. > > On 10/25/19 5:04 PM, Brian Goetz wrote: >> Spec in Class.java: >> >> ?- Various {@code RecordComponent} should be {@link RecordComponent}. > > we could do that but the current approach is consistent with what we > are doing in similar APIs like Class::getDeclaredFields() > >> ?- Rather than say "if this class was declared as a record in the >> source code", instead say "is a record class", since record classes >> are a term defined by the JLS. > fixed >> ?- For isRecord/getRecordComponents, should include "@jls 8.10" link > done >> >> RecordComponent.java: >> >> ?- Add @jls 8.10 link >> ?- "Returns the name of the component represented by this record >> component." -> "Returns the name of this record component." and >> similar in other methods.? Since RC models a record component, its >> clear enough what is meant. > > done, the javadoc was following the same approach as in > java.lang.reflect.Field > >> ?- For getGenericSignature, there should be a link back to @jls or >> @jvms that describes the format of the signature string. > done, added @jvms 4.7.9.1 Signatures > >> ?- Doesn't getAnnotation() need some spec, or an {@inheritDoc}? > > yep done > > Thanks, > Vicente > > [1] > http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.01/ From maurizio.cimadamore at oracle.com Wed Oct 30 08:55:59 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 30 Oct 2019 08:55:59 +0000 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <067e32b4-4d07-73f2-73d6-21a57c70c420@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <0be9bfc0-70b1-c1f8-5af1-5c88913dbb9d@oracle.com> <067e32b4-4d07-73f2-73d6-21a57c70c420@oracle.com> Message-ID: <59df4663-b46f-f4c2-0746-873d499542db@oracle.com> On 28/10/2019 21:37, Vicente Romero wrote: > Hi Maurizio, > > Thanks for the comments > > On 10/27/19 6:09 PM, Maurizio Cimadamore wrote: >> >> Hi Vicente, looks a lot better, thanks. >> >> Some comments: >> >> Attr.java - Errors.FirstStatementMustBeCallToCanonical - not sure >> about this message , but in general, all we require is that a >> constructor delegates to another constructor - it can also be >> something other than the canonical - e.g contsructor1 -> constructor2 >> -> canonical >> > > this is what the current spec for records mandates: > 8.10.4 Record Constructor Declarations > ... > "If a record type R declares constructors other the canonical > constructor, then they must satisfy both of the > following: > The constructor body must start with an explicit constructor > invocation of the canonical constructor for the > record type R." Then I would argue the spec is overly restrictive? Is it something we can fix? > >> Attr.java - the above situation seems to also affect some other code >> in Attr - where you actually check that the invoked constructor in >> 'this' has same signature of the canonical constructor. I think these >> checks should be removed - the important thing is that the canonical >> will be called _somehow_ - but can also be call indirectly - at least >> this was my understanding >> > > ditto > >> Attr.java - not sure about the tree.sym.isRecord in the visitMethod - >> it seems like the same flag is used for both record (class) and >> canonical constructor? I'm ok with sharing the flag, but the method >> name looks a bit confusing when applied to a method symbol. I suggest >> putting 'isRecord' inside ClassSymbol, and >> 'isCanonicalRecordConstructor' on MethodSymbol, so that client code >> cannot make mistakes. >> > > I can do that if you are pretty strong about this but if we go for it > those methods you are proposing will be almost useless as it is more > straight forward to just do a bitwise and with the flag rather than > having to cast symbols to have access to the particular flavor of the > method, worst than that we would have to check if the owner of a > method is actually a class before doing the cast, in preparation of > local methods. What about renaming the method to: hasRecordFlagSet or > similar. Or I can just remove the method and do the old faithful bitwise. I think isRecord() for 'is this a record class' makes sense. But for everything else feels obscure, and perhaps reverting to bitwise is not too bad... > >> Attr.java/TypeEnter.java - overall, the checks here look nice, and >> they 'blend' in with existing code nicely, I think. Well done! >> > > cool, after shaking the box and all the pieces found their place! :) > >> Enter.java - I guess my question here on records and treatment with >> STATIC is a general question as to why isn't the code doing the same >> thing for records and enums - aren't the rules similar? (e.g. enums >> must be static, etc)? Enums are not set STATIC by default in javac >> parser, and that is, I think the difference here. What pushed you in >> this direction? >> > > I have updated the code to do the same we do for enums, I just found > my approach simpler, but it is true that is less consistent thanks - I'm pushing for this because if we ever allow things like local enums, it will be easier if the code has more commonalities with records. > >> TypeEnter.java: I suggest renaming "getCanonicalInitDecl" to >> "getCanonicalConstructorDecl" >> >> TypeEnter.java - it seems like the result of getCanonicalInitDecl is >> always given the RECORD flag - but later on (in Lower) I saw a >> comment which says that only auto-generated symbols have the RECORD >> flag set. Which one is it? >> > > the comment in Lower refers to accessors only, I will document all the > cases that uses the RECORD flag, as we are running low of flags entry > I have reused this one for several different uses but you have a point > that it could be tricky to understand when it is used and why > >> TypeEnter.java - I think the isUnchecked methods are a leftover from >> previous code - now they seem to be in Attr.java (btw, I think we >> must have those checks somewhere else in javac, look in >> Check::isUnchecked) >> > > yep I removed them from both, there was a spec change now neither > accessors nor canonical constructor can have a throws clause ok >> >> Names.java - I think this bunch of fields is also no longer used? >> >> + public final Name where; >> + public final Name non; >> + public final Name ofLazyProjection; >> + >> >> > Maurizio > yep thanks, removed > >> I have not checked the j.l.m API. >> >> Thanks >> Maurizio >> > > Thanks, > Vicente > > PS, I will be sending a new iteration soon > >> >> >> >> On 26/10/2019 21:14, Vicente Romero wrote: >>> I forgot to mention that I have added javax.lang.model code to this >>> iteration that wasn't part of the first iteration. I was planning to >>> publish it as part of a different review but I realized that there >>> was some code affected, tests, API implementation etc, which >>> belonged to the compiler code. So I added that code in this iteration, >>> >>> Thanks, >>> Vicente >>> >>> On 10/26/19 3:55 PM, Vicente Romero wrote: >>>> Hi Maurizio, >>>> >>>> Thanks again for the comments I have published another iteration at >>>> [1]. I focused on this iteration more on the implemenation than on >>>> the tests to first have an agreement on the implementation, timing, >>>> etc. Some comments inlined below. >>>> >>>> [1] >>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.01/ >>>> >>>> On 10/21/19 2:01 PM, Maurizio Cimadamore wrote: >>>>> >>>>> Hi Vicente, >>>>> I did a pretty thorough pass on most of the code. I didn't look at >>>>> tests, and I also didn't look at Lower. Comments below: >>>>> >>>>> * Flags.java - VARARGS flag for records components; I wonder, >>>>> instead of a new flag, can we use the internal VARARGS flag we >>>>> have for methods, and attach that to the record symbol? That >>>>> should also lead to more direct code in TypeHelper >>>>> >>>> removed >>>> >>>>> * Symbol.java - I think the override for 'erasure' is redundant - >>>>> isn't that the impl from supertype? >>>>> >>>> yep, removed too >>>> >>>>> * Symbol.java - I wonder if accessor list with Pair >>>>> isn't a premature generalization; we should just add a getter >>>>> symbol and that's it >>>> >>>> agreed, done >>>> >>>>> * Attr.java - I think we might want to leave the door open for a >>>>> check which forces all constructors of a record to go through the >>>>> canonical one (depending on where the spec lands) >>>>> >>>> implemented in this iteration >>>> >>>>> * Check.java - understanding checkpoint: when we see an annotation >>>>> on a record component, first we check it's one of the kinds which >>>>> are allowed (if not, error), and, if it's allowed, we add all >>>>> record component annotations to record component elements, and we >>>>> also filter away all annotations that have nothing to do with the >>>>> element in which they appear. If my understanding is correct, I >>>>> think this logic should be documented more clearly; I found the >>>>> comment after the "if (isRecordField)" to be a bit obscure. >>>>> >>>> yes that's the idea, annotations that are originally applied to >>>> record components are pushed down to all generated elements in >>>> TypeEnter, and then in Check the ones that are off-site are removed >>>>> >>>>> * Enter.java - why are you removing the static flag on records? I >>>>> don't see anything similar around for enums. >>>>> >>>> >>>> the static flag is added to all records but if the record is a top >>>> level class, it is not needed, that's why that code is there >>>> >>>>> * Flow.java - not sure I get the changes to checkInit; typically >>>>> checkInit is called at the use-site of DA/DU variables. Here it >>>>> seems you suppress some of the errors emitted for accessing record >>>>> fields inside the canonical constructor - but I hope that code >>>>> like this >>>>> >>>>> record Foo(int x) { >>>>> ?? Foo(int x) { >>>>> ?????? print(this.x); >>>>> ?? } >>>>> } >>>>> >>>>> Still give errors? >>>>> >>>> >>>> yes it gives an error >>>>> >>>>> If this works correctly, which errors does the 'guard' around the >>>>> error generation is supposed to protect against? >>>>> >>>> >>>> checkInit it not used only for what you mentioned above but also, >>>> see AssignAnalyzer::visitMethodDef, to check if an initial >>>> constructor, as the canonical constructor is in records, have >>>> initialized all the fields. The guard is there to don't issue an >>>> error if a canonical constructor hasn't initialized some fields, as >>>> the compiler will generate code to initialize those fields later in >>>> Lower >>>>> >>>>> * MemberEnter.java - why the filter for HYPOTHETICAL ? It's only >>>>> used here... >>>>> >>>> removed >>>>> >>>>> * TypeEnter.java - implicit super calls are added in >>>>> Attr::visitMethod for regular calls; we should do the same for >>>>> records (or add all in TypeEnter - that is records and class >>>>> should be consistent) >>>>> >>>> >>>> right we should be consistent, I have moved that code to Attr >>>> >>>>> * TypeEnter.java - on finishClass - you are calling memberEnter on >>>>> record fields, which I think you already did in the new RecordsPhase >>>>> >>>> >>>> nope, what I'm doing there is invoking MemberEnter to enter the >>>> members that hasn't been entered so far. Anyway that code changed a >>>> bit because I'm entering the constructors now at RecordPhase too >>>> but I have changed the code a bit to make more clear what is happening. >>>> >>>>> * TypeEnter.java - (stylistic) addRecordsMemberIfNeeded should >>>>> deal with _all_ record members (e.g. including accessors), not >>>>> just some? >>>>> >>>> yep changed that too >>>>> >>>>> * TypeEnter.java - checkForSerializationMember should probably be >>>>> moved to MemberEnter::visitVar, or even to Attr (note that the >>>>> code for the check is doing a little visit :-)) >>>>> >>>> moved to Attr >>>>> >>>>> * TypeEnter.java - again on check timings; while it's ok for the >>>>> code in here to add new synthetic members, I think it's less ok to >>>>> add more global error checks (such as make sure that the canonical >>>>> declaration whose parameter names match the record components in >>>>> order); these should live in Attr. More generally, I think that we >>>>> should only check stuff here if we think that the check will add >>>>> any value to annotation processing. Every other check can be >>>>> deferred, and take place in a more 'deterministic' part of javac. >>>>> >>>> >>>> moved to Attr >>>> >>>>> * TypeEnter.java - I think finishClass should be a bit better at >>>>> determining as to whether default constructor is needed or not - >>>>> for instance, this check: >>>>> >>>>> if ((sym.flags() & INTERFACE) == 0 && >>>>> 928 !TreeInfo.hasConstructors(tree.defs)) { >>>>> >>>>> Should be generalized to something that works for both classes and >>>>> records; for classes you need to check if there's no other >>>>> constructor; for records you need to check if there's no other >>>>> constructor _with same signature_ as the canonical one. Then you >>>>> can simplify addRecordMembers and remove the dependency on the >>>>> boolean 'generatedConstructor' parameter. In other words the code >>>>> should: >>>>> >>>>> 1) check if default/canonical constructor generation is required >>>>> 2) if so, use the appropriate helper to generate the code >>>>> 3) at the end, add the remaining record members (under the >>>>> assumption that the canonical constructor has already been added >>>>> in (1), if that was missing) >>>>> >>>> >>>> done, in order to do that I had to enter constructors at the >>>> RecordPhase, as mentioned earlier. >>>>> >>>>> *TypeEnter.java - addAccessor can be simplified if we only worry >>>>> about getters. Again, the checks in here feel more Attr check than >>>>> MemberEnter checks. >>>>> >>>> agreed, done >>>> >>>>> *TypeEnter.java - in addRecordMembersIfNeeded, I don't get why we >>>>> create a tree for a member, and then we visit the member tree with >>>>> memberEnter, just to add it to the scope. I understand that, >>>>> currently addEnumMembers does the same, but this looks very >>>>> roundabout; I wonder if there's a way to make all this process a >>>>> bit simpler - create a symbol and add that to the scope. Or are >>>>> there important checks in MemberEnter that we would lose? >>>>> >>>> >>>> yes there are several checks we would lose, plus we would lose >>>> consistency, but I tried to do that and several things fell apart, >>>> we need to enter not only the generated method, also it's >>>> parameters etc, which is what MemberEnter is doing. >>>> >>>>> *JCTree.java/TreeMaker.java - I don't think there's any need to >>>>> store accessors in the field AST; these are only used from >>>>> TypeEnter, and TypeEnter can do whatever it does by looking at >>>>> which record components there are in the record class, and add a >>>>> getter for each. Let's make the code simpler and more direct >>>>> >>>> yep removed >>>>> >>>>> * ClassReader.java - should we just silently ignore record >>>>> attributes when not in preview mode - or should we issue classfile >>>>> errors? >>>>> >>>>> * ClassReader.java - what kind of validation should we do on >>>>> record attributes? Currently javac does nothing. Should we check >>>>> that we have (i) getters (ii) toString/hashCode/equals >>>>> implementations and (iii) a canonical constructor (ad fail if we >>>>> don't) ? At the very least I would add code to _parse_ the >>>>> attribute, even if we do nothing with it, so that at least we >>>>> throw a classfile error if the attribute is badly broken >>>>> >>>> on ClassReader, we can discuss what to do in a language meeting, I >>>> don't have any strong preference >>>>> >>>>> * Tokens.java - for "var", "yields" and other context-dependent >>>>> keywords we never added a token. We just handled that in >>>>> JavacParser. Why the difference here? I think it's best to stick >>>>> to current style and maybe fix all of them (assuming that's what >>>>> we want to do) in a followup cleanup. Actually, after looking at >>>>> parser, it seems like you already handle that manually, so I just >>>>> suggest to revert the changed to Tokens >>>>> >>>> >>>> I added the token to add it as a parameter to an error message, but >>>> I removed the token and now I'm passing a string >>>> >>>>> * TreeInfo.java - how is 'isCanonicalConstructor' not returning >>>>> 'true' for all constructors inside a record, as opposed to only >>>>> return true for the canonical one? >>>>> >>>> I have added a comment to clarify what this method is doing >>>>> >>>>> * TreeInfo.java - There is some code reuse possible between >>>>> "recordFieldTypes" and "recordFields" >>>>> >>>> yep done >>>>> >>>>> * Names.java - what is 'oldEquals' ? >>>>> >>>> removed, old code >>>>> >>>>> * JavacParser.java - timing of checks; I don't think we should >>>>> check for illegal record component names in here >>>>> >>>> removed from there >>>>> >>>>> * JavacParser.java - code can be simplified somewhat by getting >>>>> rid of accessors in VarDef AST. >>>>> >>>> >>>> done >>>> >>>> Thanks again for taking the time to do this long review, will >>>> answer the other mails separately >>>> >>>> Vicente >>>>> >>>>> >>>>> >>>>> >>>>> On 21/10/2019 13:31, Vicente Romero wrote: >>>>>> Hi, >>>>>> >>>>>> Please review the compiler code for JEP 359 (Records) [1] >>>>>> >>>>>> Thanks in advance for the feedback, >>>>>> Vicente >>>>>> >>>>>> [1] >>>>>> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ >>>>>> >>>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bsrbnd at gmail.com Wed Oct 30 12:40:01 2019 From: bsrbnd at gmail.com (B. Blaser) Date: Wed, 30 Oct 2019 13:40:01 +0100 Subject: JDK-8221373 (?) Missing checkcast in void-returning lambda Message-ID: Hi, Looking a bit at JDK-8221373, I'd like to make sure we are going in the right direction before posting a RFR. Going back to JDK-8203338, we decided in [1] to take the functional descriptor's erased return type as translation target which might cause some side-effects like in Liam's void-returning lambda where no 'checkcast' are emitted anymore. So my question is rather simple, should we put in place something closer to the initial fix I suggested in [2] to preserve the original erased expression typing? Thanks, Bernard [1] http://mail.openjdk.java.net/pipermail/compiler-dev/2018-June/012086.html [2] http://mail.openjdk.java.net/pipermail/compiler-dev/2018-June/012076.html From vicente.romero at oracle.com Wed Oct 30 18:07:53 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 30 Oct 2019 14:07:53 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Message-ID: Hi Srikanth, Thanks for the review, comments inlined below. On 10/28/19 5:10 AM, Srikanth wrote: > Hi Vicente, > > I plan to make one more separate pass over annotation handling later > this week, in the > mean time, here are several comments. > > I omitted anything already called out by Maurizio or Jan. > > HTH, > Thanks > Srikanth > > > (1) Flags.java: Is there a reason for choosing the flags for RECORD to > be 1L<<61, leaving 1<<59 and 1<<60 as holes ?? no reason, I have covered the gap > > (2) javadoc for flag RECORD inconsistent with the // comment (one > mentions methods the other does not) true, I have fixed that > > (3) MemberRecordClassFlags LocalRecordFlags - naming inconsistent; > former should be MemberRecordFlags ? fixed > > (4) com.sun.tools.javac.parser.JavacParser#isRestrictedRecordTypeName > appears unused removed > > (5) (Ignorable) Field `names' is changed from private to protected > because it needs to be referenced in ReplParser I guess. This could > have been worked around by reaching to token.name().table.names.record > instead. I have fixed that too > > (6) Javac allows a top level record to be static - is this intentional > ? Top levels classes may not be. > This code compiles: > static public record X(int x, int y) { > > } correct, this was already fixed in the last iteration > > (7) Local records cannot be explicitly tagged final. (Likewise > annotations will be rejected) > > public class X { > ??? public static void main(String [] args) { > ??????? final record X(int x, int y) {? // <<-- does not compile > ??????? } > ??? } > } fixed > > > (8) if (isRecordToken() && > ??????????? (peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) || > ???????????? peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) { > ??????????? JCModifiers mods = modifiersOpt(); > ??????????? dc = token.comment(CommentStyle.JAVADOC); > ??????????? return List.of(recordDeclaration(mods, dc)); > ??????? } > > The call to modifiersOpt - is this misplaced ? We have already seen > `record' and the peek is signalling an IDENTIFIER ?? > > (The default is moved out of the switch - it took me a while to > recognize that the semantics are unaffected. So this appears fine) actually I think that you are right, the call to modifiersOpt seems to be unnecessary at that point. I have removed it > > (9) I was surprised to see the emission of Errors.RecordCantBeAbstract in > com.sun.tools.javac.parser.JavacParser#recordDeclaration. > I would have expected this check inside > com.sun.tools.javac.comp.Check#checkFlags > See that this latter place is where abstract enums are complained > against. right it was actually been also checked in Check::checkFlags, I have removed the check in JavacParser > > (10) List defs = List.nil(); inside > JavacParser#recordDeclaration is a redundant initialization. fixed > > (11) Likewise I was surprised to see > Errors.RecordCantDeclareDuplicateFields being emitted > in com.sun.tools.javac.parser.JavacParser#recordDeclaration. > I would have expected this to be emitted in > com.sun.tools.javac.comp.Check#checkUnique right, there are two opposed forces here. The check is in JavacParser because record components exists until JavacParser. From that point on, they are not record components anymore but fields and parameters to a constructor. So if they are repeated then we would be talking to the user about fields and method parameters that he didn't declare he just declared record components. That's why the code is there. I can move it but then the user will probably have spurious error messages. > > (12) Compact constructor trees are modified in in > com.sun.tools.javac.parser.JavacParser#recordDeclaration to become > elaborated tree - I thought this practice of modifying parse trees in > the early stages is frowned upon ?? (Other parse tree transformations > also happen here) right but no other feature allows to declare a parameter-less method. If not expanded here the compact constructor would have to be expanded in TypeEnter, which probably is not very nice either, so I didn't see a perfect solution > > (13) com.sun.tools.javac.parser.JavacParser#formalParameter() is > unused ?? yep removed, I created another flavor that must be used by all clients > > (14) Check.java: Seems import java.util.stream.Collectors; is unused I see one use of it at: boolean merge(ListBuffer litBuf, ListBuffer opStack) {} > > (15) Symbol.java: several unused imports seem to have crept in. > import com.sun.tools.javac.util.Name; > import com.sun.tools.javac.code.MissingInfoHandler; > import com.sun.tools.javac.code.Symbol; > import static > com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP; > import com.sun.tools.javac.code.Type; removed > > (16) The various isXXX methods differ in how they access the > flags_field. Some use > flags() while others use flags_field. I think it is better to use > flags() as it will > trigger completion (as it should ??) In any case the difference seems > gratuitous I would prefer not to trigger completion, I have moved all of them to use the field > > (17) Does com.sun.tools.javac.code.Symbol.MethodSymbol#isDynamic serve > a purpose - seems > to be identical to super implementation ?? no, removed, it probably ended there after a merge and I oversaw it > > (18) Attr: Errors.MethodMustBePublic emission code could use the new > Symbol.isPublic() > (100 lines below we do use the new method) done > > (19) Attr.isUnchecked() the new methods are mirror images of the > Check.isUnchecked methods ? > Is there a reason for the duplication ?? those were removed already > > (20) Javadoc of > com.sun.tools.javac.comp.Attr#checkFirstConstructorStat does not > document all parameters done > > (21) I didn't quite understand what we do this in MemberEnter for: > ??? else if (v.owner.kind == MTH || (v.flags_field & (Flags.PRIVATE | > Flags.FINAL | Flags.MANDATED | Flags.RECORD)) != 0) { > ??????????? enclScope.enter(v); > ??????? } > I have added a comment, that means that we are dealing with a field that was obtained from a record component. It should be entered Thanks for all the comments, Vicente PS, I will be generating another webrev that will also include last comments from Maurizio > > On 21/10/19 6:01 PM, Vicente Romero wrote: >> Hi, >> >> Please review the compiler code for JEP 359 (Records) [1] >> >> Thanks in advance for the feedback, >> Vicente >> >> [1] >> http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.00/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Wed Oct 30 18:11:29 2019 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 30 Oct 2019 19:11:29 +0100 (CET) Subject: RFR: JEP 359-Records: reflection code In-Reply-To: <48bbd0e4-7b46-f916-5ca9-8ee4d84305e6@oracle.com> References: <541027a7-171c-f416-3e6b-1dce1c148503@oracle.com> <9f1e7585-1754-afd2-21f4-bdd1931936bf@oracle.com> <65316668-fc7c-e887-52be-2d098d4eb0a2@oracle.com> <48bbd0e4-7b46-f916-5ca9-8ee4d84305e6@oracle.com> Message-ID: <1780230427.1113933.1572459089437.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "joe darcy" > ?: "Vicente Romero" , "Brian Goetz" , "amber-dev" > , "compiler-dev" > Envoy?: Mercredi 30 Octobre 2019 02:24:38 > Objet: Re: RFR: JEP 359-Records: reflection code > Hello, > > A few comments on the 01 iteration: > > For Class.isRecord, I suggest explicitly stating that java.lang.Record > is *not* a record. > > It would be reasonable for ElementType to make some reference to the > special annotation-handling rules for records. > > For the equals method operating on floating-point values, > Double.compare/Float.compare comparing the result against 0 are likely > to do what one wants more so than ==. I see the ObjectMethods > implementation already does this. yes ! otherwise we can not have an inline record because equals() will be incompatible with how == works currently on an inline type. > > For ObjectMethods, note that void.class is regarded by core reflection > as being a primitive class and should likely be treated specially. > > It seems odd their isn't a better return type than Object for the > bootstrap method. Should the invokedynamic and dynamic constant cases be > handled by the same method? > > I recommend some more descriptive parameter names: > > ??? @param theClass???? the class hosting the components => > > ??? @param hostClass > > At least in isolation, I don't think it is clear how the lookup object > is used. > > Cheers, > > -Joe R?mi > > On 10/27/2019 4:41 PM, Vicente Romero wrote: >> Hi Brian, >> >> Thanks for your comments. I have published another review iteration >> [1]. Some comments inlined below. >> >> On 10/25/19 5:04 PM, Brian Goetz wrote: >>> Spec in Class.java: >>> >>> ?- Various {@code RecordComponent} should be {@link RecordComponent}. >> >> we could do that but the current approach is consistent with what we >> are doing in similar APIs like Class::getDeclaredFields() >> >>> ?- Rather than say "if this class was declared as a record in the >>> source code", instead say "is a record class", since record classes >>> are a term defined by the JLS. >> fixed >>> ?- For isRecord/getRecordComponents, should include "@jls 8.10" link >> done >>> >>> RecordComponent.java: >>> >>> ?- Add @jls 8.10 link >>> ?- "Returns the name of the component represented by this record >>> component." -> "Returns the name of this record component." and >>> similar in other methods.? Since RC models a record component, its >>> clear enough what is meant. >> >> done, the javadoc was following the same approach as in >> java.lang.reflect.Field >> >>> ?- For getGenericSignature, there should be a link back to @jls or >>> @jvms that describes the format of the signature string. >> done, added @jvms 4.7.9.1 Signatures >> >>> ?- Doesn't getAnnotation() need some spec, or an {@inheritDoc}? >> >> yep done >> >> Thanks, >> Vicente >> >> [1] > > http://cr.openjdk.java.net/~vromero/records.review/reflection/webrev.01/ From maurizio.cimadamore at oracle.com Wed Oct 30 18:54:57 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 30 Oct 2019 18:54:57 +0000 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Message-ID: <87361b52-5d2a-e41c-cbcd-8e2237d35066@oracle.com> I agree with Srikanth here - while I understand that after pars8ing, components are just fields, they are still fields with special status (e.g. flag), and TypeEnter knows about them, so it should be possible to issue the 'right' error message there. Maurizio On 30/10/2019 18:07, Vicente Romero wrote: >> >> (11) Likewise I was surprised to see >> Errors.RecordCantDeclareDuplicateFields being emitted >> in com.sun.tools.javac.parser.JavacParser#recordDeclaration. >> I would have expected this to be emitted in >> com.sun.tools.javac.comp.Check#checkUnique > > right, there are two opposed forces here. The check is in JavacParser > because record components exists until JavacParser. From that point > on, they are not record components anymore but fields and parameters > to a constructor. So if they are repeated then we would be talking to > the user about fields and method parameters that he didn't declare he > just declared record components. That's why the code is there. I can > move it but then the user will probably have spurious error messages. From vicente.romero at oracle.com Wed Oct 30 19:03:50 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 30 Oct 2019 15:03:50 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <87361b52-5d2a-e41c-cbcd-8e2237d35066@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <87361b52-5d2a-e41c-cbcd-8e2237d35066@oracle.com> Message-ID: OK will do that, Vicente On 10/30/19 2:54 PM, Maurizio Cimadamore wrote: > I agree with Srikanth here - while I understand that after pars8ing, > components are just fields, they are still fields with special status > (e.g. flag), and TypeEnter knows about them, so it should be possible > to issue the 'right' error message there. > > Maurizio > > On 30/10/2019 18:07, Vicente Romero wrote: >>> >>> (11) Likewise I was surprised to see >>> Errors.RecordCantDeclareDuplicateFields being emitted >>> in com.sun.tools.javac.parser.JavacParser#recordDeclaration. >>> I would have expected this to be emitted in >>> com.sun.tools.javac.comp.Check#checkUnique >> >> right, there are two opposed forces here. The check is in JavacParser >> because record components exists until JavacParser. From that point >> on, they are not record components anymore but fields and parameters >> to a constructor. So if they are repeated then we would be talking to >> the user about fields and method parameters that he didn't declare he >> just declared record components. That's why the code is there. I can >> move it but then the user will probably have spurious error messages. From jonathan.gibbons at oracle.com Wed Oct 30 23:50:16 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Wed, 30 Oct 2019 16:50:16 -0700 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> Message-ID: Please review a moderately small update to the proposed support for records in javadoc. The primary change is to include record components in the signature of a record displayed near the top of the page. In addition, a "combo test" is added into TestRecordTypes.java to verify the presence or absence of annotations in various places in the generated page for a record, depending on the `@Target` of the annotations. Finally, there are some small cosmetic changes, and the supporting files for some previously published examples. Two webrevs are provided. The first is a cumulative webrev of the modified javadoc source and test files, compared against the default branch of the amber repo (i.e. the state of the jdk/jdk repo) http://cr.openjdk.java.net/~jjg/amber-records/webrev.default/ The second is a "delta webrev" of the recently modified javadoc source and test files, compared against the tip of the records branch of the amber repo. http://cr.openjdk.java.net/~jjg/amber-records/webrev.tip/ Also, the sets of examples are updated, showing examples linked and not linked to JDK API docs http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ Finally, I note a curiosity, arising from the proposed spec.? This is the first occurrence that I can think of in which an item that is syntactically necessary in the source code does /not/ show up in the same place in the generated documentation.? In general, in previous instances where the documented signatures differ from the source code, the difference has been the addition of default or mandated elements.? Here, the presence of an annotation on the declaration of a record component in source code may not show up in the corresponding place in the documented signature, depending on the specified @Target for the annotation. I'm not saying that's wrong, but it is curious, and may need explaining to some. -- Jon JEP 359: https://openjdk.java.net/jeps/359 From srikanth.adayapalam at oracle.com Thu Oct 31 03:41:09 2019 From: srikanth.adayapalam at oracle.com (Srikanth) Date: Thu, 31 Oct 2019 09:11:09 +0530 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> Message-ID: <9bd7787a-9fc1-dbb5-5da6-b6a12a2d19c8@oracle.com> On 30/10/19 11:37 PM, Vicente Romero wrote: > (12) Compact constructor trees are modified in in > com.sun.tools.javac.parser.JavacParser#recordDeclaration to become > elaborated tree - I thought this practice of modifying parse trees in > the early stages is frowned upon ?? (Other parse tree transformations > also happen here) > > right but no other feature allows to declare a parameter-less method. > If not expanded here the compact constructor would have to be expanded > in TypeEnter, which probably is not very nice either, so I didn't see > a perfect solution It may be quite a bit of work, but the canonical solution would be to introduce a new node type to model these. Not asking it to be done. Just saying. Srikanth From chris.hegarty at oracle.com Thu Oct 31 10:31:36 2019 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Thu, 31 Oct 2019 10:31:36 +0000 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> Message-ID: <143D28AD-946C-4B43-93D7-E88BF1AAD895@oracle.com> Jon, > On 30 Oct 2019, at 23:50, Jonathan Gibbons wrote: > > ... > > Also, the sets of examples are updated, showing examples linked and not linked to JDK API docs > http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ > http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ The API docs should show all records as final, regardless of whether or not the final keywords appears in the source code. ( I?m not sure that this is currently the case in the changes ). Additionally, ( something that I forgot previously ) I think that the API doc for all nested records should show them as static, regardless of whether or not the static keyword appears in the source code. ( A nested record is implicitly static ). -Chris. From vicente.romero at oracle.com Thu Oct 31 13:22:25 2019 From: vicente.romero at oracle.com (Vicente Romero) Date: Thu, 31 Oct 2019 09:22:25 -0400 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <9bd7787a-9fc1-dbb5-5da6-b6a12a2d19c8@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <9bd7787a-9fc1-dbb5-5da6-b6a12a2d19c8@oracle.com> Message-ID: Hi Srikanth, On 10/30/19 11:41 PM, Srikanth wrote: > > > On 30/10/19 11:37 PM, Vicente Romero wrote: >> (12) Compact constructor trees are modified in in >> com.sun.tools.javac.parser.JavacParser#recordDeclaration to become >> elaborated tree - I thought this practice of modifying parse trees in >> the early stages is frowned upon ?? (Other parse tree transformations >> also happen here) >> >> right but no other feature allows to declare a parameter-less method. >> If not expanded here the compact constructor would have to be >> expanded in TypeEnter, which probably is not very nice either, so I >> didn't see a perfect solution > > It may be quite a bit of work, but the canonical solution would be to > introduce a new node type to model these. Not asking it to be done. > Just saying. yep, what you are saying sounds good, we could revisit this later on > > Srikanth > Thanks, Vicente From jonathan.gibbons at oracle.com Thu Oct 31 13:59:33 2019 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Thu, 31 Oct 2019 06:59:33 -0700 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: <143D28AD-946C-4B43-93D7-E88BF1AAD895@oracle.com> References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <143D28AD-946C-4B43-93D7-E88BF1AAD895@oracle.com> Message-ID: On 10/31/19 3:31 AM, Chris Hegarty wrote: > Jon, > >> On 30 Oct 2019, at 23:50, Jonathan Gibbons wrote: >> >> ... >> >> Also, the sets of examples are updated, showing examples linked and not linked to JDK API docs >> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ >> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ > The API docs should show all records as final, regardless of whether or not the final keywords appears in the source code. ( I?m not sure that this is currently the case in the changes ). > > Additionally, ( something that I forgot previously ) I think that the API doc for all nested records should show them as static, regardless of whether or not the static keyword appears in the source code. ( A nested record is implicitly static ). > > -Chris. Chris, Thanks for the comment. I'll check with the experts on this. While it is true that records are implicitly static final, javadoc does not show implicit modifiers in other similar contexts, like interfaces. -- Jon From maurizio.cimadamore at oracle.com Thu Oct 31 14:03:17 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 31 Oct 2019 14:03:17 +0000 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <9bd7787a-9fc1-dbb5-5da6-b6a12a2d19c8@oracle.com> Message-ID: <7bdcb1b3-8275-0e48-784e-40c1342422bb@oracle.com> The idea sounds good, in the sense that a compact record constructor is more similar to an initializer block than it is to a regular constructor, so I can see it being modeled as a JCBlock with the RECORD flag set. This is also made easier by the fact that we no longer allow instance initializers on records (**). That said, if the compact constructor becomes a block, I'm pretty sure we'll run into issues with respect to source reflection - blocks are typically looked at in Attr, which is too late for source reflection/annotation processing. So I agree that, while it looks like a promising direction, it will probably be a non-trivial effort, and it would better be postponed as a followup cleanup Maurizio (*) In the list of error messages in [1] I don't see anything about 'illegal instance initializer in record declaration' - is that an omission in the diagnostic examples, or a more serious issue in the code/spec? [1] - http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.02/ On 31/10/2019 13:22, Vicente Romero wrote: > Hi Srikanth, > > On 10/30/19 11:41 PM, Srikanth wrote: >> >> >> On 30/10/19 11:37 PM, Vicente Romero wrote: >>> (12) Compact constructor trees are modified in in >>> com.sun.tools.javac.parser.JavacParser#recordDeclaration to become >>> elaborated tree - I thought this practice of modifying parse trees >>> in the early stages is frowned upon ?? (Other parse tree >>> transformations also happen here) >>> >>> right but no other feature allows to declare a parameter-less >>> method. If not expanded here the compact constructor would have to >>> be expanded in TypeEnter, which probably is not very nice either, so >>> I didn't see a perfect solution >> >> It may be quite a bit of work, but the canonical solution would be to >> introduce a new node type to model these. Not asking it to be done. >> Just saying. > > yep, what you are saying sounds good, we could revisit this later on >> >> Srikanth >> > Thanks, > Vicente From brian.goetz at oracle.com Thu Oct 31 14:05:33 2019 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 31 Oct 2019 10:05:33 -0400 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <143D28AD-946C-4B43-93D7-E88BF1AAD895@oracle.com> Message-ID: Let?s look at this through the lens of ?what information would the reader want to know about this class.? And surely, finality is one of the bits of information the reader wants to know, because they might be wondering ?can I subclass this.? On the other hand, you might say ?well of course, readers know that records are final, because the language says they are.? And the treatment of enums (and public interface methods) in Javadoc is consistent with this counter-theory. So I think its OK to go either way on finality, and consistency probably pushes us towards doing the same thing we do with enums. For nested classes, on the other hand, I?m not quite as sure. The rule about ?nested records are implicitly static? is a little more subtle than the one about finality. > On Oct 31, 2019, at 9:59 AM, Jonathan Gibbons wrote: > > > On 10/31/19 3:31 AM, Chris Hegarty wrote: >> Jon, >> >>> On 30 Oct 2019, at 23:50, Jonathan Gibbons wrote: >>> >>> ... >>> >>> Also, the sets of examples are updated, showing examples linked and not linked to JDK API docs >>> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ >>> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ >> The API docs should show all records as final, regardless of whether or not the final keywords appears in the source code. ( I?m not sure that this is currently the case in the changes ). >> >> Additionally, ( something that I forgot previously ) I think that the API doc for all nested records should show them as static, regardless of whether or not the static keyword appears in the source code. ( A nested record is implicitly static ). >> >> -Chris. > > Chris, > > Thanks for the comment. I'll check with the experts on this. While it is true that records are implicitly static final, javadoc does not show implicit modifiers in other similar contexts, like interfaces. > > -- Jon > From maurizio.cimadamore at oracle.com Thu Oct 31 14:05:47 2019 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 31 Oct 2019 14:05:47 +0000 Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> Message-ID: Aside from Chris comments on modifiers, I think the compact record signature looks great, and adds a lot of value (which will pay further dividends when we add pattern matching). Well done. Annotations also look good. Maurizio On 30/10/2019 23:50, Jonathan Gibbons wrote: > Please review a moderately small update to the proposed support for > records in javadoc. > > The primary change is to include record components in the signature of > a record displayed near the top of the page. > > In addition, a "combo test" is added into TestRecordTypes.java to > verify the presence or absence of annotations in various places in the > generated page for a record, depending on the `@Target` of the > annotations. > > Finally, there are some small cosmetic changes, and the supporting > files for some previously published examples. > > Two webrevs are provided. > > The first is a cumulative webrev of the modified javadoc source and > test files, compared against the default branch of the amber repo > (i.e. the state of the jdk/jdk repo) > http://cr.openjdk.java.net/~jjg/amber-records/webrev.default/ > > The second is a "delta webrev" of the recently modified javadoc source > and test files, compared against the tip of the records branch of the > amber repo. > http://cr.openjdk.java.net/~jjg/amber-records/webrev.tip/ > > Also, the sets of examples are updated, showing examples linked and > not linked to JDK API docs > http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ > http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ > > Finally, I note a curiosity, arising from the proposed spec.? This is > the first occurrence that I can think of in which an item that is > syntactically necessary in the source code does /not/ show up in the > same place in the generated documentation.? In general, in previous > instances where the documented signatures differ from the source code, > the difference has been the addition of default or mandated elements.? > Here, the presence of an annotation on the declaration of a record > component in source code may not show up in the corresponding place in > the documented signature, depending on the specified @Target for the > annotation. I'm not saying that's wrong, but it is curious, and may > need explaining to some. > > -- Jon > > JEP 359: https://openjdk.java.net/jeps/359 > From forax at univ-mlv.fr Thu Oct 31 14:18:50 2019 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 31 Oct 2019 15:18:50 +0100 (CET) Subject: RFR: JEP 359-Records: javadoc code In-Reply-To: References: <914ab35b-ff07-1b9e-472c-9a04f7bc49dc@oracle.com> <143D28AD-946C-4B43-93D7-E88BF1AAD895@oracle.com> Message-ID: <1401005874.1279819.1572531530885.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Brian Goetz" > ?: "jonathan gibbons" > Cc: "amber-dev" , "javadoc-dev" , "compiler-dev" > , "Chris Hegarty" > Envoy?: Jeudi 31 Octobre 2019 15:05:33 > Objet: Re: RFR: JEP 359-Records: javadoc code > Let?s look at this through the lens of ?what information would the reader want > to know about this class.? And surely, finality is one of the bits of > information the reader wants to know, because they might be wondering ?can I > subclass this.? On the other hand, you might say ?well of course, readers know > that records are final, because the language says they are.? And the treatment > of enums (and public interface methods) in Javadoc is consistent with this > counter-theory. > > So I think its OK to go either way on finality, and consistency probably pushes > us towards doing the same thing we do with enums. > > For nested classes, on the other hand, I?m not quite as sure. The rule about > ?nested records are implicitly static? is a little more subtle than the one > about finality. I will just add that enums have exactly the same rule, an enum is always static when nested in another class, so whatever we decide, it should be the same for enums. R?mi > >> On Oct 31, 2019, at 9:59 AM, Jonathan Gibbons >> wrote: >> >> >> On 10/31/19 3:31 AM, Chris Hegarty wrote: >>> Jon, >>> >>>> On 30 Oct 2019, at 23:50, Jonathan Gibbons wrote: >>>> >>>> ... >>>> >>>> Also, the sets of examples are updated, showing examples linked and not linked >>>> to JDK API docs >>>> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-with-link/ >>>> http://cr.openjdk.java.net/~jjg/amber-records/examples/api-no-link/ >>> The API docs should show all records as final, regardless of whether or not the >>> final keywords appears in the source code. ( I?m not sure that this is >>> currently the case in the changes ). >>> >>> Additionally, ( something that I forgot previously ) I think that the API doc >>> for all nested records should show them as static, regardless of whether or not >>> the static keyword appears in the source code. ( A nested record is implicitly >>> static ). >>> >>> -Chris. >> >> Chris, >> >> Thanks for the comment. I'll check with the experts on this. While it is true >> that records are implicitly static final, javadoc does not show implicit >> modifiers in other similar contexts, like interfaces. >> >> -- Jon From jan.lahoda at oracle.com Thu Oct 31 17:08:36 2019 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 31 Oct 2019 18:08:36 +0100 Subject: RFR: JEP 359-Records: compiler code In-Reply-To: <7bdcb1b3-8275-0e48-784e-40c1342422bb@oracle.com> References: <1cfed5da-a0eb-be75-9008-8a0a5666a6f9@oracle.com> <9bd7787a-9fc1-dbb5-5da6-b6a12a2d19c8@oracle.com> <7bdcb1b3-8275-0e48-784e-40c1342422bb@oracle.com> Message-ID: <685c3c23-b2be-dbd8-e0b8-eabfb3715492@oracle.com> Not sure if the compact constructor should be modeled as a block - the constructors may have annotations, the explicit statements may contain references to the parameters, etc. One possibility might be to have the MethodTree.getParameters() return null ("missing in the source code"). Or, the injected parameters, when entered, could be marked MANDATED, which may be as easy as: diff -r ad4a9419b8e0 src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Oct 31 00:41:57 2019 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Oct 31 18:05:23 2019 +0100 @@ -3746,7 +3746,7 @@ ListBuffer tmpParams = new ListBuffer<>(); for (JCVariableDecl param : headerFields) { tmpParams.add(F.at(param) - .VarDef(F.Modifiers(Flags.PARAMETER | param.mods.flags & Flags.VARARGS | param.mods.flags & Flags.FINAL), + .VarDef(F.Modifiers(Flags.PARAMETER | Flags.MANDATED | param.mods.flags & Flags.VARARGS | param.mods.flags & Flags.FINAL), param.name, param.vartype, null)); } methDef.params = tmpParams.toList(); Jan On 31. 10. 19 15:03, Maurizio Cimadamore wrote: > The idea sounds good, in the sense that a compact record constructor is > more similar to an initializer block than it is to a regular > constructor, so I can see it being modeled as a JCBlock with the RECORD > flag set. This is also made easier by the fact that we no longer allow > instance initializers on records (**). > > That said, if the compact constructor becomes a block, I'm pretty sure > we'll run into issues with respect to source reflection - blocks are > typically looked at in Attr, which is too late for source > reflection/annotation processing. So I agree that, while it looks like a > promising direction, it will probably be a non-trivial effort, and it > would better be postponed as a followup cleanup > > Maurizio > > (*) In the list of error messages in [1] I don't see anything about > 'illegal instance initializer in record declaration' - is that an > omission in the diagnostic examples, or a more serious issue in the > code/spec? > > [1] - > http://cr.openjdk.java.net/~vromero/records.review/compiler/webrev.02/ > > On 31/10/2019 13:22, Vicente Romero wrote: >> Hi Srikanth, >> >> On 10/30/19 11:41 PM, Srikanth wrote: >>> >>> >>> On 30/10/19 11:37 PM, Vicente Romero wrote: >>>> (12) Compact constructor trees are modified in in >>>> com.sun.tools.javac.parser.JavacParser#recordDeclaration to become >>>> elaborated tree - I thought this practice of modifying parse trees >>>> in the early stages is frowned upon ?? (Other parse tree >>>> transformations also happen here) >>>> >>>> right but no other feature allows to declare a parameter-less >>>> method. If not expanded here the compact constructor would have to >>>> be expanded in TypeEnter, which probably is not very nice either, so >>>> I didn't see a perfect solution >>> >>> It may be quite a bit of work, but the canonical solution would be to >>> introduce a new node type to model these. Not asking it to be done. >>> Just saying. >> >> yep, what you are saying sounds good, we could revisit this later on >>> >>> Srikanth >>> >> Thanks, >> Vicente