New Issue: should type constructors participate in function disambiguation?

18817, "mppf", "should type constructors participate in function disambiguation?", "2021-12-08T19:21:30Z"

PR #18700 implemented a pattern in the compiler/next resolver that needs more discussion.

For a generic class or record type, the compiler generates a type constructor. This process is described in Generics — Chapel Documentation 1.25 . In the spec, the type constructor is described as a function that the compiler is generating. That led me to thinking that this generated function should participate in overload resolution along with other functions.

Here is a specific example that we can consider:

record R {
  type t;
}

{
  proc R(arg: int) {
    return arg;
  }

  var x = R(arg=1); // trying to call proc R above
  var y:R(t=real); // trying to call the type constructor
}

What we get today when we try to compile this program is this error:

bb.chpl:11: error: unresolved call 'R(t=type real(64))'
bb.chpl:6: note: this candidate did not match: R(arg: int)
bb.chpl:11: note: because call uses named argument t
bb.chpl:6: note: but function contains no formal named t

Notably, this error message does not say anything about ambiguity or shadowing. At first I thought that this error might have come about as a result of #13315 but testing with 1.19 which should be before that PR shows similar behavior.

Here is another example that doesn't use an inner scope:

record B {
  param p;
}
proc B(type t) type { // maybe this is desired as a convenience
  return B(0:t);
}

var x: B(1); // trying to call type constructor
var y: B(int); // trying to call type returning function

Today, this fails to compile with:

cc.chpl:1: error: 'B' has multiple definitions, redefined at:
  cc.chpl:4

This issue is asking if either of these program should compile - and if not, what the error message should be indicating.

Arguments in favor of them compiling:

  • it's convenient to describe the type constructor as an automatically generated type-returning function; the spec does that today; and this description would imply that the generated function will be resolved the same as other functions
  • if a generic record changes which fields are generic, then code doing type construction of that record will need to change too. Being able to add a regular type-returning function overload can help library authors to support backwards compatibility and deprecation.

Arguments against them compiling:

  • if there is both a proc R and a record R, then use of the record R would be ambiguous with capturing the function R unless we introduce an idea that the name resolution depends on how the name is used. (More broadly, a variable can be called syntactically, since myVar(i) runs the .this function, so it would be challenging to disambiguate myVar(i) in the presence of a .this as well as a proc myVar).

This issue is tangentially related to #18177 in that paren-less and paren-full methods with the same name in the same scope might be viewed as a similar idea.