[cfe] Implement dispatchPatternSchema

Part of https://github.com/dart-lang/sdk/issues/49749

Change-Id: I9fa3ad41501422990d47bc637d46cbd22fdb54fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277004
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Chloe Stefantsova 2023-03-01 22:51:33 +00:00 committed by Commit Queue
parent 638ca5cfd4
commit ecef1a0137
11 changed files with 295 additions and 9 deletions

View file

@ -9606,11 +9606,63 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
DartType dispatchPatternSchema(TreeNode node) {
// The front end's representation of a switch cases currently doesn't have
// any support for patterns; each case is represented as an expression. So
// analyze it as a constant pattern.
return analyzeConstantPatternSchema();
DartType dispatchPatternSchema(Node node) {
if (node is AndPattern) {
return analyzeLogicalAndPatternSchema(node.left, node.right);
} else if (node is AssignedVariablePattern) {
return analyzeAssignedVariablePatternSchema(node.variable);
} else if (node is CastPattern) {
return analyzeCastPatternSchema();
} else if (node is ConstantPattern) {
return analyzeConstantPatternSchema();
} else if (node is ListPattern) {
return analyzeListPatternSchema(
elementType: node.typeArgument, elements: node.patterns);
} else if (node is MapPattern) {
return analyzeMapPatternSchema(
typeArguments: node.keyType != null && node.valueType != null
? new MapPatternTypeArguments<DartType>(
keyType: node.keyType!, valueType: node.valueType!)
: null,
elements: node.entries);
} else if (node is NamedPattern) {
return dispatchPatternSchema(node.pattern);
} else if (node is NullAssertPattern) {
return analyzeNullCheckOrAssertPatternSchema(node.pattern,
isAssert: true);
} else if (node is NullCheckPattern) {
return analyzeNullCheckOrAssertPatternSchema(node.pattern,
isAssert: false);
} else if (node is ObjectPattern) {
return analyzeObjectPatternSchema(node.type);
} else if (node is OrPattern) {
return analyzeLogicalOrPatternSchema(node.left, node.right);
} else if (node is RecordPattern) {
return analyzeRecordPatternSchema(
fields: <RecordPatternField<TreeNode, Pattern>>[
for (Pattern element in node.patterns)
if (element is NamedPattern)
new RecordPatternField<TreeNode, Pattern>(
node: element, name: element.name, pattern: element.pattern)
else
new RecordPatternField<TreeNode, Pattern>(
node: element, name: null, pattern: element)
]);
} else if (node is RelationalPattern) {
return analyzeRelationalPatternSchema();
} else if (node is RestPattern) {
// This pattern can't appear on it's own.
return const InvalidType();
} else if (node is VariablePattern) {
return analyzeDeclaredVariablePatternSchema(node.type);
} else if (node is WildcardPattern) {
return analyzeDeclaredVariablePatternSchema(node.type);
} else if (node is InvalidPattern) {
return const InvalidType();
} else {
return problems.unhandled("${node.runtimeType}", "dispatchPatternSchema",
node is TreeNode ? node.fileOffset : TreeNode.noOffset, helper.uri);
}
}
@override

View file

@ -517,7 +517,8 @@ class OperationsCfe
@override
DartType glb(DartType type1, DartType type2) {
throw new UnimplementedError('TODO(paulberry)');
return typeEnvironment.getStandardLowerBound(type1, type2,
isNonNullableByDefault: true);
}
@override
@ -546,7 +547,7 @@ class OperationsCfe
@override
DartType makeNullable(DartType type) {
throw new UnimplementedError('TODO(paulberry)');
return type.withDeclaredNullability(Nullability.nullable);
}
@override
@ -600,8 +601,18 @@ class OperationsCfe
@override
DartType? matchIterableType(DartType type) {
// TODO(scheglov): implement matchIterableType
throw new UnimplementedError('TODO(scheglov)');
if (type is! InterfaceType) {
return null;
} else {
InterfaceType? interfaceType = typeEnvironment.getTypeAsInstanceOf(type,
typeEnvironment.coreTypes.iterableClass, typeEnvironment.coreTypes,
isNonNullableByDefault: isNonNullableByDefault);
if (interfaceType == null) {
return null;
} else {
return interfaceType.typeArguments.single;
}
}
}
}

View file

