dart-lang / language

Design of the Dart language
Other
2.66k stars 205 forks source link

[patterns] Void patterns should not support member access? #3504

Open modulovalue opened 10 months ago

modulovalue commented 10 months ago

Consider:

void main() {
  if (0 case Void(hashCode: final h)) {
    print("$h");
  }
}

typedef Void = void;

Direct void patterns (void()) are not supported, but we can have void patterns by using a typedef.

final void a; ... ; a.hashCode is not supported, so maybe the same should also not be supported if we use patterns to access members of a void pattern?

@eernstg wrote (see https://github.com/dart-lang/sdk/issues/54246#issuecomment-1845039410 for context):

Well, I think a pattern like void(...) is going to be difficult to use in a meaningful way: void is a top type, which means that testing whether something is void (except that we can't even do that unless we use a type alias) is true for every object whatsoever; hence, void(...) isn't capable of selecting any set of objects, it just accepts all objects. Next, any void pattern with field patterns (like void(hashCode: int h)) should arguably be a compile-time error, because it is doing the same thing as int h = s.hashCode; where s is the scrutinee object, and s has the static type void, and that is a compile-time error. In other words, a void pattern can basically never be anything other than a no-op (unless we introduce a bunch of other exceptions to the treatment of void typed objects).

lrhn commented 10 months ago

Agree, should not be allowed. We didn't encode a lot of void-restrictions into the pattern spec, not as much as I'd have liked (q.v. https://github.com/dart-lang/language/issues/2907), but we should make sure to patch holes as we find them.

Doing Void(hashCode: var x) is effectively invoking the hashCode getter on a value with static type void, which one should never do. (Probably also never will, so not a big problem, but might as well make sure.)

Maybe we should just say, officially, that the void type does not have the Object-members. Then doing Void(hashCode: ...) would fail with the error message that void doesn't have a hashCode member. (The object behind it does, but the void type itself would be empty.)