Skip to content

Commit

Permalink
Version 3.0.0-113.0.dev
Browse files Browse the repository at this point in the history
Merge eba2188 into dev
  • Loading branch information
Dart CI committed Jan 11, 2023
2 parents 22fa50e + eba2188 commit 1896d94
Show file tree
Hide file tree
Showing 160 changed files with 3,245 additions and 2,017 deletions.
7 changes: 6 additions & 1 deletion pkg/front_end/lib/src/fasta/kernel/body_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7532,7 +7532,12 @@ class BodyBuilder extends StackListenerImpl
..fileOffset = switchKeyword.charOffset;
}
Statement result = switchStatement;
if (target.hasUsers) {
// We create a labeled statement enclosing the switch statement if it has
// explicit break statements targeting it, or if the patterns feature is
// enabled, in which case synthetic break statements might be inserted.
// TODO(johnniwinther): Remove [LabeledStatement]s in inference visitor
// when they have no target.
if (target.hasUsers || libraryFeatures.patterns.isEnabled) {
LabeledStatement labeledStatement = forest.createLabeledStatement(result);
target.resolveBreaks(forest, labeledStatement, switchStatement);
result = labeledStatement;
Expand Down
110 changes: 110 additions & 0 deletions pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) 2022 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.

import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';

bool computeIsAlwaysExhaustiveType(DartType type, CoreTypes coreTypes) {
return type.accept1(const ExhaustiveDartTypeVisitor(), coreTypes);
}

class ExhaustiveDartTypeVisitor implements DartTypeVisitor1<bool, CoreTypes> {
const ExhaustiveDartTypeVisitor();

@override
bool defaultDartType(DartType type, CoreTypes coreTypes) {
throw new UnsupportedError('Unsupported type $type');
}

@override
bool visitDynamicType(DynamicType type, CoreTypes coreTypes) {
return false;
}

@override
bool visitExtensionType(ExtensionType type, CoreTypes coreTypes) {
return false;
}

@override
bool visitFunctionType(FunctionType type, CoreTypes coreTypes) {
return false;
}

@override
bool visitFutureOrType(FutureOrType type, CoreTypes coreTypes) {
// TODO(johnniwinther): Why? This doesn't work if the value is a Future.
return type.typeArgument.accept1(this, coreTypes);
}

@override
bool visitInlineType(InlineType type, CoreTypes coreTypes) {
return type.instantiatedRepresentationType.accept1(this, coreTypes);
}

@override
bool visitInterfaceType(InterfaceType type, CoreTypes coreTypes) {
if (type.classNode == coreTypes.boolClass) {
return true;
} else if (type.classNode.isEnum) {
return true;
} else if (type.classNode.isSealed) {
return true;
} else {
return false;
}
}

@override
bool visitIntersectionType(IntersectionType type, CoreTypes coreTypes) {
// TODO(johnniwinther): Why don't we use the bound?
return false;
}

@override
bool visitInvalidType(InvalidType type, CoreTypes coreTypes) {
return false;
}

@override
bool visitNeverType(NeverType type, CoreTypes coreTypes) {
return false;
}

@override
bool visitNullType(NullType type, CoreTypes coreTypes) {
return true;
}

@override
bool visitRecordType(RecordType type, CoreTypes coreTypes) {
for (DartType positional in type.positional) {
if (!positional.accept1(this, coreTypes)) {
return false;
}
}
for (NamedType named in type.named) {
if (!named.type.accept1(this, coreTypes)) {
return false;
}
}
return true;
}

@override
bool visitTypeParameterType(TypeParameterType type, CoreTypes coreTypes) {
// TODO(johnniwinther): Why don't we use the bound?
return false;
}

@override
bool visitTypedefType(TypedefType type, CoreTypes coreTypes) {
return type.unalias.accept1(this, coreTypes);
}

@override
bool visitVoidType(VoidType type, CoreTypes coreTypes) {
return false;
}
}
30 changes: 20 additions & 10 deletions pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import '../kernel/collections.dart'
SpreadElement,
SpreadMapEntry,
convertToElement;
import '../kernel/exhaustiveness.dart';
import '../kernel/implicit_type_argument.dart' show ImplicitTypeArgument;
import '../kernel/internal_ast.dart';
import '../kernel/late_lowering.dart' as late_lowering;
Expand Down Expand Up @@ -139,7 +140,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
this.constructorDeclaration, this.operations)
: options = new TypeAnalyzerOptions(
nullSafetyEnabled: inferrer.libraryBuilder.isNonNullableByDefault,
patternsEnabled: false),
patternsEnabled:
inferrer.libraryBuilder.libraryFeatures.patterns.isEnabled),
super(inferrer, helper);

