~sircmpwn/hare#957: 
Issues with default arguments

  • NaNs currently cause a harec assertion failure, because the ability to hash NaNs isn't yet implemented, nor is it clear how it even should be implemented.
  • The spec only restricts default arguments to the translation compatible expression subset, but this poses an issue: how should pointers be hashed? They can't be compared at compile-time, and so it follows that it's not possible to give them a unique hash. We could "solve" this by disallowing addresses in default arguments, but that kinda sucks, since they could potentially be useful.
  • Default arguments sometimes aren't emitted correctly in typedefs. For one, aliases of void emit as plain void (and cause harec to error later). Additionally, default arguments are only emitted in declarations; not in types. This can cause compiler errors, or potentially even miscompilations. It also makes error messages inaccurate, since the type named by the error message doesn't include the default argument.
  • Slices aren't hashed correctly: [1, 2, 3, 4], [1, 2, 3, 4][..3], and [1, 2, 3, 4][1..] are all considered equivalent, whereas [1, 2, 3] and [1, 2, 3, 4][..3] aren't.
  • Expression hashing is underspecified, and so it's sometimes unclear whether two expressions should hash equivalently:
    • Do 0.0 and -0.0 hash equivalently? Currently no, and that's probably correct, but it's notable, because they "compare" equal everywhere else. That is, if harec's current behavior is correct, then we need to specify that the rules for expression hash equivalence may be different than the rules for expression equality. This is also relevant for NaNs, if we decide that all NaNs should be hashed equivalently.
    • Should t { x = 0 } and t { ... } hash equivalently? They currently do in harec, but that should be explicitly specified.
    • If we allow address arguments, then given let x: union { x: int, y: int }, are &x.x and &x.y hashed equivalently?
    • When are two slices equivalent? Does that question even make sense? They're stack-allocated, so the "value" will be different everytime the function is called.
    • How about strings? Intuitively, string literals should be hashed by their contents (as they currently are). But equivalent string literals aren't guaranteed to refer to the same object, so two "identical" strings may (or may not!) point to different addresses. This shouldn't ever cause any real problems, but our current rules with expression hashing sorta imply that functions with equivalent types will have the exact same default arguments (and that the same function will always have the exact same default arguments, regardless of where it's called from), even though this isn't necessarily true.

A pattern with these issues is that they all stem from the fact that default arguments are hashed as part of the function type itself. This necessitates expression hashing; something which isn't used in any other circumstance. It would be much simpler if default arguments were stored as a property of a function declaration. This would prohibit using them in function types, but maybe that tradeoff is worth it. However, all of these issues would also apply to @default in its current form, so unless that RFC is revised or rejected, there's not much point in not hashing them with function types (we should definitely consider making function pointers assignable if they only differ in their default arguments though).

Status
REPORTED
Submitter
~sebsite
Assigned to
No-one
Submitted
3 months ago
Updated
3 months ago
Labels
bug design harec spec