Skip to content

Commit

Permalink
[cfe] Allow void typed switch expression
Browse files Browse the repository at this point in the history
This allows void typed switch expressions by allowed void typed
expressions in all subexpressions inferred through the shared type
analysis.

This might lead to allowing void in intended places but the current
approach employed by the CFE doesn't really scale so we need to revisit
it anyway.

In response to #52191

Change-Id: Iee53670d3c316764cfc1309dc76cf37bb3b03629
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/299020
Reviewed-by: Chloe Stefantsova <[email protected]>
Commit-Queue: Johnni Winther <[email protected]>
  • Loading branch information
johnniwinther authored and Commit Queue committed Apr 28, 2023
1 parent d7b70f9 commit 88721ba
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -9392,7 +9392,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
parent is RelationalPattern && parent.expression == node;

ExpressionInferenceResult expressionResult =
inferExpression(node, context).stopShorting();
// TODO(johnniwinther): Handle [isVoidAllowed] through
// [dispatchExpression].
inferExpression(node, context, isVoidAllowed: true).stopShorting();

if (needsCoercion) {
expressionResult =
Expand Down
25 changes: 25 additions & 0 deletions pkg/front_end/testcases/patterns/issue52191.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

void printBugsSwitch(int n) => switch (n) {
0 => print('no bugs'),
1 => print('one bug'),
_ => print('$n bugs'),
};

void printBugsConditional(int n) => n == 0
? print('no bugs')
: n == 1
? print('one bug')
: print('$n bugs');

main() {
printBugsSwitch(0);
printBugsSwitch(1);
printBugsSwitch(2);

printBugsConditional(0);
printBugsConditional(1);
printBugsConditional(2);
}
45 changes: 45 additions & 0 deletions pkg/front_end/testcases/patterns/issue52191.dart.strong.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

static method printBugsSwitch(core::int n) → void
return block {
void #t1;
final synthesized core::int #0#0 = n;
#L1:
{
{
if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("no bugs");
break #L1;
}
}
{
if(#C2 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("one bug");
break #L1;
}
}
{
if(true) {
#t1 = core::print("${n} bugs");
break #L1;
}
}
}
} =>#t1;
static method printBugsConditional(core::int n) → void
return n =={core::num::==}{(core::Object) → core::bool} 0 ?{void} core::print("no bugs") : n =={core::num::==}{(core::Object) → core::bool} 1 ?{void} core::print("one bug") : core::print("${n} bugs");
static method main() → dynamic {
self::printBugsSwitch(0);
self::printBugsSwitch(1);
self::printBugsSwitch(2);
self::printBugsConditional(0);
self::printBugsConditional(1);
self::printBugsConditional(2);
}

constants {
#C1 = 0
#C2 = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

static method printBugsSwitch(core::int n) → void
return block {
void #t1;
final synthesized core::int #0#0 = n;
#L1:
{
{
if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("no bugs");
break #L1;
}
}
{
if(#C2 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("one bug");
break #L1;
}
}
{
if(true) {
#t1 = core::print("${n} bugs");
break #L1;
}
}
}
} =>#t1;
static method printBugsConditional(core::int n) → void
return n =={core::num::==}{(core::Object) → core::bool} 0 ?{void} core::print("no bugs") : n =={core::num::==}{(core::Object) → core::bool} 1 ?{void} core::print("one bug") : core::print("${n} bugs");
static method main() → dynamic {
self::printBugsSwitch(0);
self::printBugsSwitch(1);
self::printBugsSwitch(2);
self::printBugsConditional(0);
self::printBugsConditional(1);
self::printBugsConditional(2);
}

constants {
#C1 = 0
#C2 = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
void printBugsSwitch(int n) => switch (n) {};
void printBugsConditional(int n) => n == 0
? print('no bugs')
: n == 1
? print('one bug')
: print('$n bugs');
main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
switch (n) {}
void printBugsSwitch(int n) =>
---- unknown chunk starts ----
;
---- unknown chunk ends ----
main() {}
void printBugsConditional(int n) => n == 0 ? print('no bugs') : n == 1 ? print('one bug') : print('$n bugs');
47 changes: 47 additions & 0 deletions pkg/front_end/testcases/patterns/issue52191.dart.weak.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;

static method printBugsSwitch(core::int n) → void
return block {
void #t1;
final synthesized core::int #0#0 = n;
#L1:
{
{
if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("no bugs");
break #L1;
}
}
{
if(#C2 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("one bug");
break #L1;
}
}
{
if(true) {
#t1 = core::print("${n} bugs");
break #L1;
}
}
throw new _in::ReachabilityError::•("`null` encountered as case in a switch expression with a non-nullable type.");
}
} =>#t1;
static method printBugsConditional(core::int n) → void
return n =={core::num::==}{(core::Object) → core::bool} 0 ?{void} core::print("no bugs") : n =={core::num::==}{(core::Object) → core::bool} 1 ?{void} core::print("one bug") : core::print("${n} bugs");
static method main() → dynamic {
self::printBugsSwitch(0);
self::printBugsSwitch(1);
self::printBugsSwitch(2);
self::printBugsConditional(0);
self::printBugsConditional(1);
self::printBugsConditional(2);
}

constants {
#C1 = 0
#C2 = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;

static method printBugsSwitch(core::int n) → void
return block {
void #t1;
final synthesized core::int #0#0 = n;
#L1:
{
{
if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("no bugs");
break #L1;
}
}
{
if(#C2 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("one bug");
break #L1;
}
}
{
if(true) {
#t1 = core::print("${n} bugs");
break #L1;
}
}
throw new _in::ReachabilityError::•("`null` encountered as case in a switch expression with a non-nullable type.");
}
} =>#t1;
static method printBugsConditional(core::int n) → void
return n =={core::num::==}{(core::Object) → core::bool} 0 ?{void} core::print("no bugs") : n =={core::num::==}{(core::Object) → core::bool} 1 ?{void} core::print("one bug") : core::print("${n} bugs");
static method main() → dynamic {
self::printBugsSwitch(0);
self::printBugsSwitch(1);
self::printBugsSwitch(2);
self::printBugsConditional(0);
self::printBugsConditional(1);
self::printBugsConditional(2);
}

constants {
#C1 = 0
#C2 = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;

static method printBugsSwitch(core::int n) → void
;
static method printBugsConditional(core::int n) → void
;
static method main() → dynamic
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;

static method printBugsSwitch(core::int n) → void
return block {
void #t1;
final synthesized core::int #0#0 = n;
#L1:
{
{
if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("no bugs");
break #L1;
}
}
{
if(#C2 =={core::num::==}{(core::Object) → core::bool} #0#0) {
#t1 = core::print("one bug");
break #L1;
}
}
{
if(true) {
#t1 = core::print("${n} bugs");
break #L1;
}
}
throw new _in::ReachabilityError::•("`null` encountered as case in a switch expression with a non-nullable type.");
}
} =>#t1;
static method printBugsConditional(core::int n) → void
return n =={core::num::==}{(core::Object) → core::bool} 0 ?{void} core::print("no bugs") : n =={core::num::==}{(core::Object) → core::bool} 1 ?{void} core::print("one bug") : core::print("${n} bugs");
static method main() → dynamic {
self::printBugsSwitch(0);
self::printBugsSwitch(1);
self::printBugsSwitch(2);
self::printBugsConditional(0);
self::printBugsConditional(1);
self::printBugsConditional(2);
}

constants {
#C1 = 0
#C2 = 1
}

0 comments on commit 88721ba

Please sign in to comment.