@@ -39,11 +39,13 @@ goog.requireType('ee.Function');
3939 * and both 'func' and 'args' must be null. If all arguments are null, the
4040 * object is considered an unnamed variable, and a name will be generated
4141 * when it is included in an ee.CustomFunction.
42+ * @param {?boolean= } opt_unbound Whether the object is unbound, i.e., called
43+ * from a mapped or iterated function.
4244 * @constructor
4345 * @extends {ee.Encodable }
4446 * @template T
4547 */
46- ee . ComputedObject = function ( func , args , opt_varName ) {
48+ ee . ComputedObject = function ( func , args , opt_varName , opt_unbound ) {
4749 // Constructor safety.
4850 if ( ! ( this instanceof ee . ComputedObject ) ) {
4951 return ee . ComputedObject . construct ( ee . ComputedObject , arguments ) ;
@@ -76,6 +78,12 @@ ee.ComputedObject = function(func, args, opt_varName) {
7678 * @protected
7779 */
7880 this . varName = opt_varName || null ;
81+
82+ /**
83+ * Whether the computed object is an unbound variable.
84+ * @type {boolean }
85+ */
86+ this . unbound = ! ! opt_unbound ;
7987} ;
8088goog . inherits ( ee . ComputedObject , ee . Encodable ) ;
8189// Exporting manually to avoid marking the class public in the docs.
@@ -153,14 +161,20 @@ ee.ComputedObject.prototype.encodeCloudValue = function(serializer) {
153161 if ( this . isVariable ( ) ) {
154162 const name = this . varName || serializer . unboundName ;
155163 if ( ! name ) {
156- // We are trying to call getInfo() or make some other server call inside a
157- // function passed to collection.map() or .iterate(), and the call uses
158- // one of the function arguments. The argument will be unbound outside of
159- // the map operation and cannot be evaluated. See the Count Functions case
160- // in customfunction.js for details on the unboundName mechanism.
161- // TODO(user): Report the name of the offending argument.
162- throw new Error (
163- 'A mapped function\'s arguments cannot be used in client-side operations' ) ;
164+ if ( this . unbound ) {
165+ // We are trying to call getInfo() or make some other server call inside
166+ // a function passed to collection.map() or .iterate(), and the call
167+ // uses one of the function arguments. The argument will be unbound
168+ // outside of the map operation and cannot be evaluated. See the Count
169+ // Functions case in customfunction.js for details on the unboundName
170+ // mechanism.
171+ // TODO(user): Report the name of the offending argument.
172+ throw new Error ( `A mapped function's arguments (${
173+ this . name ( ) } ) cannot be used in client-side operations.`) ;
174+ } else {
175+ throw new Error (
176+ `Invalid cast to ${ this . name ( ) } from a client-side object.` ) ;
177+ }
164178 }
165179 return ee . rpc_node . argumentReference ( name ) ;
166180 } else {
0 commit comments