You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (Jira)" <ji...@apache.org> on 2026/10/20 01:28:01 UTC
[jira] [Closed] (GROOVY-12264) Optimize the unrelated-default-method scan during class generation
[ https://issues.apache.org/jira/browse/GROOVY-12264?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Paul King closed GROOVY-12264.
------------------------------
> Optimize the unrelated-default-method scan during class generation
> ------------------------------------------------------------------
>
> Key: GROOVY-12264
> URL: https://issues.apache.org/jira/browse/GROOVY-12264
> Project: Groovy
> Issue Type: Improvement
> Reporter: Daniel Sun
> Assignee: Daniel Sun
> Priority: Major
> Fix For: 6.0.0-beta-3
>
>
> {{Verifier}} rejects a type that inherits two unrelated {{default}} methods of the same signature (GROOVY-10381, refined by GROOVY-11560). The scan runs in class generation for every type that lists two or more interfaces.
> Class generation is a large share of compile wall time. The scan must stay cheap on the common path, where there is no conflict.
> h3. Problem
> * Stream / {{flatMap}} allocation on every such type.
> * {{ClassNode.getAllDeclaredMethods()}} on the class and again on every interface. Each call rebuilds a full hierarchy method map and revisits inherited defaults.
> On a wide or deep interface DAG the second point is quadratic in the number of interfaces.
> h3. Approach
> * Walk each interface's own methods ({{getMethods()}}) with loops. {{getAllInterfaces()}} already includes super-interfaces, so each {{default}} is visited once.
> * Build the override-signature set only when two unrelated defaults actually collide, and only from the class plus its superclasses.
> * Avoid the {{Optional}} allocation in {{MethodNode.isDefault()}}.
> Before:
> {code:java}
> Set<String> declared = node.getAllDeclaredMethods().stream()
> .filter(m -> !m.isDefault())
> .map(MethodNodeUtils::methodDescriptorWithoutReturnType)
> .collect(Collectors.toSet());
> node.getAllInterfaces().stream()
> .flatMap(iface -> iface.getAllDeclaredMethods().stream())
> .filter(MethodNode::isDefault)
> .forEach(method -> {
> // conflict check
> });
> {code}
> After:
> {code:java}
> for (ClassNode iface : node.getAllInterfaces()) {
> for (MethodNode method : iface.getMethods()) { // this interface only
> if (!method.isDefault()) {
> continue;
> }
> // conflict check; collect overrides only on a real collision
> }
> }
> {code}
> Same conflict rules. No intended behaviour change.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)