-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
invocation.dart
144 lines (122 loc) · 5.32 KB
/
invocation.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) 2012, 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.
part of dart.core;
/// Representation of the invocation of a member on an object.
///
/// This is the type of objects passed to [Object.noSuchMethod] when
/// an object doesn't support the member invocation that was attempted
/// on it.
abstract class Invocation {
Invocation();
/// Creates an invocation corresponding to a method invocation.
///
/// The method invocation has no type arguments.
/// If the named arguments are omitted, they default to no named arguments.
@pragma("wasm:entry-point")
factory Invocation.method(
Symbol memberName, Iterable<Object?>? positionalArguments,
[Map<Symbol, Object?>? namedArguments]) =>
_Invocation.method(memberName, null, positionalArguments, namedArguments);
/// Creates an invocation corresponding to a generic method invocation.
///
/// If [typeArguments] is `null` or empty, the constructor is equivalent to
/// calling [Invocation.method] with the remaining arguments.
/// All the individual type arguments must be non-null.
///
/// If the named arguments are omitted, they default to no named arguments.
@pragma("wasm:entry-point")
factory Invocation.genericMethod(Symbol memberName,
Iterable<Type>? typeArguments, Iterable<Object?>? positionalArguments,
[Map<Symbol, Object?>? namedArguments]) =>
_Invocation.method(
memberName, typeArguments, positionalArguments, namedArguments);
/// Creates an invocation corresponding to a getter invocation.
@pragma("wasm:entry-point")
factory Invocation.getter(Symbol name) = _Invocation.getter;
/// Creates an invocation corresponding to a setter invocation.
///
/// This constructor accepts any [Symbol] as [memberName], but remember that
/// *actual setter names* end in `=`, so the invocation corresponding
/// to `object.member = value` is
/// ```dart
/// Invocation.setter(const Symbol("member="), value)
/// ```
@pragma("wasm:entry-point")
factory Invocation.setter(Symbol memberName, Object? argument) =
_Invocation.setter;
/// The name of the invoked member.
Symbol get memberName;
/// An unmodifiable view of the type arguments of the call.
///
/// If the member is a getter, setter or operator,
/// the type argument list is always empty.
List<Type> get typeArguments => const <Type>[];
/// An unmodifiable view of the positional arguments of the call.
///
/// If the member is a getter, the positional arguments list is
/// always empty.
List<dynamic> get positionalArguments;
/// An unmodifiable view of the named arguments of the call.
///
/// If the member is a getter, setter or operator,
/// the named arguments map is always empty.
Map<Symbol, dynamic> get namedArguments;
/// Whether the invocation was a method call.
bool get isMethod;
/// Whether the invocation was a getter call.
/// If so, all three types of arguments lists are empty.
bool get isGetter;
/// Whether the invocation was a setter call.
///
/// If so, [positionalArguments] has exactly one positional
/// argument, [namedArguments] is empty, and typeArguments is
/// empty.
bool get isSetter;
/// Whether the invocation was a getter or a setter call.
bool get isAccessor => isGetter || isSetter;
}
/// Implementation of [Invocation] used by its factory constructors.
class _Invocation implements Invocation {
final Symbol memberName;
final List<Type> typeArguments;
// Positional arguments is `null` for getters only.
final List<Object?>? _positional;
// Named arguments is `null` for accessors only.
final Map<Symbol, Object?>? _named;
_Invocation.method(this.memberName, Iterable<Type>? types,
Iterable<Object?>? positional, Map<Symbol, Object?>? named)
: typeArguments = _ensureNonNullTypes(types),
_positional = positional == null
? const <Object?>[]
: List<Object?>.unmodifiable(positional),
_named = (named == null || named.isEmpty)
? const <Symbol, Object?>{}
: Map<Symbol, Object?>.unmodifiable(named);
_Invocation.getter(this.memberName)
: typeArguments = const <Type>[],
_positional = null,
_named = null;
_Invocation.setter(this.memberName, Object? argument)
: typeArguments = const <Type>[],
_positional = List<Object?>.unmodifiable([argument]),
_named = null;
List<dynamic> get positionalArguments => _positional ?? const <Object>[];
Map<Symbol, dynamic> get namedArguments => _named ?? const <Symbol, Object>{};
bool get isMethod => _named != null;
bool get isGetter => _positional == null;
bool get isSetter => _positional != null && _named == null;
bool get isAccessor => _named == null;
/// Checks that the elements of [types] are not null.
static List<Type> _ensureNonNullTypes(Iterable<Type>? types) {
if (types == null) return const <Type>[];
List<Type> typeArguments = List<Type>.unmodifiable(types);
for (int i = 0; i < typeArguments.length; i++) {
if (typeArguments[i] == null) {
throw ArgumentError.value(types, "types",
"Type arguments must be non-null, was null at index $i.");
}
}
return typeArguments;
}
}