// 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? positionalArguments, [ Map? 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? typeArguments, Iterable? positionalArguments, [ Map? 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 get typeArguments => const []; /// An unmodifiable view of the positional arguments of the call. /// /// If the member is a getter, the positional arguments list is /// always empty. List 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 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 typeArguments; // Positional arguments is `null` for getters only. final List? _positional; // Named arguments is `null` for accessors only. final Map? _named; _Invocation.method( this.memberName, Iterable? types, Iterable? positional, Map? named, ) : typeArguments = _ensureNonNullTypes(types), _positional = positional == null ? const [] : List.unmodifiable(positional), _named = (named == null || named.isEmpty) ? const {} : Map.unmodifiable(named); _Invocation.getter(this.memberName) : typeArguments = const [], _positional = null, _named = null; _Invocation.setter(this.memberName, Object? argument) : typeArguments = const [], _positional = List.unmodifiable([argument]), _named = null; List get positionalArguments => _positional ?? const []; Map get namedArguments => _named ?? const {}; 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 _ensureNonNullTypes(Iterable? types) { if (types == null) return const []; List typeArguments = List.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; } }