GROOVY-11896: Support module import declarations#2429
GROOVY-11896: Support module import declarations#2429paulk-asert wants to merge 2 commits intoapache:masterfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2429 +/- ##
==================================================
+ Coverage 66.4890% 66.6274% +0.1384%
- Complexity 30230 30773 +543
==================================================
Files 1408 1435 +27
Lines 117815 119676 +1861
Branches 20934 21197 +263
==================================================
+ Hits 78334 79737 +1403
- Misses 33035 33367 +332
- Partials 6446 6572 +126
🚀 New features to boost your workflow:
|
|
It's better to verify if current implementation supports Here are some discussions about module discovery functionality: |
3b4fbe8 to
07e5977
Compare
| * Known differences from Java's module import behavior: | ||
| * <ul> | ||
| * <li>Ambiguous class names from multiple module imports silently resolve | ||
| * to the last match, consistent with Groovy's existing star import | ||
| * semantics. Java reports a compile-time error for such ambiguities.</li> | ||
| * <li>Explicit single-type imports take priority over module-expanded | ||
| * star imports (same as Java).</li> | ||
| * </ul> |
There was a problem hiding this comment.
I think Java's semantic is all public classes. Adding all these star imports includes private types as well.
There was a problem hiding this comment.
Yes, existing star imports includes package-private while Java doesn't. I created GROOVY-11916 in case we want to change that. I think it is okay to follow existing Groovy behavior and change it in GROOVY-11916 if we don't like that. I am not sure we document that difference for star imports. But we should do for both the same way. I'll await thoughts on GROOVY-11916 before making changes here.
There was a problem hiding this comment.
I could see it getting vexing if module imports and star imports have conflicts around one module's package-private class beating out another one's public class. That would violate the principle of least surprise, I think. It's hard to think of a case where implementing https://issues.apache.org/jira/browse/GROOVY-11916 would trip somebody up, since actual construction or use of the classes would throw an exception anyway.
I'd support merging this and moving on GROOVY-11916 separately, though, if we're trying to avoid that becoming a blocker.
There was a problem hiding this comment.
@jonnybot0 I agree. Public trumps package private from my testing if I tested all cases.
eric-milles
left a comment
There was a problem hiding this comment.
Does the original import stay in the AST? If not, then there is nothing left for code navigation support in eclipse. Although, I'm not 100% what sort of nav is possible for a module name.
This doesn't create some kind of (new) ModuleImportNode AST type but rather replaces with one or more star imports. We could track via node metadata as some kind of alternative to a new AST type. But as you say, is there a need? |
07e5977 to
174e2f2
Compare
For module navigation, I can see that IntelliJ just takes me to |
|
Overall, I agree that following Java's example seems more prudent than Scala's. I suspect that treating module imports as a distinct thing from static star imports, at least at some level in the AST, might be prudent. That could be because I never fully recovered from the psychic damage I took in the OSGi salt mines. 🙂 That caveat aside, it does seem like there's something from the module imports JEP that we're not supporting: Transitive dependencies across modules (as described in JEP 476).
Unless I have made an error, the existing branch does not do this. I've added a test to my fork (see 301582f) that demonstrates the issue. This is part of what makes me think we may well need specific semantics for the AST of module imports. There are additional expectations built into the JEP that make me think we'd need some specific things to handle them properly. |
…modules) Thanks to @jonnybot0
Nice catch @jonnybot0! I updated the PR to include this ability. |
|
I think this is good to merge, but I have found some other things we might want to fix-forward. I'm going to note them here, but can open up another PR, as they may be worth discussing separately and I don't want to be a blocker. I've combed over this by doing some comparisons with the relevant JEPs (476, 494, 511) and the Java Language Specification for Module Import Declarations. Besides importing the package-private stuff (which is fine and appropriately backlogged), there are a handful of other differences with how Java handles module imports. Issue 1: Ambiguous ImportsThe most significant difference is how this would handle ambiguity between module imports. In Java, this is a compile-time error, but Groovy will just pick one silently and run with it. There are a few specific examples of this in the Java specification (7.5.5, https://docs.oracle.com/javase/specs/jls/se25/html/jls-7.html#jls-7.5.5). You can reproduce these in jshell: Granted, we're already more chill about static star imports than Java, so maybe not throwing that error is the consistent thing? But given that module support is new, I think we could go the more "conservative" way and be okay, since no one is going to depend on the more lax behavior. Issue 2: Import priorityThe Java Language specification specifies a priority for imports of single-type > type-on-demand > module-import. See 6.4.1 of the spec. On this branch, if a user writes import foo.* and also import module M where M exports foo, the list ordering decides which import wins, not the specification precedence. Addressing the issuesThere's a couple of ways Claude & I could hack up that would address these two problems. The first is a smaller change: simply make a separate list of module imports, then resolve them later. The second is a bigger departure from this branch, and actually represents the module imports within the AST. Both approaches solve these two problems (as shown by having the same passing test in their diff). I suspect that the second path is a better direction to head. It looks like it would better support other aspects of and expansions to the JPMS down the road. That said, it's a more significant departure, and may have more knock-on effects; there's a lot of code using Way ForwardI think the best approach is probably to merge this branch, then open a PR from my second branch and take feedback on that separately. That said, it might be quickest for @paulk-asert to just take the diff from the first branch, incorporate it in, and then do a PR from something like the second branch at our leisure, while still pocketing the win today. Let me know what you think is best. Thanks for giving a generous period for feedback! |
see https://issues.apache.org/jira/browse/GROOVY-11896