Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request chapel-lang#7659 from mppf/real32-coerce
Improve resolution of coercions & enums This PR: * Enables param coercions from int/real/complex to real and complex when the value is perfectly representable * Enables param handling of real/imag/complex + (but in order for that to be user-facing, we'd need param operator overloads in ChapelBase - the subject of PR chapel-lang#7668). * Significantly improves enum behavior, so that enums can coerce to integral types in which the enum constants will fit. What's the headline behavior improvement? * the literal 0.0 can coerce to real(32) * the literal 1 can coerce to real(32) Resolves chapel-lang#5922. ### Summary of Behavior Changes Here are some top-level features that continue to work as they did before: * param i = 1:uint(32) + 1; results in y.type being uint(32) * integer literals such as 1 prefer to resolve to 'int', if other arguments did not indicate a stronger preference * int, uint, enum, bool param/literals resolve to "default size" when crossing type category (e.g. bool to int(?w)) but otherwise prefer whichever overload is smallest (e.g. int(8) will prefer int(16) over int(64)). Here are some top-level features that work after this PR (and not before): * 0.0, 1, or other numeric values that are exactly representable can pass to a real(32) argument + for param reals, that means verifying both the mantissa and exponent will fit * int(8), int(16) non-param values can pass to a real(32) argument (since they are exactly representable) * param r = 1:real(32) + 0.0; results in r.type being real(32) (after we add real param ops in PR chapel-lang#7688) * enum X { a, b, c = a + b } works at all * enum Y { a=1 } var x:myenum; f(x); can now dispatch to f(any integral type), since the enum value fits into any integral type. This works even without resulting in ambiguity if overloads for all integer types are present! * real param/literals resolve to "default size" when crossing type but otherwise prefer whichever overload is smallest * 15 futures retired! ### Enum Examples that Behave Differently ``` chapel enum myenum { v } proc foo(x:uint(8)) { writeln("uint(8)"); } proc foo(x:uint) { writeln("uint"); } var x:myenum; foo(x); ``` After this PR, this resolves to the 'uint' foo; on master it fails to resolve, with ambiguity. I think it makes sense to prefer the "default sized type" in this case (even before this PR, we would prefer an 'int' version), but more importantly adding this rule helps to prevent surprising ambiguity errors that arise from complex relationships between the various most-specific-argument rules. ``` chapel enum myenum { X=1, Y=1000 } proc foo(x:int(8)) { writeln("int(8) version"); } proc foo(x:int(32)) { writeln("int(32) version"); } foo(myenum.X); ``` After this PR, this resolves to "int(32) version" rather than "int(8) version". In fact it could resolve to the int(8) version if it were the only option, but the int(32) version is preferred because the enum type, myenum, which is the type of myenum.X, can always dispatch to int(32), but myenum.X can only dispatch to the int(8) version because it happens to be a param with the value 1. ### Testing and Review Passes full local futures testing. Reviewed by @vasslitvinov - thanks! ### Future Work * consider also enabling coercions from int(32) to real(32) (discuss in issue chapel-lang#7740) * actually adding 'real' param functions (PR chapel-lang#7688 is a start) * spec changes to describe actual behavior of "param prefers" in the resolution section (note though that some of the features, such as passing an int(8) variable to a real(32) argument, are already described as something that should work in the spec. Other areas, such as how function disambiguation works with param arguments, are incorrectly described in the spec.).
- Loading branch information