Chapel: Domain(string).length() hits compiler assertion

Created on 27 Mar 2019  路  7Comments  路  Source: chapel-lang/chapel

Special/Edge Case where calling length() on a domain(string) seems to trigger an assertion here: https://github.com/chapel-lang/chapel/blob/1426f363c00a415bc3ca77cf4033689031759f64/compiler/resolution/wrappers.cpp#L1653

var D: domain(string);
D.length();

TIO

Note that the following does work...

var D: domain(string);
D.length;

TIO

Found By @ajoshpratt

Compiler Bug user issue

Most helpful comment

The longstanding challenge with accepting parens on a paren-less method is that if the paren-less method returns something that _can_ take parens, then there's a potential ambiguity (do the parens bind to the function call, or the thing that it returned). This is also why we don't support overloading between paren-ful and paren-less methods.

In the case of length, since it returns an integer (or, in this promoted case, a collection of integers) and neither integers nor the collection of integers support a 0-argument this method, I think that this should definitely be a user error. It could either be "cannot resolve call length()" or "cannot access array of ints (or whatever type it is) with 0-argument call" or something like that depending on what we're trying to bind the parens to.

All 7 comments

I recategorized this as a bug (in that user code should not result in internal errors). @vasslitvinov, this looks to be in code you've added fairly recently if you have time to take a quick look.

It looks like the working program is doing a _promoted_ method call on all of the elements in D, since associative domains do not have a method called length while strings do.

This internal error appears to be generalizable to "adding parentheses to a promoted parentheses-less method call or field access". Here are a couple of examples demonstrating this:

var d: domain(string);

writeln(d.numCodepoints()); // internal error
record R {
  var foo = 1;
}

var a: [1..10] R;

writeln(a.foo()); // internal error
record R {
  proc foo {
    return 1;
  }
}

var a: [1..10] R;

writeln(a.foo()); // internal error

looks like the working program is doing a promoted method call

This diagnosis makes sense.

Meanwhile, what should we do about length ?

  • Define it on associative domains. Seriously.

  • When the user writes something .length(), warn that length is a paren-less method?

  • Better yet, just accept .length() ? Why should the user worry about parens?

(Don't we have an issue talking about lengths already?)

[EDIT] This got me. The Chapel name for arrays' and domains' num elements is size, not length. Dunno whether we should do something about users invoking length or length() on a domain/array. Calling those can be an error or it can be intentional.

P.S. Replace length with size in my bullets above?

Should note that in my original code snippet, replacing .length() with .size() does not result in compiler error.

The longstanding challenge with accepting parens on a paren-less method is that if the paren-less method returns something that _can_ take parens, then there's a potential ambiguity (do the parens bind to the function call, or the thing that it returned). This is also why we don't support overloading between paren-ful and paren-less methods.

In the case of length, since it returns an integer (or, in this promoted case, a collection of integers) and neither integers nor the collection of integers support a 0-argument this method, I think that this should definitely be a user error. It could either be "cannot resolve call length()" or "cannot access array of ints (or whatever type it is) with 0-argument call" or something like that depending on what we're trying to bind the parens to.

IMO, an ideal error message would inform the user of the following:

  • The compiler was unable to resolve domain(string).length(), so it attempted to resolve as a promoted expression
  • The compiler was unable to resolve string.length()
  • A paren-less string.length exists in case that's what the user meant.

    • I'd argue the 0-arg this() method on the element type will seldom be what the user wants, so suggesting a paren-less alternative (if it exists) would be more helpful.

That would pretty heroic though. Emitting something like "cannot resolve call string.length()" instead of an internal error would probably suffice for closing this issue.

I think that that style of error message would be challenging to generate because I think the path the compiler goes through is something like this:

1) "Does domain(string) have a method or field called length? No, so I can't call that."
2) "Can domain(string) be used to promote things? Yes, as type string."
3) "Does the string type have a method or field called length? yes and it returns an integer."
4) "It's a zero-argument method so I can call it in a promoted manner as D.length giving me an iterator of integers out"
5) "Do iterators of integers support zero-argument this calls? No. So there's an error."

The point being that (I believe) the compiler doesn't treat this() holistically since a function call x.foo(i) could mean "call foo(i) on x" or "call foo on x and then call (i) on the result." (e.g., imagine foo was a paren-less method that returned an array; or potentially even an iterator of integers where we wanted to take the ith entry). This is why I think it's more likely that without a heroic amount of work, the error message is likely to say something like "iterator expressions of integers can't be called with empty argument lists (())" or something like that.

Was this page helpful?
0 / 5 - 0 ratings