chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.79k stars 421 forks source link

Functions with array parameters always deemed as 'generic' when trying to use as first class functions #22238

Open stonea opened 1 year ago

stonea commented 1 year ago

For the following:

proc foo(x : [0..1] int) { writeln("Hello world"); }

var x = foo;
var y : [0..1] int;
x(y);

I get: the proc 'foo' is generic and cannot be captured.

I suppose this is because the domain mapping for the array is unspecified?

However, even in the following program where we explicitly apply a mapping to 'x' as we do in baz, it errors out with the "proc is generic and can't be captured" error.

use BlockDist;

const D = {0..1};
const DB = {0..1} dmapped Block({0..1});

proc foo(x: [0..1] int) : void { writeln("In foo"); }
proc bar(x: [D] int) : void { writeln("In bar"); }
proc baz(x: [DB] int) : void { writeln("In baz"); }

var x: [0..1] int;
var y: [D] int;
var z: [DB] int;

// foo is generic in that I can pass in all three arrays
foo(x);
foo(y);
foo(z);

// bar is too (though I'd forgotten that it would work this way... hmm...)
bar(x);
bar(y);
bar(z);

// baz is not, or at least not sufficiently generic to take the others as arguments
//baz(x);
//baz(y);
baz(z);

// Given what we see above we would expect these f and g to be generic,
// although it would be nice if we were able to capture them:
/* var f = foo;
   var g = bar; */

// I would expect this to work but it still fails as generic:
var h = baz;

Configuration Information

``` $ chpl --version chpl version 1.31.0 pre-release (90636e61f7) built with LLVM version 14.0.6 available LLVM targets: amdgcn, r600, nvptx64, nvptx, aarch64_32, aarch64_be, aarch64, arm64_32, arm64, x86-64, x86 Copyright 2020-2023 Hewlett Packard Enterprise Development LP Copyright 2004-2019 Cray Inc. (See LICENSE file for more details) $CHPL_HOME/util/printchplenv --anonymize CHPL_TARGET_PLATFORM: darwin CHPL_TARGET_COMPILER: llvm CHPL_TARGET_ARCH: x86_64 CHPL_TARGET_CPU: none * CHPL_LOCALE_MODEL: flat CHPL_COMM: gasnet * CHPL_COMM_SUBSTRATE: udp CHPL_GASNET_SEGMENT: everything CHPL_TASKS: qthreads CHPL_LAUNCHER: amudprun CHPL_TIMERS: generic CHPL_UNWIND: none CHPL_MEM: jemalloc CHPL_ATOMICS: cstdlib CHPL_NETWORK_ATOMICS: none CHPL_GMP: none CHPL_HWLOC: bundled CHPL_RE2: none * CHPL_LLVM: bundled CHPL_AUX_FILESYS: none ```
vasslitvinov commented 1 year ago

I reverse-engineered our existing rule as "Add-on 4" in https://github.com/chapel-lang/chapel/issues/17122#issuecomment-1516693176 . So, the following works:

type T = [0..1] int;

proc foo(arg : T) { writeln("Hello world"); }

var x = foo;

var y : [0..2] int;
x(y);
foo(y);

Apparently T in the above is still generic w.r.t. the runtime domain value, even allowing different dimension sizes.

lydia-duncan commented 5 months ago

Luca encountered this on Gitter over the weekend:

why is this function considered generic?

use CTypes;

proc normalize(ref ret: [1..3] real(64), const ref input: [1..3] real(64)): void {
  var tot = + reduce input;
  for i in ret.domain {
    ret[i] = input[i] / tot;
  }
}

var f = c_ptrTo(normalize);

When trying to convert that to a C pointer I get

error: the proc 'normalize' is generic and cannot be captured