Summary
Follow-up to #172, which fixed the type shown for config options with several accepted types. The description for those options has the same order-dependence and is still wrong: it is taken from whichever overload is enumerated first, and only one overload per directive is annotated. Some process directives lose their documentation entirely, and others gain or lose it between runs of the same build.
Mechanism
SpecNode.processScope() (in nf-lang) builds the process scope by walking ProcessDsl$DirectiveDsl.getDeclaredMethods(), keeping the one-parameter overloads. Decompiled, it does:
if( !map.containsKey(method.getName()) )
map.put(method.getName(), new Option(annotatedDescription(method, ""), types));
map.get(method.getName()).types.add(method.getParameterTypes()[0]);
The type list accumulates across every overload — which is what #172 was able to fix by joining them. The description is only read from the first overload encountered, and later overloads contribute nothing but their type.
Exactly one overload per directive carries @Description:
HAS @Description <- void arch(Map<String, ?>);
no @Description <- void arch(Map<String, ?>, String);
no @Description <- void arch(String);
HAS @Description <- void cache(String);
no @Description <- void cache(Boolean);
So the description survives only when the annotated overload happens to be enumerated first.
Impact
Two distinct symptoms, both from that one line.
1. Descriptions permanently lost. Where the annotated overload is reliably not first, the option never has documentation. arch, disk and publishDir returned an empty description in 6 out of 6 runs. arch is annotated on arch(Map) but arch(String) is enumerated first, so the text is never used.
2. Descriptions appear and disappear between runs. For the rest, enumeration order is not stable, so the same build gives different answers. Over 6 runs of the same language-server-all.jar, requesting completion inside a process { } block:
| option |
description present |
description empty |
accelerator |
1 |
5 |
cache |
1 |
5 |
clusterOptions |
1 |
5 |
pod |
1 |
5 |
shell |
1 |
5 |
arch |
0 |
6 |
disk |
0 |
6 |
publishDir |
0 |
6 |
Non-overloaded directives are unaffected — cpus has a single annotated overload and returned its description in 6 of 6 runs.
Hover is affected the same way, since ConfigHoverProvider reads the same option.description().
Note that Class.getDeclaredMethods() order was stable across 5 runs when called in isolation on a bare JVM, so the instability appears to depend on the surrounding load rather than on reflection order alone. The synchronized added to ConfigSpecFactory.defaultScopes() in #172 did not remove it.
Reproduction
Workspace with main.nf (any valid script) and:
Session: initialize → initialized → didChangeConfiguration → didOpen main.nf → didOpen nextflow.config → completion on the blank line inside process {. Read the documentation field of the returned items and repeat with a fresh server process. Opening the .nf file first matters — config-only sessions were stable in my earlier testing on #172.
Suggested fix
When merging overloads, do not let the first one decide the description — prefer a non-empty one. Mirroring #172's shape, something like keeping the existing description only if the incoming one is empty:
var existing = map.get(name);
var description = annotatedDescription(method, "");
if( existing.description().isEmpty() && !description.isEmpty() )
// adopt the annotated description
Making the enumeration order deterministic would fix symptom 2 but not symptom 1, since arch, disk and publishDir would still deterministically pick the unannotated overload.
Environment
Found by the JAR-versus-native-image response equivalence check added in #146: with the #172 fix in place the type comparison is now stable, and this is what the diff surfaced next.
Summary
Follow-up to #172, which fixed the type shown for config options with several accepted types. The description for those options has the same order-dependence and is still wrong: it is taken from whichever overload is enumerated first, and only one overload per directive is annotated. Some process directives lose their documentation entirely, and others gain or lose it between runs of the same build.
Mechanism
SpecNode.processScope()(innf-lang) builds the process scope by walkingProcessDsl$DirectiveDsl.getDeclaredMethods(), keeping the one-parameter overloads. Decompiled, it does:The type list accumulates across every overload — which is what #172 was able to fix by joining them. The description is only read from the first overload encountered, and later overloads contribute nothing but their type.
Exactly one overload per directive carries
@Description:So the description survives only when the annotated overload happens to be enumerated first.
Impact
Two distinct symptoms, both from that one line.
1. Descriptions permanently lost. Where the annotated overload is reliably not first, the option never has documentation.
arch,diskandpublishDirreturned an empty description in 6 out of 6 runs.archis annotated onarch(Map)butarch(String)is enumerated first, so the text is never used.2. Descriptions appear and disappear between runs. For the rest, enumeration order is not stable, so the same build gives different answers. Over 6 runs of the same
language-server-all.jar, requesting completion inside aprocess { }block:acceleratorcacheclusterOptionspodshellarchdiskpublishDirNon-overloaded directives are unaffected —
cpushas a single annotated overload and returned its description in 6 of 6 runs.Hover is affected the same way, since
ConfigHoverProviderreads the sameoption.description().Note that
Class.getDeclaredMethods()order was stable across 5 runs when called in isolation on a bare JVM, so the instability appears to depend on the surrounding load rather than on reflection order alone. Thesynchronizedadded toConfigSpecFactory.defaultScopes()in #172 did not remove it.Reproduction
Workspace with
main.nf(any valid script) and:process { cpus = 4 }Session:
initialize→initialized→didChangeConfiguration→didOpen main.nf→didOpen nextflow.config→ completion on the blank line insideprocess {. Read thedocumentationfield of the returned items and repeat with a fresh server process. Opening the.nffile first matters — config-only sessions were stable in my earlier testing on #172.Suggested fix
When merging overloads, do not let the first one decide the description — prefer a non-empty one. Mirroring #172's shape, something like keeping the existing description only if the incoming one is empty:
Making the enumeration order deterministic would fix symptom 2 but not symptom 1, since
arch,diskandpublishDirwould still deterministically pick the unannotated overload.Environment
main@ fd0be65 (i.e. including the Config completion and hover show an arbitrary type for options with multiple accepted types #172 fix),nf-lang26.04.6Found by the JAR-versus-native-image response equivalence check added in #146: with the #172 fix in place the type comparison is now stable, and this is what the diff surfaced next.