Skip to content

Commit b71bd25

Browse files
eernstgCommit Bot
authored and
Commit Bot
committedApr 8, 2022
Add test about evaluation order
This CL adds a test of the evaluation order in the case where a function invocation `g(a)` or `r.g(a)` involves the invocation of a getter `g` that returns a function object, and that function object is invoked with an actual argument `a`. The expectation in the test is that evaluation occurs left-to-right in every case, with one exception: when `g` is a class instance getter (this does not apply to extension instance getters) the actual argument list is evaluated before the getter. This is the actually implemented behavior, and the specification is being updated to specify this behavior (cf. dart-lang/language#2182). ------- Old description: A piece of technical debt which has been around for several years is the fact that the specified left-to-right evaluation order isn't implemented everywhere. In particular, with an ordinary invocation like `r.m(a)` where `m` is a getter that returns a function, the argument is evaluated before the getter is called, which is not a left-to-right ordering. This CL adds a test (with 2 libraries) where the evaluation order is detected, such that we can decide how to proceed. Change-Id: Ia2619fe6b4c4cf4cec63bac9c9f834306bdefe52 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/238903 Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Erik Ernst <eernst@google.com>
1 parent ca59d05 commit b71bd25

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Used from 'evaluation_order_test.dart'.
6+
7+
import 'evaluation_order_test.dart';
8+
9+
get arg => argumentEffect();
10+
11+
void Function(void) get m {
12+
getterEffect();
13+
return (_) {};
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test tests the evaluation order in the case where a function
6+
// invocation `m(a)` or `r.m(a)` involves the invocation of a getter `m`
7+
// that returns a function object, and that function object is invoked
8+
// with an actual argument `arg`.
9+
//
10+
// The expectation is that evaluation occurs left-to-right in every case,
11+
// with one exception: when `m` is a class instance getter (this does not
12+
// even apply to extension instance getters) the actual argument list is
13+
// evaluated before the getter.
14+
15+
import 'package:expect/expect.dart';
16+
import 'evaluation_order_lib.dart' as lib;
17+
18+
String effects = '';
19+
20+
void clearEffects() {
21+
effects = '';
22+
}
23+
24+
void getterEffect() {
25+
effects += 'G';
26+
}
27+
28+
void argumentEffect() {
29+
effects += 'A';
30+
}
31+
32+
get arg => argumentEffect();
33+
34+
class A {
35+
void Function(void) get m {
36+
getterEffect();
37+
return (_) {};
38+
}
39+
40+
static void Function(void) get n {
41+
getterEffect();
42+
return (_) {};
43+
}
44+
}
45+
46+
class B extends A {
47+
void doTest() {
48+
test('Instance getter on explicit this', 'AG', () => this.m(arg));
49+
test('Instance getter on implicit this', 'GA', () => m(arg));
50+
test('Instance getter on super', 'GA', () => super.m(arg));
51+
}
52+
}
53+
54+
mixin M on A {
55+
void doTest() {
56+
test('Instance getter on explicit this', 'AG', () => this.m(arg));
57+
test('Instance getter on implicit this', 'GA', () => m(arg));
58+
test('Instance getter on super', 'GA', () => super.m(arg));
59+
}
60+
}
61+
62+
class AM = A with M;
63+
class MockAM = MockA with M;
64+
65+
class MockA implements A {
66+
noSuchMethod(Invocation i) {
67+
getterEffect();
68+
return (_) {};
69+
}
70+
71+
void Function(void) get m;
72+
}
73+
74+
void Function(void) get m {
75+
getterEffect();
76+
return (_) {};
77+
}
78+
79+
extension E on int {
80+
void Function(void) get m {
81+
getterEffect();
82+
return (_) {};
83+
}
84+
85+
static void Function(void) get n {
86+
getterEffect();
87+
return (_) {};
88+
}
89+
}
90+
91+
void test(String name, String expectation, void Function() code) {
92+
clearEffects();
93+
code();
94+
Expect.equals(expectation, effects, name);
95+
}
96+
97+
main() {
98+
var a = A();
99+
dynamic d = a;
100+
A mockA = MockA();
101+
dynamic mockD = mockA;
102+
103+
test('Instance getter on A', 'AG', () => a.m(arg));
104+
test('Instance getter on dynamic A', 'AG', () => d.m(arg));
105+
test('Instance getter on MockA', 'AG', () => mockA.m(arg));
106+
test('Instance getter on dynamic MockA', 'AG', () => mockD.m(arg));
107+
test('Static getter', 'GA', () => A.n(arg));
108+
test('Top-level getter', 'GA', () => m(arg));
109+
test('Prefix-imported getter', 'GA', () => lib.m(arg));
110+
test('Extension instance getter', 'GA', () => 1.m(arg));
111+
test('Extension static getter', 'GA', () => E.n(arg));
112+
B().doTest();
113+
AM().doTest();
114+
MockAM().doTest();
115+
}

0 commit comments

Comments
 (0)
Please sign in to comment.