[cfe] Make IfNullJudgment an internal expression

Change-Id: I68c81e10692823e9fad552272167c0bf87144db4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117942
Reviewed-by: Jens Johansen <jensj@google.com>
This commit is contained in:
Johnni Winther 2019-09-24 07:55:45 +00:00
parent 2777806901
commit 2b3541da57
26 changed files with 96 additions and 74 deletions

View file

@ -108,6 +108,8 @@ import 'kernel_api.dart';
import 'kernel_ast_api.dart';
import 'kernel_shadow_ast.dart';
import 'kernel_builder.dart';
// TODO(ahe): Remove this and ensure all nodes have a location.
@ -1517,16 +1519,7 @@ class BodyBuilder extends ScopeListener<JumpTarget>
void doIfNull(Token token) {
Expression b = popForValue();
Expression a = popForValue();
VariableDeclaration variable = new VariableDeclaration.forValue(a);
push(new IfNullJudgment(
variable,
forest.createConditionalExpression(
buildIsNull(new VariableGet(variable), offsetForToken(token), this),
token,
b,
null,
new VariableGet(variable)))
..fileOffset = offsetForToken(token));
push(new IfNullExpression(a, b)..fileOffset = offsetForToken(token));
}
/// Handle `a?.b(...)`.

View file

@ -49,6 +49,8 @@ class InferenceVisitor
return visitCompoundSuperIndexSet(node, typeContext);
case InternalExpressionKind.DeferredCheck:
return visitDeferredCheck(node, typeContext);
case InternalExpressionKind.IfNull:
return visitIfNull(node, typeContext);
case InternalExpressionKind.IfNullIndexSet:
return visitIfNullIndexSet(node, typeContext);
case InternalExpressionKind.IfNullPropertySet:
@ -684,13 +686,17 @@ class InferenceVisitor
skipTypeArgumentInference: true);
}
ExpressionInferenceResult visitIfNullJudgment(
IfNullJudgment node, DartType typeContext) {
ExpressionInferenceResult visitIfNull(
IfNullExpression node, DartType typeContext) {
// To infer `e0 ?? e1` in context K:
// - Infer e0 in context K to get T0
DartType lhsType =
inferrer.inferExpression(node.left, typeContext, true).inferredType;
node.variable.type = lhsType;
Member equalsMember = inferrer
.findInterfaceMember(lhsType, equalsName, node.fileOffset)
.member;
// - Let J = T0 if K is `?` else K.
// - Infer e1 in context J to get T1
DartType rhsType;
@ -708,8 +714,15 @@ class InferenceVisitor
// - Then the inferred type is T.
DartType inferredType =
inferrer.typeSchemaEnvironment.getStandardUpperBound(lhsType, rhsType);
node.body.staticType = inferredType;
return new ExpressionInferenceResult(inferredType);
VariableDeclaration variable = createVariable(node.left, lhsType);
MethodInvocation equalsNull = createEqualsNull(
node.left.fileOffset, createVariableGet(variable), equalsMember);
ConditionalExpression conditional = new ConditionalExpression(
equalsNull, node.right, createVariableGet(variable), inferredType);
Expression replacement = new Let(variable, conditional)
..fileOffset = node.fileOffset;
node.replaceWith(replacement);
return new ExpressionInferenceResult(inferredType, replacement);
}
@override

View file

@ -89,7 +89,6 @@ export 'kernel_shadow_ast.dart'
DeferredCheck,
FactoryConstructorInvocationJudgment,
FunctionDeclarationImpl,
IfNullJudgment,
InvalidSuperInitializerJudgment,
LoadLibraryTearOff,
MethodInvocationImpl,

View file

@ -188,6 +188,7 @@ enum InternalExpressionKind {
CompoundPropertySet,
CompoundSuperIndexSet,
DeferredCheck,
IfNull,
IfNullIndexSet,
IfNullPropertySet,
IfNullSet,
@ -495,29 +496,40 @@ class InvalidSuperInitializerJudgment extends LocalInitializer
}
}
/// Concrete shadow object representing an if-null expression.
/// Internal expression representing an if-null expression.
///
/// An if-null expression of the form `a ?? b` is represented as the kernel
/// expression:
/// An if-null expression of the form `a ?? b` is encoded as:
///
/// let v = a in v == null ? b : v
class IfNullJudgment extends Let implements ExpressionJudgment {
IfNullJudgment(VariableDeclaration variable, Expression body)
: super(variable, body);
///
class IfNullExpression extends InternalExpression {
Expression left;
Expression right;
IfNullExpression(this.left, this.right) {
left?.parent = this;
right?.parent = this;
}
@override
ConditionalExpression get body => super.body;
/// Returns the expression to the left of `??`.
Expression get left => variable.initializer;
/// Returns the expression to the right of `??`.
Expression get right => body.then;
InternalExpressionKind get kind => InternalExpressionKind.IfNull;
@override
ExpressionInferenceResult acceptInference(
InferenceVisitor visitor, DartType typeContext) {
return visitor.visitIfNullJudgment(this, typeContext);
void visitChildren(Visitor<dynamic> v) {
left?.accept(v);
right?.accept(v);
}
@override
void transformChildren(Transformer v) {
if (left != null) {
left = left.accept<TreeNode>(v);
left?.parent = this;
}
if (right != null) {
right = right.accept<TreeNode>(v);
right?.parent = this;
}
}
}

View file

@ -17,6 +17,6 @@ static method main() → dynamic {
self::Foo::staticField.{core::num::==}(null) ?{core::int*} self::Foo::staticField = 5 : null;
let final self::Foo* #t3 = foo in #t3.{core::Object::==}(null) ?{core::int*} null : #t3.{self::Foo::field}.{core::num::==}(null) ?{core::int*} #t3.{self::Foo::field} = 5 : null;
self::Foo::staticField.{core::num::==}(null) ?{core::int*} self::Foo::staticField = 5 : null;
core::int* intValue = let final core::int* #t4 = foo.{self::Foo::field} in #t4.==(null) ?{core::int*} 6 : #t4;
core::num* numValue = let final core::int* #t5 = foo.{self::Foo::field} in #t5.==(null) ?{core::num*} 4.5 : #t5;
core::int* intValue = let final core::int* #t4 = foo.{self::Foo::field} in #t4.{core::num::==}(null) ?{core::int*} 6 : #t4;
core::num* numValue = let final core::int* #t5 = foo.{self::Foo::field} in #t5.{core::num::==}(null) ?{core::num*} 4.5 : #t5;
}

View file

@ -17,6 +17,6 @@ static method main() → dynamic {
self::Foo::staticField.{core::num::==}(null) ?{core::int*} self::Foo::staticField = 5 : null;
let final self::Foo* #t3 = foo in #t3.{core::Object::==}(null) ?{core::int*} null : #t3.{self::Foo::field}.{core::num::==}(null) ?{core::int*} #t3.{self::Foo::field} = 5 : null;
self::Foo::staticField.{core::num::==}(null) ?{core::int*} self::Foo::staticField = 5 : null;
core::int* intValue = let final core::int* #t4 = foo.{self::Foo::field} in #t4.==(null) ?{core::int*} 6 : #t4;
core::num* numValue = let final core::int* #t5 = foo.{self::Foo::field} in #t5.==(null) ?{core::num*} 4.5 : #t5;
core::int* intValue = let final core::int* #t4 = foo.{self::Foo::field} in #t4.{core::num::==}(null) ?{core::int*} 6 : #t4;
core::num* numValue = let final core::int* #t5 = foo.{self::Foo::field} in #t5.{core::num::==}(null) ?{core::num*} 4.5 : #t5;
}

View file

@ -9,20 +9,21 @@ void foo<E>(C<E> c, int cmp(E a, E b)) {}
class C<E> {
void barA([int cmp(E a, E b)]) {
/*@ typeArgs=C::E* */ foo(this, cmp ?? _default);
/*@ typeArgs=C::E* */ foo(this, cmp /*@ target=Object::== */ ?? _default);
}
void barB([int cmp(E a, E b)]) {
/*@ typeArgs=C::E* */ foo(this, cmp ?? (_default as int Function(E, E)));
/*@ typeArgs=C::E* */ foo(
this, cmp /*@ target=Object::== */ ?? (_default as int Function(E, E)));
}
void barC([int cmp(E a, E b)]) {
int Function(E, E) v = _default;
/*@ typeArgs=C::E* */ foo(this, cmp ?? v);
/*@ typeArgs=C::E* */ foo(this, cmp /*@ target=Object::== */ ?? v);
}
void barD([int cmp(E a, E b)]) {
foo<E>(this, cmp ?? _default);
foo<E>(this, cmp /*@ target=Object::== */ ?? _default);
}
void barE([int cmp(E a, E b)]) {

View file

@ -7,17 +7,17 @@ class C<E extends core::Object* = dynamic> extends core::Object {
: super core::Object::•()
;
method barA([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = cmp in #t1.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = cmp in #t1.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
}
method barB([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t2 = cmp in #t2.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} (#C2) as (self::C::E*, self::C::E*) →* core::int* : #t2);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t2 = cmp in #t2.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} (#C2) as (self::C::E*, self::C::E*) →* core::int* : #t2);
}
method barC([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
(self::C::E*, self::C::E*) →* core::int* v = #C2;
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t3 = cmp in #t3.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} v : #t3);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t3 = cmp in #t3.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} v : #t3);
}
method barD([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t4 = cmp in #t4.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t4);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t4 = cmp in #t4.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t4);
}
method barE([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, cmp.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : cmp);

View file

@ -7,17 +7,17 @@ class C<E extends core::Object* = dynamic> extends core::Object {
: super core::Object::•()
;
method barA([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = cmp in #t1.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = cmp in #t1.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
}
method barB([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t2 = cmp in #t2.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} (#C2) as (self::C::E*, self::C::E*) →* core::int* : #t2);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t2 = cmp in #t2.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} (#C2) as (self::C::E*, self::C::E*) →* core::int* : #t2);
}
method barC([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
(self::C::E*, self::C::E*) →* core::int* v = #C2;
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t3 = cmp in #t3.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} v : #t3);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t3 = cmp in #t3.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} v : #t3);
}
method barD([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t4 = cmp in #t4.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t4);
self::foo<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t4 = cmp in #t4.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t4);
}
method barE([(self::C::E*, self::C::E*) →* core::int* cmp = #C1]) → void {
self::foo<self::C::E*>(this, cmp.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : cmp);

View file

@ -12,7 +12,7 @@ void main() {
var /*@ type=Iterable<List<String*>*>* */ i1 =
l. /*@target=Iterable::map*/ /*@ typeArgs=List<String*>* */ map(
/*@ returnType=List<String*>* */ (/*@ type=List<String*>* */ ll) =>
ll ?? /*@ typeArgs=String* */ []);
ll /*@ target=List::== */ ?? /*@ typeArgs=String* */ []);
var /*@ type=Iterable<int*>* */ i2 =
i1. /*@target=Iterable::map*/ /*@ typeArgs=int* */ map(
/*@ returnType=int* */ (List<String> l) =>

View file

@ -4,7 +4,7 @@ import "dart:core" as core;
static method main() → void {
core::List<core::List<core::String*>*>* l = <core::List<core::String*>*>[<core::String*>["hi", "world"]];
core::Iterable<core::List<core::String*>*>* i1 = l.{core::Iterable::map}<core::List<core::String*>*>((core::List<core::String*>* ll) → core::List<core::String*>* => let final core::List<core::String*>* #t1 = ll in #t1.==(null) ?{core::List<core::String*>*} <core::String*>[] : #t1);
core::Iterable<core::List<core::String*>*>* i1 = l.{core::Iterable::map}<core::List<core::String*>*>((core::List<core::String*>* ll) → core::List<core::String*>* => let final core::List<core::String*>* #t1 = ll in #t1.{core::List::==}(null) ?{core::List<core::String*>*} <core::String*>[] : #t1);
core::Iterable<core::int*>* i2 = i1.{core::Iterable::map}<core::int*>((core::List<core::String*>* l) → core::int* => l.{core::List::length});
core::print(i2);
}

View file

@ -4,7 +4,7 @@ import "dart:core" as core;
static method main() → void {
core::List<core::List<core::String*>*>* l = <core::List<core::String*>*>[<core::String*>["hi", "world"]];
core::Iterable<core::List<core::String*>*>* i1 = l.{core::Iterable::map}<core::List<core::String*>*>((core::List<core::String*>* ll) → core::List<core::String*>* => let final core::List<core::String*>* #t1 = ll in #t1.==(null) ?{core::List<core::String*>*} <core::String*>[] : #t1);
core::Iterable<core::List<core::String*>*>* i1 = l.{core::Iterable::map}<core::List<core::String*>*>((core::List<core::String*>* ll) → core::List<core::String*>* => let final core::List<core::String*>* #t1 = ll in #t1.{core::List::==}(null) ?{core::List<core::String*>*} <core::String*>[] : #t1);
core::Iterable<core::int*>* i2 = i1.{core::Iterable::map}<core::int*>((core::List<core::String*>* l) → core::int* => l.{core::List::length});
core::print(i2);
}

View file

@ -18,18 +18,20 @@ void test() {
MyFuture<int> f;
Future<int> t1 = f. /*@ typeArgs=int* */ /*@target=MyFuture::then*/ then(
/*@ returnType=Future<int*>* */ (/*@ type=int* */ x) async =>
x ?? await new Future<int>.value(3));
x /*@ target=num::== */ ?? await new Future<int>.value(3));
Future<int> t2 = f. /*@ typeArgs=int* */ /*@target=MyFuture::then*/ then(
/*@ returnType=Future<int*>* */ (/*@ type=int* */ x) async {
return /*info:DOWN_CAST_COMPOSITE*/ await x ?? new Future<int>.value(3);
return /*info:DOWN_CAST_COMPOSITE*/ await x /*@ target=num::== */ ??
new Future<int>.value(3);
});
Future<int> t5 = f. /*@ typeArgs=int* */ /*@target=MyFuture::then*/ then(
/*error:INVALID_CAST_FUNCTION_EXPR*/
/*@ returnType=FutureOr<int*>* */ (/*@ type=int* */ x) =>
x ?? new Future<int>.value(3));
x /*@ target=num::== */ ?? new Future<int>.value(3));
Future<int> t6 = f. /*@ typeArgs=int* */ /*@target=MyFuture::then*/ then(
/*@ returnType=FutureOr<int*>* */ (/*@ type=int* */ x) {
return /*info:DOWN_CAST_COMPOSITE*/ x ?? new Future<int>.value(3);
return /*info:DOWN_CAST_COMPOSITE*/ x /*@ target=num::== */ ??
new Future<int>.value(3);
});
}

View file

@ -25,13 +25,13 @@ class MyFuture<T extends core::Object* = dynamic> extends core::Object implement
}
static method test() → void {
self::MyFuture<core::int*>* f;
asy::Future<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* async => let final core::int* #t1 = x in #t1.==(null) ?{core::int*} await asy::Future::value<core::int*>(3) : #t1);
asy::Future<core::int*>* t1 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* async => let final core::int* #t1 = x in #t1.{core::num::==}(null) ?{core::int*} await asy::Future::value<core::int*>(3) : #t1);
asy::Future<core::int*>* t2 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::Future<core::int*>* async {
return (let final core::int* #t2 = await x in #t2.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t2) as{TypeError} asy::FutureOr<core::int*>*;
return (let final core::int* #t2 = await x in #t2.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t2) as{TypeError} asy::FutureOr<core::int*>*;
});
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* => (let final core::int* #t3 = x in #t3.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t3) as{TypeError} asy::FutureOr<core::int*>*);
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* => (let final core::int* #t3 = x in #t3.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t3) as{TypeError} asy::FutureOr<core::int*>*);
asy::Future<core::int*>* t6 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* {
return (let final core::int* #t4 = x in #t4.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
return (let final core::int* #t4 = x in #t4.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
});
}
static method main() → dynamic {}

View file

@ -40,7 +40,7 @@ static method test() → void {
#L1:
{
final core::int* #t1 = x;
if(#t1.==(null)) {
if(#t1.{core::num::==}(null)) {
[yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
:async_temporary_0 = :result;
}
@ -76,7 +76,7 @@ static method test() → void {
#L2:
{
[yield] let dynamic #t3 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
:return_value = (let final core::int* #t4 = :result in #t4.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
:return_value = (let final core::int* #t4 = :result in #t4.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
break #L2;
}
asy::_completeOnAsyncReturn(:async_completer, :return_value);
@ -91,9 +91,9 @@ static method test() → void {
:async_completer.start(:async_op);
return :async_completer.{asy::Completer::future};
});
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* => (let final core::int* #t5 = x in #t5.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t5) as{TypeError} asy::FutureOr<core::int*>*);
asy::Future<core::int*>* t5 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* => (let final core::int* #t5 = x in #t5.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t5) as{TypeError} asy::FutureOr<core::int*>*);
asy::Future<core::int*>* t6 = f.{self::MyFuture::then}<core::int*>((core::int* x) → asy::FutureOr<core::int*>* {
return (let final core::int* #t6 = x in #t6.==(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t6) as{TypeError} asy::FutureOr<core::int*>*;
return (let final core::int* #t6 = x in #t6.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t6) as{TypeError} asy::FutureOr<core::int*>*;
});
}
static method main() → dynamic {}

View file

@ -7,7 +7,8 @@ library test;
abstract class C<E> {
void sort([int compare(E a, E b)]) {
/*@ typeArgs=C::E* */ sort2(this, compare ?? _compareAny);
/*@ typeArgs=C::E* */ sort2(
this, compare /*@ target=Object::== */ ?? _compareAny);
}
static int _compareAny(a, b) {

View file

@ -7,7 +7,7 @@ abstract class C<E extends core::Object* = dynamic> extends core::Object {
: super core::Object::•()
;
method sort([(self::C::E*, self::C::E*) →* core::int* compare = #C1]) → void {
self::C::sort2<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = compare in #t1.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
self::C::sort2<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = compare in #t1.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
}
static method _compareAny(dynamic a, dynamic b) → core::int* {
throw "unimplemented";

View file

@ -7,7 +7,7 @@ abstract class C<E extends core::Object* = dynamic> extends core::Object {
: super core::Object::•()
;
method sort([(self::C::E*, self::C::E*) →* core::int* compare = #C1]) → void {
self::C::sort2<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = compare in #t1.==(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
self::C::sort2<self::C::E*>(this, let final (self::C::E*, self::C::E*) →* core::int* #t1 = compare in #t1.{core::Object::==}(null) ?{(self::C::E*, self::C::E*) →* core::int*} #C2 : #t1);
}
static method _compareAny(dynamic a, dynamic b) → core::int* {
throw "unimplemented";

View file

@ -7,6 +7,7 @@ library test;
main() {
List<int> x;
var /*@ type=List<int*>* */ y = x ?? /*@ typeArgs=int* */ [];
var /*@ type=List<int*>* */ y =
x /*@ target=List::== */ ?? /*@ typeArgs=int* */ [];
List<int> z = y;
}

View file

@ -4,6 +4,6 @@ import "dart:core" as core;
static method main() → dynamic {
core::List<core::int*>* x;
core::List<core::int*>* y = let final core::List<core::int*>* #t1 = x in #t1.==(null) ?{core::List<core::int*>*} <core::int*>[] : #t1;
core::List<core::int*>* y = let final core::List<core::int*>* #t1 = x in #t1.{core::List::==}(null) ?{core::List<core::int*>*} <core::int*>[] : #t1;
core::List<core::int*>* z = y;
}

View file

@ -4,6 +4,6 @@ import "dart:core" as core;
static method main() → dynamic {
core::List<core::int*>* x;
core::List<core::int*>* y = let final core::List<core::int*>* #t1 = x in #t1.==(null) ?{core::List<core::int*>*} <core::int*>[] : #t1;
core::List<core::int*>* y = let final core::List<core::int*>* #t1 = x in #t1.{core::List::==}(null) ?{core::List<core::int*>*} <core::int*>[] : #t1;
core::List<core::int*>* z = y;
}

View file

@ -7,5 +7,5 @@ library test;
main() {
List<int> x;
List<num> y = x ?? /*@ typeArgs=num* */ [];
List<num> y = x /*@ target=List::== */ ?? /*@ typeArgs=num* */ [];
}

View file

@ -4,5 +4,5 @@ import "dart:core" as core;
static method main() → dynamic {
core::List<core::int*>* x;
core::List<core::num*>* y = let final core::List<core::int*>* #t1 = x in #t1.==(null) ?{core::List<core::num*>*} <core::num*>[] : #t1;
core::List<core::num*>* y = let final core::List<core::int*>* #t1 = x in #t1.{core::List::==}(null) ?{core::List<core::num*>*} <core::num*>[] : #t1;
}

View file

@ -4,5 +4,5 @@ import "dart:core" as core;
static method main() → dynamic {
core::List<core::int*>* x;
core::List<core::num*>* y = let final core::List<core::int*>* #t1 = x in #t1.==(null) ?{core::List<core::num*>*} <core::num*>[] : #t1;
core::List<core::num*>* y = let final core::List<core::int*>* #t1 = x in #t1.{core::List::==}(null) ?{core::List<core::num*>*} <core::num*>[] : #t1;
}

View file

@ -33,7 +33,7 @@ static method main() → dynamic {
self::test_nullable_function_type_formal_param(f: () → core::int => 2);
}
static method test_nullable_function_type_formal_param({() →? core::int f = #C1}) → core::int {
return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
return let final core::int #t1 = f.call() in #t1.{core::num::==}(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
}
constants {

View file

@ -33,7 +33,7 @@ static method main() → dynamic {
self::test_nullable_function_type_formal_param(f: () → core::int => 2);
}
static method test_nullable_function_type_formal_param({() →? core::int f = #C1}) → core::int {
return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
return let final core::int #t1 = f.call() in #t1.{core::num::==}(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
}
constants {