@ -0,0 +1,17 @@
// 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.
class A {
int get foo => 0;
}
List<T> foo<T>(void Function(T) f) => throw 0;
test1() {
var <A>[var x] = foo((a) => a.foo);
}
test2() {
var [var x, ...y] = foo((e) => e);
}

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
get foo() → core::int
return 0;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
return throw 0;
static method test1() → dynamic {
self::A x;
{
final dynamic #0#0 = self::foo<self::A>((self::A a) → void => a.{self::A::foo}{core::int});
if(!(#0#0{core::List<self::A>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = x = #0#0{core::List<self::A>}.{core::List::[]}(0){(core::int) → self::A} in true)))
throw new _in::ReachabilityError::•();
}
}
static method test2() → dynamic {
core::Object? x;
core::List<core::Object?> y;
{
final dynamic #0#0 = self::foo<core::Object?>((core::Object? e) → void => e);
if(!(#0#0{core::List<core::Object?>}.{core::List::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool} && (let final dynamic #t2 = x = #0#0{core::List<core::Object?>}.{core::List::[]}(0){(core::int) → core::Object?} in true) && (let final dynamic #t3 = y = #0#0{core::List<core::Object?>}.{core::List::sublist}(1){(core::int, [core::int?]) → core::List<core::Object?>} in true)))
throw new _in::ReachabilityError::•();
}
}
constants {
#C1 = 1
}

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
get foo() → core::int
return 0;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
return throw 0;
static method test1() → dynamic {
self::A x;
{
final dynamic #0#0 = self::foo<self::A>((self::A a) → void => a.{self::A::foo}{core::int});
if(!(#0#0{core::List<self::A>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final self::A #t1 = x = #0#0{core::List<self::A>}.{core::List::[]}(0){(core::int) → self::A} in true)))
throw new _in::ReachabilityError::•();
}
}
static method test2() → dynamic {
core::Object? x;
core::List<core::Object?> y;
{
final dynamic #0#0 = self::foo<core::Object?>((core::Object? e) → void => e);
if(!(#0#0{core::List<core::Object?>}.{core::List::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool} && (let final core::Object? #t2 = x = #0#0{core::List<core::Object?>}.{core::List::[]}(0){(core::int) → core::Object?} in true) && (let final core::List<core::Object?> #t3 = y = #0#0{core::List<core::Object?>}.{core::List::sublist}(1){(core::int, [core::int?]) → core::List<core::Object?>} in true)))
throw new _in::ReachabilityError::•();
}
}
constants {
#C1 = 1
}

View file

@ -0,0 +1,7 @@
class A {
int get foo => 0;
}
List<T> foo<T>(void Function(T) f) => throw 0;
test1() {}
test2() {}

View file

@ -0,0 +1,8 @@
List<T> foo<T>(void Function(T) f) => throw 0;
class A {
int get foo => 0;
}
test1() {}
test2() {}

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
get foo() → core::int
return 0;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
return throw 0;
static method test1() → dynamic {
self::A x;
{
final dynamic #0#0 = self::foo<self::A>((self::A a) → void => a.{self::A::foo}{core::int});
if(!(#0#0{core::List<self::A>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = x = #0#0{core::List<self::A>}.{core::List::[]}(0){(core::int) → self::A} in true)))
throw new _in::ReachabilityError::•();
}
}
static method test2() → dynamic {
core::Object? x;
core::List<core::Object?> y;
{
final dynamic #0#0 = self::foo<core::Object?>((core::Object? e) → void => e);
if(!(#0#0{core::List<core::Object?>}.{core::List::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool} && (let final dynamic #t2 = x = #0#0{core::List<core::Object?>}.{core::List::[]}(0){(core::int) → core::Object?} in true) && (let final dynamic #t3 = y = #0#0{core::List<core::Object?>}.{core::List::sublist}(1){(core::int, [core::int?]) → core::List<core::Object?>} in true)))
throw new _in::ReachabilityError::•();
}
}
constants {
#C1 = 1
}

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
get foo() → core::int
return 0;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
return throw 0;
static method test1() → dynamic {
self::A x;
{
final dynamic #0#0 = self::foo<self::A>((self::A a) → void => a.{self::A::foo}{core::int});
if(!(#0#0{core::List<self::A>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = x = #0#0{core::List<self::A>}.{core::List::[]}(0){(core::int) → self::A} in true)))
throw new _in::ReachabilityError::•();
}
}
static method test2() → dynamic {
core::Object? x;
core::List<core::Object?> y;
{
final dynamic #0#0 = self::foo<core::Object?>((core::Object? e) → void => e);
if(!(#0#0{core::List<core::Object?>}.{core::List::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool} && (let final dynamic #t2 = x = #0#0{core::List<core::Object?>}.{core::List::[]}(0){(core::int) → core::Object?} in true) && (let final dynamic #t3 = y = #0#0{core::List<core::Object?>}.{core::List::sublist}(1){(core::int, [core::int?]) → core::List<core::Object?>} in true)))
throw new _in::ReachabilityError::•();
}
}
constants {
#C1 = 1
}

View file

@ -0,0 +1,16 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A extends core::Object {
synthetic constructor •() → self::A
;
get foo() → core::int
;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
;
static method test1() → dynamic
;
static method test2() → dynamic
;

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
get foo() → core::int
return 0;
}
static method foo<T extends core::Object? = dynamic>((self::foo::T%) → void f) → core::List<self::foo::T%>
return throw 0;
static method test1() → dynamic {
self::A x;
{
final dynamic #0#0 = self::foo<self::A>((self::A a) → void => a.{self::A::foo}{core::int});
if(!(#0#0{core::List<self::A>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final self::A #t1 = x = #0#0{core::List<self::A>}.{core::List::[]}(0){(core::int) → self::A} in true)))
throw new _in::ReachabilityError::•();
}
}
static method test2() → dynamic {
core::Object? x;
core::List<core::Object?> y;
{
final dynamic #0#0 = self::foo<core::Object?>((core::Object? e) → void => e);
if(!(#0#0{core::List<core::Object?>}.{core::List::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool} && (let final core::Object? #t2 = x = #0#0{core::List<core::Object?>}.{core::List::[]}(0){(core::int) → core::Object?} in true) && (let final core::List<core::Object?> #t3 = y = #0#0{core::List<core::Object?>}.{core::List::sublist}(1){(core::int, [core::int?]) → core::List<core::Object?>} in true)))
throw new _in::ReachabilityError::•();
}
}
constants {
#C1 = 1
}