chapel icon indicating copy to clipboard operation
chapel copied to clipboard

Procedures with variadic arguments and following default argument(s) are not properly resolved

Open LouisJenkinsCS opened this issue 7 years ago • 9 comments

When declaring a procedure with variadic arguments and then following with an argument with a default value, the compiler is unable to resolve this. Example below...

proc p(args : int ...?N, defaultArg = true) {
	writeln("Success!");
}

p(1);

TIO

Note that this will work if the user specifies a value for defaultArg

proc p(args : int ...?N, defaultArg = true) {
	writeln("Success!");
}

p(1, true);

TIO

As well if more than one argument is passed and if default argument is of type of the variadic function, it works...

proc p(args : int ...?N, defaultArg = 0) {
	writeln("Success!");
}

p(1,2,3);

TIO

LouisJenkinsCS avatar Nov 11 '18 01:11 LouisJenkinsCS

Interesting... thanks for reporting this.

bradcray avatar Nov 12 '18 05:11 bradcray

A contributor working on the product iterator from #12657 stumbled across this issue as well:

proc p(args...?n, repeat=1)  {
  writeln('args: ', args);
  writeln('repeat: ', repeat);
}

p('AB', repeat=2); // works
p('AB'); // fails to resolve

Compilation output:

error: unresolved call 'p("AB")'
note: candidates are: p(args ...?n, repeat = 1)

Currently, we can work around this by adding an explicit overload for the default arg(s):

proc p(args...?n, repeat:int)  {
  writeln('args: ', args);
  writeln('repeat: ', repeat);
}
proc p(args...?n)  {
  p((...args), repeat=1);
}

p('AB', repeat=2); // works
p('AB'); // works now

ben-albrecht avatar Mar 24 '19 14:03 ben-albrecht

p('AB', [1,2]); // fails to resolve

It looks to me that this doesn't fail to resolve, but rather it incorrectly binds [1, 2] to repeat rather than to args(2)? Is that not what you're seeing as well? (Try it online)

bradcray avatar Mar 25 '19 16:03 bradcray

I seem to have missed the fact that this only impacts the single-argument case. Sorry about that @bradcray. I've updated the example in the original comment to reflect this.

ben-albrecht avatar Mar 25 '19 17:03 ben-albrecht

OK, thanks for clarifying and updating. That sounds consistent with the incorrect behavior I was seeing. I.e., if the compiler is trying to bind the last argument to repeat rather than the varargs, yet we don't support 0-tuples / 0-argument calls to varargs functions, it probably won't match unless the call has two or more arguments (where the last can legally match against repeat?).

bradcray avatar Mar 25 '19 18:03 bradcray

Can you have overloads that accepts a scalar and one that accepts various non-scalars such as args : [], args : range, etc.?

LouisJenkinsCS avatar Mar 25 '19 18:03 LouisJenkinsCS

This one is a toughie. The problem is that the compiler expands var-args before it performs alignment checking (which is wrong). So, it can't distinguish between the p(1, true); and p(1,2) cases, since the number of actuals is the same, and it doesn't know whether true is a vararg actual or if it's a value for the defaulted formal.

Fixing this would require a lot of changes to the way that we handle call resolution (I hit a wall when I realized we need to do rewriting for lifetime checking and where clauses). That said, Dyno seems to support this case just fine. Thus, I think it's best to simply wait for Dyno's resolver to hit production.

DanilaFe avatar Jul 10 '24 22:07 DanilaFe

Whew! I thought you were describing the dyno resolver in your first paragraph. I completely agree that fixing issues in the production resolver that aren't very simple doesn't make sense at this point, particularly if dyno's got it right.

bradcray avatar Jul 10 '24 22:07 bradcray

Associated future tests:

  • test/distributions/corrado/factoryMethods/typeMethodsBroken.chpl will be added by https://github.com/chapel-lang/chapel/pull/27160

DanilaFe avatar Apr 25 '25 03:04 DanilaFe