blob: 0f77761ff8e7ed27df00ea1cc581996e43b30238 [file] [log] [blame]
// 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.
// This test verifies that when considering whether to perform a `.call` tearoff
// on the RHS of an assignment, the implementations use the unpromoted type of
// the variable (rather than the promoted type).
// NOTICE: This test checks the currently implemented behavior, even though the
// implemented behavior does not match the language specification. Until an
// official decision has been made about whether to change the implementation to
// match the specification, or vice versa, this regression test is intended to
// protect against inadvertent implementation changes.
import "package:expect/expect.dart";
import '../static_type_helper.dart';
class B {
Object call() => 'B.call called';
}
class C extends B {
String call() => 'C.call called';
}
void testClassPromoted() {
B x = C();
x as C;
x.expectStaticType<Exactly<C>>();
var y = x = C(); // No implicit tearoff of `.call`, no demotion
x.expectStaticType<Exactly<C>>();
Expect.type<C>(x);
Expect.equals('C.call called', x());
y.expectStaticType<Exactly<C>>();
Expect.type<C>(y);
Expect.equals('C.call called', y());
}
void testClassUnpromoted() {
B x = B();
var y = x = C(); // No implicit tearoff of `.call`, no promotion
x.expectStaticType<Exactly<B>>();
Expect.type<C>(x);
Expect.equals('C.call called', x());
y.expectStaticType<Exactly<C>>();
Expect.type<C>(y);
Expect.equals('C.call called', y());
}
void testFunctionPromoted() {
String f() => 'f called';
Object Function() x = f;
x as String Function();
x.expectStaticType<Exactly<String Function()>>();
var y = x = C(); // Implicit tearoff of `.call`, no demotion
x.expectStaticType<Exactly<String Function()>>();
Expect.type<String Function()>(x);
Expect.equals('C.call called', x());
y.expectStaticType<Exactly<String Function()>>();
Expect.type<String Function()>(y);
Expect.equals('C.call called', y());
}
void testFunctionUnpromoted() {
Object f() => 'f called';
Object Function() x = f;
var y = x = B(); // Implicit tearoff of `.call`, no promotion
x.expectStaticType<Exactly<Object Function()>>();
Expect.type<Object Function()>(x);
Expect.equals('B.call called', x());
y.expectStaticType<Exactly<Object Function()>>();
Expect.type<Object Function()>(y);
Expect.equals('B.call called', y());
}
void testObjectPromotedToClass() {
Object x = B();
x as B;
x.expectStaticType<Exactly<B>>();
var y = x = C(); // No implicit tearoff of `.call`, x remains promoted
x.expectStaticType<Exactly<B>>();
Expect.type<C>(x);
Expect.equals('C.call called', x());
y.expectStaticType<Exactly<C>>();
Expect.type<C>(y);
Expect.equals('C.call called', y());
}
void testObjectPromotedToFunction() {
Object f() => 'f called';
Object x = f;
x as Object Function();
x.expectStaticType<Exactly<Object Function()>>();
var y = x = B(); // No implicit tearoff of `.call`, demotes x
x.expectStaticType<Exactly<Object>>();
Expect.type<B>(x);
Expect.equals('B.call called', (x as B)());
y.expectStaticType<Exactly<B>>();
Expect.type<B>(y);
Expect.equals('B.call called', y());
}
void testObjectUnpromoted() {
Object x = 'initial value';
var y = x = B(); // No implicit tearoff of `.call`, no promotion
x.expectStaticType<Exactly<Object>>();
Expect.type<B>(x);
Expect.equals('B.call called', (x as B)());
y.expectStaticType<Exactly<B>>();
Expect.type<B>(y);
Expect.equals('B.call called', y());
}
main() {
testClassPromoted();
testClassUnpromoted();
testFunctionPromoted();
testFunctionUnpromoted();
testObjectPromotedToClass();
testObjectPromotedToFunction();
testObjectUnpromoted();
}