Skip to content

fix(compiler): keep the type arguments of generic function values - #530

Merged
paralin merged 1 commit into
s4wave:masterfrom
cogentcore:fix/generic-func-value-type-args
Oct 24, 2026
Merged

paralin merged 1 commit into
s4wave:masterfrom
cogentcore:fix/generic-func-value-type-args

Conversation

@rcoreilly

Copy link
Copy Markdown
Contributor

A generic function instantiated with several type arguments and used as a value lowered to the bare function, so calling the value passed no type arguments. For example, a site registers simulations as

sims := map[string]func(tree.Node){"neuron": embed[neuron.Sim, neuron.Config]}

and embed calls a function that does cfg := any(new(C)).(Config). Called through the map, C fell back to an empty interface, new(C) did not make a *neuron.Config, and the assertion panicked with "inline type conversion panic: value is ..., not egui.Config". Called directly, the same instantiation worked.

lowerIndexExpr already wraps a function instantiated with one type argument in lowerGenericFunctionValue, which binds the type arguments; lowerExpr lowered an IndexListExpr (two or more type arguments) as its function alone. This lowers such an IndexListExpr with lowerGenericFunctionValue too. Because calls pass no type arguments to override functions that do not take them (the slices override, for example), lowerGenericFunctionValue now leaves those functions as their own values, as the selector call path decides, so slices.Index[[]int, int] as a value keeps working.

The new compliance test generic_func_value_type_args covers calls, variables and map values of a two-parameter generic function, a single-parameter one, and a slices override function; no other compliance output changes. With this change the simulation pages of compcogneuro.org built with goscript load and run.

A related case is not covered here: a generic function used as a value with its type arguments inferred, as in var f func(int) int = id, also lowers to the bare function. Fixing it means telling value uses from callees in lowerExpr, since several call paths lower their callee through it, so I left it for a separate change.

A generic function instantiated with several type arguments and used as
a value, as in

	sims := map[string]func(){"neuron": embed[Sim, Config]}

lowered to the bare function, so calling the value passed no type
arguments: its type parameters fell back to an empty interface, and
new(C) did not make a *Config, so asserting it to an interface that
*Config implements panicked. lowerIndexExpr already wrapped a function
instantiated with one type argument in lowerGenericFunctionValue;
lowerExpr lowered an IndexListExpr as its function alone.

Lower such an IndexListExpr with lowerGenericFunctionValue too. Since
calls do not pass type arguments to override functions that do not take
them, such as those of the slices override, lowerGenericFunctionValue
leaves those functions as their own values. Add a compliance test for
calls, variables and map values of generic functions.

Signed-off-by: Randall C. O'Reilly <oreilly@ucdavis.edu>
@paralin
paralin merged commit d6bbc9b into s4wave:master Oct 24, 2026
7 checks passed
@rcoreilly
rcoreilly deleted the fix/generic-func-value-type-args branch October 24, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants