[cfe] Instance method invocations for const functions.

Change-Id: I2e7d8b3859f09dd906e78e6e6d44722a0aabaeb6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196140
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Kallen Tu 2021-04-26 18:11:47 +00:00 committed by commit-bot@chromium.org
parent b101a7d002
commit 8a0801572c
11 changed files with 1085 additions and 32 deletions

View file

@ -6406,7 +6406,9 @@ class BodyBuilder extends ScopeListener<JumpTarget>
{bool isConstantExpression: false,
bool isNullAware: false,
bool isSuper: false}) {
if (constantContext != ConstantContext.none && !isConstantExpression) {
if (constantContext != ConstantContext.none &&
!isConstantExpression &&
!enableConstFunctionsInLibrary) {
return buildProblem(
fasta.templateNotConstantExpression
.withArguments('Method invocation'),

View file

@ -1207,7 +1207,10 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
if (env.isEmpty) {
// We only try to evaluate the same [node] *once* within an empty
// environment.
if (nodeCache.containsKey(node)) {
// For const functions, recompute getters instead of using the cached
// value.
bool isGetter = node is InstanceGet || node is PropertyGet;
if (nodeCache.containsKey(node) && !(enableConstFunctions && isGetter)) {
result = nodeCache[node];
if (result == null) {
// [null] is a sentinel value only used when still evaluating the same
@ -2088,9 +2091,17 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
}
Constant _handleInvocation(
Expression node, Name name, Constant receiver, List<Constant> arguments) {
Expression node, Name name, Constant receiver, List<Constant> arguments,
{List<DartType> typeArguments, Map<String, Constant> namedArguments}) {
final String op = name.text;
// TODO(kallentu): Handle all constant toString methods.
if (receiver is PrimitiveConstant &&
op == 'toString' &&
enableConstFunctions) {
return new StringConstant(receiver.value.toString());
}
// Handle == and != first (it's common between all types). Since `a != b` is
// parsed as `!(a == b)` it is handled implicitly through ==.
if (arguments.length == 1 && op == '==') {
@ -2262,31 +2273,38 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
}
}
} else if (receiver is InstanceConstant && enableConstFunctions) {
if (arguments.length == 1) {
final Constant other = arguments[0];
if (receiver.classNode.name == '_ImmutableMap') {
switch (op) {
case '[]':
final ListConstant values = receiver.fieldValues.entries
.firstWhere(
(entry) => entry.key.canonicalName.name == '_kvPairs',
orElse: () => null)
.value;
assert(values != null);
final Class instanceClass = receiver.classNode;
assert(typeEnvironment.hierarchy is ClassHierarchy);
final Member member = (typeEnvironment.hierarchy as ClassHierarchy)
.getDispatchTarget(instanceClass, name);
final FunctionNode function = member.function;
// Each i index element in [values] is a key whose value is the
// i+1 index element.
int keyIndex = values.entries.indexOf(other);
if (keyIndex != -1) {
int valueIndex = keyIndex + 1;
assert(valueIndex != values.entries.length);
return values.entries[valueIndex];
} else {
// Null value if key is not in the map.
return new NullConstant();
}
// TODO(kallentu): Implement [Object] class methods which have backend
// specific functions that cannot be run by the constant evaluator.
final bool isObjectMember = member.enclosingClass != null &&
member.enclosingClass.name == "Object";
if (function != null && !isObjectMember) {
return withNewInstanceBuilder(instanceClass, typeArguments, () {
final EvaluationEnvironment newEnv = new EvaluationEnvironment();
for (int i = 0; i < instanceClass.typeParameters.length; i++) {
newEnv.addTypeParameterValue(
instanceClass.typeParameters[i], receiver.typeArguments[i]);
}
}
// Ensure that fields are visible for instance access.
receiver.fieldValues.forEach((Reference fieldRef, Constant value) =>
instanceBuilder.setFieldValue(fieldRef.asField, value));
return _handleFunctionInvocation(
function, receiver.typeArguments, arguments, namedArguments,
functionEnvironment: newEnv);
});
}
switch (op) {
case 'toString':
// Default value for toString() of instances.
return new StringConstant(
"Instance of '${receiver.classReference.toStringInternal()}'");
}
}
@ -2324,7 +2342,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
assert(_gotError == null);
assert(arguments != null);
if (enableConstFunctions && receiver is FunctionValue) {
if (enableConstFunctions) {
// Evaluate type arguments of the method invoked.
List<DartType> types = _evaluateTypeArguments(node, node.arguments);
if (types == null && _gotError != null) {
@ -2346,9 +2364,14 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
assert(_gotError == null);
assert(named != null);
return _handleFunctionInvocation(
receiver.function, types, arguments, named,
functionEnvironment: receiver.environment);
if (receiver is FunctionValue) {
return _handleFunctionInvocation(
receiver.function, types, arguments, named,
functionEnvironment: receiver.environment);
}
return _handleInvocation(node, node.name, receiver, arguments,
typeArguments: types, namedArguments: named);
}
if (shouldBeUnevaluated) {
@ -3940,8 +3963,13 @@ class EvaluationEnvironment {
}
DartType substituteType(DartType type) {
if (_typeVariables.isEmpty) return type;
return substitute(type, _typeVariables);
if (_typeVariables.isEmpty) return _parent?.substituteType(type) ?? type;
final DartType substitutedType = substitute(type, _typeVariables);
if (identical(substitutedType, type) && _parent != null) {
// No distinct type created, substitute type in parent.
return _parent.substituteType(type);
}
return substitutedType;
}
}

View file

@ -0,0 +1,106 @@
// Copyright (c) 2021, 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.
// Tests invocations of instance functions with const functions.
import "package:expect/expect.dart";
class A {
const A();
}
class B {
const B();
@override
String toString() => "B";
}
class C {
final int y;
const C(this.y);
int fn() {
if (y == 1) return 100;
return 200;
}
}
class D extends C {
const D(int y) : super(y);
@override
int fn() => 300;
}
class E extends C {
const E(int y) : super(y);
}
class F<T, U, V> {
const F();
U fn(U x) => x;
}
class G<T> extends F<T, String, num> {
const G();
}
const var1 = fn();
String fn() => const A().toString();
const toString1 = const A().toString();
const var2 = fn2();
String fn2() => const B().toString();
const toString2 = const B().toString();
const var3 = fn3();
const var4 = fn4();
int fn3() => const C(0).fn();
int fn4() => const C(1).fn();
const fnVal1 = const C(0).fn();
const fnVal2 = const C(1).fn();
const var5 = fn5();
int fn5() => const D(1).fn();
const fnVal3 = const D(1).fn();
const var6 = fn6();
int fn6() => const E(1).fn();
const fnVal4 = const E(0).fn();
const var7 = fn7();
String fn7() => const F<int, String, num>().fn("string");
const fnVal5 = const F<int, String, num>().fn("string");
const var8 = fn8();
String fn8() => const G<int>().fn("string");
const fnVal6 = const G<int>().fn("string");
void main() {
Expect.equals(var1, const A().toString());
Expect.equals(toString1, const A().toString());
Expect.equals(var2, const B().toString());
Expect.equals(toString2, const B().toString());
Expect.equals(var3, 200);
Expect.equals(var4, 100);
Expect.equals(fnVal1, 200);
Expect.equals(fnVal2, 100);
Expect.equals(var5, 300);
Expect.equals(fnVal3, 300);
Expect.equals(var6, 100);
Expect.equals(fnVal4, 200);
Expect.equals(var7, "string");
Expect.equals(fnVal5, "string");
Expect.equals(var8, "string");
Expect.equals(fnVal6, "string");
}

View file

@ -0,0 +1,138 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class A extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::A
: super core::Object::•()
;
}
class B extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::B
: super core::Object::•()
;
@#C1
method toString() → core::String
return "B";
}
class C extends core::Object /*hasConstConstructor*/ {
final field core::int y;
const constructor •(core::int y) → self::C
: self::C::y = y, super core::Object::•()
;
method fn() → core::int {
if(this.{self::C::y}.{core::num::==}(1))
return 100;
return 200;
}
}
class D extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::D
: super self::C::•(y)
;
@#C1
method fn() → core::int
return 300;
}
class E extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::E
: super self::C::•(y)
;
}
class F<T extends core::Object? = dynamic, U extends core::Object? = dynamic, V extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::F<self::F::T%, self::F::U%, self::F::V%>
: super core::Object::•()
;
method fn(generic-covariant-impl self::F::U% x) → self::F::U%
return x;
}
class G<T extends core::Object? = dynamic> extends self::F<self::G::T%, core::String, core::num> /*hasConstConstructor*/ {
const constructor •() → self::G<self::G::T%>
: super self::F::•()
;
}
static const field core::String var1 = #C2;
static const field core::String toString1 = #C2;
static const field core::String var2 = #C3;
static const field core::String toString2 = #C3;
static const field core::int var3 = #C4;
static const field core::int var4 = #C5;
static const field core::int fnVal1 = #C4;
static const field core::int fnVal2 = #C5;
static const field core::int var5 = #C6;
static const field core::int fnVal3 = #C6;
static const field core::int var6 = #C5;
static const field core::int fnVal4 = #C4;
static const field core::String var7 = #C7;
static const field core::String fnVal5 = #C7;
static const field core::String var8 = #C7;
static const field core::String fnVal6 = #C7;
static method fn() → core::String
return (#C8).{core::Object::toString}();
static method fn2() → core::String
return (#C9).{self::B::toString}();
static method fn3() → core::int
return (#C11).{self::C::fn}();
static method fn4() → core::int
return (#C13).{self::C::fn}();
static method fn5() → core::int
return (#C14).{self::D::fn}();
static method fn6() → core::int
return (#C15).{self::C::fn}();
static method fn7() → core::String
return (#C16).{self::F::fn}("string");
static method fn8() → core::String
return (#C17).{self::F::fn}("string");
static method main() → void {
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
}
constants {
#C1 = core::_Override {}
#C2 = "Instance of 'A'"
#C3 = "B"
#C4 = 200
#C5 = 100
#C6 = 300
#C7 = "string"
#C8 = self::A {}
#C9 = self::B {}
#C10 = 0
#C11 = self::C {y:#C10}
#C12 = 1
#C13 = self::C {y:#C12}
#C14 = self::D {y:#C12}
#C15 = self::E {y:#C12}
#C16 = self::F<core::int, core::String, core::num> {}
#C17 = self::G<core::int> {}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_instance_methods.dart:
- A. (from org-dartlang-testcase:///const_functions_instance_methods.dart:10:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
- B. (from org-dartlang-testcase:///const_functions_instance_methods.dart:14:9)
- C. (from org-dartlang-testcase:///const_functions_instance_methods.dart:23:9)
- D. (from org-dartlang-testcase:///const_functions_instance_methods.dart:32:9)
- E. (from org-dartlang-testcase:///const_functions_instance_methods.dart:39:9)
- F. (from org-dartlang-testcase:///const_functions_instance_methods.dart:43:9)
- G. (from org-dartlang-testcase:///const_functions_instance_methods.dart:48:9)

View file

@ -0,0 +1,138 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class A extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::A
: super core::Object::•()
;
}
class B extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::B
: super core::Object::•()
;
@#C1
method toString() → core::String
return "B";
}
class C extends core::Object /*hasConstConstructor*/ {
final field core::int y;
const constructor •(core::int y) → self::C
: self::C::y = y, super core::Object::•()
;
method fn() → core::int {
if(this.{self::C::y}.{core::num::==}(1))
return 100;
return 200;
}
}
class D extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::D
: super self::C::•(y)
;
@#C1
method fn() → core::int
return 300;
}
class E extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::E
: super self::C::•(y)
;
}
class F<T extends core::Object? = dynamic, U extends core::Object? = dynamic, V extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::F<self::F::T%, self::F::U%, self::F::V%>
: super core::Object::•()
;
method fn(generic-covariant-impl self::F::U% x) → self::F::U%
return x;
}
class G<T extends core::Object? = dynamic> extends self::F<self::G::T%, core::String, core::num> /*hasConstConstructor*/ {
const constructor •() → self::G<self::G::T%>
: super self::F::•()
;
}
static const field core::String var1 = #C2;
static const field core::String toString1 = #C2;
static const field core::String var2 = #C3;
static const field core::String toString2 = #C3;
static const field core::int var3 = #C4;
static const field core::int var4 = #C5;
static const field core::int fnVal1 = #C4;
static const field core::int fnVal2 = #C5;
static const field core::int var5 = #C6;
static const field core::int fnVal3 = #C6;
static const field core::int var6 = #C5;
static const field core::int fnVal4 = #C4;
static const field core::String var7 = #C7;
static const field core::String fnVal5 = #C7;
static const field core::String var8 = #C7;
static const field core::String fnVal6 = #C7;
static method fn() → core::String
return (#C8).{core::Object::toString}();
static method fn2() → core::String
return (#C9).{self::B::toString}();
static method fn3() → core::int
return (#C11).{self::C::fn}();
static method fn4() → core::int
return (#C13).{self::C::fn}();
static method fn5() → core::int
return (#C14).{self::D::fn}();
static method fn6() → core::int
return (#C15).{self::C::fn}();
static method fn7() → core::String
return (#C16).{self::F::fn}("string");
static method fn8() → core::String
return (#C17).{self::F::fn}("string");
static method main() → void {
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
}
constants {
#C1 = core::_Override {}
#C2 = "Instance of 'A'"
#C3 = "B"
#C4 = 200
#C5 = 100
#C6 = 300
#C7 = "string"
#C8 = self::A {}
#C9 = self::B {}
#C10 = 0
#C11 = self::C {y:#C10}
#C12 = 1
#C13 = self::C {y:#C12}
#C14 = self::D {y:#C12}
#C15 = self::E {y:#C12}
#C16 = self::F<core::int, core::String, core::num> {}
#C17 = self::G<core::int> {}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_instance_methods.dart:
- A. (from org-dartlang-testcase:///const_functions_instance_methods.dart:10:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
- B. (from org-dartlang-testcase:///const_functions_instance_methods.dart:14:9)
- C. (from org-dartlang-testcase:///const_functions_instance_methods.dart:23:9)
- D. (from org-dartlang-testcase:///const_functions_instance_methods.dart:32:9)
- E. (from org-dartlang-testcase:///const_functions_instance_methods.dart:39:9)
- F. (from org-dartlang-testcase:///const_functions_instance_methods.dart:43:9)
- G. (from org-dartlang-testcase:///const_functions_instance_methods.dart:48:9)

View file

@ -0,0 +1,62 @@
import "package:expect/expect.dart";
class A {
const A();
}
class B {
const B();
@override
String toString() => "B";
}
class C {
final int y;
const C(this.y);
int fn() {}
}
class D extends C {
const D(int y) : super(y);
@override
int fn() => 300;
}
class E extends C {
const E(int y) : super(y);
}
class F<T, U, V> {
const F();
U fn(U x) => x;
}
class G<T> extends F<T, String, num> {
const G();
}
const var1 = fn();
String fn() => const A().toString();
const toString1 = const A().toString();
const var2 = fn2();
String fn2() => const B().toString();
const toString2 = const B().toString();
const var3 = fn3();
const var4 = fn4();
int fn3() => const C(0).fn();
int fn4() => const C(1).fn();
const fnVal1 = const C(0).fn();
const fnVal2 = const C(1).fn();
const var5 = fn5();
int fn5() => const D(1).fn();
const fnVal3 = const D(1).fn();
const var6 = fn6();
int fn6() => const E(1).fn();
const fnVal4 = const E(0).fn();
const var7 = fn7();
String fn7() => const F<int, String, num>().fn("string");
const fnVal5 = const F<int, String, num>().fn("string");
const var8 = fn8();
String fn8() => const G<int>().fn("string");
const fnVal6 = const G<int>().fn("string");
void main() {}

View file

@ -0,0 +1,63 @@
import "package:expect/expect.dart";
String fn() => const A().toString();
String fn2() => const B().toString();
String fn7() => const F<int, String, num>().fn("string");
String fn8() => const G<int>().fn("string");
class A {
const A();
}
class B {
@override
String toString() => "B";
const B();
}
class C {
const C(this.y);
final int y;
int fn() {}
}
class D extends C {
const D(int y) : super(y);
@override
int fn() => 300;
}
class E extends C {
const E(int y) : super(y);
}
class F<T, U, V> {
U fn(U x) => x;
const F();
}
class G<T> extends F<T, String, num> {
const G();
}
const fnVal1 = const C(0).fn();
const fnVal2 = const C(1).fn();
const fnVal3 = const D(1).fn();
const fnVal4 = const E(0).fn();
const fnVal5 = const F<int, String, num>().fn("string");
const fnVal6 = const G<int>().fn("string");
const toString1 = const A().toString();
const toString2 = const B().toString();
const var1 = fn();
const var2 = fn2();
const var3 = fn3();
const var4 = fn4();
const var5 = fn5();
const var6 = fn6();
const var7 = fn7();
const var8 = fn8();
int fn3() => const C(0).fn();
int fn4() => const C(1).fn();
int fn5() => const D(1).fn();
int fn6() => const E(1).fn();
void main() {}

View file

@ -0,0 +1,138 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class A extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::A
: super core::Object::•()
;
}
class B extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::B
: super core::Object::•()
;
@#C1
method toString() → core::String
return "B";
}
class C extends core::Object /*hasConstConstructor*/ {
final field core::int y;
const constructor •(core::int y) → self::C
: self::C::y = y, super core::Object::•()
;
method fn() → core::int {
if(this.{self::C::y}.{core::num::==}(1))
return 100;
return 200;
}
}
class D extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::D
: super self::C::•(y)
;
@#C1
method fn() → core::int
return 300;
}
class E extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::E
: super self::C::•(y)
;
}
class F<T extends core::Object? = dynamic, U extends core::Object? = dynamic, V extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::F<self::F::T%, self::F::U%, self::F::V%>
: super core::Object::•()
;
method fn(generic-covariant-impl self::F::U% x) → self::F::U%
return x;
}
class G<T extends core::Object? = dynamic> extends self::F<self::G::T%, core::String, core::num> /*hasConstConstructor*/ {
const constructor •() → self::G<self::G::T%>
: super self::F::•()
;
}
static const field core::String var1 = #C2;
static const field core::String toString1 = #C2;
static const field core::String var2 = #C3;
static const field core::String toString2 = #C3;
static const field core::int var3 = #C4;
static const field core::int var4 = #C5;
static const field core::int fnVal1 = #C4;
static const field core::int fnVal2 = #C5;
static const field core::int var5 = #C6;
static const field core::int fnVal3 = #C6;
static const field core::int var6 = #C5;
static const field core::int fnVal4 = #C4;
static const field core::String var7 = #C7;
static const field core::String fnVal5 = #C7;
static const field core::String var8 = #C7;
static const field core::String fnVal6 = #C7;
static method fn() → core::String
return (#C8).{core::Object::toString}();
static method fn2() → core::String
return (#C9).{self::B::toString}();
static method fn3() → core::int
return (#C11).{self::C::fn}();
static method fn4() → core::int
return (#C13).{self::C::fn}();
static method fn5() → core::int
return (#C14).{self::D::fn}();
static method fn6() → core::int
return (#C15).{self::C::fn}();
static method fn7() → core::String
return (#C16).{self::F::fn}("string");
static method fn8() → core::String
return (#C17).{self::F::fn}("string");
static method main() → void {
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
}
constants {
#C1 = core::_Override {}
#C2 = "Instance of 'A'"
#C3 = "B"
#C4 = 200
#C5 = 100
#C6 = 300
#C7 = "string"
#C8 = self::A {}
#C9 = self::B {}
#C10 = 0
#C11 = self::C {y:#C10}
#C12 = 1
#C13 = self::C {y:#C12}
#C14 = self::D {y:#C12}
#C15 = self::E {y:#C12}
#C16 = self::F<core::int*, core::String*, core::num*> {}
#C17 = self::G<core::int*> {}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_instance_methods.dart:
- A. (from org-dartlang-testcase:///const_functions_instance_methods.dart:10:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
- B. (from org-dartlang-testcase:///const_functions_instance_methods.dart:14:9)
- C. (from org-dartlang-testcase:///const_functions_instance_methods.dart:23:9)
- D. (from org-dartlang-testcase:///const_functions_instance_methods.dart:32:9)
- E. (from org-dartlang-testcase:///const_functions_instance_methods.dart:39:9)
- F. (from org-dartlang-testcase:///const_functions_instance_methods.dart:43:9)
- G. (from org-dartlang-testcase:///const_functions_instance_methods.dart:48:9)

View file

@ -0,0 +1,100 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart";
class A extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::A
: super core::Object::•()
;
}
class B extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::B
: super core::Object::•()
;
@core::override
method toString() → core::String
;
}
class C extends core::Object /*hasConstConstructor*/ {
final field core::int y;
const constructor •(core::int y) → self::C
: self::C::y = y, super core::Object::•()
;
method fn() → core::int
;
}
class D extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::D
: super self::C::•(y)
;
@core::override
method fn() → core::int
;
}
class E extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::E
: super self::C::•(y)
;
}
class F<T extends core::Object? = dynamic, U extends core::Object? = dynamic, V extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::F<self::F::T%, self::F::U%, self::F::V%>
: super core::Object::•()
;
method fn(generic-covariant-impl self::F::U% x) → self::F::U%
;
}
class G<T extends core::Object? = dynamic> extends self::F<self::G::T%, core::String, core::num> /*hasConstConstructor*/ {
const constructor •() → self::G<self::G::T%>
: super self::F::•()
;
}
static const field core::String var1 = self::fn();
static const field core::String toString1 = const self::A::•().{core::Object::toString}();
static const field core::String var2 = self::fn2();
static const field core::String toString2 = const self::B::•().{self::B::toString}();
static const field core::int var3 = self::fn3();
static const field core::int var4 = self::fn4();
static const field core::int fnVal1 = const self::C::•(0).{self::C::fn}();
static const field core::int fnVal2 = const self::C::•(1).{self::C::fn}();
static const field core::int var5 = self::fn5();
static const field core::int fnVal3 = const self::D::•(1).{self::D::fn}();
static const field core::int var6 = self::fn6();
static const field core::int fnVal4 = const self::E::•(0).{self::C::fn}();
static const field core::String var7 = self::fn7();
static const field core::String fnVal5 = const self::F::•<core::int, core::String, core::num>().{self::F::fn}("string");
static const field core::String var8 = self::fn8();
static const field core::String fnVal6 = const self::G::•<core::int>().{self::F::fn}("string");
static method fn() → core::String
;
static method fn2() → core::String
;
static method fn3() → core::int
;
static method fn4() → core::int
;
static method fn5() → core::int
;
static method fn6() → core::int
;
static method fn7() → core::String
;
static method fn8() → core::String
;
static method main() → void
;
Extra constant evaluation status:
Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_instance_methods.dart:16:4 -> InstanceConstant(const _Override{})
Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_instance_methods.dart:34:4 -> InstanceConstant(const _Override{})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:54:25 -> InstanceConstant(const A{})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:59:25 -> InstanceConstant(const B{})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:66:22 -> InstanceConstant(const C{C.y: 0})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:67:22 -> InstanceConstant(const C{C.y: 1})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:72:22 -> InstanceConstant(const D{C.y: 1})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:77:22 -> InstanceConstant(const E{C.y: 0})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:82:22 -> InstanceConstant(const F<int*, String*, num*>{})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_methods.dart:87:22 -> InstanceConstant(const G<int*>{})
Extra constant evaluation: evaluated: 29, effectively constant: 10

View file

@ -0,0 +1,138 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class A extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::A
: super core::Object::•()
;
}
class B extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::B
: super core::Object::•()
;
@#C1
method toString() → core::String
return "B";
}
class C extends core::Object /*hasConstConstructor*/ {
final field core::int y;
const constructor •(core::int y) → self::C
: self::C::y = y, super core::Object::•()
;
method fn() → core::int {
if(this.{self::C::y}.{core::num::==}(1))
return 100;
return 200;
}
}
class D extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::D
: super self::C::•(y)
;
@#C1
method fn() → core::int
return 300;
}
class E extends self::C /*hasConstConstructor*/ {
const constructor •(core::int y) → self::E
: super self::C::•(y)
;
}
class F<T extends core::Object? = dynamic, U extends core::Object? = dynamic, V extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
const constructor •() → self::F<self::F::T%, self::F::U%, self::F::V%>
: super core::Object::•()
;
method fn(generic-covariant-impl self::F::U% x) → self::F::U%
return x;
}
class G<T extends core::Object? = dynamic> extends self::F<self::G::T%, core::String, core::num> /*hasConstConstructor*/ {
const constructor •() → self::G<self::G::T%>
: super self::F::•()
;
}
static const field core::String var1 = #C2;
static const field core::String toString1 = #C2;
static const field core::String var2 = #C3;
static const field core::String toString2 = #C3;
static const field core::int var3 = #C4;
static const field core::int var4 = #C5;
static const field core::int fnVal1 = #C4;
static const field core::int fnVal2 = #C5;
static const field core::int var5 = #C6;
static const field core::int fnVal3 = #C6;
static const field core::int var6 = #C5;
static const field core::int fnVal4 = #C4;
static const field core::String var7 = #C7;
static const field core::String fnVal5 = #C7;
static const field core::String var8 = #C7;
static const field core::String fnVal6 = #C7;
static method fn() → core::String
return (#C8).{core::Object::toString}();
static method fn2() → core::String
return (#C9).{self::B::toString}();
static method fn3() → core::int
return (#C11).{self::C::fn}();
static method fn4() → core::int
return (#C13).{self::C::fn}();
static method fn5() → core::int
return (#C14).{self::D::fn}();
static method fn6() → core::int
return (#C15).{self::C::fn}();
static method fn7() → core::String
return (#C16).{self::F::fn}("string");
static method fn8() → core::String
return (#C17).{self::F::fn}("string");
static method main() → void {
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C2, (#C8).{core::Object::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C3, (#C9).{self::B::toString}());
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C6, 300);
exp::Expect::equals(#C5, 100);
exp::Expect::equals(#C4, 200);
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
exp::Expect::equals(#C7, "string");
}
constants {
#C1 = core::_Override {}
#C2 = "Instance of 'A'"
#C3 = "B"
#C4 = 200
#C5 = 100
#C6 = 300
#C7 = "string"
#C8 = self::A {}
#C9 = self::B {}
#C10 = 0
#C11 = self::C {y:#C10}
#C12 = 1
#C13 = self::C {y:#C12}
#C14 = self::D {y:#C12}
#C15 = self::E {y:#C12}
#C16 = self::F<core::int*, core::String*, core::num*> {}
#C17 = self::G<core::int*> {}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_instance_methods.dart:
- A. (from org-dartlang-testcase:///const_functions_instance_methods.dart:10:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
- B. (from org-dartlang-testcase:///const_functions_instance_methods.dart:14:9)
- C. (from org-dartlang-testcase:///const_functions_instance_methods.dart:23:9)
- D. (from org-dartlang-testcase:///const_functions_instance_methods.dart:32:9)
- E. (from org-dartlang-testcase:///const_functions_instance_methods.dart:39:9)
- F. (from org-dartlang-testcase:///const_functions_instance_methods.dart:43:9)
- G. (from org-dartlang-testcase:///const_functions_instance_methods.dart:48:9)

View file

@ -0,0 +1,140 @@
// Copyright (c) 2021, 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.
// Tests invocations of instance functions with const functions.
// SharedOptions=--enable-experiment=const-functions
import "package:expect/expect.dart";
class A {
const A();
}
class B {
const B();
@override
String toString() => "B";
}
class C {
final int y;
const C(this.y);
int fn() {
if (y == 1) return 100;
return 200;
}
}
class D extends C {
const D(int y) : super(y);
@override
int fn() => 300;
}
class E extends C {
const E(int y) : super(y);
}
class F<T, U, V> {
const F();
U fn(U x) => x;
}
class G<T> extends F<T, String, num> {
const G();
}
const var1 = fn();
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
String fn() => const A().toString();
const toString1 = const A().toString();
// ^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var2 = fn2();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
String fn2() => const B().toString();
const toString2 = const B().toString();
// ^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var3 = fn3();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var4 = fn4();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn3() => const C(0).fn();
int fn4() => const C(1).fn();
const fnVal1 = const C(0).fn();
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const fnVal2 = const C(1).fn();
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var5 = fn5();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn5() => const D(1).fn();
const fnVal3 = const D(1).fn();
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var6 = fn6();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn6() => const E(1).fn();
const fnVal4 = const E(0).fn();
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var7 = fn7();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
String fn7() => const F<int, String, num>().fn("string");
const fnVal5 = const F<int, String, num>().fn("string");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var8 = fn8();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
String fn8() => const G<int>().fn("string");
const fnVal6 = const G<int>().fn("string");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
void main() {
Expect.equals(var1, const A().toString());
Expect.equals(toString1, const A().toString());
Expect.equals(var2, const B().toString());
Expect.equals(toString2, const B().toString());
Expect.equals(var3, 200);
Expect.equals(var4, 100);
Expect.equals(fnVal1, 200);
Expect.equals(fnVal2, 100);
Expect.equals(var5, 300);
Expect.equals(fnVal3, 300);
Expect.equals(var6, 100);
Expect.equals(fnVal4, 200);
Expect.equals(var7, "string");
Expect.equals(fnVal5, "string");
Expect.equals(var8, "string");
Expect.equals(fnVal6, "string");
}