From rsmogura at gmail.com Sat Sep 2 17:20:06 2017 From: rsmogura at gmail.com (Radek Smogura) Date: Sat, 2 Sep 2017 10:20:06 -0700 Subject: Question about get Method Handle to interface field Message-ID: <27220E4D-9039-4798-B8CA-BF00E479F0DC@gmail.com> Hi all, Recently I played a little bit and tried to obtain MethodHandle to GET method for interface static field. The code which I try to use is new Pool.MethodHandle(ClassFile.REF_getStatic, sym, types); But it fails on assertion: Assert.check(!refSym.owner.isInterface() || interfaceOwner) located in MethodHandle.checkConsistent:365 ? I wonder if such handles are allowed? Thanks, Radek P.S. Sorry if I post this message twice, but I got SMTP issues From forax at univ-mlv.fr Sat Sep 2 19:26:26 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 2 Sep 2017 21:26:26 +0200 (CEST) Subject: Question about get Method Handle to interface field In-Reply-To: <27220E4D-9039-4798-B8CA-BF00E479F0DC@gmail.com> References: <27220E4D-9039-4798-B8CA-BF00E479F0DC@gmail.com> Message-ID: <125713978.2481758.1504380386597.JavaMail.zimbra@u-pem.fr> Hi Radek, Do you still trying to implement properties in Java ? It seem to be an overlook to me, getstatic and putstatic are allowed on a static field declared in an interface, getstatic and putstatic use a CONSTANT_Fieldref so unlike constant method handle based on method which need to know if the owner is an interface or not (to generate a CONSTANT_Methodref or a CONSTANT_InterfaceMethodRef), see JVMS 4.4.2. The following patch should fix the issue case ClassFile.REF_getStatic: case ClassFile.REF_putStatic: staticOk = true; + interfaceOwner = true; case ClassFile.REF_getField: R?mi ----- Mail original ----- > De: "Radek Smogura" > ?: compiler-dev at openjdk.java.net > Envoy?: Samedi 2 Septembre 2017 19:20:06 > Objet: Question about get Method Handle to interface field > Hi all, > > Recently I played a little bit and tried to obtain MethodHandle to GET method > for interface static field. The code which I try to use is > > new Pool.MethodHandle(ClassFile.REF_getStatic, sym, types); > > But it fails on assertion: Assert.check(!refSym.owner.isInterface() || > interfaceOwner) located in MethodHandle.checkConsistent:365 ? > > I wonder if such handles are allowed? > > Thanks, > Radek > > P.S. Sorry if I post this message twice, but I got SMTP issues From maurizio.cimadamore at oracle.com Tue Sep 5 08:25:45 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 5 Sep 2017 09:25:45 +0100 Subject: Question about get Method Handle to interface field In-Reply-To: <125713978.2481758.1504380386597.JavaMail.zimbra@u-pem.fr> References: <27220E4D-9039-4798-B8CA-BF00E479F0DC@gmail.com> <125713978.2481758.1504380386597.JavaMail.zimbra@u-pem.fr> Message-ID: <2b9766af-1997-0398-be49-cbd0cad21162@oracle.com> On 02/09/17 20:26, Remi Forax wrote: > Hi Radek, > Do you still trying to implement properties in Java ? > > It seem to be an overlook to me, > getstatic and putstatic are allowed on a static field declared in an interface, getstatic and putstatic use a CONSTANT_Fieldref so unlike constant method handle based on method which need to know if the owner is an interface or not (to generate a CONSTANT_Methodref or a CONSTANT_InterfaceMethodRef), see JVMS 4.4.2. > > The following patch should fix the issue > case ClassFile.REF_getStatic: > case ClassFile.REF_putStatic: > staticOk = true; > + interfaceOwner = true; > case ClassFile.REF_getField: > > R?mi That's right - that code is buggy and does not handle field handles correctly, mostly because does not need them. Anyway, if you come up with a patch which works for your use case, I'd be happy to take a look. What Remi suggests seems sensible, although I have a feeling that this logic could be simplified a little. Maurizio > > ----- Mail original ----- >> De: "Radek Smogura" >> ?: compiler-dev at openjdk.java.net >> Envoy?: Samedi 2 Septembre 2017 19:20:06 >> Objet: Question about get Method Handle to interface field >> Hi all, >> >> Recently I played a little bit and tried to obtain MethodHandle to GET method >> for interface static field. The code which I try to use is >> >> new Pool.MethodHandle(ClassFile.REF_getStatic, sym, types); >> >> But it fails on assertion: Assert.check(!refSym.owner.isInterface() || >> interfaceOwner) located in MethodHandle.checkConsistent:365 ? >> >> I wonder if such handles are allowed? >> >> Thanks, >> Radek >> >> P.S. Sorry if I post this message twice, but I got SMTP issues From cushon at google.com Tue Sep 5 16:58:52 2017 From: cushon at google.com (Liam Miller-Cushon) Date: Tue, 5 Sep 2017 09:58:52 -0700 Subject: RFR 8187247: canonical import check compares classes by simple name Message-ID: This change fixes a bug that causes javac to incorrectly accept non-canonical imports if the actual and expected symbols have the same simple name. Bug: https://bugs.openjdk.java.net/browse/JDK-8187247 Webrev: http://cr.openjdk.java.net/~cushon/8187247/webrev.00/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From weijun.wang at oracle.com Wed Sep 6 04:17:33 2017 From: weijun.wang at oracle.com (Weijun Wang) Date: Wed, 6 Sep 2017 12:17:33 +0800 Subject: RFR 8148371: Remove policytool In-Reply-To: References: Message-ID: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> Hi All Please review the change, which spans to root, jdk and langtools repos. http://cr.openjdk.java.net/~weijun/8148371/ I've searched for the "policytool" word in the whole jdk10/jdk10 forests, removed all files having the word inside the path name, and remove almost all occurrences of the word in other places. The exceptions are: 1. Two files with the jdk8 word in file name. I assume I should not touch them. Please advise me. jdk/src/java.base/share/classes/jdk/internal/module/jdk8_packages.dat: 1288 sun.security.tools.jarsigner 1289 sun.security.tools.keytool 1290: sun.security.tools.policytool 1291 sun.security.util 1292 sun.security.validator langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdk8_internals.txt: 977 sun.security.tools.jarsigner 978 sun.security.tools.keytool 979: sun.security.tools.policytool 980 sun.security.util 981 sun.security.validator 2. A swing test containing a full JDK 1.4.2 README text. Keep unchanged. jdk/test/javax/swing/JTextArea/4697612/bug4697612.txt: 122 bin/ktab and jre/bin/ktab 123 Kerberos key table manager 124: bin/policytool and jre/bin/policytool 125 Policy File Creation and Management Tool 126 bin/orbd and jre/bin/orbd 3. A manual test on what resource string are used. It is based on the pre-module source layout and needs to be updated anyway. Keep unchanged this time. https://bugs.openjdk.java.net/browse/JDK-8187265 filed. jdk/test/sun/security/util/Resources/NewResourcesNames.java: 62 "sun/security/tools/jarsigner/Resources.java", 63 "sun/security/tools/keytool/Resources.java", 64: "sun/security/tools/policytool/Resources.java", 65 "sun/security/util/Resources.java", 66 "sun/security/util/AuthResources.java", .. 103 // 104 // which is mismatch. There are only two such special cases list above. 105: // For KeyTool, there are 3 calls for showing help. For PolicyTool, 3 106 // for name prefixed with POLICY. They are covered in the two special 107 // cases above. There are some Japanese man pages containing the word. I've filed another bug (https://bugs.openjdk.java.net/browse/JDK-8187262) on it. Thanks Max From erik.joelsson at oracle.com Wed Sep 6 08:53:27 2017 From: erik.joelsson at oracle.com (Erik Joelsson) Date: Wed, 6 Sep 2017 10:53:27 +0200 Subject: RFR 8148371: Remove policytool In-Reply-To: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> References: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> Message-ID: From a build point of view this looks good. /Erik On 2017-09-06 06:17, Weijun Wang wrote: > Hi All > > Please review the change, which spans to root, jdk and langtools repos. > > http://cr.openjdk.java.net/~weijun/8148371/ > > I've searched for the "policytool" word in the whole jdk10/jdk10 forests, removed all files having the word inside the path name, and remove almost all occurrences of the word in other places. > > The exceptions are: > > 1. Two files with the jdk8 word in file name. I assume I should not touch them. Please advise me. > > jdk/src/java.base/share/classes/jdk/internal/module/jdk8_packages.dat: > 1288 sun.security.tools.jarsigner > 1289 sun.security.tools.keytool > 1290: sun.security.tools.policytool > 1291 sun.security.util > 1292 sun.security.validator > > langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdk8_internals.txt: > 977 sun.security.tools.jarsigner > 978 sun.security.tools.keytool > 979: sun.security.tools.policytool > 980 sun.security.util > 981 sun.security.validator > > 2. A swing test containing a full JDK 1.4.2 README text. Keep unchanged. > > jdk/test/javax/swing/JTextArea/4697612/bug4697612.txt: > 122 bin/ktab and jre/bin/ktab > 123 Kerberos key table manager > 124: bin/policytool and jre/bin/policytool > 125 Policy File Creation and Management Tool > 126 bin/orbd and jre/bin/orbd > > 3. A manual test on what resource string are used. It is based on the pre-module source layout and needs to be updated anyway. Keep unchanged this time. https://bugs.openjdk.java.net/browse/JDK-8187265 filed. > > jdk/test/sun/security/util/Resources/NewResourcesNames.java: > 62 "sun/security/tools/jarsigner/Resources.java", > 63 "sun/security/tools/keytool/Resources.java", > 64: "sun/security/tools/policytool/Resources.java", > 65 "sun/security/util/Resources.java", > 66 "sun/security/util/AuthResources.java", > .. > 103 // > 104 // which is mismatch. There are only two such special cases list above. > 105: // For KeyTool, there are 3 calls for showing help. For PolicyTool, 3 > 106 // for name prefixed with POLICY. They are covered in the two special > 107 // cases above. > > There are some Japanese man pages containing the word. I've filed another bug (https://bugs.openjdk.java.net/browse/JDK-8187262) on it. > > Thanks > Max > From Alan.Bateman at oracle.com Wed Sep 6 09:24:22 2017 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Wed, 6 Sep 2017 10:24:22 +0100 Subject: RFR 8148371: Remove policytool In-Reply-To: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> References: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> Message-ID: On 06/09/2017 05:17, Weijun Wang wrote: > Hi All > > Please review the change, which spans to root, jdk and langtools repos. > > http://cr.openjdk.java.net/~weijun/8148371/ > > I've searched for the "policytool" word in the whole jdk10/jdk10 forests, removed all files having the word inside the path name, and remove almost all occurrences of the word in other places. > This looks good, the only change that I'm not sure about is the change to ct.properties as it may be used when compiling to older releases. Someone on compiler-dev should be able to help you on that. -Alan From forax at univ-mlv.fr Thu Sep 7 22:52:24 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 8 Sep 2017 00:52:24 +0200 (CEST) Subject: Backporting JDK-8144185 Message-ID: <1009746602.2277202.1504824744789.JavaMail.zimbra@u-pem.fr> Hi all, hi Srikanth, It's not clear for me if JDK-8144185 [1] was backported to 8 and 9 or not, if it's not, given that we, the ASM team, have seen several independent reports of this issue, we think that this issue, which generate invalid class files, is a good candidate for backports. cheers, R?mi [1] https://bugs.openjdk.java.net/browse/JDK-8144185 From weijun.wang at oracle.com Fri Sep 8 01:51:07 2017 From: weijun.wang at oracle.com (Weijun Wang) Date: Fri, 8 Sep 2017 09:51:07 +0800 Subject: RFR 8148371: Remove policytool In-Reply-To: References: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> Message-ID: <7FD840F2-15D3-40F1-B2A1-9F816E4A8BD0@oracle.com> > On Sep 6, 2017, at 5:24 PM, Alan Bateman wrote: > > > > On 06/09/2017 05:17, Weijun Wang wrote: >> Hi All >> >> Please review the change, which spans to root, jdk and langtools repos. >> >> http://cr.openjdk.java.net/~weijun/8148371/ >> >> I've searched for the "policytool" word in the whole jdk10/jdk10 forests, removed all files having the word inside the path name, and remove almost all occurrences of the word in other places. >> > This looks good, the only change that I'm not sure about is the change to ct.properties as it may be used when compiling to older releases. Someone on compiler-dev should be able to help you on that. Jon suggested reverting this change, offline. --Max > > -Alan From bsrbnd at gmail.com Sat Sep 9 11:53:16 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Sat, 9 Sep 2017 13:53:16 +0200 Subject: Request for feedback on annotation processing API changes made in JDK 9 In-Reply-To: <58E57E6C.9090209@oracle.com> References: <58E57E6C.9090209@oracle.com> Message-ID: Joe, I know this is a bit late to give you my feedback on this, but it's probably better than never... I tried my annotation processor [1] using JDK 9 and all seems to keep on working fine with the precious help of "--add-exports" to access the internal API (as mentioned previously in the thread). The latter being slightly modified, due to module implementation, is causing the processor to be only few updated, mainly when using "ClassReader". The processor [1] being quite old, I noticed that the tree translation would need some rewriting along with some style refresh. I hope this helps, Bernard [1] https://github.com/bsrbnd/draft/blob/master/src/symprog/SymProc.java On 6 April 2017 at 01:31, Joseph D. Darcy wrote: > Hello annotation processing users and authors, > > As has been done previously during Java SE 7 and Java SE 8, the JSR 269 > annotation processing API is undergoing a maintenance review (MR) as part of > Java SE 9. > > Most of the API changes are in support of adding modules to the platform, > both as a language structure in javax.lang.model.* as well as another > interaction points in javax.annotation.processing in the Filer and > elsewhere. A small API change was also done to better support repeating > annotations. A more detailed summary of the API changes as well as an issue > list is included in the MR material: > > http://cr.openjdk.java.net/~darcy/JDK-9-JSR-269-Changes/summary-2017-03-27.html > http://cr.openjdk.java.net/~darcy/JDK-9-JSR-269-Changes/issue-list-2017-03-27.txt > > A specdiff of the changes compared to Java SE 8 is also available: > > http://cr.openjdk.java.net/~darcy/JDK-9-JSR-269-Changes/specdiff-2017-04-05/ > > The API changes are intended to be largely compatible with the sources of > existing processors, their binary linkage, as well as their runtime > behavior. However, it would be helpful to verify that your existing > processors work as expected when run under JDK 9. JDK 9 early access > binaries are available for download: > > https://jdk9.java.net/download/ > > The current build, b163, includes all planned changes to existing types. The > next build, b164, scheduled to be available later this week will also > include the type javax.annotation.processing.Generated. The new type > javax.annotation.processing.Generated is intended to be a drop-in > replacement for javax.annotation.Generated. (The type > javax.annotation.Generated is in a module no longer visible by default.) > > Please report experiences running processors under JDK 9 and feedback on the > API changes. > > Thanks, > > -Joe From srikanth.adayapalam at oracle.com Mon Sep 11 15:11:31 2017 From: srikanth.adayapalam at oracle.com (Srikanth) Date: Mon, 11 Sep 2017 20:41:31 +0530 Subject: Backporting JDK-8144185 In-Reply-To: <1009746602.2277202.1504824744789.JavaMail.zimbra@u-pem.fr> References: <1009746602.2277202.1504824744789.JavaMail.zimbra@u-pem.fr> Message-ID: <59B6A7A3.8050808@oracle.com> Hi Remi, Thanks for the note. I'll take a look and see what can be done here. Srikanth On Friday 08 September 2017 04:22 AM, Remi Forax wrote: > Hi all, hi Srikanth, > It's not clear for me if JDK-8144185 [1] was backported to 8 and 9 or not, > if it's not, given that we, the ASM team, have seen several independent reports of this issue, > we think that this issue, which generate invalid class files, is a good candidate for backports. > > cheers, > R?mi > > [1] https://bugs.openjdk.java.net/browse/JDK-8144185 From joe.darcy at oracle.com Mon Sep 11 16:04:23 2017 From: joe.darcy at oracle.com (joe darcy) Date: Mon, 11 Sep 2017 09:04:23 -0700 Subject: Request for feedback on annotation processing API changes made in JDK 9 In-Reply-To: References: <58E57E6C.9090209@oracle.com> Message-ID: <260d72f3-8ac7-201f-611b-3d6b245aefcd@oracle.com> Hi Bernard, Getting confirmation that the annotation processor API updates are generally fine even a little before GA is better than getting the notice after GA ;-) Thanks, -Joe On 9/9/2017 4:53 AM, B. Blaser wrote: > Joe, > > I know this is a bit late to give you my feedback on this, but it's > probably better than never... > > I tried my annotation processor [1] using JDK 9 and all seems to keep > on working fine with the precious help of "--add-exports" to access > the internal API (as mentioned previously in the thread). > > The latter being slightly modified, due to module implementation, is > causing the processor to be only few updated, mainly when using > "ClassReader". > > The processor [1] being quite old, I noticed that the tree translation > would need some rewriting along with some style refresh. > > I hope this helps, > Bernard > > [1] https://github.com/bsrbnd/draft/blob/master/src/symprog/SymProc.java > > From jonathan.gibbons at oracle.com Mon Sep 11 20:23:35 2017 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Mon, 11 Sep 2017 13:23:35 -0700 Subject: RFR: 8181897: JDK 9 change to symlink handling affects SourceFile attributes In-Reply-To: References: <595129EF.7090005@oracle.com> Message-ID: <59B6F0C7.8050005@oracle.com> +1 -- Jon On 07/06/2017 12:27 PM, Liam Miller-Cushon wrote: > Thanks Jan - this looks good to me, for what that's worth. > > On Mon, Jun 26, 2017 at 8:36 AM, Jan Lahoda > wrote: > > Hi, > > I'd like to propose a simple fix for: > https://bugs.openjdk.java.net/browse/JDK-8181897 > > > The proposed fix is to use the original/user path for toUri(): > http://cr.openjdk.java.net/~jlahoda/8181897/webrev.00/ > > > I believe this is conceptually consistent with the JDK 8 behavior. > > Jan > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Mon Sep 11 21:31:33 2017 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 11 Sep 2017 23:31:33 +0200 (CEST) Subject: Backporting JDK-8144185 In-Reply-To: <59B6A7A3.8050808@oracle.com> References: <1009746602.2277202.1504824744789.JavaMail.zimbra@u-pem.fr> <59B6A7A3.8050808@oracle.com> Message-ID: <1661648799.675129.1505165493826.JavaMail.zimbra@u-pem.fr> Thanks Srikanth. R?mi ----- Mail original ----- > De: "Srikanth" > ?: "compiler-dev" > Envoy?: Lundi 11 Septembre 2017 17:11:31 > Objet: Re: Backporting JDK-8144185 > Hi Remi, > > Thanks for the note. I'll take a look and see what can be done here. > > Srikanth > > On Friday 08 September 2017 04:22 AM, Remi Forax wrote: >> Hi all, hi Srikanth, >> It's not clear for me if JDK-8144185 [1] was backported to 8 and 9 or not, >> if it's not, given that we, the ASM team, have seen several independent reports >> of this issue, >> we think that this issue, which generate invalid class files, is a good >> candidate for backports. >> >> cheers, >> R?mi >> > > [1] https://bugs.openjdk.java.net/browse/JDK-8144185 From rsmogura at gmail.com Wed Sep 13 04:04:22 2017 From: rsmogura at gmail.com (Radek Smogura) Date: Tue, 12 Sep 2017 21:04:22 -0700 Subject: Question about get Method Handle to interface field In-Reply-To: <2b9766af-1997-0398-be49-cbd0cad21162@oracle.com> References: <27220E4D-9039-4798-B8CA-BF00E479F0DC@gmail.com> <125713978.2481758.1504380386597.JavaMail.zimbra@u-pem.fr> <2b9766af-1997-0398-be49-cbd0cad21162@oracle.com> Message-ID: <52D1223F-DEF9-451E-9C40-C5F4DF0D51D0@gmail.com> Hi all, I?m really sorry but my message has bounced from SMTP again. I think that?s this change looks ok for me right now. I will try to invent something simpler. @Remi, Actually I?m not on properties I can go back to it if someone would be interested in syntax like public property int x or public property int y {get {}, set{}), I think I stopped on porting to JDK9, but still I should have a full patch, form ?early, non-module" JDK9. This what I?m on is java.expression: https://bitbucket.org/radoslaw_smogura/panama-langtools/branch/javax.expression-v2 It?s an expression API to capture and give AST of Java structures, like jinq, but giving more predictable results. Right now I?m focusing on lambda, however as lambda can declare arbitrary structure I think there is no need to limit this to lambdas. Purpose of this package is to allow transformation of Java to something else, one my build SQL, I like CUDA. I?ve used following approach: during compilation I build tagged tree: each tree, depending on type and shape, gets tag. The tagged tree is stored as a String in class (I have version which keeps it externally alongside with .class file). String is pretty good as long each tag would not exceed 7 bits (who said strings should be readable?). When lambda is created I pass this tree as new parameter to metafactory. To minimise size of this tree (which is compared to size of byte code), I wanted to use constant pool. However as there is no API to access it right now, I?m using ?virtual? pool. I pass constant references as var args to lambda metafactory. Constants and classes are passed as is, methods as handles, and fields as handles to get field (this is why I?ve found this bug). Metafactory associates those values with Lambda implementation class. It?s not optimal right now, and has some limitations, mainly due to lack of mentioned access to true constant pool. On runtime one can use ExpressionIntrospector to extract AST together with meta information (like captured variables) in the form of nice looking Expression tree. ExpressionIntrospector builds tree on demand. I?ve built API in such a way that after transformation, tree can be disposed, and only few very lightweight objects has to be kept to support execution of transformed AST (as long as someone would use good practice to parametrize transformed code with captured variables). There are still few things I?m thinking about, one is to integrate with Java model package, or reusing similar technique to reify generics. Bit out of scope, but right now I use above package to build runnable CUDA kernels, and have a lot fun allowing constructs like this: int[] data = (int[]) (Object) (((Long) (Object) dataArray) + dataChunkBegin * 4); But it?s version for hardcores only ;) - https://bitbucket.org/radoslaw_smogura/panama-langtools/branch/javax.expression-v2 (core changes) - https://bitbucket.org/radoslaw_smogura/panama-jdk/branch/javax.expression-v2 (idk changes) - https://bitbucket.org/radoslaw_smogura/panama-build/branch/javax.expression-v2 (top-level tree) - https://github.com/rsmogura/cuda-java-samples (CUDA sample) Kind regards, Radek > On 5 Sep 2017, at 01:25, Maurizio Cimadamore wrote: > > > > On 02/09/17 20:26, Remi Forax wrote: >> Hi Radek, >> Do you still trying to implement properties in Java ? >> >> It seem to be an overlook to me, >> getstatic and putstatic are allowed on a static field declared in an interface, getstatic and putstatic use a CONSTANT_Fieldref so unlike constant method handle based on method which need to know if the owner is an interface or not (to generate a CONSTANT_Methodref or a CONSTANT_InterfaceMethodRef), see JVMS 4.4.2. >> >> The following patch should fix the issue >> case ClassFile.REF_getStatic: >> case ClassFile.REF_putStatic: >> staticOk = true; >> + interfaceOwner = true; >> case ClassFile.REF_getField: >> >> R?mi > That's right - that code is buggy and does not handle field handles correctly, mostly because does not need them. Anyway, if you come up with a patch which works for your use case, I'd be happy to take a look. What Remi suggests seems sensible, although I have a feeling that this logic could be simplified a little. > > Maurizio >> >> ----- Mail original ----- >>> De: "Radek Smogura" >>> ?: compiler-dev at openjdk.java.net >>> Envoy?: Samedi 2 Septembre 2017 19:20:06 >>> Objet: Question about get Method Handle to interface field >>> Hi all, >>> >>> Recently I played a little bit and tried to obtain MethodHandle to GET method >>> for interface static field. The code which I try to use is >>> >>> new Pool.MethodHandle(ClassFile.REF_getStatic, sym, types); >>> >>> But it fails on assertion: Assert.check(!refSym.owner.isInterface() || >>> interfaceOwner) located in MethodHandle.checkConsistent:365 ? >>> >>> I wonder if such handles are allowed? >>> >>> Thanks, >>> Radek >>> >>> P.S. Sorry if I post this message twice, but I got SMTP issues From bsrbnd at gmail.com Mon Sep 18 10:29:40 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Mon, 18 Sep 2017 12:29:40 +0200 Subject: NPE in Type.UndetVar.debugString() Message-ID: You're right, sorry... Forwarding it to compiler-dev. Bernard On 18 September 2017 at 10:40, Maurizio Cimadamore wrote: > Hi, > isn't this a bug in 10? Shouldn't this mail belong to compiler-dev? > > Maurizio > > > > On 16/09/17 14:54, B. Blaser wrote: >> >> Hi, >> >> When working on [1], I saw that "Type.UndetVar.debugString()" >> sometimes throws a NPE when called from within "UndetVar", for example >> in "addBound()" as here under, which is annoying... >> >> Could someone eventually push the following harmless fix to the amber >> and jdk10 repositories? >> >> This might be really helpful when debugging... >> >> Thanks, >> Bernard >> >> [1] >> http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002061.html >> >> diff --git >> a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >> b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >> @@ -1974,7 +1974,7 @@ >> } >> for (InferenceBound bound: InferenceBound.values()) { >> List aboundList = bounds.get(bound); >> - if (aboundList.size() > 0) { >> + if (aboundList != null && aboundList.size() > 0) { >> result += bound + " = " + aboundList + '\n'; >> } >> } >> @@ -2112,6 +2112,7 @@ >> bounds.put(ib, prevBounds.prepend(bound2)); >> notifyBoundChange(ib, bound2, false); >> } >> +//System.err.println("debug: " + debugString()); >> } >> //where >> TypeMapping toTypeVarMap = new >> StructuralTypeMapping() { > > From vicente.romero at oracle.com Mon Sep 18 14:23:51 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 18 Sep 2017 10:23:51 -0400 Subject: NPE in Type.UndetVar.debugString() In-Reply-To: References: Message-ID: <87a523db-1985-6c61-b954-5ade8f16aed6@oracle.com> Hi Bernard, Thanks for the bug report and the fix, I will take care of it, Vicente On 09/18/2017 06:29 AM, B. Blaser wrote: > You're right, sorry... > Forwarding it to compiler-dev. > > Bernard > > On 18 September 2017 at 10:40, Maurizio Cimadamore > wrote: >> Hi, >> isn't this a bug in 10? Shouldn't this mail belong to compiler-dev? >> >> Maurizio >> >> >> >> On 16/09/17 14:54, B. Blaser wrote: >>> Hi, >>> >>> When working on [1], I saw that "Type.UndetVar.debugString()" >>> sometimes throws a NPE when called from within "UndetVar", for example >>> in "addBound()" as here under, which is annoying... >>> >>> Could someone eventually push the following harmless fix to the amber >>> and jdk10 repositories? >>> >>> This might be really helpful when debugging... >>> >>> Thanks, >>> Bernard >>> >>> [1] >>> http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002061.html >>> >>> diff --git >>> a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >>> b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >>> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >>> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java >>> @@ -1974,7 +1974,7 @@ >>> } >>> for (InferenceBound bound: InferenceBound.values()) { >>> List aboundList = bounds.get(bound); >>> - if (aboundList.size() > 0) { >>> + if (aboundList != null && aboundList.size() > 0) { >>> result += bound + " = " + aboundList + '\n'; >>> } >>> } >>> @@ -2112,6 +2112,7 @@ >>> bounds.put(ib, prevBounds.prepend(bound2)); >>> notifyBoundChange(ib, bound2, false); >>> } >>> +//System.err.println("debug: " + debugString()); >>> } >>> //where >>> TypeMapping toTypeVarMap = new >>> StructuralTypeMapping() { >> From maurizio.cimadamore at oracle.com Mon Sep 18 16:14:36 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 18 Sep 2017 17:14:36 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference Message-ID: Hi, this change adds support for local variable type inference (JEP 286 [1]). A webrev of the change is available here: http://cr.openjdk.java.net/~mcimadamore/8177466 The patch is relatively straightforward: implicitly typed locals are modeled in a similar fashion to implicit lambda parameters: their AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). There are few tricky parts to this changeset: 1) tweak the parser to give 'var' special meaning depending on the version number and context 2) Add logic in name resolution to catch bad reference to types named 'var' 3) add logic to map initializer type back to a suitable variable declared type As for (1), the parser has been extended so as to special case local variables with special name 'var', so that the type will be left out of the corresponding AST representing the variable declaration. This behavior will only affect latest source version. The parser has a number of extra checks to prevent 'var to be used in places where it does not belong (according to the spec draft [2]); for instance, declaring a class whose name is 'var' is rejected in the parser. As a general rule, I tried to implement all such checks in the parser, as that gives very early and precise feedback about what's wrong with the code. The changes are implemented in Parser.java. There are however errors which cannot be caught in the parser, and that's why (2) is needed. Basically, whenever 'var' is used in a position where it could be either a type or a package name, the parser can't simply rule that out, so we have to accept the code, and give an error if, later on, we discover that 'var' was really used in a type position (see changes in Resolve.java). As far as (3) is concerned, we need to 'uncapture' captured types from initializers. That means that if we have a 'var' like this: class Foo { ??? void test() { ??????? var x = getClass().getSuperClass(); ??? } } The initializer type will be something like Class, where #CAP <: Foo In this case, the compiler will project this type back to the less specific type Class, and use that as the declared type for 'x'. This logic is defined in Types.java. As this logic is the same logic needed by jshell to render type of standalone expressions, jshell class VarTypePrinter has been removed and jshell has been rewired to point at the (now) official routine in Types. Jshell also needed several other tweaks to (i) accept 'var' and (ii) to deal with non-denotable types (intersection types and anonymous class types) that can be produced by the LVTI machinery (many thanks to Jan for doing those changes!) As far as testing is concerned, I wrote several tests to check that the parser was behaving as expected; to check the behavior of the LVTI inference machinery, I wrote a test harness which leverages annotation on 'var' so that we can write down assertions such as: @InferredType("java.util.List") var s = extString(); Regarding compiler diagnostics, for those interested, a comprehensive list of examples of new diagnostics triggered by the LVTI compiler can be found here: http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html Finally, a finder has been added to detect local variable decls whose declared type can be replaced by 'var' - to enable it, the hidden option -XDfind=local should be used. Thanks Maurizio [1] - http://openjdk.java.net/jeps/286 [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html From Sergey.Bylokhov at oracle.com Mon Sep 18 22:44:44 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Mon, 18 Sep 2017 15:44:44 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: Hi, Maurizio. I am not sure is it expected or not, but in some cases the new 'var' produce some non-easy to read error messages: var s = true ? new ArrayList() : new ArrayList(); s.add(new String()); testVar.java:9: error: no suitable method found for add(String) s.add(new String()); ^ method Collection.add(CAP#1) is not applicable (argument mismatch; String cannot be converted to CAP#1) method List.add(CAP#1) is not applicable (argument mismatch; String cannot be converted to CAP#1) method AbstractCollection.add(CAP#1) is not applicable (argument mismatch; String cannot be converted to CAP#1) method AbstractList.add(CAP#1) is not applicable (argument mismatch; String cannot be converted to CAP#1) method ArrayList.add(CAP#1) is not applicable (argument mismatch; String cannot be converted to CAP#1) where CAP#1 is a fresh type-variable: CAP#1 extends INT#1 from capture of ? extends INT#1 where INT#1,INT#2 are intersection types: INT#1 extends Object,Serializable,Comparable INT#2 extends Object,Serializable,Comparable Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output On 9/18/17 09:14, Maurizio Cimadamore wrote: > Hi, > this change adds support for local variable type inference (JEP 286 > [1]). A webrev of the change is available here: > > http://cr.openjdk.java.net/~mcimadamore/8177466 > > The patch is relatively straightforward: implicitly typed locals are > modeled in a similar fashion to implicit lambda parameters: their AST > node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). > > There are few tricky parts to this changeset: > > 1) tweak the parser to give 'var' special meaning depending on the > version number and context > > 2) Add logic in name resolution to catch bad reference to types named 'var' > > 3) add logic to map initializer type back to a suitable variable > declared type > > As for (1), the parser has been extended so as to special case local > variables with special name 'var', so that the type will be left out of > the corresponding AST representing the variable declaration. This > behavior will only affect latest source version. > > The parser has a number of extra checks to prevent 'var to be used in > places where it does not belong (according to the spec draft [2]); for > instance, declaring a class whose name is 'var' is rejected in the > parser. As a general rule, I tried to implement all such checks in the > parser, as that gives very early and precise feedback about what's wrong > with the code. The changes are implemented in Parser.java. > > There are however errors which cannot be caught in the parser, and > that's why (2) is needed. Basically, whenever 'var' is used in a > position where it could be either a type or a package name, the parser > can't simply rule that out, so we have to accept the code, and give an > error if, later on, we discover that 'var' was really used in a type > position (see changes in Resolve.java). > > As far as (3) is concerned, we need to 'uncapture' captured types from > initializers. That means that if we have a 'var' like this: > > class Foo { > ??? void test() { > ??????? var x = getClass().getSuperClass(); > ??? } > } > > The initializer type will be something like Class, where > #CAP <: Foo > > In this case, the compiler will project this type back to the less > specific type Class, and use that as the declared type for 'x'. This > logic is defined in Types.java. As this logic is the same logic needed > by jshell to render type of standalone expressions, jshell class > VarTypePrinter has been removed and jshell has been rewired to point at > the (now) official routine in Types. Jshell also needed several other > tweaks to (i) accept 'var' and (ii) to deal with non-denotable types > (intersection types and anonymous class types) that can be produced by > the LVTI machinery (many thanks to Jan for doing those changes!) > > > As far as testing is concerned, I wrote several tests to check that the > parser was behaving as expected; to check the behavior of the LVTI > inference machinery, I wrote a test harness which leverages annotation > on 'var' so that we can write down assertions such as: > > @InferredType("java.util.List") > var s = extString(); > > > Regarding compiler diagnostics, for those interested, a comprehensive > list of examples of new diagnostics triggered by the LVTI compiler can > be found here: > > http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html > > Finally, a finder has been added to detect local variable decls whose > declared type can be replaced by 'var' - to enable it, the hidden option > -XDfind=local should be used. > > > Thanks > Maurizio > > [1] - http://openjdk.java.net/jeps/286 > [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html > > -- Best regards, Sergey. From maurizio.cimadamore at oracle.com Mon Sep 18 23:35:46 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 00:35:46 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> Uhm - this is a bug in the diagnostic generation for overload resolution - although not a bug in the 'var' support. I could reproduce same issue with this code: import java.util.*; class Test { void test() { ?? make(new ArrayList(), new ArrayList()).add(""); } Z make(Z z1, Z z2) { ?? return null; } } So, I'd suggest that we deal with this as a separate diagnostic-related issue in JDK 10 (I could also reproduce it in 8 and 9). Maurizio On 18/09/17 23:44, Sergey Bylokhov wrote: > Hi, Maurizio. > I am not sure is it expected or not, but in some cases the new 'var' > produce some non-easy to read error messages: > > var s = true ? new ArrayList() : new ArrayList(); > s.add(new String()); > > testVar.java:9: error: no suitable method found for add(String) > ??????? s.add(new String()); > ???????? ^ > ??? method Collection.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method List.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method AbstractCollection.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method AbstractList.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method ArrayList.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ? where CAP#1 is a fresh type-variable: > ??? CAP#1 extends INT#1 from capture of ? extends INT#1 > ? where INT#1,INT#2 are intersection types: > ??? INT#1 extends Object,Serializable,Comparable > ??? INT#2 extends Object,Serializable,Comparable > Note: Some messages have been simplified; recompile with > -Xdiags:verbose to get full output > > > On 9/18/17 09:14, Maurizio Cimadamore wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 >> [1]). A webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are >> modeled in a similar fashion to implicit lambda parameters: their AST >> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the >> version number and context >> >> 2) Add logic in name resolution to catch bad reference to types named >> 'var' >> >> 3) add logic to map initializer type back to a suitable variable >> declared type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out >> of the corresponding AST representing the variable declaration. This >> behavior will only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in >> places where it does not belong (according to the spec draft [2]); >> for instance, declaring a class whose name is 'var' is rejected in >> the parser. As a general rule, I tried to implement all such checks >> in the parser, as that gives very early and precise feedback about >> what's wrong with the code. The changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and >> that's why (2) is needed. Basically, whenever 'var' is used in a >> position where it could be either a type or a package name, the >> parser can't simply rule that out, so we have to accept the code, and >> give an error if, later on, we discover that 'var' was really used in >> a type position (see changes in Resolve.java). >> >> As far as (3) is concerned, we need to 'uncapture' captured types >> from initializers. That means that if we have a 'var' like this: >> >> class Foo { >> ???? void test() { >> ???????? var x = getClass().getSuperClass(); >> ???? } >> } >> >> The initializer type will be something like Class, >> where #CAP <: Foo >> >> In this case, the compiler will project this type back to the less >> specific type Class, and use that as the declared type for 'x'. >> This logic is defined in Types.java. As this logic is the same logic >> needed by jshell to render type of standalone expressions, jshell >> class VarTypePrinter has been removed and jshell has been rewired to >> point at the (now) official routine in Types. Jshell also needed >> several other tweaks to (i) accept 'var' and (ii) to deal with >> non-denotable types (intersection types and anonymous class types) >> that can be produced by the LVTI machinery (many thanks to Jan for >> doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that >> the parser was behaving as expected; to check the behavior of the >> LVTI inference machinery, I wrote a test harness which leverages >> annotation on 'var' so that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive >> list of examples of new diagnostics triggered by the LVTI compiler >> can be found here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden >> option -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> > > From maurizio.cimadamore at oracle.com Mon Sep 18 23:38:49 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 00:38:49 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> References: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> Message-ID: <839c7a4d-c51a-bad9-58f0-c63ef775984f@oracle.com> On 19/09/17 00:35, Maurizio Cimadamore wrote: > Uhm - this is a bug in the diagnostic generation for overload > resolution - although not a bug in the 'var' support. > > I could reproduce same issue with this code: > > import java.util.*; > > class Test { > > void test() { > ?? make(new ArrayList(), new ArrayList()).add(""); > } > > Z make(Z z1, Z z2) { > ?? return null; > } > } Actually, you don't even need intersection types to reproduce; the following will do: ?new ArrayList().add(""); error: no suitable method found for add(String) ?? new ArrayList().add(""); ?????????????????????????? ^ ??? method Collection.add(Integer) is not applicable ????? (argument mismatch; String cannot be converted to Integer) ??? method List.add(Integer) is not applicable ????? (argument mismatch; String cannot be converted to Integer) ??? method AbstractCollection.add(Integer) is not applicable ????? (argument mismatch; String cannot be converted to Integer) ??? method AbstractList.add(Integer) is not applicable ????? (argument mismatch; String cannot be converted to Integer) ??? method ArrayList.add(Integer) is not applicable ????? (argument mismatch; String cannot be converted to Integer) Seems like something is up in the logic that should pick the 'most specific' signature to report in the diagnostic. Maurizio > > > So, I'd suggest that we deal with this as a separate > diagnostic-related issue in JDK 10 (I could also reproduce it in 8 and > 9). > > Maurizio > > On 18/09/17 23:44, Sergey Bylokhov wrote: >> Hi, Maurizio. >> I am not sure is it expected or not, but in some cases the new 'var' >> produce some non-easy to read error messages: >> >> var s = true ? new ArrayList() : new ArrayList(); >> s.add(new String()); >> >> testVar.java:9: error: no suitable method found for add(String) >> ??????? s.add(new String()); >> ???????? ^ >> ??? method Collection.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method List.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method AbstractCollection.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method AbstractList.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method ArrayList.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ? where CAP#1 is a fresh type-variable: >> ??? CAP#1 extends INT#1 from capture of ? extends INT#1 >> ? where INT#1,INT#2 are intersection types: >> ??? INT#1 extends Object,Serializable,Comparable >> ??? INT#2 extends Object,Serializable,Comparable >> Note: Some messages have been simplified; recompile with >> -Xdiags:verbose to get full output >> >> >> On 9/18/17 09:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their >>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>> null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types >>> named 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used >>> in places where it does not belong (according to the spec draft >>> [2]); for instance, declaring a class whose name is 'var' is >>> rejected in the parser. As a general rule, I tried to implement all >>> such checks in the parser, as that gives very early and precise >>> feedback about what's wrong with the code. The changes are >>> implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, >>> and give an error if, later on, we discover that 'var' was really >>> used in a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ???? void test() { >>> ???????? var x = getClass().getSuperClass(); >>> ???? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a >>> comprehensive list of examples of new diagnostics triggered by the >>> LVTI compiler can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls >>> whose declared type can be replaced by 'var' - to enable it, the >>> hidden option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> >> > From Sergey.Bylokhov at oracle.com Tue Sep 19 00:03:04 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Mon, 18 Sep 2017 17:03:04 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> References: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> Message-ID: <79b3f713-4472-c2c2-5338-c65f031bf891@oracle.com> On 9/18/17 16:35, Maurizio Cimadamore wrote: > So, I'd suggest that we deal with this as a separate diagnostic-related > issue in JDK 10 (I could also reproduce it in 8 and 9). Sure, it was just a random example. Your comment about jdk8/9 just highlighted one more place, in: http://cr.openjdk.java.net/~mcimadamore/8177466/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties.sdiff.html "as of release 9, 'var' is a restricted local variable type and cannot be used for type declarations" I guess it is restricted from jdk 10? > > Maurizio > > On 18/09/17 23:44, Sergey Bylokhov wrote: >> Hi, Maurizio. >> I am not sure is it expected or not, but in some cases the new 'var' >> produce some non-easy to read error messages: >> >> var s = true ? new ArrayList() : new ArrayList(); >> s.add(new String()); >> >> testVar.java:9: error: no suitable method found for add(String) >> ??????? s.add(new String()); >> ???????? ^ >> ??? method Collection.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method List.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method AbstractCollection.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method AbstractList.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ??? method ArrayList.add(CAP#1) is not applicable >> ????? (argument mismatch; String cannot be converted to CAP#1) >> ? where CAP#1 is a fresh type-variable: >> ??? CAP#1 extends INT#1 from capture of ? extends INT#1 >> ? where INT#1,INT#2 are intersection types: >> ??? INT#1 extends Object,Serializable,Comparable >> ??? INT#2 extends Object,Serializable,Comparable >> Note: Some messages have been simplified; recompile with >> -Xdiags:verbose to get full output >> >> >> On 9/18/17 09:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their AST >>> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types named >>> 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used in >>> places where it does not belong (according to the spec draft [2]); >>> for instance, declaring a class whose name is 'var' is rejected in >>> the parser. As a general rule, I tried to implement all such checks >>> in the parser, as that gives very early and precise feedback about >>> what's wrong with the code. The changes are implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, and >>> give an error if, later on, we discover that 'var' was really used in >>> a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ???? void test() { >>> ???????? var x = getClass().getSuperClass(); >>> ???? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a comprehensive >>> list of examples of new diagnostics triggered by the LVTI compiler >>> can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls whose >>> declared type can be replaced by 'var' - to enable it, the hidden >>> option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> >> > -- Best regards, Sergey. From Sergey.Bylokhov at oracle.com Tue Sep 19 00:21:36 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Mon, 18 Sep 2017 17:21:36 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: <08e8ceed-2f9d-c38b-cc81-7debc28c8615@oracle.com> It is also interesting how the new 'var' should work in case of conditional expression: String s = true ? new String() : new int[1]; // incompatible types: bad type in conditional expression int[] s = true ? new String() : new int[1]; // incompatible types: bad type in conditional expression var s = true ? new String() : new int[1]; // works fine Is it expected that this code compiles? One related example: var s = true ? new String() : new int[1]; s[0]=123; testVar.java:11: error: array required, but Serializable found s[0]=123; ^ 1 error Looks like a surprise - 's' is of type "Serializable"? On 9/18/17 15:44, Sergey Bylokhov wrote: > Hi, Maurizio. > I am not sure is it expected or not, but in some cases the new 'var' > produce some non-easy to read error messages: > > var s = true ? new ArrayList() : new ArrayList(); > s.add(new String()); > > testVar.java:9: error: no suitable method found for add(String) > ??????? s.add(new String()); > ???????? ^ > ??? method Collection.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method List.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method AbstractCollection.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method AbstractList.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ??? method ArrayList.add(CAP#1) is not applicable > ????? (argument mismatch; String cannot be converted to CAP#1) > ? where CAP#1 is a fresh type-variable: > ??? CAP#1 extends INT#1 from capture of ? extends INT#1 > ? where INT#1,INT#2 are intersection types: > ??? INT#1 extends Object,Serializable,Comparable > ??? INT#2 extends Object,Serializable,Comparable > Note: Some messages have been simplified; recompile with -Xdiags:verbose > to get full output > > > On 9/18/17 09:14, Maurizio Cimadamore wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 >> [1]). A webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are >> modeled in a similar fashion to implicit lambda parameters: their AST >> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the >> version number and context >> >> 2) Add logic in name resolution to catch bad reference to types named >> 'var' >> >> 3) add logic to map initializer type back to a suitable variable >> declared type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out >> of the corresponding AST representing the variable declaration. This >> behavior will only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in >> places where it does not belong (according to the spec draft [2]); for >> instance, declaring a class whose name is 'var' is rejected in the >> parser. As a general rule, I tried to implement all such checks in the >> parser, as that gives very early and precise feedback about what's >> wrong with the code. The changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and >> that's why (2) is needed. Basically, whenever 'var' is used in a >> position where it could be either a type or a package name, the parser >> can't simply rule that out, so we have to accept the code, and give an >> error if, later on, we discover that 'var' was really used in a type >> position (see changes in Resolve.java). >> >> As far as (3) is concerned, we need to 'uncapture' captured types from >> initializers. That means that if we have a 'var' like this: >> >> class Foo { >> ???? void test() { >> ???????? var x = getClass().getSuperClass(); >> ???? } >> } >> >> The initializer type will be something like Class, where >> #CAP <: Foo >> >> In this case, the compiler will project this type back to the less >> specific type Class, and use that as the declared type for 'x'. >> This logic is defined in Types.java. As this logic is the same logic >> needed by jshell to render type of standalone expressions, jshell >> class VarTypePrinter has been removed and jshell has been rewired to >> point at the (now) official routine in Types. Jshell also needed >> several other tweaks to (i) accept 'var' and (ii) to deal with >> non-denotable types (intersection types and anonymous class types) >> that can be produced by the LVTI machinery (many thanks to Jan for >> doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that >> the parser was behaving as expected; to check the behavior of the LVTI >> inference machinery, I wrote a test harness which leverages annotation >> on 'var' so that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive >> list of examples of new diagnostics triggered by the LVTI compiler can >> be found here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden >> option -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> > > -- Best regards, Sergey. From maurizio.cimadamore at oracle.com Tue Sep 19 11:32:41 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 12:32:41 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <79b3f713-4472-c2c2-5338-c65f031bf891@oracle.com> References: <313e36ed-1dcf-580f-2660-04a178a2f680@oracle.com> <79b3f713-4472-c2c2-5338-c65f031bf891@oracle.com> Message-ID: <864a1ad4-6bf8-26aa-1f71-0040318addbf@oracle.com> On 19/09/17 01:03, Sergey Bylokhov wrote: > On 9/18/17 16:35, Maurizio Cimadamore wrote: >> So, I'd suggest that we deal with this as a separate >> diagnostic-related issue in JDK 10 (I could also reproduce it in 8 >> and 9). > > Sure, it was just a random example. > > Your comment about jdk8/9 just highlighted one more place, in: > http://cr.openjdk.java.net/~mcimadamore/8177466/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties.sdiff.html > > > "as of release 9, 'var' is a restricted local variable type and cannot > be used for type declarations" > > I guess it is restricted from jdk 10? Whoops - correct, well spotted Maurizio > >> >> Maurizio >> >> On 18/09/17 23:44, Sergey Bylokhov wrote: >>> Hi, Maurizio. >>> I am not sure is it expected or not, but in some cases the new 'var' >>> produce some non-easy to read error messages: >>> >>> var s = true ? new ArrayList() : new ArrayList(); >>> s.add(new String()); >>> >>> testVar.java:9: error: no suitable method found for add(String) >>> ??????? s.add(new String()); >>> ???????? ^ >>> ??? method Collection.add(CAP#1) is not applicable >>> ????? (argument mismatch; String cannot be converted to CAP#1) >>> ??? method List.add(CAP#1) is not applicable >>> ????? (argument mismatch; String cannot be converted to CAP#1) >>> ??? method AbstractCollection.add(CAP#1) is not applicable >>> ????? (argument mismatch; String cannot be converted to CAP#1) >>> ??? method AbstractList.add(CAP#1) is not applicable >>> ????? (argument mismatch; String cannot be converted to CAP#1) >>> ??? method ArrayList.add(CAP#1) is not applicable >>> ????? (argument mismatch; String cannot be converted to CAP#1) >>> ? where CAP#1 is a fresh type-variable: >>> ??? CAP#1 extends INT#1 from capture of ? extends INT#1 >>> ? where INT#1,INT#2 are intersection types: >>> ??? INT#1 extends Object,Serializable,Comparable >>> ??? INT#2 extends Object,Serializable,Comparable >>> Note: Some messages have been simplified; recompile with >>> -Xdiags:verbose to get full output >>> >>> >>> On 9/18/17 09:14, Maurizio Cimadamore wrote: >>>> Hi, >>>> this change adds support for local variable type inference (JEP 286 >>>> [1]). A webrev of the change is available here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>> >>>> The patch is relatively straightforward: implicitly typed locals >>>> are modeled in a similar fashion to implicit lambda parameters: >>>> their AST node is a JCVariableDecl whose 'vartype' field is not set >>>> (e.g. null). >>>> >>>> There are few tricky parts to this changeset: >>>> >>>> 1) tweak the parser to give 'var' special meaning depending on the >>>> version number and context >>>> >>>> 2) Add logic in name resolution to catch bad reference to types >>>> named 'var' >>>> >>>> 3) add logic to map initializer type back to a suitable variable >>>> declared type >>>> >>>> As for (1), the parser has been extended so as to special case >>>> local variables with special name 'var', so that the type will be >>>> left out of the corresponding AST representing the variable >>>> declaration. This behavior will only affect latest source version. >>>> >>>> The parser has a number of extra checks to prevent 'var to be used >>>> in places where it does not belong (according to the spec draft >>>> [2]); for instance, declaring a class whose name is 'var' is >>>> rejected in the parser. As a general rule, I tried to implement all >>>> such checks in the parser, as that gives very early and precise >>>> feedback about what's wrong with the code. The changes are >>>> implemented in Parser.java. >>>> >>>> There are however errors which cannot be caught in the parser, and >>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>> position where it could be either a type or a package name, the >>>> parser can't simply rule that out, so we have to accept the code, >>>> and give an error if, later on, we discover that 'var' was really >>>> used in a type position (see changes in Resolve.java). >>>> >>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>> from initializers. That means that if we have a 'var' like this: >>>> >>>> class Foo { >>>> ???? void test() { >>>> ???????? var x = getClass().getSuperClass(); >>>> ???? } >>>> } >>>> >>>> The initializer type will be something like Class, >>>> where #CAP <: Foo >>>> >>>> In this case, the compiler will project this type back to the less >>>> specific type Class, and use that as the declared type for 'x'. >>>> This logic is defined in Types.java. As this logic is the same >>>> logic needed by jshell to render type of standalone expressions, >>>> jshell class VarTypePrinter has been removed and jshell has been >>>> rewired to point at the (now) official routine in Types. Jshell >>>> also needed several other tweaks to (i) accept 'var' and (ii) to >>>> deal with non-denotable types (intersection types and anonymous >>>> class types) that can be produced by the LVTI machinery (many >>>> thanks to Jan for doing those changes!) >>>> >>>> >>>> As far as testing is concerned, I wrote several tests to check that >>>> the parser was behaving as expected; to check the behavior of the >>>> LVTI inference machinery, I wrote a test harness which leverages >>>> annotation on 'var' so that we can write down assertions such as: >>>> >>>> @InferredType("java.util.List") >>>> var s = extString(); >>>> >>>> >>>> Regarding compiler diagnostics, for those interested, a >>>> comprehensive list of examples of new diagnostics triggered by the >>>> LVTI compiler can be found here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>> >>>> Finally, a finder has been added to detect local variable decls >>>> whose declared type can be replaced by 'var' - to enable it, the >>>> hidden option -XDfind=local should be used. >>>> >>>> >>>> Thanks >>>> Maurizio >>>> >>>> [1] - http://openjdk.java.net/jeps/286 >>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>> >>>> >>> >>> >> > > From maurizio.cimadamore at oracle.com Tue Sep 19 11:40:30 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 12:40:30 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <08e8ceed-2f9d-c38b-cc81-7debc28c8615@oracle.com> References: <08e8ceed-2f9d-c38b-cc81-7debc28c8615@oracle.com> Message-ID: <5158f227-4f3b-bb4a-542c-87b9ffff5b18@oracle.com> On 19/09/17 01:21, Sergey Bylokhov wrote: > It is also interesting how the new 'var' should work in case of > conditional expression: > > String s = true ? new String() : new int[1]; // incompatible types: > bad type in conditional expression > int[] s = true ? new String() : new int[1];? // incompatible types: > bad type in conditional expression In this case, both arms of the conditional return reference types, so the conditional is a poly expression (see JLS 15.25.3). That means that in the first case, you need to check that: String is assignable to String, ok int[] is assignable to String, not ok In the second case you have the dual case: String is assignable to int[], not ok int[] is assignable to int[], ok So, in neither declarations, both branches of the check are satisfied - which is why you get an error. > > var s = true ? new String() : new int[1]; // works fine > Is it expected that this code compiles? Now, in this case the conditional is treated as a standalone conditional - because there's no target type. The type of the initializer is then computed using the classic rules, which in this case give lub(String, int[]) = Serializable. So the type of 'var' is Serializable (all arrays have Serializable as superinterface, see JLS 4.10.3). Maurizio > > > One related example: > ??????? var s = true ? new String() : new int[1]; > ??????? s[0]=123; > > testVar.java:11: error: array required, but Serializable found > ??????? s[0]=123; > ???????? ^ > 1 error > > Looks like a surprise - 's' is of type "Serializable"? > > On 9/18/17 15:44, Sergey Bylokhov wrote: >> Hi, Maurizio. >> I am not sure is it expected or not, but in some cases the new 'var' >> produce some non-easy to read error messages: >> >> var s = true ? new ArrayList() : new ArrayList(); >> s.add(new String()); >> >> testVar.java:9: error: no suitable method found for add(String) >> ???????? s.add(new String()); >> ????????? ^ >> ???? method Collection.add(CAP#1) is not applicable >> ?????? (argument mismatch; String cannot be converted to CAP#1) >> ???? method List.add(CAP#1) is not applicable >> ?????? (argument mismatch; String cannot be converted to CAP#1) >> ???? method AbstractCollection.add(CAP#1) is not applicable >> ?????? (argument mismatch; String cannot be converted to CAP#1) >> ???? method AbstractList.add(CAP#1) is not applicable >> ?????? (argument mismatch; String cannot be converted to CAP#1) >> ???? method ArrayList.add(CAP#1) is not applicable >> ?????? (argument mismatch; String cannot be converted to CAP#1) >> ?? where CAP#1 is a fresh type-variable: >> ???? CAP#1 extends INT#1 from capture of ? extends INT#1 >> ?? where INT#1,INT#2 are intersection types: >> ???? INT#1 extends Object,Serializable,Comparable >> ???? INT#2 extends Object,Serializable,Comparable >> Note: Some messages have been simplified; recompile with >> -Xdiags:verbose to get full output >> >> >> On 9/18/17 09:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their >>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>> null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types >>> named 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used >>> in places where it does not belong (according to the spec draft >>> [2]); for instance, declaring a class whose name is 'var' is >>> rejected in the parser. As a general rule, I tried to implement all >>> such checks in the parser, as that gives very early and precise >>> feedback about what's wrong with the code. The changes are >>> implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, >>> and give an error if, later on, we discover that 'var' was really >>> used in a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ???? void test() { >>> ???????? var x = getClass().getSuperClass(); >>> ???? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a >>> comprehensive list of examples of new diagnostics triggered by the >>> LVTI compiler can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls >>> whose declared type can be replaced by 'var' - to enable it, the >>> hidden option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> >> > > From maurizio.cimadamore at oracle.com Tue Sep 19 15:04:34 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 16:04:34 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Hi, I have put together a slightly updated webrev: * as pointed out, one diagnostic used to say '9' instead of '10' (this will likely need to change again because of new release cadence, but good enough for now) * the previous webrev contained a spurious added file (TypeHarness) which was caused by a glitch in the lvti branch in the amber repo. New webrev: http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ New diags: http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html Maurizio On 18/09/17 17:14, Maurizio Cimadamore wrote: > Hi, > this change adds support for local variable type inference (JEP 286 > [1]). A webrev of the change is available here: > > http://cr.openjdk.java.net/~mcimadamore/8177466 > > The patch is relatively straightforward: implicitly typed locals are > modeled in a similar fashion to implicit lambda parameters: their AST > node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). > > There are few tricky parts to this changeset: > > 1) tweak the parser to give 'var' special meaning depending on the > version number and context > > 2) Add logic in name resolution to catch bad reference to types named > 'var' > > 3) add logic to map initializer type back to a suitable variable > declared type > > As for (1), the parser has been extended so as to special case local > variables with special name 'var', so that the type will be left out > of the corresponding AST representing the variable declaration. This > behavior will only affect latest source version. > > The parser has a number of extra checks to prevent 'var to be used in > places where it does not belong (according to the spec draft [2]); for > instance, declaring a class whose name is 'var' is rejected in the > parser. As a general rule, I tried to implement all such checks in the > parser, as that gives very early and precise feedback about what's > wrong with the code. The changes are implemented in Parser.java. > > There are however errors which cannot be caught in the parser, and > that's why (2) is needed. Basically, whenever 'var' is used in a > position where it could be either a type or a package name, the parser > can't simply rule that out, so we have to accept the code, and give an > error if, later on, we discover that 'var' was really used in a type > position (see changes in Resolve.java). > > As far as (3) is concerned, we need to 'uncapture' captured types from > initializers. That means that if we have a 'var' like this: > > class Foo { > ??? void test() { > ??????? var x = getClass().getSuperClass(); > ??? } > } > > The initializer type will be something like Class, where > #CAP <: Foo > > In this case, the compiler will project this type back to the less > specific type Class, and use that as the declared type for 'x'. > This logic is defined in Types.java. As this logic is the same logic > needed by jshell to render type of standalone expressions, jshell > class VarTypePrinter has been removed and jshell has been rewired to > point at the (now) official routine in Types. Jshell also needed > several other tweaks to (i) accept 'var' and (ii) to deal with > non-denotable types (intersection types and anonymous class types) > that can be produced by the LVTI machinery (many thanks to Jan for > doing those changes!) > > > As far as testing is concerned, I wrote several tests to check that > the parser was behaving as expected; to check the behavior of the LVTI > inference machinery, I wrote a test harness which leverages annotation > on 'var' so that we can write down assertions such as: > > @InferredType("java.util.List") > var s = extString(); > > > Regarding compiler diagnostics, for those interested, a comprehensive > list of examples of new diagnostics triggered by the LVTI compiler can > be found here: > > http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html > > Finally, a finder has been added to detect local variable decls whose > declared type can be replaced by 'var' - to enable it, the hidden > option -XDfind=local should be used. > > > Thanks > Maurizio > > [1] - http://openjdk.java.net/jeps/286 > [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html > > From Sergey.Bylokhov at oracle.com Tue Sep 19 16:44:23 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Tue, 19 Sep 2017 09:44:23 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: Hi, Maurizio. One more question about generics, in the code below the "case1" compiles successfully, but the "case2" produce an error: public class testVar { class Component { final Container getContainer() { return null; } void windowToLocal() { // case1 Component cp1 = this; cp1 = cp1.getContainer(); // case2 var cp2 = this; cp2 = cp2.getContainer(); } } class Container extends Component { } } //error testVar.java:13: error: incompatible types: testVar.Container cannot be converted to testVar.Component cp2 = cp2.getContainer(); ^ where T,D are type-variables: T extends Object declared in class testVar.Component D extends Object declared in class testVar.Component where CAP#1,CAP#2 are fresh type-variables: CAP#1 extends Object from capture of ? CAP#2 extends Object from capture of ? 1 error On 9/19/17 08:04, Maurizio Cimadamore wrote: > Hi, > I have put together a slightly updated webrev: > > * as pointed out, one diagnostic used to say '9' instead of '10' (this > will likely need to change again because of new release cadence, but > good enough for now) > * the previous webrev contained a spurious added file (TypeHarness) > which was caused by a glitch in the lvti branch in the amber repo. > > New webrev: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ > > New diags: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html > > Maurizio > > > On 18/09/17 17:14, Maurizio Cimadamore wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 >> [1]). A webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are >> modeled in a similar fashion to implicit lambda parameters: their AST >> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the >> version number and context >> >> 2) Add logic in name resolution to catch bad reference to types named >> 'var' >> >> 3) add logic to map initializer type back to a suitable variable >> declared type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out >> of the corresponding AST representing the variable declaration. This >> behavior will only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in >> places where it does not belong (according to the spec draft [2]); for >> instance, declaring a class whose name is 'var' is rejected in the >> parser. As a general rule, I tried to implement all such checks in the >> parser, as that gives very early and precise feedback about what's >> wrong with the code. The changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and >> that's why (2) is needed. Basically, whenever 'var' is used in a >> position where it could be either a type or a package name, the parser >> can't simply rule that out, so we have to accept the code, and give an >> error if, later on, we discover that 'var' was really used in a type >> position (see changes in Resolve.java). >> >> As far as (3) is concerned, we need to 'uncapture' captured types from >> initializers. That means that if we have a 'var' like this: >> >> class Foo { >> ??? void test() { >> ??????? var x = getClass().getSuperClass(); >> ??? } >> } >> >> The initializer type will be something like Class, where >> #CAP <: Foo >> >> In this case, the compiler will project this type back to the less >> specific type Class, and use that as the declared type for 'x'. >> This logic is defined in Types.java. As this logic is the same logic >> needed by jshell to render type of standalone expressions, jshell >> class VarTypePrinter has been removed and jshell has been rewired to >> point at the (now) official routine in Types. Jshell also needed >> several other tweaks to (i) accept 'var' and (ii) to deal with >> non-denotable types (intersection types and anonymous class types) >> that can be produced by the LVTI machinery (many thanks to Jan for >> doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that >> the parser was behaving as expected; to check the behavior of the LVTI >> inference machinery, I wrote a test harness which leverages annotation >> on 'var' so that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive >> list of examples of new diagnostics triggered by the LVTI compiler can >> be found here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden >> option -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> > -- Best regards, Sergey. From Sergey.Bylokhov at oracle.com Tue Sep 19 16:58:45 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Tue, 19 Sep 2017 09:58:45 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <5158f227-4f3b-bb4a-542c-87b9ffff5b18@oracle.com> References: <08e8ceed-2f9d-c38b-cc81-7debc28c8615@oracle.com> <5158f227-4f3b-bb4a-542c-87b9ffff5b18@oracle.com> Message-ID: <01394173-a286-77e4-c466-00df04aa1c57@oracle.com> On 9/19/17 04:40, Maurizio Cimadamore wrote: > > So, in neither declarations, both branches of the check are satisfied - > which is why you get an error. >> >> var s = true ? new String() : new int[1]; // works fine >> Is it expected that this code compiles? > Now, in this case the conditional is treated as a standalone conditional > - because there's no target type. The type of the initializer is then > computed using the classic rules, which in this case give lub(String, > int[]) = Serializable. So the type of 'var' is Serializable (all arrays > have Serializable as superinterface, see JLS 4.10.3). I understood these rules, but hope it could be simplified in case of "var". Just to clarify, Text like "INT#1","CAP#1", etc are standard elements of the error messages, or a bugs? public class testVar { static class One implements Comparable, Serializable{ @Override public int compareTo(Object o) { return 0; } } static class Two implements Comparable, Serializable{ @Override public int compareTo(Object o) { return 0; } } public static void main(String[] args) { var t = true ? new One(): new Two(); t[1]=0; System.out.println("t.getClass() = " + t.getClass()); } } produce an error: testVar.java:41: error: array required, but INT#1 found t[1]=0; ^ where INT#1 is an intersection type: INT#1 extends Object,Serializable,Comparable 1 error -- Best regards, Sergey. From maurizio.cimadamore at oracle.com Tue Sep 19 20:21:31 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 21:21:31 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <01394173-a286-77e4-c466-00df04aa1c57@oracle.com> References: <08e8ceed-2f9d-c38b-cc81-7debc28c8615@oracle.com> <5158f227-4f3b-bb4a-542c-87b9ffff5b18@oracle.com> <01394173-a286-77e4-c466-00df04aa1c57@oracle.com> Message-ID: On 19/09/17 17:58, Sergey Bylokhov wrote: > On 9/19/17 04:40, Maurizio Cimadamore wrote: >> >> So, in neither declarations, both branches of the check are satisfied >> - which is why you get an error. >>> >>> var s = true ? new String() : new int[1]; // works fine >>> Is it expected that this code compiles? >> Now, in this case the conditional is treated as a standalone >> conditional - because there's no target type. The type of the >> initializer is then computed using the classic rules, which in this >> case give lub(String, int[]) = Serializable. So the type of 'var' is >> Serializable (all arrays have Serializable as superinterface, see JLS >> 4.10.3). > > I understood these rules, but hope it could be simplified in case of > "var". > > Just to clarify, Text like "INT#1","CAP#1", etc are standard elements > of the error messages, or a bugs? These are normal features of javac diagnostics involving intersection types and captured types. Maurizio > > public class testVar { > > ??? static class One implements Comparable, Serializable{ > > ??????? @Override > ??????? public int compareTo(Object o) { > ??????????? return 0; > ??????? } > ??? } > > ??? static class Two implements Comparable, Serializable{ > > ??????? @Override > ??????? public int compareTo(Object o) { > ??????????? return 0; > ??????? } > ??? } > > ??? public static void main(String[] args) { > ??????? var t = true ? new One(): new Two(); > ??????? t[1]=0; > ??????? System.out.println("t.getClass() = " + t.getClass()); > ??? } > } > > produce an error: > testVar.java:41: error: array required, but INT#1 found > ??????? t[1]=0; > ???????? ^ > ? where INT#1 is an intersection type: > ??? INT#1 extends Object,Serializable,Comparable > 1 error > From maurizio.cimadamore at oracle.com Tue Sep 19 20:24:47 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 19 Sep 2017 21:24:47 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: The type of this is not Component but Component. So, when you use an explicit type, you force the type of 'cp1' to be less sharp, which then works for the followup assignment. But if you use 'var', the compiler will just infer whatever type the initializer has, which in this case is Component. And the type of c2.getContainer (Component<#CAP1, #CAP2>) is not compatible with Component. Maurizio On 19/09/17 17:44, Sergey Bylokhov wrote: > Hi, Maurizio. > One more question about generics, in the code below the "case1" > compiles successfully, but the "case2" produce an error: > > public class testVar { > > ??? class Component { > > ??????? final Container getContainer() { > ??????????? return null; > ??????? } > > ??????? void windowToLocal() { > ??????????? // case1 > ??????????? Component cp1 = this; > ??????????? cp1 = cp1.getContainer(); > ??????????? // case2 > ??????????? var cp2 = this; > ??????????? cp2 = cp2.getContainer(); > ??????? } > ??? } > ??? class Container > ??????????? extends Component { > > ??? } > } > > //error > testVar.java:13: error: incompatible types: > testVar.Container cannot be converted to > testVar.Component > ??????????? cp2 = cp2.getContainer(); > ????????????????????????????????? ^ > ? where T,D are type-variables: > ??? T extends Object declared in class testVar.Component > ??? D extends Object declared in class testVar.Component > ? where CAP#1,CAP#2 are fresh type-variables: > ??? CAP#1 extends Object from capture of ? > ??? CAP#2 extends Object from capture of ? > 1 error > > On 9/19/17 08:04, Maurizio Cimadamore wrote: >> Hi, >> I have put together a slightly updated webrev: >> >> * as pointed out, one diagnostic used to say '9' instead of '10' >> (this will likely need to change again because of new release >> cadence, but good enough for now) >> * the previous webrev contained a spurious added file (TypeHarness) >> which was caused by a glitch in the lvti branch in the amber repo. >> >> New webrev: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >> >> New diags: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >> >> Maurizio >> >> >> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their >>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>> null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types >>> named 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used >>> in places where it does not belong (according to the spec draft >>> [2]); for instance, declaring a class whose name is 'var' is >>> rejected in the parser. As a general rule, I tried to implement all >>> such checks in the parser, as that gives very early and precise >>> feedback about what's wrong with the code. The changes are >>> implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, >>> and give an error if, later on, we discover that 'var' was really >>> used in a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ??? void test() { >>> ??????? var x = getClass().getSuperClass(); >>> ??? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a >>> comprehensive list of examples of new diagnostics triggered by the >>> LVTI compiler can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls >>> whose declared type can be replaced by 'var' - to enable it, the >>> hidden option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> > > From Sergey.Bylokhov at oracle.com Wed Sep 20 00:20:12 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Tue, 19 Sep 2017 17:20:12 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: <0f10b813-de2e-73ce-2b31-89213e4e4e35@oracle.com> Just thoughts on a subject... Its seems that most of "surprising" behavior comes from the reassigning, The new "var" adds one new feature: it will be possible to have a reference to the anonymous class and call the methods defined in it. So it is not simply a syntactic sugar. var probablySerializable = new Serializable() { public void test() { } }; ..... probablySerializable.test(); And because of that the reassigned will not work: var probablySerializable = new Serializable() { public void test() { } }; probablySerializable = new Serializable() { }; testVar.java:13: error: incompatible types: cannot be converted to name = new Serializable() { On 9/19/17 13:24, Maurizio Cimadamore wrote: > The type of this is not Component but Component. So, when > you use an explicit type, you force the type of 'cp1' to be less sharp, > which then works for the followup assignment. But if you use 'var', the > compiler will just infer whatever type the initializer has, which in > this case is Component. And the type of c2.getContainer > (Component<#CAP1, #CAP2>) is not compatible with Component. > > Maurizio > > > On 19/09/17 17:44, Sergey Bylokhov wrote: >> Hi, Maurizio. >> One more question about generics, in the code below the "case1" >> compiles successfully, but the "case2" produce an error: >> >> public class testVar { >> >> ??? class Component { >> >> ??????? final Container getContainer() { >> ??????????? return null; >> ??????? } >> >> ??????? void windowToLocal() { >> ??????????? // case1 >> ??????????? Component cp1 = this; >> ??????????? cp1 = cp1.getContainer(); >> ??????????? // case2 >> ??????????? var cp2 = this; >> ??????????? cp2 = cp2.getContainer(); >> ??????? } >> ??? } >> ??? class Container >> ??????????? extends Component { >> >> ??? } >> } >> >> //error >> testVar.java:13: error: incompatible types: >> testVar.Container cannot be converted to >> testVar.Component >> ??????????? cp2 = cp2.getContainer(); >> ????????????????????????????????? ^ >> ? where T,D are type-variables: >> ??? T extends Object declared in class testVar.Component >> ??? D extends Object declared in class testVar.Component >> ? where CAP#1,CAP#2 are fresh type-variables: >> ??? CAP#1 extends Object from capture of ? >> ??? CAP#2 extends Object from capture of ? >> 1 error >> >> On 9/19/17 08:04, Maurizio Cimadamore wrote: >>> Hi, >>> I have put together a slightly updated webrev: >>> >>> * as pointed out, one diagnostic used to say '9' instead of '10' >>> (this will likely need to change again because of new release >>> cadence, but good enough for now) >>> * the previous webrev contained a spurious added file (TypeHarness) >>> which was caused by a glitch in the lvti branch in the amber repo. >>> >>> New webrev: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>> >>> New diags: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>> >>> Maurizio >>> >>> >>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>> Hi, >>>> this change adds support for local variable type inference (JEP 286 >>>> [1]). A webrev of the change is available here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>> >>>> The patch is relatively straightforward: implicitly typed locals are >>>> modeled in a similar fashion to implicit lambda parameters: their >>>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>>> null). >>>> >>>> There are few tricky parts to this changeset: >>>> >>>> 1) tweak the parser to give 'var' special meaning depending on the >>>> version number and context >>>> >>>> 2) Add logic in name resolution to catch bad reference to types >>>> named 'var' >>>> >>>> 3) add logic to map initializer type back to a suitable variable >>>> declared type >>>> >>>> As for (1), the parser has been extended so as to special case local >>>> variables with special name 'var', so that the type will be left out >>>> of the corresponding AST representing the variable declaration. This >>>> behavior will only affect latest source version. >>>> >>>> The parser has a number of extra checks to prevent 'var to be used >>>> in places where it does not belong (according to the spec draft >>>> [2]); for instance, declaring a class whose name is 'var' is >>>> rejected in the parser. As a general rule, I tried to implement all >>>> such checks in the parser, as that gives very early and precise >>>> feedback about what's wrong with the code. The changes are >>>> implemented in Parser.java. >>>> >>>> There are however errors which cannot be caught in the parser, and >>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>> position where it could be either a type or a package name, the >>>> parser can't simply rule that out, so we have to accept the code, >>>> and give an error if, later on, we discover that 'var' was really >>>> used in a type position (see changes in Resolve.java). >>>> >>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>> from initializers. That means that if we have a 'var' like this: >>>> >>>> class Foo { >>>> ??? void test() { >>>> ??????? var x = getClass().getSuperClass(); >>>> ??? } >>>> } >>>> >>>> The initializer type will be something like Class, >>>> where #CAP <: Foo >>>> >>>> In this case, the compiler will project this type back to the less >>>> specific type Class, and use that as the declared type for 'x'. >>>> This logic is defined in Types.java. As this logic is the same logic >>>> needed by jshell to render type of standalone expressions, jshell >>>> class VarTypePrinter has been removed and jshell has been rewired to >>>> point at the (now) official routine in Types. Jshell also needed >>>> several other tweaks to (i) accept 'var' and (ii) to deal with >>>> non-denotable types (intersection types and anonymous class types) >>>> that can be produced by the LVTI machinery (many thanks to Jan for >>>> doing those changes!) >>>> >>>> >>>> As far as testing is concerned, I wrote several tests to check that >>>> the parser was behaving as expected; to check the behavior of the >>>> LVTI inference machinery, I wrote a test harness which leverages >>>> annotation on 'var' so that we can write down assertions such as: >>>> >>>> @InferredType("java.util.List") >>>> var s = extString(); >>>> >>>> >>>> Regarding compiler diagnostics, for those interested, a >>>> comprehensive list of examples of new diagnostics triggered by the >>>> LVTI compiler can be found here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>> >>>> Finally, a finder has been added to detect local variable decls >>>> whose declared type can be replaced by 'var' - to enable it, the >>>> hidden option -XDfind=local should be used. >>>> >>>> >>>> Thanks >>>> Maurizio >>>> >>>> [1] - http://openjdk.java.net/jeps/286 >>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>> >>>> >>> >> >> > -- Best regards, Sergey. From maurizio.cimadamore at oracle.com Wed Sep 20 00:38:56 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 20 Sep 2017 01:38:56 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <0f10b813-de2e-73ce-2b31-89213e4e4e35@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <0f10b813-de2e-73ce-2b31-89213e4e4e35@oracle.com> Message-ID: On 20/09/17 01:20, Sergey Bylokhov wrote: > Just thoughts on a subject... > > Its seems that most of "surprising" behavior comes from the reassigning, > The new "var" adds one new feature: it will be possible to have a > reference to the anonymous class and call the methods defined in it. > So it is not simply a syntactic sugar. You touch on an important point - the type inferred for 'var' might be non-denotable - when that happens, re-assignment is going to give 'surprising' results, where the level of surprise might vary depending on what the expectations for this feature are. This issue was discussed here: http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-April/000023.html As you can see, there's a multitude of options in the design space when defining what 'var' means. The currently implemented approach (and spec draft) chose this point: * forbid 'null' * normalize captured types * leave intersection types and anonymous classes as is (note that for the last two bullets - there might occur recursively inside other types, such as arrays or parameterized types). I would suggest that we try and keep this thread confined to the code review - that said, your feedback is greatly appreciated, and I suggest you to direct it to the amber-spec-experts mailing list. Thanks Maurizio > > var probablySerializable = new Serializable() { > ??? public void test() { > ??? } > }; > ..... > probablySerializable.test(); > > > And because of that the reassigned will not work: > var probablySerializable = new Serializable() { > ??? public void test() { > ??? } > }; > probablySerializable = new Serializable() { > }; > > testVar.java:13: error: incompatible types: > cannot be converted to > ??????? name = new Serializable() { > > > On 9/19/17 13:24, Maurizio Cimadamore wrote: >> The type of this is not Component but Component. So, when >> you use an explicit type, you force the type of 'cp1' to be less >> sharp, which then works for the followup assignment. But if you use >> 'var', the compiler will just infer whatever type the initializer >> has, which in this case is Component. And the type of >> c2.getContainer (Component<#CAP1, #CAP2>) is not compatible with >> Component. >> >> Maurizio >> >> >> On 19/09/17 17:44, Sergey Bylokhov wrote: >>> Hi, Maurizio. >>> One more question about generics, in the code below the "case1" >>> compiles successfully, but the "case2" produce an error: >>> >>> public class testVar { >>> >>> ??? class Component { >>> >>> ??????? final Container getContainer() { >>> ??????????? return null; >>> ??????? } >>> >>> ??????? void windowToLocal() { >>> ??????????? // case1 >>> ??????????? Component cp1 = this; >>> ??????????? cp1 = cp1.getContainer(); >>> ??????????? // case2 >>> ??????????? var cp2 = this; >>> ??????????? cp2 = cp2.getContainer(); >>> ??????? } >>> ??? } >>> ??? class Container >>> ??????????? extends Component { >>> >>> ??? } >>> } >>> >>> //error >>> testVar.java:13: error: incompatible types: >>> testVar.Container cannot be converted to >>> testVar.Component >>> ??????????? cp2 = cp2.getContainer(); >>> ????????????????????????????????? ^ >>> ? where T,D are type-variables: >>> ??? T extends Object declared in class testVar.Component >>> ??? D extends Object declared in class testVar.Component >>> ? where CAP#1,CAP#2 are fresh type-variables: >>> ??? CAP#1 extends Object from capture of ? >>> ??? CAP#2 extends Object from capture of ? >>> 1 error >>> >>> On 9/19/17 08:04, Maurizio Cimadamore wrote: >>>> Hi, >>>> I have put together a slightly updated webrev: >>>> >>>> * as pointed out, one diagnostic used to say '9' instead of '10' >>>> (this will likely need to change again because of new release >>>> cadence, but good enough for now) >>>> * the previous webrev contained a spurious added file (TypeHarness) >>>> which was caused by a glitch in the lvti branch in the amber repo. >>>> >>>> New webrev: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>>> >>>> New diags: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>>> >>>> Maurizio >>>> >>>> >>>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>>> Hi, >>>>> this change adds support for local variable type inference (JEP >>>>> 286 [1]). A webrev of the change is available here: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>>> >>>>> The patch is relatively straightforward: implicitly typed locals >>>>> are modeled in a similar fashion to implicit lambda parameters: >>>>> their AST node is a JCVariableDecl whose 'vartype' field is not >>>>> set (e.g. null). >>>>> >>>>> There are few tricky parts to this changeset: >>>>> >>>>> 1) tweak the parser to give 'var' special meaning depending on the >>>>> version number and context >>>>> >>>>> 2) Add logic in name resolution to catch bad reference to types >>>>> named 'var' >>>>> >>>>> 3) add logic to map initializer type back to a suitable variable >>>>> declared type >>>>> >>>>> As for (1), the parser has been extended so as to special case >>>>> local variables with special name 'var', so that the type will be >>>>> left out of the corresponding AST representing the variable >>>>> declaration. This behavior will only affect latest source version. >>>>> >>>>> The parser has a number of extra checks to prevent 'var to be used >>>>> in places where it does not belong (according to the spec draft >>>>> [2]); for instance, declaring a class whose name is 'var' is >>>>> rejected in the parser. As a general rule, I tried to implement >>>>> all such checks in the parser, as that gives very early and >>>>> precise feedback about what's wrong with the code. The changes are >>>>> implemented in Parser.java. >>>>> >>>>> There are however errors which cannot be caught in the parser, and >>>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>>> position where it could be either a type or a package name, the >>>>> parser can't simply rule that out, so we have to accept the code, >>>>> and give an error if, later on, we discover that 'var' was really >>>>> used in a type position (see changes in Resolve.java). >>>>> >>>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>>> from initializers. That means that if we have a 'var' like this: >>>>> >>>>> class Foo { >>>>> ??? void test() { >>>>> ??????? var x = getClass().getSuperClass(); >>>>> ??? } >>>>> } >>>>> >>>>> The initializer type will be something like Class, >>>>> where #CAP <: Foo >>>>> >>>>> In this case, the compiler will project this type back to the less >>>>> specific type Class, and use that as the declared type for 'x'. >>>>> This logic is defined in Types.java. As this logic is the same >>>>> logic needed by jshell to render type of standalone expressions, >>>>> jshell class VarTypePrinter has been removed and jshell has been >>>>> rewired to point at the (now) official routine in Types. Jshell >>>>> also needed several other tweaks to (i) accept 'var' and (ii) to >>>>> deal with non-denotable types (intersection types and anonymous >>>>> class types) that can be produced by the LVTI machinery (many >>>>> thanks to Jan for doing those changes!) >>>>> >>>>> >>>>> As far as testing is concerned, I wrote several tests to check >>>>> that the parser was behaving as expected; to check the behavior of >>>>> the LVTI inference machinery, I wrote a test harness which >>>>> leverages annotation on 'var' so that we can write down assertions >>>>> such as: >>>>> >>>>> @InferredType("java.util.List") >>>>> var s = extString(); >>>>> >>>>> >>>>> Regarding compiler diagnostics, for those interested, a >>>>> comprehensive list of examples of new diagnostics triggered by the >>>>> LVTI compiler can be found here: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>>> >>>>> Finally, a finder has been added to detect local variable decls >>>>> whose declared type can be replaced by 'var' - to enable it, the >>>>> hidden option -XDfind=local should be used. >>>>> >>>>> >>>>> Thanks >>>>> Maurizio >>>>> >>>>> [1] - http://openjdk.java.net/jeps/286 >>>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>>> >>>>> >>>> >>> >>> >> > > From bsrbnd at gmail.com Wed Sep 20 14:56:58 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Wed, 20 Sep 2017 16:56:58 +0200 Subject: Most specific method in diagnostic generation for overload resolution Message-ID: Hi, Related to [1], I wrote a specialized map to store only the most specific candidates during the diagnostic generation for overload resolution, here under. It's then used in "Resolve.InapplicableSymbolsError.mapCandidates()" when non-applicable methods are collected to generate the diagnostic. What do you think? Bernard [1] http://mail.openjdk.java.net/pipermail/compiler-dev/2017-September/011062.html diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -59,6 +59,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.function.BiFunction; @@ -3995,14 +3996,29 @@ } //where private Map mapCandidates() { - Map candidates = new LinkedHashMap<>(); + MostSpecificMap candidates = new MostSpecificMap(); for (Candidate c : resolveContext.candidates) { if (c.isApplicable()) continue; - candidates.put(c.sym, c.details); + candidates.put(c); } return candidates; } + @SuppressWarnings("serial") + private class MostSpecificMap extends LinkedHashMap { + private void put(Candidate c) { + new LinkedList<>(keySet()).stream() + .filter( s -> !s.equals(c.sym) ) + .filter( s -> c.sym.overrides(s, (TypeSymbol)s.owner, types, false) ) + .forEach( s -> remove(s) ); + + if (!keySet().stream() + .filter( s -> !s.equals(c.sym) ) + .anyMatch( s -> s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false) )) + put(c.sym, c.details); + } + } + Map filterCandidates(Map candidatesMap) { Map candidates = new LinkedHashMap<>(); for (Map.Entry _entry : candidatesMap.entrySet()) { From vicente.romero at oracle.com Wed Sep 20 19:36:56 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 20 Sep 2017 15:36:56 -0400 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: Hi, Another great piece of work! some high level comments: at Types: * new visitors TypeProjection and CaptureScanner would benefit of having some documentation added, it should be made clear what (!upward) means as there is no explicit reference to the downward projection in the code. Instead of passing a boolean, using an enum could be beneficial for self documentation. Like enum Projection {UPWARD, DOWNWARD}, the enum could have a getInverseProjection() or getComplementProjection() method. ??? - also probably examples of expected output for a given input could be added, but I'm not too strong about this though ??? - also could it be beneficial to include some unit tests for them? I realize that they need to be public for a jtreg test to be able to access them but I think it will be important to check that the upward projection is yielding the ????? expected result. I'm mostly interested in this code path: "Type lower = t.map(this, !upward);" at TypeProjection.mapTypeArgument() Attr: why at attribLazyConstantValue you do: ??? - variable.sym.type = chk.checkLocalVarType(variable, itype, variable.name); and at visitVarDef: ?? - v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);? // baseType() is invoked in this case JavacParser: general question: can't the parser do an early detection of cases like "var s = () -> {};"? Thanks, Vicente On 09/19/2017 11:04 AM, Maurizio Cimadamore wrote: > Hi, > I have put together a slightly updated webrev: > > * as pointed out, one diagnostic used to say '9' instead of '10' (this > will likely need to change again because of new release cadence, but > good enough for now) > * the previous webrev contained a spurious added file (TypeHarness) > which was caused by a glitch in the lvti branch in the amber repo. > > New webrev: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ > > New diags: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html > > Maurizio > > > On 18/09/17 17:14, Maurizio Cimadamore wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 >> [1]). A webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are >> modeled in a similar fashion to implicit lambda parameters: their AST >> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the >> version number and context >> >> 2) Add logic in name resolution to catch bad reference to types named >> 'var' >> >> 3) add logic to map initializer type back to a suitable variable >> declared type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out >> of the corresponding AST representing the variable declaration. This >> behavior will only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in >> places where it does not belong (according to the spec draft [2]); >> for instance, declaring a class whose name is 'var' is rejected in >> the parser. As a general rule, I tried to implement all such checks >> in the parser, as that gives very early and precise feedback about >> what's wrong with the code. The changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and >> that's why (2) is needed. Basically, whenever 'var' is used in a >> position where it could be either a type or a package name, the >> parser can't simply rule that out, so we have to accept the code, and >> give an error if, later on, we discover that 'var' was really used in >> a type position (see changes in Resolve.java). >> >> As far as (3) is concerned, we need to 'uncapture' captured types >> from initializers. That means that if we have a 'var' like this: >> >> class Foo { >> ??? void test() { >> ??????? var x = getClass().getSuperClass(); >> ??? } >> } >> >> The initializer type will be something like Class, >> where #CAP <: Foo >> >> In this case, the compiler will project this type back to the less >> specific type Class, and use that as the declared type for 'x'. >> This logic is defined in Types.java. As this logic is the same logic >> needed by jshell to render type of standalone expressions, jshell >> class VarTypePrinter has been removed and jshell has been rewired to >> point at the (now) official routine in Types. Jshell also needed >> several other tweaks to (i) accept 'var' and (ii) to deal with >> non-denotable types (intersection types and anonymous class types) >> that can be produced by the LVTI machinery (many thanks to Jan for >> doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that >> the parser was behaving as expected; to check the behavior of the >> LVTI inference machinery, I wrote a test harness which leverages >> annotation on 'var' so that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive >> list of examples of new diagnostics triggered by the LVTI compiler >> can be found here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden >> option -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> > From maurizio.cimadamore at oracle.com Wed Sep 20 21:14:40 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 20 Sep 2017 22:14:40 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> Thanks for the comments - some responses below On 20/09/17 20:36, Vicente Romero wrote: > Hi, > > Another great piece of work! some high level comments: > > at Types: > * new visitors TypeProjection and CaptureScanner would benefit of > having some documentation added, it should be made clear what > (!upward) means as there is no explicit reference to the downward > projection in the code. Instead of passing a boolean, using an enum > could be beneficial for self documentation. Like enum Projection > {UPWARD, DOWNWARD}, the enum could have a getInverseProjection() or > getComplementProjection() method. Good idea, I'll play with it a bit > ??? - also probably examples of expected output for a given input > could be added, but I'm not too strong about this though > ??? - also could it be beneficial to include some unit tests for them? > I realize that they need to be public for a jtreg test to be able to > access them but I think it will be important to check that the upward > projection is yielding the > ????? expected result. I'm mostly interested in this code path: "Type > lower = t.map(this, !upward);" at TypeProjection.mapTypeArgument() I think a TypeHarness test would be a natural way to unit test this. Not sure though if this needs to be done now or as a follow up - after all, the test harness for LVTI is already providing some sort of unit testing of this part, look at this: http://cr.openjdk.java.net/~mcimadamore/8177466_v2/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java.html > > Attr: > why at attribLazyConstantValue you do: > ??? - variable.sym.type = chk.checkLocalVarType(variable, itype, > variable.name); and at visitVarDef: > ?? - v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), > tree.name);? // baseType() is invoked in this case > As to why there's a baseType in visitVarDef, I believe it is because we can get into that code path if a 'var' is not final but its initializer is a constant - e.g. : var s = "Hello!" In this case we don't want the type of 's' to be constant. Regarding attribLazyConstantValue, I think it's probably better to use baseType() there too. But I will have to double check if lack of baseType is creating issues. > > JavacParser: > general question: can't the parser do an early detection of cases like > "var s = () -> {};"? I think it's maybe doable, but it gets convoluted if you have casts and other things before the lambda. > > Thanks, > Vicente > > > On 09/19/2017 11:04 AM, Maurizio Cimadamore wrote: >> Hi, >> I have put together a slightly updated webrev: >> >> * as pointed out, one diagnostic used to say '9' instead of '10' >> (this will likely need to change again because of new release >> cadence, but good enough for now) >> * the previous webrev contained a spurious added file (TypeHarness) >> which was caused by a glitch in the lvti branch in the amber repo. >> >> New webrev: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >> >> New diags: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >> >> Maurizio >> >> >> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their >>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>> null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types >>> named 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used >>> in places where it does not belong (according to the spec draft >>> [2]); for instance, declaring a class whose name is 'var' is >>> rejected in the parser. As a general rule, I tried to implement all >>> such checks in the parser, as that gives very early and precise >>> feedback about what's wrong with the code. The changes are >>> implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, >>> and give an error if, later on, we discover that 'var' was really >>> used in a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ??? void test() { >>> ??????? var x = getClass().getSuperClass(); >>> ??? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a >>> comprehensive list of examples of new diagnostics triggered by the >>> LVTI compiler can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls >>> whose declared type can be replaced by 'var' - to enable it, the >>> hidden option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> > From vicente.romero at oracle.com Wed Sep 20 21:26:23 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 20 Sep 2017 17:26:23 -0400 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> Message-ID: <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> On 09/20/2017 05:14 PM, Maurizio Cimadamore wrote: > Thanks for the comments - some responses below > > > On 20/09/17 20:36, Vicente Romero wrote: >> Hi, >> >> Another great piece of work! some high level comments: >> >> at Types: >> * new visitors TypeProjection and CaptureScanner would benefit of >> having some documentation added, it should be made clear what >> (!upward) means as there is no explicit reference to the downward >> projection in the code. Instead of passing a boolean, using an enum >> could be beneficial for self documentation. Like enum Projection >> {UPWARD, DOWNWARD}, the enum could have a getInverseProjection() or >> getComplementProjection() method. > Good idea, I'll play with it a bit >> ??? - also probably examples of expected output for a given input >> could be added, but I'm not too strong about this though >> ??? - also could it be beneficial to include some unit tests for >> them? I realize that they need to be public for a jtreg test to be >> able to access them but I think it will be important to check that >> the upward projection is yielding the >> ????? expected result. I'm mostly interested in this code path: "Type >> lower = t.map(this, !upward);" at TypeProjection.mapTypeArgument() > I think a TypeHarness test would be a natural way to unit test this. > Not sure though if this needs to be done now or as a follow up right it doesn't have to be right now, it can wait. > - after all, the test harness for LVTI is already providing some sort > of unit testing of this part, look at this: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java.html > >> >> Attr: >> why at attribLazyConstantValue you do: >> ??? - variable.sym.type = chk.checkLocalVarType(variable, itype, >> variable.name); and at visitVarDef: >> ?? - v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), >> tree.name);? // baseType() is invoked in this case >> > As to why there's a baseType in visitVarDef, I believe it is because > we can get into that code path if a 'var' is not final but its > initializer is a constant - e.g. : > > var s = "Hello!" > > In this case we don't want the type of 's' to be constant. > > Regarding attribLazyConstantValue, I think it's probably better to use > baseType() there too. But I will have to double check if lack of > baseType is creating issues. ok thanks for the clarification, yes I think that we need to investigate if you need to use baseType() for lazy evaluation too which should be triggered by: final var s = "Hello!" right? >> >> JavacParser: >> general question: can't the parser do an early detection of cases >> like "var s = () -> {};"? > I think it's maybe doable, but it gets convoluted if you have casts > and other things before the lambda. right but if there is a cast then there is no issue as there is a target, we need to discard only the cases when a "raw" lambda or method reference is used to initialize a variable with no explicit type. Again if you consider that code won't benefit from this then let's let it as it is. But it could be worthy trying to discard ill formed expressions as soon as possible >> >> Thanks, >> Vicente Vicente >> >> >> On 09/19/2017 11:04 AM, Maurizio Cimadamore wrote: >>> Hi, >>> I have put together a slightly updated webrev: >>> >>> * as pointed out, one diagnostic used to say '9' instead of '10' >>> (this will likely need to change again because of new release >>> cadence, but good enough for now) >>> * the previous webrev contained a spurious added file (TypeHarness) >>> which was caused by a glitch in the lvti branch in the amber repo. >>> >>> New webrev: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>> >>> New diags: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>> >>> Maurizio >>> >>> >>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>> Hi, >>>> this change adds support for local variable type inference (JEP 286 >>>> [1]). A webrev of the change is available here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>> >>>> The patch is relatively straightforward: implicitly typed locals >>>> are modeled in a similar fashion to implicit lambda parameters: >>>> their AST node is a JCVariableDecl whose 'vartype' field is not set >>>> (e.g. null). >>>> >>>> There are few tricky parts to this changeset: >>>> >>>> 1) tweak the parser to give 'var' special meaning depending on the >>>> version number and context >>>> >>>> 2) Add logic in name resolution to catch bad reference to types >>>> named 'var' >>>> >>>> 3) add logic to map initializer type back to a suitable variable >>>> declared type >>>> >>>> As for (1), the parser has been extended so as to special case >>>> local variables with special name 'var', so that the type will be >>>> left out of the corresponding AST representing the variable >>>> declaration. This behavior will only affect latest source version. >>>> >>>> The parser has a number of extra checks to prevent 'var to be used >>>> in places where it does not belong (according to the spec draft >>>> [2]); for instance, declaring a class whose name is 'var' is >>>> rejected in the parser. As a general rule, I tried to implement all >>>> such checks in the parser, as that gives very early and precise >>>> feedback about what's wrong with the code. The changes are >>>> implemented in Parser.java. >>>> >>>> There are however errors which cannot be caught in the parser, and >>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>> position where it could be either a type or a package name, the >>>> parser can't simply rule that out, so we have to accept the code, >>>> and give an error if, later on, we discover that 'var' was really >>>> used in a type position (see changes in Resolve.java). >>>> >>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>> from initializers. That means that if we have a 'var' like this: >>>> >>>> class Foo { >>>> ??? void test() { >>>> ??????? var x = getClass().getSuperClass(); >>>> ??? } >>>> } >>>> >>>> The initializer type will be something like Class, >>>> where #CAP <: Foo >>>> >>>> In this case, the compiler will project this type back to the less >>>> specific type Class, and use that as the declared type for 'x'. >>>> This logic is defined in Types.java. As this logic is the same >>>> logic needed by jshell to render type of standalone expressions, >>>> jshell class VarTypePrinter has been removed and jshell has been >>>> rewired to point at the (now) official routine in Types. Jshell >>>> also needed several other tweaks to (i) accept 'var' and (ii) to >>>> deal with non-denotable types (intersection types and anonymous >>>> class types) that can be produced by the LVTI machinery (many >>>> thanks to Jan for doing those changes!) >>>> >>>> >>>> As far as testing is concerned, I wrote several tests to check that >>>> the parser was behaving as expected; to check the behavior of the >>>> LVTI inference machinery, I wrote a test harness which leverages >>>> annotation on 'var' so that we can write down assertions such as: >>>> >>>> @InferredType("java.util.List") >>>> var s = extString(); >>>> >>>> >>>> Regarding compiler diagnostics, for those interested, a >>>> comprehensive list of examples of new diagnostics triggered by the >>>> LVTI compiler can be found here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>> >>>> Finally, a finder has been added to detect local variable decls >>>> whose declared type can be replaced by 'var' - to enable it, the >>>> hidden option -XDfind=local should be used. >>>> >>>> >>>> Thanks >>>> Maurizio >>>> >>>> [1] - http://openjdk.java.net/jeps/286 >>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>> >>>> >>> >> > From Sergey.Bylokhov at oracle.com Wed Sep 20 21:47:10 2017 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Wed, 20 Sep 2017 14:47:10 -0700 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <0f10b813-de2e-73ce-2b31-89213e4e4e35@oracle.com> Message-ID: On 9/19/17 17:38, Maurizio Cimadamore wrote: > You touch on an important point - the type inferred for 'var' might be > non-denotable - when that happens, re-assignment is going to give > 'surprising' results, where the level of surprise might vary depending > on what the expectations for this feature are. > > This issue was discussed here: > > http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-April/000023.html Thank you for the link, I have no any comments about the changes, it is fine to me(not a reviewer in compiler-dev), I tried to replace the usual types by the "var" inside the jdk and test this functionality and it seems to work w/o any issues except the cases I sent previously. > > > As you can see, there's a multitude of options in the design space when > defining what 'var' means. The currently implemented approach (and spec > draft) chose this point: > > * forbid 'null' > * normalize captured types > * leave intersection types and anonymous classes as is > > (note that for the last two bullets - there might occur recursively > inside other types, such as arrays or parameterized types). > > I would suggest that we try and keep this thread confined to the code > review - that said, your feedback is greatly appreciated, and I suggest > you to direct it to the amber-spec-experts mailing list. -- Best regards, Sergey. From maurizio.cimadamore at oracle.com Wed Sep 20 22:54:38 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 20 Sep 2017 23:54:38 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> Message-ID: On 20/09/17 22:26, Vicente Romero wrote: > > > On 09/20/2017 05:14 PM, Maurizio Cimadamore wrote: >> Thanks for the comments - some responses below >> >> >> On 20/09/17 20:36, Vicente Romero wrote: >>> Hi, >>> >>> Another great piece of work! some high level comments: >>> >>> at Types: >>> * new visitors TypeProjection and CaptureScanner would benefit of >>> having some documentation added, it should be made clear what >>> (!upward) means as there is no explicit reference to the downward >>> projection in the code. Instead of passing a boolean, using an enum >>> could be beneficial for self documentation. Like enum Projection >>> {UPWARD, DOWNWARD}, the enum could have a getInverseProjection() or >>> getComplementProjection() method. >> Good idea, I'll play with it a bit >>> ??? - also probably examples of expected output for a given input >>> could be added, but I'm not too strong about this though >>> ??? - also could it be beneficial to include some unit tests for >>> them? I realize that they need to be public for a jtreg test to be >>> able to access them but I think it will be important to check that >>> the upward projection is yielding the >>> ????? expected result. I'm mostly interested in this code path: >>> "Type lower = t.map(this, !upward);" at >>> TypeProjection.mapTypeArgument() >> I think a TypeHarness test would be a natural way to unit test this. >> Not sure though if this needs to be done now or as a follow up > > right it doesn't have to be right now, it can wait. > >> - after all, the test harness for LVTI is already providing some sort >> of unit testing of this part, look at this: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java.html >> >>> >>> Attr: >>> why at attribLazyConstantValue you do: >>> ??? - variable.sym.type = chk.checkLocalVarType(variable, itype, >>> variable.name); and at visitVarDef: >>> ?? - v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), >>> tree.name);? // baseType() is invoked in this case >>> >> As to why there's a baseType in visitVarDef, I believe it is because >> we can get into that code path if a 'var' is not final but its >> initializer is a constant - e.g. : >> >> var s = "Hello!" >> >> In this case we don't want the type of 's' to be constant. >> >> Regarding attribLazyConstantValue, I think it's probably better to >> use baseType() there too. But I will have to double check if lack of >> baseType is creating issues. > ok thanks for the clarification, yes I think that we need to > investigate if you need to use baseType() for lazy evaluation too > which should be triggered by: > > final var s = "Hello!" right? Yes, lazy evaluation would happen for final vars. >>> >>> JavacParser: >>> general question: can't the parser do an early detection of cases >>> like "var s = () -> {};"? >> I think it's maybe doable, but it gets convoluted if you have casts >> and other things before the lambda. > > right but if there is a cast then there is no issue as there is a > target, we need to discard only the cases when a "raw" lambda or > method reference is used to initialize a variable with no explicit > type. Again if you consider that code won't benefit from this then > let's let it as it is. But it could be worthy trying to discard ill > formed expressions as soon as possible You are right - a cast is the dumbest example I could have come up with :-) but think of this: var s = (cond) ? "Hello!" : () -> { } Again, this is all doable, we could do lookahead, or we could look at the parsed expression after the fact and rule it out as there's a lambda in the middle - but it seemed simpler to simply special case it in the Attr visitors. That way, no matter how deeply nested the lambda is, you will get a consistent error message. Maurizio > >>> >>> Thanks, >>> Vicente > > Vicente > > >>> >>> >>> On 09/19/2017 11:04 AM, Maurizio Cimadamore wrote: >>>> Hi, >>>> I have put together a slightly updated webrev: >>>> >>>> * as pointed out, one diagnostic used to say '9' instead of '10' >>>> (this will likely need to change again because of new release >>>> cadence, but good enough for now) >>>> * the previous webrev contained a spurious added file (TypeHarness) >>>> which was caused by a glitch in the lvti branch in the amber repo. >>>> >>>> New webrev: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>>> >>>> New diags: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>>> >>>> Maurizio >>>> >>>> >>>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>>> Hi, >>>>> this change adds support for local variable type inference (JEP >>>>> 286 [1]). A webrev of the change is available here: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>>> >>>>> The patch is relatively straightforward: implicitly typed locals >>>>> are modeled in a similar fashion to implicit lambda parameters: >>>>> their AST node is a JCVariableDecl whose 'vartype' field is not >>>>> set (e.g. null). >>>>> >>>>> There are few tricky parts to this changeset: >>>>> >>>>> 1) tweak the parser to give 'var' special meaning depending on the >>>>> version number and context >>>>> >>>>> 2) Add logic in name resolution to catch bad reference to types >>>>> named 'var' >>>>> >>>>> 3) add logic to map initializer type back to a suitable variable >>>>> declared type >>>>> >>>>> As for (1), the parser has been extended so as to special case >>>>> local variables with special name 'var', so that the type will be >>>>> left out of the corresponding AST representing the variable >>>>> declaration. This behavior will only affect latest source version. >>>>> >>>>> The parser has a number of extra checks to prevent 'var to be used >>>>> in places where it does not belong (according to the spec draft >>>>> [2]); for instance, declaring a class whose name is 'var' is >>>>> rejected in the parser. As a general rule, I tried to implement >>>>> all such checks in the parser, as that gives very early and >>>>> precise feedback about what's wrong with the code. The changes are >>>>> implemented in Parser.java. >>>>> >>>>> There are however errors which cannot be caught in the parser, and >>>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>>> position where it could be either a type or a package name, the >>>>> parser can't simply rule that out, so we have to accept the code, >>>>> and give an error if, later on, we discover that 'var' was really >>>>> used in a type position (see changes in Resolve.java). >>>>> >>>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>>> from initializers. That means that if we have a 'var' like this: >>>>> >>>>> class Foo { >>>>> ??? void test() { >>>>> ??????? var x = getClass().getSuperClass(); >>>>> ??? } >>>>> } >>>>> >>>>> The initializer type will be something like Class, >>>>> where #CAP <: Foo >>>>> >>>>> In this case, the compiler will project this type back to the less >>>>> specific type Class, and use that as the declared type for 'x'. >>>>> This logic is defined in Types.java. As this logic is the same >>>>> logic needed by jshell to render type of standalone expressions, >>>>> jshell class VarTypePrinter has been removed and jshell has been >>>>> rewired to point at the (now) official routine in Types. Jshell >>>>> also needed several other tweaks to (i) accept 'var' and (ii) to >>>>> deal with non-denotable types (intersection types and anonymous >>>>> class types) that can be produced by the LVTI machinery (many >>>>> thanks to Jan for doing those changes!) >>>>> >>>>> >>>>> As far as testing is concerned, I wrote several tests to check >>>>> that the parser was behaving as expected; to check the behavior of >>>>> the LVTI inference machinery, I wrote a test harness which >>>>> leverages annotation on 'var' so that we can write down assertions >>>>> such as: >>>>> >>>>> @InferredType("java.util.List") >>>>> var s = extString(); >>>>> >>>>> >>>>> Regarding compiler diagnostics, for those interested, a >>>>> comprehensive list of examples of new diagnostics triggered by the >>>>> LVTI compiler can be found here: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>>> >>>>> Finally, a finder has been added to detect local variable decls >>>>> whose declared type can be replaced by 'var' - to enable it, the >>>>> hidden option -XDfind=local should be used. >>>>> >>>>> >>>>> Thanks >>>>> Maurizio >>>>> >>>>> [1] - http://openjdk.java.net/jeps/286 >>>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>>> >>>>> >>>> >>> >> > From vicente.romero at oracle.com Thu Sep 21 00:06:20 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 20 Sep 2017 20:06:20 -0400 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> Message-ID: <03c269e7-1f62-0747-0e24-0565c24a195a@oracle.com> On 09/20/2017 06:54 PM, Maurizio Cimadamore wrote: > > > On 20/09/17 22:26, Vicente Romero wrote: >> >> >> On 09/20/2017 05:14 PM, Maurizio Cimadamore wrote: >>> Thanks for the comments - some responses below >>> >>> >>> On 20/09/17 20:36, Vicente Romero wrote: >>>> Hi, >>>> >>>> Another great piece of work! some high level comments: >>>> >>>> at Types: >>>> * new visitors TypeProjection and CaptureScanner would benefit of >>>> having some documentation added, it should be made clear what >>>> (!upward) means as there is no explicit reference to the downward >>>> projection in the code. Instead of passing a boolean, using an enum >>>> could be beneficial for self documentation. Like enum Projection >>>> {UPWARD, DOWNWARD}, the enum could have a getInverseProjection() or >>>> getComplementProjection() method. >>> Good idea, I'll play with it a bit >>>> ??? - also probably examples of expected output for a given input >>>> could be added, but I'm not too strong about this though >>>> ??? - also could it be beneficial to include some unit tests for >>>> them? I realize that they need to be public for a jtreg test to be >>>> able to access them but I think it will be important to check that >>>> the upward projection is yielding the >>>> ????? expected result. I'm mostly interested in this code path: >>>> "Type lower = t.map(this, !upward);" at >>>> TypeProjection.mapTypeArgument() >>> I think a TypeHarness test would be a natural way to unit test this. >>> Not sure though if this needs to be done now or as a follow up >> >> right it doesn't have to be right now, it can wait. >> >>> - after all, the test harness for LVTI is already providing some >>> sort of unit testing of this part, look at this: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java.html >>> >>>> >>>> Attr: >>>> why at attribLazyConstantValue you do: >>>> ??? - variable.sym.type = chk.checkLocalVarType(variable, itype, >>>> variable.name); and at visitVarDef: >>>> ?? - v.type = chk.checkLocalVarType(tree, >>>> tree.init.type.baseType(), tree.name);? // baseType() is invoked in >>>> this case >>>> >>> As to why there's a baseType in visitVarDef, I believe it is because >>> we can get into that code path if a 'var' is not final but its >>> initializer is a constant - e.g. : >>> >>> var s = "Hello!" >>> >>> In this case we don't want the type of 's' to be constant. >>> >>> Regarding attribLazyConstantValue, I think it's probably better to >>> use baseType() there too. But I will have to double check if lack of >>> baseType is creating issues. >> ok thanks for the clarification, yes I think that we need to >> investigate if you need to use baseType() for lazy evaluation too >> which should be triggered by: >> >> final var s = "Hello!" right? > Yes, lazy evaluation would happen for final vars. >>>> >>>> JavacParser: >>>> general question: can't the parser do an early detection of cases >>>> like "var s = () -> {};"? >>> I think it's maybe doable, but it gets convoluted if you have casts >>> and other things before the lambda. >> >> right but if there is a cast then there is no issue as there is a >> target, we need to discard only the cases when a "raw" lambda or >> method reference is used to initialize a variable with no explicit >> type. Again if you consider that code won't benefit from this then >> let's let it as it is. But it could be worthy trying to discard ill >> formed expressions as soon as possible > You are right - a cast is the dumbest example I could have come up > with :-) > > but think of this: > > var s = (cond) ? "Hello!" : () -> { } > > Again, this is all doable, we could do lookahead, or we could look at > the parsed expression after the fact and rule it out as there's a > lambda in the middle - but it seemed simpler to simply special case it > in the Attr visitors. That way, no matter how deeply nested the lambda > is, you will get a consistent error message. right, yes I think that you are right and Attr should be the best place, it was just too tempting to put it in the parser :) > > Maurizio Vicente >> >>>> >>>> Thanks, >>>> Vicente >> >> Vicente >> >> >>>> >>>> >>>> On 09/19/2017 11:04 AM, Maurizio Cimadamore wrote: >>>>> Hi, >>>>> I have put together a slightly updated webrev: >>>>> >>>>> * as pointed out, one diagnostic used to say '9' instead of '10' >>>>> (this will likely need to change again because of new release >>>>> cadence, but good enough for now) >>>>> * the previous webrev contained a spurious added file >>>>> (TypeHarness) which was caused by a glitch in the lvti branch in >>>>> the amber repo. >>>>> >>>>> New webrev: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>>>> >>>>> New diags: >>>>> >>>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>>>> >>>>> Maurizio >>>>> >>>>> >>>>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>>>> Hi, >>>>>> this change adds support for local variable type inference (JEP >>>>>> 286 [1]). A webrev of the change is available here: >>>>>> >>>>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>>>> >>>>>> The patch is relatively straightforward: implicitly typed locals >>>>>> are modeled in a similar fashion to implicit lambda parameters: >>>>>> their AST node is a JCVariableDecl whose 'vartype' field is not >>>>>> set (e.g. null). >>>>>> >>>>>> There are few tricky parts to this changeset: >>>>>> >>>>>> 1) tweak the parser to give 'var' special meaning depending on >>>>>> the version number and context >>>>>> >>>>>> 2) Add logic in name resolution to catch bad reference to types >>>>>> named 'var' >>>>>> >>>>>> 3) add logic to map initializer type back to a suitable variable >>>>>> declared type >>>>>> >>>>>> As for (1), the parser has been extended so as to special case >>>>>> local variables with special name 'var', so that the type will be >>>>>> left out of the corresponding AST representing the variable >>>>>> declaration. This behavior will only affect latest source version. >>>>>> >>>>>> The parser has a number of extra checks to prevent 'var to be >>>>>> used in places where it does not belong (according to the spec >>>>>> draft [2]); for instance, declaring a class whose name is 'var' >>>>>> is rejected in the parser. As a general rule, I tried to >>>>>> implement all such checks in the parser, as that gives very early >>>>>> and precise feedback about what's wrong with the code. The >>>>>> changes are implemented in Parser.java. >>>>>> >>>>>> There are however errors which cannot be caught in the parser, >>>>>> and that's why (2) is needed. Basically, whenever 'var' is used >>>>>> in a position where it could be either a type or a package name, >>>>>> the parser can't simply rule that out, so we have to accept the >>>>>> code, and give an error if, later on, we discover that 'var' was >>>>>> really used in a type position (see changes in Resolve.java). >>>>>> >>>>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>>>> from initializers. That means that if we have a 'var' like this: >>>>>> >>>>>> class Foo { >>>>>> ??? void test() { >>>>>> ??????? var x = getClass().getSuperClass(); >>>>>> ??? } >>>>>> } >>>>>> >>>>>> The initializer type will be something like Class, >>>>>> where #CAP <: Foo >>>>>> >>>>>> In this case, the compiler will project this type back to the >>>>>> less specific type Class, and use that as the declared type >>>>>> for 'x'. This logic is defined in Types.java. As this logic is >>>>>> the same logic needed by jshell to render type of standalone >>>>>> expressions, jshell class VarTypePrinter has been removed and >>>>>> jshell has been rewired to point at the (now) official routine in >>>>>> Types. Jshell also needed several other tweaks to (i) accept >>>>>> 'var' and (ii) to deal with non-denotable types (intersection >>>>>> types and anonymous class types) that can be produced by the LVTI >>>>>> machinery (many thanks to Jan for doing those changes!) >>>>>> >>>>>> >>>>>> As far as testing is concerned, I wrote several tests to check >>>>>> that the parser was behaving as expected; to check the behavior >>>>>> of the LVTI inference machinery, I wrote a test harness which >>>>>> leverages annotation on 'var' so that we can write down >>>>>> assertions such as: >>>>>> >>>>>> @InferredType("java.util.List") >>>>>> var s = extString(); >>>>>> >>>>>> >>>>>> Regarding compiler diagnostics, for those interested, a >>>>>> comprehensive list of examples of new diagnostics triggered by >>>>>> the LVTI compiler can be found here: >>>>>> >>>>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>>>> >>>>>> Finally, a finder has been added to detect local variable decls >>>>>> whose declared type can be replaced by 'var' - to enable it, the >>>>>> hidden option -XDfind=local should be used. >>>>>> >>>>>> >>>>>> Thanks >>>>>> Maurizio >>>>>> >>>>>> [1] - http://openjdk.java.net/jeps/286 >>>>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>>>> >>>>>> >>>>> >>>> >>> >> > From maurizio.cimadamore at oracle.com Thu Sep 21 12:45:08 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 21 Sep 2017 13:45:08 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <03c269e7-1f62-0747-0e24-0565c24a195a@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> <03c269e7-1f62-0747-0e24-0565c24a195a@oracle.com> Message-ID: <6aaafb95-1733-d7c4-406c-bf48139e850e@oracle.com> On 21/09/17 01:06, Vicente Romero wrote: >>> Regarding attribLazyConstantValue, I think it's probably better to >>> use baseType() there too. But I will have to double check if lack of >>> baseType is creating issues. >> ok thanks for the clarification, yes I think that we need to >> investigate if you need to use baseType() for lazy evaluation too >> which should be triggered by: >> >> final var s = "Hello!" right? > Yes, lazy evaluation would happen for final vars. I have investigated this a bit more. The short story is that the submitted patch is a bit inconsistent with the rest of javac, but this inconsistency is harmless. Long story below :-) When you have a final variable whose initializer is a compile-time constant, the variable symbol will always get a 'constant value'. This constant value will be accessed from Attr::checkIdInternal (see call to VarSymbol.getConstantValue), so that, if a const value is found on the variable, the resulting type from type-checking the var identifier, will be set to be a constant value. So, in the case of final variable, it doesn't really matter much whether the variable type is itself a constant type or not - as checkIdInternal will always look at the symbol's constant value and override the resulting type that way. That is why, despite the missing 'baseType()' call, everything worked as expected. Now, the opposite is not true - if you have a non-final variable with a compile-time constant initializer: String s = ""; In this case the symbol for 's' won't receive any constant value. So Attr::checkIdInternal will return whatever type is associated with the variable. So, in this case it matters a lot as to whether the variable type is constant or not - if, by accident, the type of 's' was set to a constant type, the compiler will start treating 's' as a compile-time constant, which would be wrong. So, as a general rule, the type of variables is always a non-constant type in javac. But, some variable symbols (those for final variables with constant initializers) might have a constant value attached to them, which Attr then uses in order to propagate constant-ness around. I've fixed this, and also rewrote and added comments to the projections in types. I will run some tests and I'll submit another patch for review tomorrow. Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Thu Sep 21 12:52:27 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Thu, 21 Sep 2017 08:52:27 -0400 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <6aaafb95-1733-d7c4-406c-bf48139e850e@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <6de51010-6519-a095-50e6-e070072ae9fe@oracle.com> <2b1d313a-bbd0-b661-791b-cb984faa8604@oracle.com> <03c269e7-1f62-0747-0e24-0565c24a195a@oracle.com> <6aaafb95-1733-d7c4-406c-bf48139e850e@oracle.com> Message-ID: <0a4ed647-2e42-c9f3-c3da-a41589a5149e@oracle.com> Hi Maurizio, On 09/21/2017 08:45 AM, Maurizio Cimadamore wrote: > > > > On 21/09/17 01:06, Vicente Romero wrote: >>>> Regarding attribLazyConstantValue, I think it's probably better to >>>> use baseType() there too. But I will have to double check if lack >>>> of baseType is creating issues. >>> ok thanks for the clarification, yes I think that we need to >>> investigate if you need to use baseType() for lazy evaluation too >>> which should be triggered by: >>> >>> final var s = "Hello!" right? >> Yes, lazy evaluation would happen for final vars. > I have investigated this a bit more. The short story is that the > submitted patch is a bit inconsistent with the rest of javac, but this > inconsistency is harmless. > > Long story below :-) > > When you have a final variable whose initializer is a compile-time > constant, the variable symbol will always get a 'constant value'. This > constant value will be accessed from Attr::checkIdInternal (see call > to VarSymbol.getConstantValue), so that, if a const value is found on > the variable, the resulting type from type-checking the var > identifier, will be set to be a constant value. > > So, in the case of final variable, it doesn't really matter much > whether the variable type is itself a constant type or not - as > checkIdInternal will always look at the symbol's constant value and > override the resulting type that way. That is why, despite the missing > 'baseType()' call, everything worked as expected. > > Now, the opposite is not true - if you have a non-final variable with > a compile-time constant initializer: > > String s = ""; > > In this case the symbol for 's' won't receive any constant value. So > Attr::checkIdInternal will return whatever type is associated with the > variable. So, in this case it matters a lot as to whether the variable > type is constant or not - if, by accident, the type of 's' was set to > a constant type, the compiler will start treating 's' as a > compile-time constant, which would be wrong. > > So, as a general rule, the type of variables is always a non-constant > type in javac. But, some variable symbols (those for final variables > with constant initializers) might have a constant value attached to > them, which Attr then uses in order to propagate constant-ness around. > > I've fixed this, and also rewrote and added comments to the > projections in types. I will run some tests and I'll submit another > patch for review tomorrow. thanks for the investigation, yes it all makes sense now > > Maurizio Vicente -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Sep 21 14:40:08 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 21 Sep 2017 15:40:08 +0100 Subject: RFR: 8187784: IntelliJ langtools project exclusion settings are too broad Message-ID: Hi, I realized that there's an issue with the langtools IJ project - to make it more optimized, I've excluded src/ make/ and test/ folders - to avoid indexing and hg overhead (only langtools source folders are then added back as source roots). But in doing so, hg support is completely disabled, and there's no highlighting in the IDE when a change is made to an existing file. So, I'm keeping the build/ exclusion, but dropping the others. I also removed an extra root (test) which was only used in the previous setup. http://cr.openjdk.java.net/~mcimadamore/8187784/ Thanks Maurizio From jan.lahoda at oracle.com Thu Sep 21 15:43:21 2017 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 21 Sep 2017 17:43:21 +0200 Subject: RFR 8187247: canonical import check compares classes by simple name In-Reply-To: References: Message-ID: <59C3DE19.4080107@oracle.com> Hi Liam, I apologize for belated answer. Seems OK to me, thanks for doing this. Only maybe put the test into a directory where it will be separate (e.g. importChecks/ImportCanonicalSameName) to avoid interference between this test and possible future tests. Should I integrate this change? Jan On 5.9.2017 18:58, Liam Miller-Cushon wrote: > This change fixes a bug that causes javac to incorrectly accept > non-canonical imports if the actual and expected symbols have the same > simple name. > > Bug: https://bugs.openjdk.java.net/browse/JDK-8187247 > Webrev: http://cr.openjdk.java.net/~cushon/8187247/webrev.00/ From bsrbnd at gmail.com Thu Sep 21 16:12:24 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Thu, 21 Sep 2017 18:12:24 +0200 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: Hi Maurizio, On 18 September 2017 at 18:14, Maurizio Cimadamore wrote: > Hi, > this change adds support for local variable type inference (JEP 286 [1]). A > webrev of the change is available here: > > http://cr.openjdk.java.net/~mcimadamore/8177466 > > The patch is relatively straightforward: implicitly typed locals are modeled > in a similar fashion to implicit lambda parameters: their AST node is a > JCVariableDecl whose 'vartype' field is not set (e.g. null). > > There are few tricky parts to this changeset: > > 1) tweak the parser to give 'var' special meaning depending on the version > number and context > > 2) Add logic in name resolution to catch bad reference to types named 'var' > > 3) add logic to map initializer type back to a suitable variable declared > type > > As for (1), the parser has been extended so as to special case local > variables with special name 'var', so that the type will be left out of the > corresponding AST representing the variable declaration. This behavior will > only affect latest source version. > > The parser has a number of extra checks to prevent 'var to be used in places > where it does not belong (according to the spec draft [2]); for instance, > declaring a class whose name is 'var' is rejected in the parser. As a > general rule, I tried to implement all such checks in the parser, as that > gives very early and precise feedback about what's wrong with the code. The > changes are implemented in Parser.java. > > There are however errors which cannot be caught in the parser, and that's > why (2) is needed. Basically, whenever 'var' is used in a position where it > could be either a type or a package name, the parser can't simply rule that > out, so we have to accept the code, and give an error if, later on, we > discover that 'var' was really used in a type position (see changes in > Resolve.java). While syntactic choices have already been carefully studied, I think a dedicated symbolism might make sense here. * It could help disambiguating the syntax and facilitate the parsing. * The other compilation phases would probably be lightened. * Compatibility with legacy sources would be more guarantied. I could suggest something like "?" (or any other symbolism) instead of a keyword like "var", for example: ? list = new ArrayList(); After having implemented a solution with "var", what would be your opinion on using a dedicated symbolism? Bernard > As far as (3) is concerned, we need to 'uncapture' captured types from > initializers. That means that if we have a 'var' like this: > > class Foo { > void test() { > var x = getClass().getSuperClass(); > } > } > > The initializer type will be something like Class, where #CAP > <: Foo > > In this case, the compiler will project this type back to the less specific > type Class, and use that as the declared type for 'x'. This logic is > defined in Types.java. As this logic is the same logic needed by jshell to > render type of standalone expressions, jshell class VarTypePrinter has been > removed and jshell has been rewired to point at the (now) official routine > in Types. Jshell also needed several other tweaks to (i) accept 'var' and > (ii) to deal with non-denotable types (intersection types and anonymous > class types) that can be produced by the LVTI machinery (many thanks to Jan > for doing those changes!) > > > As far as testing is concerned, I wrote several tests to check that the > parser was behaving as expected; to check the behavior of the LVTI inference > machinery, I wrote a test harness which leverages annotation on 'var' so > that we can write down assertions such as: > > @InferredType("java.util.List") > var s = extString(); > > > Regarding compiler diagnostics, for those interested, a comprehensive list > of examples of new diagnostics triggered by the LVTI compiler can be found > here: > > http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html > > Finally, a finder has been added to detect local variable decls whose > declared type can be replaced by 'var' - to enable it, the hidden option > -XDfind=local should be used. > > > Thanks > Maurizio > > [1] - http://openjdk.java.net/jeps/286 > [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html > > From maurizio.cimadamore at oracle.com Thu Sep 21 16:32:47 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 21 Sep 2017 17:32:47 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: Message-ID: <93b6e0cd-510c-2643-9787-bf8553f0ea11@oracle.com> On 21/09/17 17:12, B. Blaser wrote: > Hi Maurizio, > > On 18 September 2017 at 18:14, Maurizio Cimadamore > wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 [1]). A >> webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are modeled >> in a similar fashion to implicit lambda parameters: their AST node is a >> JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the version >> number and context >> >> 2) Add logic in name resolution to catch bad reference to types named 'var' >> >> 3) add logic to map initializer type back to a suitable variable declared >> type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out of the >> corresponding AST representing the variable declaration. This behavior will >> only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in places >> where it does not belong (according to the spec draft [2]); for instance, >> declaring a class whose name is 'var' is rejected in the parser. As a >> general rule, I tried to implement all such checks in the parser, as that >> gives very early and precise feedback about what's wrong with the code. The >> changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and that's >> why (2) is needed. Basically, whenever 'var' is used in a position where it >> could be either a type or a package name, the parser can't simply rule that >> out, so we have to accept the code, and give an error if, later on, we >> discover that 'var' was really used in a type position (see changes in >> Resolve.java). > While syntactic choices have already been carefully studied, I think a > dedicated symbolism might make sense here. > > * It could help disambiguating the syntax and facilitate the parsing. > * The other compilation phases would probably be lightened. > * Compatibility with legacy sources would be more guarantied. > > I could suggest something like "?" (or any other symbolism) instead of > a keyword like "var", for example: > > ? list = new ArrayList(); > > After having implemented a solution with "var", what would be your > opinion on using a dedicated symbolism? Thanks for your email - at this point syntactic decisions are settled. There has been a poll an year ago or so: http://mail.openjdk.java.net/pipermail/platform-jep-discuss/2016-December/000066.html Maurizio > > Bernard > > >> As far as (3) is concerned, we need to 'uncapture' captured types from >> initializers. That means that if we have a 'var' like this: >> >> class Foo { >> void test() { >> var x = getClass().getSuperClass(); >> } >> } >> >> The initializer type will be something like Class, where #CAP >> <: Foo >> >> In this case, the compiler will project this type back to the less specific >> type Class, and use that as the declared type for 'x'. This logic is >> defined in Types.java. As this logic is the same logic needed by jshell to >> render type of standalone expressions, jshell class VarTypePrinter has been >> removed and jshell has been rewired to point at the (now) official routine >> in Types. Jshell also needed several other tweaks to (i) accept 'var' and >> (ii) to deal with non-denotable types (intersection types and anonymous >> class types) that can be produced by the LVTI machinery (many thanks to Jan >> for doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that the >> parser was behaving as expected; to check the behavior of the LVTI inference >> machinery, I wrote a test harness which leverages annotation on 'var' so >> that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive list >> of examples of new diagnostics triggered by the LVTI compiler can be found >> here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden option >> -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> From maurizio.cimadamore at oracle.com Fri Sep 22 10:52:17 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 22 Sep 2017 11:52:17 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> Message-ID: <4aba6239-8e1c-1b8a-d97d-667b81e5de7f@oracle.com> Here's another revision: http://cr.openjdk.java.net/~mcimadamore/8177466_v3/ diagnostics: http://cr.openjdk.java.net/~mcimadamore/8177466_v3/diags.html Changes: * Rewrote logic of type projection in Types.java to use an enum * Added several javadoc on Types.java * added call to baseType() in Attr::attribLazyConstantValue * fixed an issue in TypeHarness where type var was created with null lower bound (as of this patch, javac is stricter and will assert on null bounds, as they are problematic to deal with when doing projections) If there are no major comments, my plan is to push this on jdk10/master early next week. Thanks! Maurizio On 19/09/17 16:04, Maurizio Cimadamore wrote: > Hi, > I have put together a slightly updated webrev: > > * as pointed out, one diagnostic used to say '9' instead of '10' (this > will likely need to change again because of new release cadence, but > good enough for now) > * the previous webrev contained a spurious added file (TypeHarness) > which was caused by a glitch in the lvti branch in the amber repo. > > New webrev: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ > > New diags: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html > > Maurizio > > > On 18/09/17 17:14, Maurizio Cimadamore wrote: >> Hi, >> this change adds support for local variable type inference (JEP 286 >> [1]). A webrev of the change is available here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466 >> >> The patch is relatively straightforward: implicitly typed locals are >> modeled in a similar fashion to implicit lambda parameters: their AST >> node is a JCVariableDecl whose 'vartype' field is not set (e.g. null). >> >> There are few tricky parts to this changeset: >> >> 1) tweak the parser to give 'var' special meaning depending on the >> version number and context >> >> 2) Add logic in name resolution to catch bad reference to types named >> 'var' >> >> 3) add logic to map initializer type back to a suitable variable >> declared type >> >> As for (1), the parser has been extended so as to special case local >> variables with special name 'var', so that the type will be left out >> of the corresponding AST representing the variable declaration. This >> behavior will only affect latest source version. >> >> The parser has a number of extra checks to prevent 'var to be used in >> places where it does not belong (according to the spec draft [2]); >> for instance, declaring a class whose name is 'var' is rejected in >> the parser. As a general rule, I tried to implement all such checks >> in the parser, as that gives very early and precise feedback about >> what's wrong with the code. The changes are implemented in Parser.java. >> >> There are however errors which cannot be caught in the parser, and >> that's why (2) is needed. Basically, whenever 'var' is used in a >> position where it could be either a type or a package name, the >> parser can't simply rule that out, so we have to accept the code, and >> give an error if, later on, we discover that 'var' was really used in >> a type position (see changes in Resolve.java). >> >> As far as (3) is concerned, we need to 'uncapture' captured types >> from initializers. That means that if we have a 'var' like this: >> >> class Foo { >> ??? void test() { >> ??????? var x = getClass().getSuperClass(); >> ??? } >> } >> >> The initializer type will be something like Class, >> where #CAP <: Foo >> >> In this case, the compiler will project this type back to the less >> specific type Class, and use that as the declared type for 'x'. >> This logic is defined in Types.java. As this logic is the same logic >> needed by jshell to render type of standalone expressions, jshell >> class VarTypePrinter has been removed and jshell has been rewired to >> point at the (now) official routine in Types. Jshell also needed >> several other tweaks to (i) accept 'var' and (ii) to deal with >> non-denotable types (intersection types and anonymous class types) >> that can be produced by the LVTI machinery (many thanks to Jan for >> doing those changes!) >> >> >> As far as testing is concerned, I wrote several tests to check that >> the parser was behaving as expected; to check the behavior of the >> LVTI inference machinery, I wrote a test harness which leverages >> annotation on 'var' so that we can write down assertions such as: >> >> @InferredType("java.util.List") >> var s = extString(); >> >> >> Regarding compiler diagnostics, for those interested, a comprehensive >> list of examples of new diagnostics triggered by the LVTI compiler >> can be found here: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >> >> Finally, a finder has been added to detect local variable decls whose >> declared type can be replaced by 'var' - to enable it, the hidden >> option -XDfind=local should be used. >> >> >> Thanks >> Maurizio >> >> [1] - http://openjdk.java.net/jeps/286 >> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >> >> > From bsrbnd at gmail.com Sat Sep 23 16:15:46 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Sat, 23 Sep 2017 18:15:46 +0200 Subject: JDK-8026527: Unchecked conversion is allowed by method type argument bound checking Message-ID: Hi, Following [1], I tried to investigate a bit more issue JDK-8026527. A JBS comment mention the following example, not far from [1]: class Test { @SuppressWarnings({"unchecked"}) Object parseEnumValue(Class enumType, String constName) { return Enum.valueOf(enumType, constName); } } With: public static > T valueOf(Class enumType, String name); As it isn't clearly established if the latter should compile or not, I tried to follow JLS 9 ?18.5.1 to see what's happening on the bound set of T: >From "Enum.valueOf()" : T <: Enum (?18.5.1 + ?18.1.3) >From formal parameters & actual arguments * Constraint formula < enumType -> Class > (?18.5.1) * Reduced to < Class -> Class > (?18.2.1 + ?5.1.10) * Reduced to < Class <: Class > (?18.2.2) * Reduced to < CAP#1 <= T > (?18.2.3) * Reduced to < CAP#1 = T > (?18.2.3) * Reduced to bound : CAP#1 = T (?18.2.4) >From incorporation of complementary pairs of bounds * Constraint formula < CAP#1 <: Enum > (?18.3.1) * Reduced to : false (?18.2.3) Which is similar to [1]. So, I think this example should fail to compile as the others (the two from JDK-8026527 and the enhanced enums one [1]). My conclusion is that the fix, like here under, could perhaps be as straightforward as replacing "isSubtypeUnchecked()" by "isSubtype()" in "Resolve.rawInstantiate()" [2] per ?15.12.2.2-3 and in "Infer.IncorporationBinaryOpKind.IS_SUBTYPE()" [3] per ?18.2.3. What do you think? Thanks, Bernard [1] http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002075.html [2] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java#l582 [3] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java#l1189 diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -1186,7 +1186,7 @@ IS_SUBTYPE() { @Override boolean apply(Type op1, Type op2, Warner warn, Types types) { - return types.isSubtypeUnchecked(op1, op2, warn); + return types.isSubtype(op1, op2); } }, IS_SAME_TYPE() { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -579,7 +579,7 @@ List bounds = types.subst(types.getBounds((TypeVar)formals.head), pmt.tvars, typeargtypes); for (; bounds.nonEmpty(); bounds = bounds.tail) { - if (!types.isSubtypeUnchecked(actuals.head, bounds.head, warn)) + if (!types.isSubtype(actuals.head, bounds.head)) throw inapplicableMethodException.setMessage("explicit.param.do.not.conform.to.bounds",actuals.head, bounds); } formals = formals.tail; From maurizio.cimadamore at oracle.com Mon Sep 25 08:24:17 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 25 Sep 2017 09:24:17 +0100 Subject: JDK-8026527: Unchecked conversion is allowed by method type argument bound checking In-Reply-To: References: Message-ID: Hi Bernard, we are aware of the issue and the patch - the hard thing here is to establish as to whether the fix is doing more harm than good. As described in the comment you quote, a fix for this has been attempted, but then aborted in the light of these kinds of incompatibilities. There is a number of type-system issues being worked on at the moment (at the spec level) [1] - I think it's best to defer any such point fixes after we have a clear picture of where the spec will land. [1] - https://bugs.openjdk.java.net/browse/JDK-8078095?jql=labels%20%3D%20jls-types Cheers Maurizio On 23/09/17 17:15, B. Blaser wrote: > Hi, > > Following [1], I tried to investigate a bit more issue JDK-8026527. > > A JBS comment mention the following example, not far from [1]: > > class Test { > @SuppressWarnings({"unchecked"}) > Object parseEnumValue(Class enumType, String constName) { > return Enum.valueOf(enumType, constName); > } > } > > With: > > public static > T valueOf(Class enumType, String name); > > As it isn't clearly established if the latter should compile or not, I > tried to follow JLS 9 ?18.5.1 to see what's happening on the bound set > of T: > > From "Enum.valueOf()" : T <: Enum > (?18.5.1 + ?18.1.3) > From formal parameters & actual arguments > * Constraint formula < enumType -> Class > > (?18.5.1) > * Reduced to < Class -> Class >> (?18.2.1 + ?5.1.10) > * Reduced to < Class <: Class > > (?18.2.2) > * Reduced to < CAP#1 <= T > > (?18.2.3) > * Reduced to < CAP#1 = T > > (?18.2.3) > * Reduced to bound : CAP#1 = T > (?18.2.4) > > From incorporation of complementary pairs of bounds > * Constraint formula < CAP#1 <: Enum > > (?18.3.1) > * Reduced to : false > (?18.2.3) > > Which is similar to [1]. > > So, I think this example should fail to compile as the others (the two > from JDK-8026527 and the enhanced enums one [1]). > > My conclusion is that the fix, like here under, could perhaps be as > straightforward as replacing "isSubtypeUnchecked()" by "isSubtype()" > in "Resolve.rawInstantiate()" [2] per ?15.12.2.2-3 and in > "Infer.IncorporationBinaryOpKind.IS_SUBTYPE()" [3] per ?18.2.3. > > What do you think? > > Thanks, > Bernard > > [1] http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002075.html > [2] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java#l582 > [3] http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java#l1189 > > > diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java > b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java > --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java > +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java > @@ -1186,7 +1186,7 @@ > IS_SUBTYPE() { > @Override > boolean apply(Type op1, Type op2, Warner warn, Types types) { > - return types.isSubtypeUnchecked(op1, op2, warn); > + return types.isSubtype(op1, op2); > } > }, > IS_SAME_TYPE() { > diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > @@ -579,7 +579,7 @@ > List bounds = > types.subst(types.getBounds((TypeVar)formals.head), > pmt.tvars, typeargtypes); > for (; bounds.nonEmpty(); bounds = bounds.tail) { > - if (!types.isSubtypeUnchecked(actuals.head, > bounds.head, warn)) > + if (!types.isSubtype(actuals.head, bounds.head)) > throw > inapplicableMethodException.setMessage("explicit.param.do.not.conform.to.bounds",actuals.head, > bounds); > } > formals = formals.tail; From jan.lahoda at oracle.com Mon Sep 25 08:26:09 2017 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Mon, 25 Sep 2017 10:26:09 +0200 Subject: RFR: JDK-8187883: NewClassDefEnclosing.java fails on windows Message-ID: <59C8BDA1.1090603@oracle.com> Hello, The test for JDK-8044853 is normalizing whitespaces, but is not recognizing the Windows line endings. The proposed fix is to use \s+ to normalize whitespaces. Bug: https://bugs.openjdk.java.net/browse/JDK-8187883 Webrev: http://cr.openjdk.java.net/~jlahoda/8187883/webrev.00/ Thanks, Jan From maurizio.cimadamore at oracle.com Mon Sep 25 10:02:36 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 25 Sep 2017 11:02:36 +0100 Subject: RFR: JDK-8187883: NewClassDefEnclosing.java fails on windows In-Reply-To: <59C8BDA1.1090603@oracle.com> References: <59C8BDA1.1090603@oracle.com> Message-ID: Looks good Maurizio On 25/09/17 09:26, Jan Lahoda wrote: > Hello, > > The test for JDK-8044853 is normalizing whitespaces, but is not > recognizing the Windows line endings. The proposed fix is to use \s+ > to normalize whitespaces. > > Bug: https://bugs.openjdk.java.net/browse/JDK-8187883 > Webrev: http://cr.openjdk.java.net/~jlahoda/8187883/webrev.00/ > > Thanks, > ??? Jan From jan.lahoda at oracle.com Mon Sep 25 10:07:05 2017 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Mon, 25 Sep 2017 12:07:05 +0200 Subject: RFR: 8187784: IntelliJ langtools project exclusion settings are too broad In-Reply-To: References: Message-ID: <59C8D549.1080305@oracle.com> Looks OK to me. Jan On 21.9.2017 16:40, Maurizio Cimadamore wrote: > Hi, > I realized that there's an issue with the langtools IJ project - to make > it more optimized, I've excluded src/ make/ and test/ folders - to avoid > indexing and hg overhead (only langtools source folders are then added > back as source roots). But in doing so, hg support is completely > disabled, and there's no highlighting in the IDE when a change is made > to an existing file. So, I'm keeping the build/ exclusion, but dropping > the others. I also removed an extra root (test) which was only used in > the previous setup. > > http://cr.openjdk.java.net/~mcimadamore/8187784/ > > Thanks > Maurizio > From vicente.romero at oracle.com Mon Sep 25 14:20:31 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 25 Sep 2017 10:20:31 -0400 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: <4aba6239-8e1c-1b8a-d97d-667b81e5de7f@oracle.com> References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <4aba6239-8e1c-1b8a-d97d-667b81e5de7f@oracle.com> Message-ID: Hi Maurizio, Thanks for the updated version. I don't have any major comments. Looks good to me, Vicente On 09/22/2017 06:52 AM, Maurizio Cimadamore wrote: > Here's another revision: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v3/ > > diagnostics: > > http://cr.openjdk.java.net/~mcimadamore/8177466_v3/diags.html > > Changes: > > * Rewrote logic of type projection in Types.java to use an enum > * Added several javadoc on Types.java > * added call to baseType() in Attr::attribLazyConstantValue > * fixed an issue in TypeHarness where type var was created with null > lower bound (as of this patch, javac is stricter and will assert on > null bounds, as they are problematic to deal with when doing projections) > > If there are no major comments, my plan is to push this on > jdk10/master early next week. > > Thanks! > Maurizio > > > On 19/09/17 16:04, Maurizio Cimadamore wrote: >> Hi, >> I have put together a slightly updated webrev: >> >> * as pointed out, one diagnostic used to say '9' instead of '10' >> (this will likely need to change again because of new release >> cadence, but good enough for now) >> * the previous webrev contained a spurious added file (TypeHarness) >> which was caused by a glitch in the lvti branch in the amber repo. >> >> New webrev: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >> >> New diags: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >> >> Maurizio >> >> >> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>> Hi, >>> this change adds support for local variable type inference (JEP 286 >>> [1]). A webrev of the change is available here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>> >>> The patch is relatively straightforward: implicitly typed locals are >>> modeled in a similar fashion to implicit lambda parameters: their >>> AST node is a JCVariableDecl whose 'vartype' field is not set (e.g. >>> null). >>> >>> There are few tricky parts to this changeset: >>> >>> 1) tweak the parser to give 'var' special meaning depending on the >>> version number and context >>> >>> 2) Add logic in name resolution to catch bad reference to types >>> named 'var' >>> >>> 3) add logic to map initializer type back to a suitable variable >>> declared type >>> >>> As for (1), the parser has been extended so as to special case local >>> variables with special name 'var', so that the type will be left out >>> of the corresponding AST representing the variable declaration. This >>> behavior will only affect latest source version. >>> >>> The parser has a number of extra checks to prevent 'var to be used >>> in places where it does not belong (according to the spec draft >>> [2]); for instance, declaring a class whose name is 'var' is >>> rejected in the parser. As a general rule, I tried to implement all >>> such checks in the parser, as that gives very early and precise >>> feedback about what's wrong with the code. The changes are >>> implemented in Parser.java. >>> >>> There are however errors which cannot be caught in the parser, and >>> that's why (2) is needed. Basically, whenever 'var' is used in a >>> position where it could be either a type or a package name, the >>> parser can't simply rule that out, so we have to accept the code, >>> and give an error if, later on, we discover that 'var' was really >>> used in a type position (see changes in Resolve.java). >>> >>> As far as (3) is concerned, we need to 'uncapture' captured types >>> from initializers. That means that if we have a 'var' like this: >>> >>> class Foo { >>> ??? void test() { >>> ??????? var x = getClass().getSuperClass(); >>> ??? } >>> } >>> >>> The initializer type will be something like Class, >>> where #CAP <: Foo >>> >>> In this case, the compiler will project this type back to the less >>> specific type Class, and use that as the declared type for 'x'. >>> This logic is defined in Types.java. As this logic is the same logic >>> needed by jshell to render type of standalone expressions, jshell >>> class VarTypePrinter has been removed and jshell has been rewired to >>> point at the (now) official routine in Types. Jshell also needed >>> several other tweaks to (i) accept 'var' and (ii) to deal with >>> non-denotable types (intersection types and anonymous class types) >>> that can be produced by the LVTI machinery (many thanks to Jan for >>> doing those changes!) >>> >>> >>> As far as testing is concerned, I wrote several tests to check that >>> the parser was behaving as expected; to check the behavior of the >>> LVTI inference machinery, I wrote a test harness which leverages >>> annotation on 'var' so that we can write down assertions such as: >>> >>> @InferredType("java.util.List") >>> var s = extString(); >>> >>> >>> Regarding compiler diagnostics, for those interested, a >>> comprehensive list of examples of new diagnostics triggered by the >>> LVTI compiler can be found here: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>> >>> Finally, a finder has been added to detect local variable decls >>> whose declared type can be replaced by 'var' - to enable it, the >>> hidden option -XDfind=local should be used. >>> >>> >>> Thanks >>> Maurizio >>> >>> [1] - http://openjdk.java.net/jeps/286 >>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>> >>> >> > From bsrbnd at gmail.com Mon Sep 25 15:15:26 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Mon, 25 Sep 2017 17:15:26 +0200 Subject: JDK-8026527: Unchecked conversion is allowed by method type argument bound checking In-Reply-To: References: Message-ID: Note that conforming to the current JLS: Object parseEnumValue(Class> enumType, String constName) would also fail per ?18.2.3: * from complementary pairs of bounds < CAP#1 of ? extends Enum <: Enum > * reduced to < ? <= T > * reduced to false But: > Object parseEnumValue(Class enumType, String constName) would succeed, which make sense, at my mind. So, being compliant with the current JLS would probably and hopefully do more good than harm in this specific case... But, as the language isn't limited to this sole example, let's wait for the experts' conclusion about the specifications! Cheers, Bernard On 25 September 2017 at 10:24, Maurizio Cimadamore wrote: > Hi Bernard, > we are aware of the issue and the patch - the hard thing here is to > establish as to whether the fix is doing more harm than good. As described > in the comment you quote, a fix for this has been attempted, but then > aborted in the light of these kinds of incompatibilities. > > There is a number of type-system issues being worked on at the moment (at > the spec level) [1] - I think it's best to defer any such point fixes after > we have a clear picture of where the spec will land. > > [1] - > https://bugs.openjdk.java.net/browse/JDK-8078095?jql=labels%20%3D%20jls-types > > Cheers > Maurizio > > > > On 23/09/17 17:15, B. Blaser wrote: >> >> Hi, >> >> Following [1], I tried to investigate a bit more issue JDK-8026527. >> >> A JBS comment mention the following example, not far from [1]: >> >> class Test { >> @SuppressWarnings({"unchecked"}) >> Object parseEnumValue(Class enumType, String >> constName) { >> return Enum.valueOf(enumType, constName); >> } >> } >> >> With: >> >> public static > T valueOf(Class enumType, String >> name); >> >> As it isn't clearly established if the latter should compile or not, I >> tried to follow JLS 9 ?18.5.1 to see what's happening on the bound set >> of T: >> >> From "Enum.valueOf()" : T <: Enum >> (?18.5.1 + ?18.1.3) >> From formal parameters & actual arguments >> * Constraint formula < enumType -> Class > >> (?18.5.1) >> * Reduced to < Class -> Class >>> >>> (?18.2.1 + ?5.1.10) >> >> * Reduced to < Class <: Class > >> (?18.2.2) >> * Reduced to < CAP#1 <= T > >> (?18.2.3) >> * Reduced to < CAP#1 = T > >> (?18.2.3) >> * Reduced to bound : CAP#1 = T >> (?18.2.4) >> >> From incorporation of complementary pairs of bounds >> * Constraint formula < CAP#1 <: Enum > >> (?18.3.1) >> * Reduced to : false >> (?18.2.3) >> >> Which is similar to [1]. >> >> So, I think this example should fail to compile as the others (the two >> from JDK-8026527 and the enhanced enums one [1]). >> >> My conclusion is that the fix, like here under, could perhaps be as >> straightforward as replacing "isSubtypeUnchecked()" by "isSubtype()" >> in "Resolve.rawInstantiate()" [2] per ?15.12.2.2-3 and in >> "Infer.IncorporationBinaryOpKind.IS_SUBTYPE()" [3] per ?18.2.3. >> >> What do you think? >> >> Thanks, >> Bernard >> >> [1] >> http://mail.openjdk.java.net/pipermail/amber-dev/2017-September/002075.html >> [2] >> http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java#l582 >> [3] >> http://hg.openjdk.java.net/jdk10/master/file/4fe50ead4783/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java#l1189 >> >> >> diff --git >> a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java >> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java >> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java >> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java >> @@ -1186,7 +1186,7 @@ >> IS_SUBTYPE() { >> @Override >> boolean apply(Type op1, Type op2, Warner warn, Types types) >> { >> - return types.isSubtypeUnchecked(op1, op2, warn); >> + return types.isSubtype(op1, op2); >> } >> }, >> IS_SAME_TYPE() { >> diff --git >> a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> @@ -579,7 +579,7 @@ >> List bounds = >> types.subst(types.getBounds((TypeVar)formals.head), >> pmt.tvars, >> typeargtypes); >> for (; bounds.nonEmpty(); bounds = bounds.tail) { >> - if (!types.isSubtypeUnchecked(actuals.head, >> bounds.head, warn)) >> + if (!types.isSubtype(actuals.head, bounds.head)) >> throw >> >> inapplicableMethodException.setMessage("explicit.param.do.not.conform.to.bounds",actuals.head, >> bounds); >> } >> formals = formals.tail; > > From cushon at google.com Mon Sep 25 21:25:24 2017 From: cushon at google.com (Liam Miller-Cushon) Date: Mon, 25 Sep 2017 14:25:24 -0700 Subject: RFR 8187247: canonical import check compares classes by simple name In-Reply-To: <59C3DE19.4080107@oracle.com> References: <59C3DE19.4080107@oracle.com> Message-ID: Hi Jan, Thanks for the review. I moved the test to a directory. Updated webrev: http://cr.openjdk.java.net/~cushon/8187247/webrev.01/ The formatted patch is attached. On Thu, Sep 21, 2017 at 8:43 AM, Jan Lahoda wrote: > Hi Liam, > > I apologize for belated answer. Seems OK to me, thanks for doing this. > Only maybe put the test into a directory where it will be separate (e.g. > importChecks/ImportCanonicalSameName) to avoid interference between this > test and possible future tests. > > Should I integrate this change? > > Jan > > > On 5.9.2017 18:58, Liam Miller-Cushon wrote: > >> This change fixes a bug that causes javac to incorrectly accept >> non-canonical imports if the actual and expected symbols have the same >> simple name. >> >> Bug: https://bugs.openjdk.java.net/browse/JDK-8187247 >> Webrev: http://cr.openjdk.java.net/~cushon/8187247/webrev.00/ >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 8187247.patch Type: text/x-patch Size: 5879 bytes Desc: not available URL: From vicente.romero at oracle.com Tue Sep 26 00:14:15 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Mon, 25 Sep 2017 20:14:15 -0400 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: Message-ID: Hi Bernard, Thanks for the patch. I was playing a bit with it and made some modifications to it, my changes are just in the put method of MostSpecificMap. diff -r 19293ea3999f -r 102d38c4f033 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Sep 08 18:24:15 2017 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Sep 25 19:57:03 2017 -0400 @@ -59,6 +59,7 @@ ?import java.util.HashSet; ?import java.util.Iterator; ?import java.util.LinkedHashMap; +import java.util.LinkedList; ?import java.util.Map; ?import java.util.Set; ?import java.util.function.BiFunction; @@ -3995,14 +3996,30 @@ ???????? } ???????? //where ???????????? private Map mapCandidates() { -??????????????? Map candidates = new LinkedHashMap<>(); +??????????????? MostSpecificMap candidates = new MostSpecificMap(); ???????????????? for (Candidate c : resolveContext.candidates) { ???????????????????? if (c.isApplicable()) continue; -??????????????????? candidates.put(c.sym, c.details); +??????????????????? candidates.put(c); ???????????????? } ???????????????? return candidates; ???????????? } +??????????? @SuppressWarnings("serial") +??????????? private class MostSpecificMap extends LinkedHashMap { +??????????????? private void put(Candidate c) { +??????????????????? keySet().stream() +??????????????????????????? .filter(s -> s != c.sym) +??????????????????????????? .filter(s -> c.sym.overrides(s, (TypeSymbol)s.owner, types, false) ) +??????????????????????????? .forEach(s -> remove(s)); + +??????????????????? if (!keySet().stream() +??????????????????????????? .filter(s -> s == c.sym) +??????????????????????????? .anyMatch(s -> s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false))) { +??????????????????????? put(c.sym, c.details); +??????????????????? } +??????????????? } +??????????? } + ???????????? Map filterCandidates(Map candidatesMap) { ???????????????? Map candidates = new LinkedHashMap<>(); ???????????????? for (Map.Entry _entry : candidatesMap.entrySet()) { in your previous version you were doing: + new LinkedList<>(keySet()).stream() + .filter( s -> !s.equals(c.sym) ) + .filter( s -> c.sym.overrides(s, (TypeSymbol)s.owner, types, false) ) + .forEach( s -> remove(s) ); by creating a brand new LinkedList my impression is that any removal of a key would happen in the linked list, not in the original map so the first statement was a no-op. Also as symbols are unique in javac you can safely use the "==" operator for comparison. Does my version captures what you intended? In addition to all this I think that we should consider if List is the best data structure to store the candidates. It sounds like it could be a map to avoid duplicates, probably this won't be a great gain but there is no point on storing duplicates when we can check for them in O(1) time, Thanks, Vicente On 09/20/2017 10:56 AM, B. Blaser wrote: > Hi, > > Related to [1], I wrote a specialized map to store only the most > specific candidates during the diagnostic generation for overload > resolution, here under. > > It's then used in "Resolve.InapplicableSymbolsError.mapCandidates()" > when non-applicable methods are collected to generate the diagnostic. > > What do you think? > Bernard > > [1] http://mail.openjdk.java.net/pipermail/compiler-dev/2017-September/011062.html > > diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > @@ -59,6 +59,7 @@ > import java.util.HashSet; > import java.util.Iterator; > import java.util.LinkedHashMap; > +import java.util.LinkedList; > import java.util.Map; > import java.util.Set; > import java.util.function.BiFunction; > @@ -3995,14 +3996,29 @@ > } > //where > private Map mapCandidates() { > - Map candidates = new LinkedHashMap<>(); > + MostSpecificMap candidates = new MostSpecificMap(); > for (Candidate c : resolveContext.candidates) { > if (c.isApplicable()) continue; > - candidates.put(c.sym, c.details); > + candidates.put(c); > } > return candidates; > } > > + @SuppressWarnings("serial") > + private class MostSpecificMap extends > LinkedHashMap { > + private void put(Candidate c) { > + new LinkedList<>(keySet()).stream() > + .filter( s -> !s.equals(c.sym) ) > + .filter( s -> c.sym.overrides(s, > (TypeSymbol)s.owner, types, false) ) > + .forEach( s -> remove(s) ); > + > + if (!keySet().stream() > + .filter( s -> !s.equals(c.sym) ) > + .anyMatch( s -> s.overrides(c.sym, > (TypeSymbol)c.sym.owner, types, false) )) > + put(c.sym, c.details); > + } > + } > + > Map filterCandidates(Map JCDiagnostic> candidatesMap) { > Map candidates = new LinkedHashMap<>(); > for (Map.Entry _entry : > candidatesMap.entrySet()) { -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Sep 26 11:17:21 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 26 Sep 2017 12:17:21 +0100 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: Message-ID: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> One comment - we already have a method for 'filtering candidates' - see InapplicableSymbolsError::filterCandidates. Currently, that method is simply discarding methods with wrong arity if the compact diagnostics are enabled (default since JDK 8). I wonder if we could add to this method so that it would also filter out overridden methods? That way you could use the compiler flag to enable/disable the filtering. Maurizio On 26/09/17 01:14, Vicente Romero wrote: > Hi Bernard, > > Thanks for the patch. I was playing a bit with it and made some > modifications to it, my changes are just in the put method of > MostSpecificMap. > > diff -r 19293ea3999f -r 102d38c4f033 > src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > --- > a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > Fri Sep 08 18:24:15 2017 +0000 > +++ > b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java > Mon Sep 25 19:57:03 2017 -0400 > @@ -59,6 +59,7 @@ > ?import java.util.HashSet; > ?import java.util.Iterator; > ?import java.util.LinkedHashMap; > +import java.util.LinkedList; > ?import java.util.Map; > ?import java.util.Set; > ?import java.util.function.BiFunction; > @@ -3995,14 +3996,30 @@ > ???????? } > ???????? //where > ???????????? private Map mapCandidates() { > -??????????????? Map candidates = new > LinkedHashMap<>(); > +??????????????? MostSpecificMap candidates = new MostSpecificMap(); > ???????????????? for (Candidate c : resolveContext.candidates) { > ???????????????????? if (c.isApplicable()) continue; > -??????????????????? candidates.put(c.sym, c.details); > +??????????????????? candidates.put(c); > ???????????????? } > ???????????????? return candidates; > ???????????? } > > +??????????? @SuppressWarnings("serial") > +??????????? private class MostSpecificMap extends > LinkedHashMap { > +??????????????? private void put(Candidate c) { > +??????????????????? keySet().stream() > +??????????????????????????? .filter(s -> s != c.sym) > +??????????????????????????? .filter(s -> c.sym.overrides(s, > (TypeSymbol)s.owner, types, false) ) > +??????????????????????????? .forEach(s -> remove(s)); > + > +??????????????????? if (!keySet().stream() > +??????????????????????????? .filter(s -> s == c.sym) > +??????????????????????????? .anyMatch(s -> s.overrides(c.sym, > (TypeSymbol)c.sym.owner, types, false))) { > +??????????????????????? put(c.sym, c.details); > +??????????????????? } > +??????????????? } > +??????????? } > + > ???????????? Map filterCandidates(Map JCDiagnostic> candidatesMap) { > ???????????????? Map candidates = new > LinkedHashMap<>(); > ???????????????? for (Map.Entry _entry : > candidatesMap.entrySet()) { > > > in your previous version you were doing: > > + new LinkedList<>(keySet()).stream() > + .filter( s -> !s.equals(c.sym) ) > + .filter( s -> c.sym.overrides(s, (TypeSymbol)s.owner, types, false) ) > + .forEach( s -> remove(s) ); > by creating a brand new LinkedList my impression is that any removal > of a key would happen in the linked list, not in the original map so > the first statement was a no-op. Also as symbols are unique in javac > you can safely use the "==" operator for comparison. Does my version > captures what you intended? > > In addition to all this I think that we should consider if List is the > best data structure to store the candidates. It sounds like it could > be a map to avoid duplicates, probably this won't be a great gain but > there is no point on storing duplicates when we can check for them in > O(1) time, > > Thanks, > Vicente > > On 09/20/2017 10:56 AM, B. Blaser wrote: >> Hi, >> >> Related to [1], I wrote a specialized map to store only the most >> specific candidates during the diagnostic generation for overload >> resolution, here under. >> >> It's then used in "Resolve.InapplicableSymbolsError.mapCandidates()" >> when non-applicable methods are collected to generate the diagnostic. >> >> What do you think? >> Bernard >> >> [1]http://mail.openjdk.java.net/pipermail/compiler-dev/2017-September/011062.html >> >> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> @@ -59,6 +59,7 @@ >> import java.util.HashSet; >> import java.util.Iterator; >> import java.util.LinkedHashMap; >> +import java.util.LinkedList; >> import java.util.Map; >> import java.util.Set; >> import java.util.function.BiFunction; >> @@ -3995,14 +3996,29 @@ >> } >> //where >> private Map mapCandidates() { >> - Map candidates = new LinkedHashMap<>(); >> + MostSpecificMap candidates = new MostSpecificMap(); >> for (Candidate c : resolveContext.candidates) { >> if (c.isApplicable()) continue; >> - candidates.put(c.sym, c.details); >> + candidates.put(c); >> } >> return candidates; >> } >> >> + @SuppressWarnings("serial") >> + private class MostSpecificMap extends >> LinkedHashMap { >> + private void put(Candidate c) { >> + new LinkedList<>(keySet()).stream() >> + .filter( s -> !s.equals(c.sym) ) >> + .filter( s -> c.sym.overrides(s, >> (TypeSymbol)s.owner, types, false) ) >> + .forEach( s -> remove(s) ); >> + >> + if (!keySet().stream() >> + .filter( s -> !s.equals(c.sym) ) >> + .anyMatch( s -> s.overrides(c.sym, >> (TypeSymbol)c.sym.owner, types, false) )) >> + put(c.sym, c.details); >> + } >> + } >> + >> Map filterCandidates(Map> JCDiagnostic> candidatesMap) { >> Map candidates = new LinkedHashMap<>(); >> for (Map.Entry _entry : >> candidatesMap.entrySet()) { > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Tue Sep 26 11:59:12 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 26 Sep 2017 12:59:12 +0100 Subject: RFR: 8177466: Add compiler support for local variable type-inference In-Reply-To: References: <279f70da-de2d-e39f-b391-1a2e54fe64b6@oracle.com> <4aba6239-8e1c-1b8a-d97d-667b81e5de7f@oracle.com> Message-ID: Just pushed this: http://hg.openjdk.java.net/jdk10/master/rev/48ec75306997 Thanks to everybody for the helpful comments! Cheers Maurizio On 25/09/17 15:20, Vicente Romero wrote: > Hi Maurizio, > > Thanks for the updated version. I don't have any major comments. Looks > good to me, > > Vicente > > On 09/22/2017 06:52 AM, Maurizio Cimadamore wrote: >> Here's another revision: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v3/ >> >> diagnostics: >> >> http://cr.openjdk.java.net/~mcimadamore/8177466_v3/diags.html >> >> Changes: >> >> * Rewrote logic of type projection in Types.java to use an enum >> * Added several javadoc on Types.java >> * added call to baseType() in Attr::attribLazyConstantValue >> * fixed an issue in TypeHarness where type var was created with null >> lower bound (as of this patch, javac is stricter and will assert on >> null bounds, as they are problematic to deal with when doing >> projections) >> >> If there are no major comments, my plan is to push this on >> jdk10/master early next week. >> >> Thanks! >> Maurizio >> >> >> On 19/09/17 16:04, Maurizio Cimadamore wrote: >>> Hi, >>> I have put together a slightly updated webrev: >>> >>> * as pointed out, one diagnostic used to say '9' instead of '10' >>> (this will likely need to change again because of new release >>> cadence, but good enough for now) >>> * the previous webrev contained a spurious added file (TypeHarness) >>> which was caused by a glitch in the lvti branch in the amber repo. >>> >>> New webrev: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/ >>> >>> New diags: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html >>> >>> Maurizio >>> >>> >>> On 18/09/17 17:14, Maurizio Cimadamore wrote: >>>> Hi, >>>> this change adds support for local variable type inference (JEP 286 >>>> [1]). A webrev of the change is available here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466 >>>> >>>> The patch is relatively straightforward: implicitly typed locals >>>> are modeled in a similar fashion to implicit lambda parameters: >>>> their AST node is a JCVariableDecl whose 'vartype' field is not set >>>> (e.g. null). >>>> >>>> There are few tricky parts to this changeset: >>>> >>>> 1) tweak the parser to give 'var' special meaning depending on the >>>> version number and context >>>> >>>> 2) Add logic in name resolution to catch bad reference to types >>>> named 'var' >>>> >>>> 3) add logic to map initializer type back to a suitable variable >>>> declared type >>>> >>>> As for (1), the parser has been extended so as to special case >>>> local variables with special name 'var', so that the type will be >>>> left out of the corresponding AST representing the variable >>>> declaration. This behavior will only affect latest source version. >>>> >>>> The parser has a number of extra checks to prevent 'var to be used >>>> in places where it does not belong (according to the spec draft >>>> [2]); for instance, declaring a class whose name is 'var' is >>>> rejected in the parser. As a general rule, I tried to implement all >>>> such checks in the parser, as that gives very early and precise >>>> feedback about what's wrong with the code. The changes are >>>> implemented in Parser.java. >>>> >>>> There are however errors which cannot be caught in the parser, and >>>> that's why (2) is needed. Basically, whenever 'var' is used in a >>>> position where it could be either a type or a package name, the >>>> parser can't simply rule that out, so we have to accept the code, >>>> and give an error if, later on, we discover that 'var' was really >>>> used in a type position (see changes in Resolve.java). >>>> >>>> As far as (3) is concerned, we need to 'uncapture' captured types >>>> from initializers. That means that if we have a 'var' like this: >>>> >>>> class Foo { >>>> ??? void test() { >>>> ??????? var x = getClass().getSuperClass(); >>>> ??? } >>>> } >>>> >>>> The initializer type will be something like Class, >>>> where #CAP <: Foo >>>> >>>> In this case, the compiler will project this type back to the less >>>> specific type Class, and use that as the declared type for 'x'. >>>> This logic is defined in Types.java. As this logic is the same >>>> logic needed by jshell to render type of standalone expressions, >>>> jshell class VarTypePrinter has been removed and jshell has been >>>> rewired to point at the (now) official routine in Types. Jshell >>>> also needed several other tweaks to (i) accept 'var' and (ii) to >>>> deal with non-denotable types (intersection types and anonymous >>>> class types) that can be produced by the LVTI machinery (many >>>> thanks to Jan for doing those changes!) >>>> >>>> >>>> As far as testing is concerned, I wrote several tests to check that >>>> the parser was behaving as expected; to check the behavior of the >>>> LVTI inference machinery, I wrote a test harness which leverages >>>> annotation on 'var' so that we can write down assertions such as: >>>> >>>> @InferredType("java.util.List") >>>> var s = extString(); >>>> >>>> >>>> Regarding compiler diagnostics, for those interested, a >>>> comprehensive list of examples of new diagnostics triggered by the >>>> LVTI compiler can be found here: >>>> >>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html >>>> >>>> Finally, a finder has been added to detect local variable decls >>>> whose declared type can be replaced by 'var' - to enable it, the >>>> hidden option -XDfind=local should be used. >>>> >>>> >>>> Thanks >>>> Maurizio >>>> >>>> [1] - http://openjdk.java.net/jeps/286 >>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html >>>> >>>> >>> >> > From bsrbnd at gmail.com Tue Sep 26 13:40:30 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Tue, 26 Sep 2017 15:40:30 +0200 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: Message-ID: Hi Vicente, Thanks for looking at this. On 26 September 2017 at 02:14, Vicente Romero wrote: > Hi Bernard, > > Thanks for the patch. I was playing a bit with it and made some > modifications to it, my changes are just in the put method of > MostSpecificMap. > > in your previous version you were doing: > > + new LinkedList<>(keySet()).stream() > + .filter( s -> !s.equals(c.sym) ) > + .filter( s -> c.sym.overrides(s, > (TypeSymbol)s.owner, types, false) ) > + .forEach( s -> remove(s) ); > > by creating a brand new LinkedList my impression is that any removal of a > key would happen in the linked list, not in the original map so the first > statement was a no-op. "s -> remove(s)" is a closure on "MostSpecificMap.put()". So, "remove(s)" is applied on the map (if all goes well), which is what we expect, I think. I thought that duplicating the *keyset* was necessary because we can't modify the map ("remove(s)") while iterating on it, but we have to verify this. > Also as symbols are unique in javac you can safely > use the "==" operator for comparison. Thanks for the confirmation (I wasn't enough sure to safely use "!=") ! Note that this is "!=", not "==" as you used in: + if (!keySet().stream() + .filter(s -> s == c.sym) + .anyMatch(s -> s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false))) { + put(c.sym, c.details); Here, we would like to add a candidate if no method overrides it, *except* itself. > Does my version captures what you intended? We just need to be sure that removing elements in the map is possible while iterating on it, as explained above. > In addition to all this I think that we should consider if List is the best > data structure to store the candidates. It sounds like it could be a map to > avoid duplicates, probably this won't be a great gain but there is no point > on storing duplicates when we can check for them in O(1) time, I've already tried not to duplicate candidates but "mapCandidates()" was already using a "LinkedHashMap" and the rest of the diagnostic generation is built above that. Notice also that while "c.sym" could be added twice, the corresponding "c.details" would be different. So, using another structure would probably be more complicated I think. And while I'm very concerned about performances, I think this wouldn't be a great gain here. Do you agree? Thanks, Bernard > Thanks, > Vicente From vicente.romero at oracle.com Tue Sep 26 13:50:42 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Tue, 26 Sep 2017 09:50:42 -0400 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> Message-ID: On 09/26/2017 07:17 AM, Maurizio Cimadamore wrote: > > One comment - we already have a method for 'filtering candidates' - > see InapplicableSymbolsError::filterCandidates. > > Currently, that method is simply discarding methods with wrong arity > if the compact diagnostics are enabled (default since JDK 8). > > I wonder if we could add to this method so that it would also filter > out overridden methods? That way you could use the compiler flag to > enable/disable the filtering. > question: shouldn't overridden methods be filtered out for both diagnostics? > Maurizio > > > On 26/09/17 01:14, Vicente Romero wrote: >> Hi Bernard, >> >> Thanks for the patch. I was playing a bit with it and made some >> modifications to it, my changes are just in the put method of >> MostSpecificMap. >> >> diff -r 19293ea3999f -r 102d38c4f033 >> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> --- >> a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> Fri Sep 08 18:24:15 2017 +0000 >> +++ >> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >> Mon Sep 25 19:57:03 2017 -0400 >> @@ -59,6 +59,7 @@ >> ?import java.util.HashSet; >> ?import java.util.Iterator; >> ?import java.util.LinkedHashMap; >> +import java.util.LinkedList; >> ?import java.util.Map; >> ?import java.util.Set; >> ?import java.util.function.BiFunction; >> @@ -3995,14 +3996,30 @@ >> ???????? } >> ???????? //where >> ???????????? private Map mapCandidates() { >> -??????????????? Map candidates = new >> LinkedHashMap<>(); >> +??????????????? MostSpecificMap candidates = new MostSpecificMap(); >> ???????????????? for (Candidate c : resolveContext.candidates) { >> ???????????????????? if (c.isApplicable()) continue; >> -??????????????????? candidates.put(c.sym, c.details); >> +??????????????????? candidates.put(c); >> ???????????????? } >> ???????????????? return candidates; >> ???????????? } >> >> +??????????? @SuppressWarnings("serial") >> +??????????? private class MostSpecificMap extends >> LinkedHashMap { >> +??????????????? private void put(Candidate c) { >> +??????????????????? keySet().stream() >> +??????????????????????????? .filter(s -> s != c.sym) >> +??????????????????????????? .filter(s -> c.sym.overrides(s, >> (TypeSymbol)s.owner, types, false) ) >> +??????????????????????????? .forEach(s -> remove(s)); >> + >> +??????????????????? if (!keySet().stream() >> +??????????????????????????? .filter(s -> s == c.sym) >> +??????????????????????????? .anyMatch(s -> s.overrides(c.sym, >> (TypeSymbol)c.sym.owner, types, false))) { >> +??????????????????????? put(c.sym, c.details); >> +??????????????????? } >> +??????????????? } >> +??????????? } >> + >> ???????????? Map filterCandidates(Map> JCDiagnostic> candidatesMap) { >> ???????????????? Map candidates = new >> LinkedHashMap<>(); >> ???????????????? for (Map.Entry _entry : >> candidatesMap.entrySet()) { >> >> >> in your previous version you were doing: >> >> + new LinkedList<>(keySet()).stream() >> + .filter( s -> !s.equals(c.sym) ) >> + .filter( s -> c.sym.overrides(s, (TypeSymbol)s.owner, types, false) ) >> + .forEach( s -> remove(s) ); >> by creating a brand new LinkedList my impression is that any removal >> of a key would happen in the linked list, not in the original map so >> the first statement was a no-op. Also as symbols are unique in javac >> you can safely use the "==" operator for comparison. Does my version >> captures what you intended? >> >> In addition to all this I think that we should consider if List is >> the best data structure to store the candidates. It sounds like it >> could be a map to avoid duplicates, probably this won't be a great >> gain but there is no point on storing duplicates when we can check >> for them in O(1) time, >> >> Thanks, >> Vicente >> >> On 09/20/2017 10:56 AM, B. Blaser wrote: >>> Hi, >>> >>> Related to [1], I wrote a specialized map to store only the most >>> specific candidates during the diagnostic generation for overload >>> resolution, here under. >>> >>> It's then used in "Resolve.InapplicableSymbolsError.mapCandidates()" >>> when non-applicable methods are collected to generate the diagnostic. >>> >>> What do you think? >>> Bernard >>> >>> [1]http://mail.openjdk.java.net/pipermail/compiler-dev/2017-September/011062.html >>> >>> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >>> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >>> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >>> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java >>> @@ -59,6 +59,7 @@ >>> import java.util.HashSet; >>> import java.util.Iterator; >>> import java.util.LinkedHashMap; >>> +import java.util.LinkedList; >>> import java.util.Map; >>> import java.util.Set; >>> import java.util.function.BiFunction; >>> @@ -3995,14 +3996,29 @@ >>> } >>> //where >>> private Map mapCandidates() { >>> - Map candidates = new LinkedHashMap<>(); >>> + MostSpecificMap candidates = new MostSpecificMap(); >>> for (Candidate c : resolveContext.candidates) { >>> if (c.isApplicable()) continue; >>> - candidates.put(c.sym, c.details); >>> + candidates.put(c); >>> } >>> return candidates; >>> } >>> >>> + @SuppressWarnings("serial") >>> + private class MostSpecificMap extends >>> LinkedHashMap { >>> + private void put(Candidate c) { >>> + new LinkedList<>(keySet()).stream() >>> + .filter( s -> !s.equals(c.sym) ) >>> + .filter( s -> c.sym.overrides(s, >>> (TypeSymbol)s.owner, types, false) ) >>> + .forEach( s -> remove(s) ); >>> + >>> + if (!keySet().stream() >>> + .filter( s -> !s.equals(c.sym) ) >>> + .anyMatch( s -> s.overrides(c.sym, >>> (TypeSymbol)c.sym.owner, types, false) )) >>> + put(c.sym, c.details); >>> + } >>> + } >>> + >>> Map filterCandidates(Map>> JCDiagnostic> candidatesMap) { >>> Map candidates = new LinkedHashMap<>(); >>> for (Map.Entry _entry : >>> candidatesMap.entrySet()) { >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From bsrbnd at gmail.com Tue Sep 26 13:57:53 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Tue, 26 Sep 2017 15:57:53 +0200 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> Message-ID: Hi Maurizio, On 26 September 2017 at 13:17, Maurizio Cimadamore wrote: > One comment - we already have a method for 'filtering candidates' - see > InapplicableSymbolsError::filterCandidates. > > Currently, that method is simply discarding methods with wrong arity if the > compact diagnostics are enabled (default since JDK 8). > > I wonder if we could add to this method so that it would also filter out > overridden methods? That way you could use the compiler flag to > enable/disable the filtering. This would probably be possible, we have to look at that too. But is this really necessary to disable this filtering? Do we really need to see all the overridden methods? Thanks, Bernard > Maurizio From maurizio.cimadamore at oracle.com Tue Sep 26 14:07:24 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 26 Sep 2017 15:07:24 +0100 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> Message-ID: <191911ed-86ba-0dc6-a9f1-f02ee5617039@oracle.com> Hi, I was just pointing out that we already seem to have a piece of functionality to filter candidates, so the design for the fix should consider as to whether reuse existing machinery or coming up with new one. One can argue this in both ways - on the one hand, reusing same machinery is more economical - on the one hand, one could argue that the existing machinery is or filtering out 'near misses', while overridden method should never appear in the candidate set in the first place (as per JLS). Maurizio On 26/09/17 14:57, B. Blaser wrote: > Hi Maurizio, > > On 26 September 2017 at 13:17, Maurizio Cimadamore > wrote: >> One comment - we already have a method for 'filtering candidates' - see >> InapplicableSymbolsError::filterCandidates. >> >> Currently, that method is simply discarding methods with wrong arity if the >> compact diagnostics are enabled (default since JDK 8). >> >> I wonder if we could add to this method so that it would also filter out >> overridden methods? That way you could use the compiler flag to >> enable/disable the filtering. > This would probably be possible, we have to look at that too. > But is this really necessary to disable this filtering? > Do we really need to see all the overridden methods? > > Thanks, > Bernard > >> Maurizio From vicente.romero at oracle.com Tue Sep 26 17:33:11 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Tue, 26 Sep 2017 13:33:11 -0400 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: <191911ed-86ba-0dc6-a9f1-f02ee5617039@oracle.com> References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> <191911ed-86ba-0dc6-a9f1-f02ee5617039@oracle.com> Message-ID: <4a6f4ad5-dc50-3c4b-b642-231d832c7840@oracle.com> On 09/26/2017 10:07 AM, Maurizio Cimadamore wrote: > Hi, > I was just pointing out that we already seem to have a piece of > functionality to filter candidates, so the design for the fix should > consider as to whether reuse existing machinery or coming up with new > one. > > One can argue this in both ways - on the one hand, reusing same > machinery is more economical - on the one hand, one could argue that > the existing machinery is or filtering out 'near misses', while > overridden method should never appear in the candidate set in the > first place (as per JLS). I see, so then it seems like a more important bug could be lurking in overload resolution > > Maurizio > > > On 26/09/17 14:57, B. Blaser wrote: >> Hi Maurizio, >> >> On 26 September 2017 at 13:17, Maurizio Cimadamore >> wrote: >>> One comment - we already have a method for 'filtering candidates' - see >>> InapplicableSymbolsError::filterCandidates. >>> >>> Currently, that method is simply discarding methods with wrong arity >>> if the >>> compact diagnostics are enabled (default since JDK 8). >>> >>> I wonder if we could add to this method so that it would also filter >>> out >>> overridden methods? That way you could use the compiler flag to >>> enable/disable the filtering. >> This would probably be possible, we have to look at that too. >> But is this really necessary to disable this filtering? >> Do we really need to see all the overridden methods? >> >> Thanks, >> Bernard >> >>> Maurizio > From bsrbnd at gmail.com Tue Sep 26 17:41:34 2017 From: bsrbnd at gmail.com (B. Blaser) Date: Tue, 26 Sep 2017 19:41:34 +0200 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: Message-ID: On 26 September 2017 at 15:40, B. Blaser wrote: > Hi Vicente, > > Thanks for looking at this. > > On 26 September 2017 at 02:14, Vicente Romero wrote: >> Hi Bernard, >> >> Thanks for the patch. I was playing a bit with it and made some >> modifications to it, my changes are just in the put method of >> MostSpecificMap. >> >> in your previous version you were doing: >> >> + new LinkedList<>(keySet()).stream() >> + .filter( s -> !s.equals(c.sym) ) >> + .filter( s -> c.sym.overrides(s, >> (TypeSymbol)s.owner, types, false) ) >> + .forEach( s -> remove(s) ); >> >> by creating a brand new LinkedList my impression is that any removal of a >> key would happen in the linked list, not in the original map so the first >> statement was a no-op. > > "s -> remove(s)" is a closure on "MostSpecificMap.put()". > So, "remove(s)" is applied on the map (if all goes well), which is > what we expect, I think. > > I thought that duplicating the *keyset* was necessary because we can't > modify the map ("remove(s)") while iterating on it, but we have to > verify this. > >> Also as symbols are unique in javac you can safely >> use the "==" operator for comparison. > > Thanks for the confirmation (I wasn't enough sure to safely use "!=") ! > Note that this is "!=", not "==" as you used in: > > + if (!keySet().stream() > + .filter(s -> s == c.sym) > + .anyMatch(s -> s.overrides(c.sym, > (TypeSymbol)c.sym.owner, types, false))) { > + put(c.sym, c.details); > > Here, we would like to add a candidate if no method overrides it, > *except* itself. > >> Does my version captures what you intended? > > We just need to be sure that removing elements in the map is possible > while iterating on it, as explained above. > >> In addition to all this I think that we should consider if List is the best >> data structure to store the candidates. It sounds like it could be a map to >> avoid duplicates, probably this won't be a great gain but there is no point >> on storing duplicates when we can check for them in O(1) time, > > I've already tried not to duplicate candidates but "mapCandidates()" > was already using a "LinkedHashMap" and the rest of the diagnostic > generation is built above that. > > Notice also that while "c.sym" could be added twice, the corresponding > "c.details" would be different. > > So, using another structure would probably be more complicated I > think. And while I'm very concerned about performances, I think this > wouldn't be a great gain here. To give a concrete example not fully related to our diagnostic problem but involving duplicates in the candidates list, see "test/tools/javac/Diagnostics/compressed/T8020286.java" : class T8020286 { void m(String s) { } void m(Integer i, String s) { } void test() { m(1, 1); m(1); } } Here, "MethodResolutionContext.addInapplicableCandidate()" is applied twice with the same symbol but with different "details". The same symbol appears then twice in the "candidates" list. I'm honestly not sure if this is really expected but changing it would probably have side-effects where the list is used. But in "InapplicableSymbolsError.mapCandidates()" we store them in a map as it was done before and in the same order to preserve the same behavior. Bernard > Do you agree? > > Thanks, > Bernard > >> Thanks, >> Vicente From maurizio.cimadamore at oracle.com Tue Sep 26 17:53:01 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 26 Sep 2017 18:53:01 +0100 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: <4a6f4ad5-dc50-3c4b-b642-231d832c7840@oracle.com> References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> <191911ed-86ba-0dc6-a9f1-f02ee5617039@oracle.com> <4a6f4ad5-dc50-3c4b-b642-231d832c7840@oracle.com> Message-ID: On 26/09/17 18:33, Vicente Romero wrote: > > > On 09/26/2017 10:07 AM, Maurizio Cimadamore wrote: >> Hi, >> I was just pointing out that we already seem to have a piece of >> functionality to filter candidates, so the design for the fix should >> consider as to whether reuse existing machinery or coming up with new >> one. >> >> One can argue this in both ways - on the one hand, reusing same >> machinery is more economical - on the one hand, one could argue that >> the existing machinery is or filtering out 'near misses', while >> overridden method should never appear in the candidate set in the >> first place (as per JLS). > > I see, so then it seems like a more important bug could be lurking in > overload resolution No bug, while it's true that overload resolution in javac exposes a big set of candidates than in the JLS, that's just how javac works. When you look for a method 'm' in C, javac will look for all candidates in C, and only recur to C's supertypes if nothing is found - which is something that matches the JLS behavior. This approach has pros and cons; on the one hand is dead simple, and does not require membership calculation ahead of overload resolution, so it's fast. On the other hand, since candidates *must be accessible members*, at some point javac will have to check if what's on its hands is really a JLS-worthy candidate. So this could lead to a program flow that is hard to follow (e.g. a method seems applicable, but then javac at a later point says - you know what? I should not even look at you from a JLS perspective). That said, this is just how javac works - and it's defo outside the scope of this fix to alter that behavior. In fact, I believe altering that behavior will require a significant amount of work, and, likely, its own JEP (should we ever decide to bring javac and JLS more in sync in this regard). Maurizio > >> >> Maurizio >> >> >> On 26/09/17 14:57, B. Blaser wrote: >>> Hi Maurizio, >>> >>> On 26 September 2017 at 13:17, Maurizio Cimadamore >>> wrote: >>>> One comment - we already have a method for 'filtering candidates' - >>>> see >>>> InapplicableSymbolsError::filterCandidates. >>>> >>>> Currently, that method is simply discarding methods with wrong >>>> arity if the >>>> compact diagnostics are enabled (default since JDK 8). >>>> >>>> I wonder if we could add to this method so that it would also >>>> filter out >>>> overridden methods? That way you could use the compiler flag to >>>> enable/disable the filtering. >>> This would probably be possible, we have to look at that too. >>> But is this really necessary to disable this filtering? >>> Do we really need to see all the overridden methods? >>> >>> Thanks, >>> Bernard >>> >>>> Maurizio >> > From vicente.romero at oracle.com Tue Sep 26 17:56:44 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Tue, 26 Sep 2017 13:56:44 -0400 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: <73f31aef-2a64-a605-4b21-d56058cdf765@oracle.com> <191911ed-86ba-0dc6-a9f1-f02ee5617039@oracle.com> <4a6f4ad5-dc50-3c4b-b642-231d832c7840@oracle.com> Message-ID: <55d6b17a-a0d0-df7b-7bb6-a2332cfc734f@oracle.com> On 09/26/2017 01:53 PM, Maurizio Cimadamore wrote: > > > On 26/09/17 18:33, Vicente Romero wrote: >> >> >> On 09/26/2017 10:07 AM, Maurizio Cimadamore wrote: >>> Hi, >>> I was just pointing out that we already seem to have a piece of >>> functionality to filter candidates, so the design for the fix should >>> consider as to whether reuse existing machinery or coming up with >>> new one. >>> >>> One can argue this in both ways - on the one hand, reusing same >>> machinery is more economical - on the one hand, one could argue that >>> the existing machinery is or filtering out 'near misses', while >>> overridden method should never appear in the candidate set in the >>> first place (as per JLS). >> >> I see, so then it seems like a more important bug could be lurking in >> overload resolution > No bug, while it's true that overload resolution in javac exposes a > big set of candidates than in the JLS, that's just how javac works. > When you look for a method 'm' in C, javac will look for all > candidates in C, and only recur to C's supertypes if nothing is found > - which is something that matches the JLS behavior. > > This approach has pros and cons; on the one hand is dead simple, and > does not require membership calculation ahead of overload resolution, > so it's fast. On the other hand, since candidates *must be accessible > members*, at some point javac will have to check if what's on its > hands is really a JLS-worthy candidate. So this could lead to a > program flow that is hard to follow (e.g. a method seems applicable, > but then javac at a later point says - you know what? I should not > even look at you from a JLS perspective). > > That said, this is just how javac works - and it's defo outside the > scope of this fix to alter that behavior. In fact, I believe altering > that behavior will require a significant amount of work, and, likely, > its own JEP (should we ever decide to bring javac and JLS more in sync > in this regard). OK thanks for the background, so I guess once I have a word from Bernard regarding the change I did to his patch I will push it as it makes the output more readable > > Maurizio Vicente >> >>> >>> Maurizio >>> >>> >>> On 26/09/17 14:57, B. Blaser wrote: >>>> Hi Maurizio, >>>> >>>> On 26 September 2017 at 13:17, Maurizio Cimadamore >>>> wrote: >>>>> One comment - we already have a method for 'filtering candidates' >>>>> - see >>>>> InapplicableSymbolsError::filterCandidates. >>>>> >>>>> Currently, that method is simply discarding methods with wrong >>>>> arity if the >>>>> compact diagnostics are enabled (default since JDK 8). >>>>> >>>>> I wonder if we could add to this method so that it would also >>>>> filter out >>>>> overridden methods? That way you could use the compiler flag to >>>>> enable/disable the filtering. >>>> This would probably be possible, we have to look at that too. >>>> But is this really necessary to disable this filtering? >>>> Do we really need to see all the overridden methods? >>>> >>>> Thanks, >>>> Bernard >>>> >>>>> Maurizio >>> >> > From vicente.romero at oracle.com Tue Sep 26 18:53:29 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Tue, 26 Sep 2017 14:53:29 -0400 Subject: Most specific method in diagnostic generation for overload resolution In-Reply-To: References: Message-ID: <540dc903-7a39-285c-f649-d0ba0f6bc6c8@oracle.com> Hi Bernard, On 09/26/2017 09:40 AM, B. Blaser wrote: > Hi Vicente, > > Thanks for looking at this. > > On 26 September 2017 at 02:14, Vicente Romero wrote: >> Hi Bernard, >> >> Thanks for the patch. I was playing a bit with it and made some >> modifications to it, my changes are just in the put method of >> MostSpecificMap. >> >> in your previous version you were doing: >> >> + new LinkedList<>(keySet()).stream() >> + .filter( s -> !s.equals(c.sym) ) >> + .filter( s -> c.sym.overrides(s, >> (TypeSymbol)s.owner, types, false) ) >> + .forEach( s -> remove(s) ); >> >> by creating a brand new LinkedList my impression is that any removal of a >> key would happen in the linked list, not in the original map so the first >> statement was a no-op. > "s -> remove(s)" is a closure on "MostSpecificMap.put()". > So, "remove(s)" is applied on the map (if all goes well), which is > what we expect, I think. > > I thought that duplicating the *keyset* was necessary because we can't > modify the map ("remove(s)") while iterating on it, but we have to > verify this. yep I went to quick on this you are right :( we have to duplicate the keyset, I will apply your original patch with the change of !s.equals() for "!=" Thanks, Vicente > >> Also as symbols are unique in javac you can safely >> use the "==" operator for comparison. > Thanks for the confirmation (I wasn't enough sure to safely use "!=") ! > Note that this is "!=", not "==" as you used in: > > + if (!keySet().stream() > + .filter(s -> s == c.sym) > + .anyMatch(s -> s.overrides(c.sym, > (TypeSymbol)c.sym.owner, types, false))) { > + put(c.sym, c.details); > > Here, we would like to add a candidate if no method overrides it, > *except* itself. > >> Does my version captures what you intended? > We just need to be sure that removing elements in the map is possible > while iterating on it, as explained above. > >> In addition to all this I think that we should consider if List is the best >> data structure to store the candidates. It sounds like it could be a map to >> avoid duplicates, probably this won't be a great gain but there is no point >> on storing duplicates when we can check for them in O(1) time, > I've already tried not to duplicate candidates but "mapCandidates()" > was already using a "LinkedHashMap" and the rest of the diagnostic > generation is built above that. > > Notice also that while "c.sym" could be added twice, the corresponding > "c.details" would be different. > > So, using another structure would probably be more complicated I > think. And while I'm very concerned about performances, I think this > wouldn't be a great gain here. > > Do you agree? > > Thanks, > Bernard > >> Thanks, >> Vicente From joe.darcy at oracle.com Wed Sep 27 01:34:48 2017 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Tue, 26 Sep 2017 18:34:48 -0700 Subject: JDK 10 RFR of JDK-8187982: Update SourceVersion to mention restricted keywords Message-ID: <59CB0038.1030903@oracle.com> Hello, Please review this small change to make the javax.lang.model.SourceVersion name-related predicates more explicit in their handling of restricted keywords: JDK-8187982 : Update SourceVersion to mention restricted keywords http://cr.openjdk.java.net/~darcy/8187982.0/ Patch below. (A subsequent fix for JDK-8187951: "Update javax.lang.model.SourceVersion for "var" name" will add appropriate spec and/or behavior changes for "var".) Thanks, -Joe --- old/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java 2017-09-26 18:27:23.156381931 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java 2017-09-26 18:27:22.764381920 -0700 @@ -216,8 +216,9 @@ * Character#isJavaIdentifierStart(int)} returns {@code true}, * followed only by characters for which {@link * Character#isJavaIdentifierPart(int)} returns {@code true}. - * This pattern matches regular identifiers, keywords, and the - * literals {@code "true"}, {@code "false"}, and {@code "null"}. + * This pattern matches regular identifiers, keywords, restricted + * keywords, and the literals {@code "true"}, {@code "false"}, and + * {@code "null"}. * The method returns {@code false} for all other strings. * * @param name the string to check @@ -251,10 +252,13 @@ * qualified name in the latest source version. Unlike {@link * #isIdentifier isIdentifier}, this method returns {@code false} * for keywords, boolean literals, and the null literal. + * This method returns {@code true} for restricted + * keywords. * * @param name the string to check * @return {@code true} if this string is a * syntactically valid name, {@code false} otherwise. + * @jls 3.9 Keywords * @jls 6.2 Names and Identifiers */ public static boolean isName(CharSequence name) { @@ -266,11 +270,14 @@ * qualified name in the given source version. Unlike {@link * #isIdentifier isIdentifier}, this method returns {@code false} * for keywords, boolean literals, and the null literal. + * This method returns {@code true} for restricted + * keywords. * * @param name the string to check * @param version the version to use * @return {@code true} if this string is a * syntactically valid name, {@code false} otherwise. + * @jls 3.9 Keywords * @jls 6.2 Names and Identifiers * @since 9 */ @@ -287,6 +294,8 @@ /** * Returns whether or not {@code s} is a keyword, boolean literal, * or null literal in the latest source version. + * This method returns {@code false} for restricted + * keywords. * * @param s the string to check * @return {@code true} if {@code s} is a keyword, or boolean @@ -302,6 +311,8 @@ /** * Returns whether or not {@code s} is a keyword, boolean literal, * or null literal in the given source version. + * This method returns {@code false} for restricted + * keywords. * * @param s the string to check * @param version the version to use --- old/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java 2017-09-26 18:27:23.916381952 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java 2017-09-26 18:27:23.560381942 -0700 @@ -87,7 +87,7 @@ * * @return {@code true} if this is an open module and {@code * false} otherwise - */ // TODO: add @jls to unnamed module section + */ boolean isOpen(); /** @@ -96,7 +96,9 @@ * * @return {@code true} if this is an unnamed module and {@code * false} otherwise - */ // TODO: add @jls to unnamed module section + * + * @jls 7.7.5 Unnamed Modules + */ boolean isUnnamed(); /** --- old/test/langtools/tools/javac/processing/model/TestSourceVersion.java 2017-09-26 18:27:24.684381973 -0700 +++ new/test/langtools/tools/javac/processing/model/TestSourceVersion.java 2017-09-26 18:27:24.300381963 -0700 @@ -41,6 +41,7 @@ public static void main(String... args) { testLatestSupported(); testVersionVaryingKeywords(); + testRestrictedKeywords(); } private static void testLatestSupported() { @@ -73,6 +74,27 @@ } } } + + private static void testRestrictedKeywords() { + // Restricted keywords are not full keywords + + /* + * JLS 3.9 + * " A further ten character sequences are restricted + * keywords: open, module, requires, transitive, exports, + * opens, to, uses, provides, and with" + */ + Set restrictedKeywords = + Set.of("open", "module", "requires", "transitive", "exports", + "opens", "to", "uses", "provides", "with"); + + for(String key : restrictedKeywords) { + for(SourceVersion version : SourceVersion.values()) { + check(false, isKeyword(key, version), "keyword", version); + check(true, isName(key, version), "name", version); + } + } + } private static void check(boolean result, boolean expected, String message, SourceVersion version) { From maurizio.cimadamore at oracle.com Wed Sep 27 08:19:33 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 27 Sep 2017 09:19:33 +0100 Subject: JDK 10 RFR of JDK-8187982: Update SourceVersion to mention restricted keywords In-Reply-To: <59CB0038.1030903@oracle.com> References: <59CB0038.1030903@oracle.com> Message-ID: Looks good - I agree that treatment of 'var' should be consistent with whatever we do for module-info keywords. Do you think it could make sense to expose the difference between keywords vs. restricted keywords more 'officially' ? E.g. public enum NameKind { ??? NAME, ??? KEYWORD ??? RESTRICTED_KEYWORD; } public getNameKind(CharSequence name, SourceVersion version) { ... } Maurizio On 27/09/17 02:34, Joseph D. Darcy wrote: > Hello, > > Please review this small change to make the > javax.lang.model.SourceVersion name-related predicates more explicit > in their handling of restricted keywords: > > ??? JDK-8187982 : Update SourceVersion to mention restricted keywords > ??? http://cr.openjdk.java.net/~darcy/8187982.0/ > > Patch below. > > (A subsequent fix for JDK-8187951: "Update > javax.lang.model.SourceVersion for "var" name" will add appropriate > spec and/or behavior changes for "var".) > > Thanks, > > -Joe > > --- > old/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java > 2017-09-26 18:27:23.156381931 -0700 > +++ > new/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java > 2017-09-26 18:27:22.764381920 -0700 > @@ -216,8 +216,9 @@ > ????? * Character#isJavaIdentifierStart(int)} returns {@code true}, > ????? * followed only by characters for which {@link > ????? * Character#isJavaIdentifierPart(int)} returns {@code true}. > -???? * This pattern matches regular identifiers, keywords, and the > -???? * literals {@code "true"}, {@code "false"}, and {@code "null"}. > +???? * This pattern matches regular identifiers, keywords, restricted > +???? * keywords, and the literals {@code "true"}, {@code "false"}, and > +???? * {@code "null"}. > ????? * The method returns {@code false} for all other strings. > ????? * > ????? * @param name the string to check > @@ -251,10 +252,13 @@ > ????? * qualified name in the latest source version.? Unlike {@link > ????? * #isIdentifier isIdentifier}, this method returns {@code false} > ????? * for keywords, boolean literals, and the null literal. > +???? * This method returns {@code true} for restricted > +???? * keywords. > ????? * > ????? * @param name the string to check > ????? * @return {@code true} if this string is a > ????? * syntactically valid name, {@code false} otherwise. > +???? * @jls 3.9 Keywords > ????? * @jls 6.2 Names and Identifiers > ????? */ > ???? public static boolean isName(CharSequence name) { > @@ -266,11 +270,14 @@ > ????? * qualified name in the given source version.? Unlike {@link > ????? * #isIdentifier isIdentifier}, this method returns {@code false} > ????? * for keywords, boolean literals, and the null literal. > +???? * This method returns {@code true} for restricted > +???? * keywords. > ????? * > ????? * @param name the string to check > ????? * @param version the version to use > ????? * @return {@code true} if this string is a > ????? * syntactically valid name, {@code false} otherwise. > +???? * @jls 3.9 Keywords > ????? * @jls 6.2 Names and Identifiers > ????? * @since 9 > ????? */ > @@ -287,6 +294,8 @@ > ???? /** > ????? * Returns whether or not {@code s} is a keyword, boolean literal, > ????? * or null literal in the latest source version. > +???? * This method returns {@code false} for restricted > +???? * keywords. > ????? * > ????? * @param s the string to check > ????? * @return {@code true} if {@code s} is a keyword, or boolean > @@ -302,6 +311,8 @@ > ???? /** > ????? * Returns whether or not {@code s} is a keyword, boolean literal, > ????? * or null literal in the given source version. > +???? * This method returns {@code false} for restricted > +???? * keywords. > ????? * > ????? * @param s the string to check > ????? * @param version the version to use > --- > old/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java > 2017-09-26 18:27:23.916381952 -0700 > +++ > new/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java > 2017-09-26 18:27:23.560381942 -0700 > @@ -87,7 +87,7 @@ > ????? * > ????? * @return {@code true} if this is an open module and {@code > ????? * false} otherwise > -???? */ // TODO: add @jls to unnamed module section > +???? */ > ???? boolean isOpen(); > > ???? /** > @@ -96,7 +96,9 @@ > ????? * > ????? * @return {@code true} if this is an unnamed module and {@code > ????? * false} otherwise > -???? */ // TODO: add @jls to unnamed module section > +???? * > +???? * @jls 7.7.5 Unnamed Modules > +???? */ > ???? boolean isUnnamed(); > > ???? /** > --- > old/test/langtools/tools/javac/processing/model/TestSourceVersion.java > 2017-09-26 18:27:24.684381973 -0700 > +++ > new/test/langtools/tools/javac/processing/model/TestSourceVersion.java > 2017-09-26 18:27:24.300381963 -0700 > @@ -41,6 +41,7 @@ > ???? public static void main(String... args) { > ???????? testLatestSupported(); > ???????? testVersionVaryingKeywords(); > +??????? testRestrictedKeywords(); > ???? } > > ???? private static void testLatestSupported() { > @@ -73,6 +74,27 @@ > ???????????? } > ???????? } > ???? } > + > +??? private static void testRestrictedKeywords() { > +??????? // Restricted keywords are not full keywords > + > +??????? /* > +???????? * JLS 3.9 > +???????? * " A further ten character sequences are restricted > +???????? * keywords: open, module, requires, transitive, exports, > +???????? * opens, to, uses, provides, and with" > +???????? */ > +??????? Set restrictedKeywords = > +??????????? Set.of("open", "module", "requires", "transitive", > "exports", > +?????????????????? "opens", "to", "uses", "provides", "with"); > + > +??????? for(String key : restrictedKeywords) { > +??????????? for(SourceVersion version : SourceVersion.values()) { > +??????????????? check(false, isKeyword(key, version), "keyword", > version); > +??????????????? check(true,? isName(key, version),??? "name", version); > +??????????? } > +??????? } > +??? } > > ???? private static void check(boolean result, boolean expected, > ?????????????????????????????? String message, SourceVersion version) { > From joe.darcy at oracle.com Wed Sep 27 17:07:32 2017 From: joe.darcy at oracle.com (joe darcy) Date: Wed, 27 Sep 2017 10:07:32 -0700 Subject: JDK 10 RFR of JDK-8187982: Update SourceVersion to mention restricted keywords In-Reply-To: References: <59CB0038.1030903@oracle.com> Message-ID: <058f9ba7-7590-6b31-a0bf-1d944af782a1@oracle.com> Hi Maurizio, On 9/27/2017 1:19 AM, Maurizio Cimadamore wrote: > Looks good - I agree that treatment of 'var' should be consistent with > whatever we do for module-info keywords. > > Do you think it could make sense to expose the difference between > keywords vs. restricted keywords more 'officially' ? E.g. > > public enum NameKind { > NAME, > KEYWORD > RESTRICTED_KEYWORD; > } > > public getNameKind(CharSequence name, SourceVersion version) { ... } > And I suppose for completeness, that kind of API would also need a non-name item or return null for non-names. Hmmm. My sense is the additional API surface is not warranted here, but if there were examples of annotation processors coding up this kind of API for their own use I would reconsider. The intention of the set of methods in question was to support some internal queries we wanted to write as part of the annotation processing implementation as well as to allow processors to have a check of "can I use this name in a program for this source version." (A heavier weight approach would be to define a enum for keywords, restricted keywords, and the like, but I think that would be overkill.) Thanks for the review, -Joe From joe.darcy at oracle.com Wed Sep 27 22:51:19 2017 From: joe.darcy at oracle.com (joe darcy) Date: Wed, 27 Sep 2017 15:51:19 -0700 Subject: Interim JDK 10 RFR of 8187951: Update javax.lang.model.SourceVersion for "var" name Message-ID: <1f9b858d-4e43-8c9d-cbc1-60c728380bdc@oracle.com> Hello, Please review the in-progress work on 8187951: Update javax.lang.model.SourceVersion for "var" name http://cr.openjdk.java.net/~darcy/8187951.0/ I'm not 100% certain of the desired semantics here. The handling of "var" doesn't align with any of the existing syntactic constructs, including restricted keywords introduced in 9 with modules. The proposal changes gives the "isName" method the semantics of "can I use this qualified name for a type, field, package, or module." Thanks, -Joe From maurizio.cimadamore at oracle.com Thu Sep 28 08:35:13 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 28 Sep 2017 09:35:13 +0100 Subject: Interim JDK 10 RFR of 8187951: Update javax.lang.model.SourceVersion for "var" name In-Reply-To: <1f9b858d-4e43-8c9d-cbc1-60c728380bdc@oracle.com> References: <1f9b858d-4e43-8c9d-cbc1-60c728380bdc@oracle.com> Message-ID: <67ca68b6-46f3-1be6-5607-c59ce97407e3@oracle.com> Not 100% sure about this. On the one hand, the concept of contextual keyword is, well, associated with a context. So 'open' is a keyword in a module-info file, and 'var' is a keyword when used in a local variable declaration. But the isName method takes no such context, so it's bound to be lossy. You tried to reformulate the semantics of isName as something similar to 'is this a valid name for a javax.lang.model.element.Element instance'? I think that _almost_ works - after all elements model: * variables/fields (VariableElement) * methods (ExecutableElement) * classes/interfaces/enums/annotations (TypeElement) * typevars (TypeParameterElement) * modules (ModuleElement) * packages (PackageElement) now, in the last two cases, I'm not sure the implemented logic works well. While 'var' is not a legal name for variables/methods/types/typevars, I think it is a valid name for packages and modules, there's no restriction there. This unfortunately makes the definition of isName messy, because it doesn't really refer to _all_ elements, but just to a subset of them. Also, I find this text: "and {@code "var"} is used for local variable type inference inthe argument version." I only got a good idea of what you meant by looking at the implementation. One alternative would be to mark this method as @Deprecated, and add a new method: public static boolean isName(CharSequence name, *ElementKind kind*, SourceVersion version) { ... } Where the semantics could be: is _name_ a valid qualified name for an element of kind _kind_ in version _version_ ? While not perfect (it still cannot handle module-info keyword, as there's no info on which compilation unit this question refers to), I think it's a step forward in that it lets you discriminate between different kind of elements. An even more complete variant would be: public static boolean isName(CharSequence name, *JavaFileObject sourceFile, ElementKind kind*, SourceVersion version) { ... } Which would let you express in full what you need to express, for both 'var' and module keywords. Maurizio On 27/09/17 23:51, joe darcy wrote: > Hello, > > Please review the in-progress work on > > ??? 8187951: Update javax.lang.model.SourceVersion for "var" name > ??? http://cr.openjdk.java.net/~darcy/8187951.0/ > > I'm not 100% certain of the desired semantics here. The handling of > "var" doesn't align with any of the existing syntactic constructs, > including restricted keywords introduced in 9 with modules. > > The proposal changes gives the "isName" method the semantics of "can I > use this qualified name for a type, field, package, or module." > > Thanks, > > -Joe > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Fri Sep 29 16:42:17 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 29 Sep 2017 17:42:17 +0100 Subject: RFR 8188144: regression in method reference type-checking Message-ID: <786fdda3-7b93-7d2b-74eb-20985a7d8216@oracle.com> Hi, here's a patch for a regression in method reference type checking: http://cr.openjdk.java.net/~mcimadamore/8188144/ JLS 15.13.1 defines the process for resolving a method reference - this is a two step process, where two searches are performed. It is sometimes possible for both searches to produce a result - when that happens, there are a bunch of rules which tell us what search wins: " the first search produces a most specific method that is |static|, and the set of applicable methods produced by the second search contains no non-|static| methods, then the compile-time declaration is the most specified method of the first search" And again: "Otherwise, if the set of applicable methods produced by the first search contains no |static| methods, and the second search produces a most specific method that is non-|static|, then the compile-time declaration is the most specific method of the second search." Javac has been rectified to correctly implement this logic as part of: https://bugs.openjdk.java.net/browse/JDK-8068995 However, in the degenerate case where both searches return _the same_ method, the rectified logic doesn't work. This is caused by the fact that we use the resolved symbol to 'infer' which search (first or second?) gave us the desired result. Note that it is important for javac to know which search produced the result as that will affect code generation (is this a bound or an unbound method reference?). Since we already had all the desired information in the class called ReferenceLookupResult - introduced as part of JDK-8068995, I have tweaked the ReferenceChooser::result signature to return one of those guys instead of a plain Symbol - this allows us to reconstruct the correct picture before returning control to Attr. Cheers Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Fri Sep 29 17:41:48 2017 From: joe.darcy at oracle.com (joe darcy) Date: Fri, 29 Sep 2017 10:41:48 -0700 Subject: Interim JDK 10 RFR of 8187951: Update javax.lang.model.SourceVersion for "var" name In-Reply-To: <67ca68b6-46f3-1be6-5607-c59ce97407e3@oracle.com> References: <1f9b858d-4e43-8c9d-cbc1-60c728380bdc@oracle.com> <67ca68b6-46f3-1be6-5607-c59ce97407e3@oracle.com> Message-ID: <72dda0f6-7317-c538-8d4d-6029c872602c@oracle.com> Hi Maurizio, I agree that implementing a more precise version of the can-I-use-this-as-a-name check requires more context, such as the element kind as you suggest. My sense is that additional API scope isn't warranted. Within the existing set of methods, I think having isName and isKeyword both return "false" for var for RELEASE_10 and later would be acceptable. What to you think? Thanks, -Joe On 9/28/2017 1:35 AM, Maurizio Cimadamore wrote: > > Not 100% sure about this. On the one hand, the concept of contextual > keyword is, well, associated with a context. So 'open' is a keyword in > a module-info file, and 'var' is a keyword when used in a local > variable declaration. > > But the isName method takes no such context, so it's bound to be lossy. > > You tried to reformulate the semantics of isName as something similar > to 'is this a valid name for a javax.lang.model.element.Element > instance'? I think that _almost_ works - after all elements model: > > * variables/fields (VariableElement) > * methods (ExecutableElement) > * classes/interfaces/enums/annotations (TypeElement) > * typevars (TypeParameterElement) > * modules (ModuleElement) > * packages (PackageElement) > > now, in the last two cases, I'm not sure the implemented logic works > well. While 'var' is not a legal name for > variables/methods/types/typevars, I think it is a valid name for > packages and modules, there's no restriction there. > > This unfortunately makes the definition of isName messy, because it > doesn't really refer to _all_ elements, but just to a subset of them. > > Also, I find this text: > > "and {@code "var"} is used for local variable type inference inthe > argument version." > > I only got a good idea of what you meant by looking at the implementation. > > One alternative would be to mark this method as @Deprecated, and add a > new method: > > public static boolean isName(CharSequence name, *ElementKind kind*, > SourceVersion version) { ... } > > Where the semantics could be: > > is _name_ a valid qualified name for an element of kind _kind_ in > version _version_ ? > > While not perfect (it still cannot handle module-info keyword, as > there's no info on which compilation unit this question refers to), I > think it's a step forward in that it lets you discriminate between > different kind of elements. > > An even more complete variant would be: > > public static boolean isName(CharSequence name, *JavaFileObject > sourceFile, ElementKind kind*, SourceVersion version) { ... } > > Which would let you express in full what you need to express, for both > 'var' and module keywords. > > Maurizio > > On 27/09/17 23:51, joe darcy wrote: >> Hello, >> >> Please review the in-progress work on >> >> 8187951: Update javax.lang.model.SourceVersion for "var" name >> http://cr.openjdk.java.net/~darcy/8187951.0/ >> >> I'm not 100% certain of the desired semantics here. The handling of >> "var" doesn't align with any of the existing syntactic constructs, >> including restricted keywords introduced in 9 with modules. >> >> The proposal changes gives the "isName" method the semantics of "can >> I use this qualified name for a type, field, package, or module." >> >> Thanks, >> >> -Joe >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Fri Sep 29 17:54:12 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Fri, 29 Sep 2017 13:54:12 -0400 Subject: RFR 8188144: regression in method reference type-checking In-Reply-To: <786fdda3-7b93-7d2b-74eb-20985a7d8216@oracle.com> References: <786fdda3-7b93-7d2b-74eb-20985a7d8216@oracle.com> Message-ID: <80d5a9c5-e489-cf00-14f5-3de56461f22c@oracle.com> looks good, nit: why static methods? not strong about this but we usually favor instance over static methods Thanks, Vicente On 09/29/2017 12:42 PM, Maurizio Cimadamore wrote: > > Hi, > here's a patch for a regression in method reference type checking: > > http://cr.openjdk.java.net/~mcimadamore/8188144/ > > JLS 15.13.1 defines the process for resolving a method reference - > this is a two step process, where two searches are performed. It is > sometimes possible for both searches to produce a result - when that > happens, there are a bunch of rules which tell us what search wins: > > " the first search produces a most specific method that is |static|, > and the set of applicable methods produced by the second search > contains no non-|static| methods, then the compile-time declaration is > the most specified method of the first search" > > And again: > > "Otherwise, if the set of applicable methods produced by the first > search contains no |static| methods, and the second search produces a > most specific method that is non-|static|, then the compile-time > declaration is the most specific method of the second search." > > Javac has been rectified to correctly implement this logic as part of: > > https://bugs.openjdk.java.net/browse/JDK-8068995 > > However, in the degenerate case where both searches return _the same_ > method, the rectified logic doesn't work. This is caused by the fact > that we use the resolved symbol to 'infer' which search (first or > second?) gave us the desired result. Note that it is important for > javac to know which search produced the result as that will affect > code generation (is this a bound or an unbound method reference?). > > Since we already had all the desired information in the class called > ReferenceLookupResult - introduced as part of JDK-8068995, I have > tweaked the ReferenceChooser::result signature to return one of those > guys instead of a plain Symbol - this allows us to reconstruct the > correct picture before returning control to Attr. > > Cheers > Maurizio > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jonathan.gibbons at oracle.com Fri Sep 29 18:12:53 2017 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Fri, 29 Sep 2017 11:12:53 -0700 Subject: Interim JDK 10 RFR of 8187951: Update javax.lang.model.SourceVersion for "var" name In-Reply-To: <72dda0f6-7317-c538-8d4d-6029c872602c@oracle.com> References: <1f9b858d-4e43-8c9d-cbc1-60c728380bdc@oracle.com> <67ca68b6-46f3-1be6-5607-c59ce97407e3@oracle.com> <72dda0f6-7317-c538-8d4d-6029c872602c@oracle.com> Message-ID: Joe, I guess I would ask, who are these methods targeted at? Both isIdentifier and isKeyword are fuzzy at best. isIdentifier does not take the appropriate Unicode standard into account, although it is probably "good enough". isKeyword has certainly become more complex in 9 and after, and anyone who really needs this info (e.g. IDEs) is probably already doing it for themselves, properly. Do you have any reasonable use-cases for a fuzzy definition of isKeyword, or should we just deprecate it words the Big Bit Bucket in the sky? -- Jon On 9/29/17 10:41 AM, joe darcy wrote: > > Hi Maurizio, > > I agree that implementing a more precise version of the > can-I-use-this-as-a-name check requires more context, such as the > element kind as you suggest. > > My sense is that additional API scope isn't warranted. Within the > existing set of methods, I think having isName and isKeyword both > return "false" for var for RELEASE_10 and later would be acceptable. > > What to you think? > > Thanks, > > -Joe > > > On 9/28/2017 1:35 AM, Maurizio Cimadamore wrote: >> >> Not 100% sure about this. On the one hand, the concept of contextual >> keyword is, well, associated with a context. So 'open' is a keyword >> in a module-info file, and 'var' is a keyword when used in a local >> variable declaration. >> >> But the isName method takes no such context, so it's bound to be lossy. >> >> You tried to reformulate the semantics of isName as something similar >> to 'is this a valid name for a javax.lang.model.element.Element >> instance'? I think that _almost_ works - after all elements model: >> >> * variables/fields (VariableElement) >> * methods (ExecutableElement) >> * classes/interfaces/enums/annotations (TypeElement) >> * typevars (TypeParameterElement) >> * modules (ModuleElement) >> * packages (PackageElement) >> >> now, in the last two cases, I'm not sure the implemented logic works >> well. While 'var' is not a legal name for >> variables/methods/types/typevars, I think it is a valid name for >> packages and modules, there's no restriction there. >> >> This unfortunately makes the definition of isName messy, because it >> doesn't really refer to _all_ elements, but just to a subset of them. >> >> Also, I find this text: >> >> "and {@code "var"} is used for local variable type inference inthe >> argument version." >> >> I only got a good idea of what you meant by looking at the >> implementation. >> >> One alternative would be to mark this method as @Deprecated, and add >> a new method: >> >> public static boolean isName(CharSequence name, *ElementKind kind*, >> SourceVersion version) { ... } >> >> Where the semantics could be: >> >> is _name_ a valid qualified name for an element of kind _kind_ in >> version _version_ ? >> >> While not perfect (it still cannot handle module-info keyword, as >> there's no info on which compilation unit this question refers to), I >> think it's a step forward in that it lets you discriminate between >> different kind of elements. >> >> An even more complete variant would be: >> >> public static boolean isName(CharSequence name, *JavaFileObject >> sourceFile, ElementKind kind*, SourceVersion version) { ... } >> >> Which would let you express in full what you need to express, for >> both 'var' and module keywords. >> >> Maurizio >> >> On 27/09/17 23:51, joe darcy wrote: >>> Hello, >>> >>> Please review the in-progress work on >>> >>> 8187951: Update javax.lang.model.SourceVersion for "var" name >>> http://cr.openjdk.java.net/~darcy/8187951.0/ >>> >>> I'm not 100% certain of the desired semantics here. The handling of >>> "var" doesn't align with any of the existing syntactic constructs, >>> including restricted keywords introduced in 9 with modules. >>> >>> The proposal changes gives the "isName" method the semantics of "can >>> I use this qualified name for a type, field, package, or module." >>> >>> Thanks, >>> >>> -Joe >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Fri Sep 29 20:29:07 2017 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 29 Sep 2017 21:29:07 +0100 Subject: RFR 8188144: regression in method reference type-checking In-Reply-To: <80d5a9c5-e489-cf00-14f5-3de56461f22c@oracle.com> References: <786fdda3-7b93-7d2b-74eb-20985a7d8216@oracle.com> <80d5a9c5-e489-cf00-14f5-3de56461f22c@oracle.com> Message-ID: <62e85357-a72f-d807-25f7-f250e5cb854f@oracle.com> On 29/09/17 18:54, Vicente Romero wrote: > looks good, > > nit: why static methods? not strong about this but we usually favor > instance over static methods There are two static methods: * ReferenceLookupResult::error is a factory, and we use static methods for factories elsewhere? (List.nil()) * ReferenceLookupResult::staticKind, because otherwise the code would not compile (can't call an instance method before delegating to other constructor) Maurizio > > Thanks, > Vicente > > On 09/29/2017 12:42 PM, Maurizio Cimadamore wrote: >> >> Hi, >> here's a patch for a regression in method reference type checking: >> >> http://cr.openjdk.java.net/~mcimadamore/8188144/ >> >> JLS 15.13.1 defines the process for resolving a method reference - >> this is a two step process, where two searches are performed. It is >> sometimes possible for both searches to produce a result - when that >> happens, there are a bunch of rules which tell us what search wins: >> >> " the first search produces a most specific method that is |static|, >> and the set of applicable methods produced by the second search >> contains no non-|static| methods, then the compile-time declaration >> is the most specified method of the first search" >> >> And again: >> >> "Otherwise, if the set of applicable methods produced by the first >> search contains no |static| methods, and the second search produces a >> most specific method that is non-|static|, then the compile-time >> declaration is the most specific method of the second search." >> >> Javac has been rectified to correctly implement this logic as part of: >> >> https://bugs.openjdk.java.net/browse/JDK-8068995 >> >> However, in the degenerate case where both searches return _the same_ >> method, the rectified logic doesn't work. This is caused by the fact >> that we use the resolved symbol to 'infer' which search (first or >> second?) gave us the desired result. Note that it is important for >> javac to know which search produced the result as that will affect >> code generation (is this a bound or an unbound method reference?). >> >> Since we already had all the desired information in the class called >> ReferenceLookupResult - introduced as part of JDK-8068995, I have >> tweaked the ReferenceChooser::result signature to return one of those >> guys instead of a plain Symbol - this allows us to reconstruct the >> correct picture before returning control to Attr. >> >> Cheers >> Maurizio >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Fri Sep 29 20:36:48 2017 From: vicente.romero at oracle.com (Vicente Romero) Date: Fri, 29 Sep 2017 16:36:48 -0400 Subject: RFR 8188144: regression in method reference type-checking In-Reply-To: <62e85357-a72f-d807-25f7-f250e5cb854f@oracle.com> References: <786fdda3-7b93-7d2b-74eb-20985a7d8216@oracle.com> <80d5a9c5-e489-cf00-14f5-3de56461f22c@oracle.com> <62e85357-a72f-d807-25f7-f250e5cb854f@oracle.com> Message-ID: <0525aaea-a6ca-eb46-fe69-32c11d5cd728@oracle.com> On 09/29/2017 04:29 PM, Maurizio Cimadamore wrote: > > > > On 29/09/17 18:54, Vicente Romero wrote: >> looks good, >> >> nit: why static methods? not strong about this but we usually favor >> instance over static methods > There are two static methods: > > * ReferenceLookupResult::error is a factory, and we use static methods > for factories elsewhere? (List.nil()) > * ReferenceLookupResult::staticKind, because otherwise the code would > not compile (can't call an instance method before delegating to other > constructor) ok sounds good > > Maurizio >> >> Thanks, >> Vicente >> >> On 09/29/2017 12:42 PM, Maurizio Cimadamore wrote: >>> >>> Hi, >>> here's a patch for a regression in method reference type checking: >>> >>> http://cr.openjdk.java.net/~mcimadamore/8188144/ >>> >>> JLS 15.13.1 defines the process for resolving a method reference - >>> this is a two step process, where two searches are performed. It is >>> sometimes possible for both searches to produce a result - when that >>> happens, there are a bunch of rules which tell us what search wins: >>> >>> " the first search produces a most specific method that is |static|, >>> and the set of applicable methods produced by the second search >>> contains no non-|static| methods, then the compile-time declaration >>> is the most specified method of the first search" >>> >>> And again: >>> >>> "Otherwise, if the set of applicable methods produced by the first >>> search contains no |static| methods, and the second search produces >>> a most specific method that is non-|static|, then the compile-time >>> declaration is the most specific method of the second search." >>> >>> Javac has been rectified to correctly implement this logic as part of: >>> >>> https://bugs.openjdk.java.net/browse/JDK-8068995 >>> >>> However, in the degenerate case where both searches return _the >>> same_ method, the rectified logic doesn't work. This is caused by >>> the fact that we use the resolved symbol to 'infer' which search >>> (first or second?) gave us the desired result. Note that it is >>> important for javac to know which search produced the result as that >>> will affect code generation (is this a bound or an unbound method >>> reference?). >>> >>> Since we already had all the desired information in the class called >>> ReferenceLookupResult - introduced as part of JDK-8068995, I have >>> tweaked the ReferenceChooser::result signature to return one of >>> those guys instead of a plain Symbol - this allows us to reconstruct >>> the correct picture before returning control to Attr. >>> >>> Cheers >>> Maurizio >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From li.jiang at oracle.com Wed Sep 6 06:19:29 2017 From: li.jiang at oracle.com (Leo Jiang) Date: Wed, 06 Sep 2017 06:19:29 -0000 Subject: RFR 8148371: Remove policytool In-Reply-To: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> References: <76E698F8-551B-4DD8-9D42-3DA2764786EB@oracle.com> Message-ID: Hi All, Kindly reminder: please file a bug to component globalization/translation and assign to Leo Jiang , when you need to add/remove a resource file which should be/was localized. We need to update a tbom file to track all of localizable resource files. Add me to email To: list would allow me being aware of these changes. Thanks, Leo On 09/06/2017 12:17 PM, Weijun Wang wrote: > Hi All > > Please review the change, which spans to root, jdk and langtools repos. > > http://cr.openjdk.java.net/~weijun/8148371/ > > I've searched for the "policytool" word in the whole jdk10/jdk10 forests, removed all files having the word inside the path name, and remove almost all occurrences of the word in other places. > > The exceptions are: > > 1. Two files with the jdk8 word in file name. I assume I should not touch them. Please advise me. > > jdk/src/java.base/share/classes/jdk/internal/module/jdk8_packages.dat: > 1288 sun.security.tools.jarsigner > 1289 sun.security.tools.keytool > 1290: sun.security.tools.policytool > 1291 sun.security.util > 1292 sun.security.validator > > langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdk8_internals.txt: > 977 sun.security.tools.jarsigner > 978 sun.security.tools.keytool > 979: sun.security.tools.policytool > 980 sun.security.util > 981 sun.security.validator > > 2. A swing test containing a full JDK 1.4.2 README text. Keep unchanged. > > jdk/test/javax/swing/JTextArea/4697612/bug4697612.txt: > 122 bin/ktab and jre/bin/ktab > 123 Kerberos key table manager > 124: bin/policytool and jre/bin/policytool > 125 Policy File Creation and Management Tool > 126 bin/orbd and jre/bin/orbd > > 3. A manual test on what resource string are used. It is based on the pre-module source layout and needs to be updated anyway. Keep unchanged this time. https://bugs.openjdk.java.net/browse/JDK-8187265 filed. > > jdk/test/sun/security/util/Resources/NewResourcesNames.java: > 62 "sun/security/tools/jarsigner/Resources.java", > 63 "sun/security/tools/keytool/Resources.java", > 64: "sun/security/tools/policytool/Resources.java", > 65 "sun/security/util/Resources.java", > 66 "sun/security/util/AuthResources.java", > .. > 103 // > 104 // which is mismatch. There are only two such special cases list above. > 105: // For KeyTool, there are 3 calls for showing help. For PolicyTool, 3 > 106 // for name prefixed with POLICY. They are covered in the two special > 107 // cases above. > > There are some Japanese man pages containing the word. I've filed another bug (https://bugs.openjdk.java.net/browse/JDK-8187262) on it. > > Thanks > Max >