ClosureContext get closureContext => _closureContext!;
Expand Down Expand Up @@ -9205,18 +9207,26 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Statement body = case_.body;
Node? rewrite = popRewrite();
// Stack: ()
// TODO(paulberry): if `isTerminating` is `false`, add a synthetic `break`.
// - I'm not sure exactly how best to do this (if `body` is a block, should
// it be inserted into it, or should we always create a fresh block that
// wraps both `body` and the `break`?)
// - I'm not sure if this should be done for the last case in a switch
// statement or not. I worry there may be a complicated interaction
// between insertion of a synthetic break and the handling of
// `shouldThrowUnsoundnessException` in `visitSwitchStatement`.
if (!identical(body, rewrite)) {
body = rewrite as Statement;
case_.body = body..parent = case_;
}
// When patterns are enable, if this is not the last case and it is not
// terminating, we insert a synthetic break.
if (libraryBuilder.libraryFeatures.patterns.isEnabled &&
!isTerminating &&
caseIndex < node.cases.length - 1) {
LabeledStatement switchLabel = node.parent as LabeledStatement;
BreakStatement syntheticBreak = new BreakStatement(switchLabel)
..fileOffset = node.fileOffset;
if (body is Block) {
body.statements.add(syntheticBreak);
syntheticBreak.parent = body;
} else {
body = new Block([body, syntheticBreak])..fileOffset = body.fileOffset;
case_.body = body..parent = case_;
}
}

if (node is PatternSwitchStatement) {
if (case_ is PatternSwitchCase) {
Expand Down Expand Up @@ -9428,7 +9438,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase

@override
bool isAlwaysExhaustiveType(DartType type) {
throw new UnimplementedError('TODO(paulberry)');
return computeIsAlwaysExhaustiveType(type, coreTypes);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ static method multipleCaseSwitch(core::int x) → core::int {
return 0;
}
static method continueLabelSwitch(core::int x) → core::int {
#L7:
switch(x) {
#L7:
#L8:
case #C7:
{
x = x.{core::num::+}(100){(core::num) → core::int};
continue #L8;
continue #L9;
}
#L9:
#L10:
case #C8:
{
continue #L7;
continue #L8;
}
#L8:
#L9:
case #C2:
{
return x.{core::num::+}(3){(core::num) → core::int};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ static method multipleCaseSwitch(core::int x) → core::int {
return 0;
}
static method continueLabelSwitch(core::int x) → core::int {
#L7:
switch(x) {
#L7:
#L8:
case #C7:
{
x = x.{core::num::+}(100){(core::num) → core::int};
continue #L8;
continue #L9;
}
#L9:
#L10:
case #C8:
{
continue #L7;
continue #L8;
}
#L8:
#L9:
case #C2:
{
return x.{core::num::+}(3){(core::num) → core::int};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ static method multipleCaseSwitch(core::int x) → core::int {
return 0;
}
static method continueLabelSwitch(core::int x) → core::int {
#L7:
switch(x) {
#L7:
#L8:
case #C7:
{
x = x.{core::num::+}(100){(core::num) → core::int};
continue #L8;
continue #L9;
}
#L9:
#L10:
case #C8:
{
continue #L7;
continue #L8;
}
#L8:
#L9:
case #C2:
{
return x.{core::num::+}(3){(core::num) → core::int};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ static method multipleCaseSwitch(core::int x) → core::int {
return 0;
}
static method continueLabelSwitch(core::int x) → core::int {
#L7:
switch(x) {
#L7:
#L8:
case #C7:
{
x = x.{core::num::+}(100){(core::num) → core::int};
continue #L8;
continue #L9;
}
#L9:
#L10:
case #C8:
{
continue #L7;
continue #L8;
}
#L8:
#L9:
case #C2:
{
return x.{core::num::+}(3){(core::num) → core::int};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ static method multipleCaseSwitch(core::int x) → core::int {
return 0;
}
static method continueLabelSwitch(core::int x) → core::int {
#L7:
switch(x) {
#L7:
#L8:
case #C7:
{
x = x.{core::num::+}(100){(core::num) → core::int};
continue #L8;
continue #L9;
}
#L9:
#L10:
case #C8:
{
continue #L7;
continue #L8;
}
#L8:
#L9:
case #C2:
{
return x.{core::num::+}(3){(core::num) → core::int};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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.

// @dart=2.19

enum Enum<T> {
a<num>(),
b<String>(),
Expand Down
Loading

0 comments on commit 1896d94

Please sign in to comment.