5.3.1.11 Procedure Invocation Argument Processing

A procedure invocation consists of a procedure expression, classified as a property, function or subroutine, an argument list consisting of positional and/or named arguments, and, if the procedure is defined in a class module, a target object.

Static semantics.

The argument expressions contained within the argument list at the site of invocation are considered the arguments. When the procedure expression is classified as a property, function or subroutine, the argument list is statically checked for compatibility with the parameters defined in the declaration of the referenced procedure as follows:

  • The arguments are first mapped to the parameters as follows:

    • Each positional argument specified is mapped in order from left to right to its respective positional parameter. If there are more positional arguments than there are parameters, the argument list is incompatible, unless the last parameter is a param array. If a positional argument is specified with its value omitted and its mapped parameter is not optional, the argument list is incompatible, even if a named argument is later mapped to this parameter.

    • Each named argument is mapped to the parameter with the same name value. If there is no parameter with the same name value, or if two or more named or positional arguments are mapped to the same parameter, the argument list is incompatible.

  • If any non-optional parameter does not have an argument mapped to it, the argument list is incompatible.

  • For each mapped parameter:

    • If the parameter is ByVal:

      • If the parameter has a declared type other than a specific class or Object, and a Let-coercion from the declared type of its mapped argument to the parameter’s declared type is invalid, the argument list is incompatible.

      • If the parameter has a declared type of a specific class or Object, and the declared type of its mapped argument is a type other than a specific class, Object, or Variant, the argument list is incompatible.

    • Otherwise, if the parameter is ByRef:

      • If the parameter has a declared type other than a specific class, Object or Variant, and the declared type of the parameter does not exactly match that of its mapped argument, the argument list is incompatible.

      • If the parameter has a declared type of a specific class or Object, and the declared type of its mapped argument is a type other than a specific class or Object, the argument list is incompatible.

    A procedure invocation is invalid if the argument list is statically incompatible with the parameter list.

    Runtime semantics.

The runtime semantics of procedure invocation for procedures are as follows:

  • The arguments are first mapped to the parameters as follows:

    • Each positional argument specified is mapped in order from left to right to its respective positional parameter. If there are more positional arguments than there are parameters, runtime error 450 (Wrong number of arguments or invalid property assignment) is raised, unless the last parameter is a param array, in which case the param array is set to a new array of element type Variant with a lower bound of 0 containing the extra arguments in order from left to right. If a positional argument is specified with its value omitted and its mapped parameter is not optional, runtime error 448 (Named argument not found) is raised, even if a named argument is later mapped to this parameter.

    • Each named argument is mapped to the parameter with the same name value. If there is no parameter with the same name value, or if two or more named or positional arguments are mapped to the same parameter, runtime error 448 (Named argument not found) is raised.

    • If the last parameter is a param array and there are not more positional arguments than there are parameters, the param array is set to a new array of element type Variant with a lower bound of 0 and an upper bound of -1.

  • If any non-optional parameters does not have an argument mapped to it, runtime error 449 (Argument not optional) is raised.

  • For each parameter, in order from left to right:

    • If the parameter has no argument mapped to it, the parameter is ByVal, or the parameter is ByRef and the mapped argument’s expression is classified as a value, function, property or unbound member, a local variable is defined with procedure extent within the procedure being invoked with the same name value and declared type as the parameter, and has its value assigned as follows:

      • If this parameter is optional and has no argument mapped to it, the parameter’s default value is assigned to the new local variable.

      • If the value type of this parameter’s mapped argument is a type other than a specific class or Nothing, the argument’s data value is Let-assigned to the new local variable.

      • Otherwise, if the value type of this parameter’s mapped argument is a specific class or Nothing, the argument’s data value is Set-assigned to the new local variable.

    • Otherwise, if the parameter is ByRef and the mapped argument’s expression is classified as a variable:

      • If the declared type of the parameter is a type other than a specific class, Object or Variant, a reference parameter binding is defined within the procedure being invoked, with the same name and declared type as the parameter, referring to the variable referenced by the argument’s expression.

      • If the declared type of the parameter is a specific class or Object:

        • If the declared type of the formal exactly matches the declared type of the argument’s expression, a reference parameter binding is defined within the procedure being invoked, with the same name and declared type as the parameter, referring to the variable referenced by the argument’s expression.

        • If the declared type of the formal does not exactly match the declared type of the argument’s expression:

          • A local variable is defined with procedure extent within the procedure being invoked with the same name value and declared type as the parameter, with the argument’s value Set-assigned to the new local variable.

          • When the procedure terminates, if it has terminated normally, the value within the local variable is Set-assigned back to the argument’s referenced variable.

      • If the declared type of the parameter is Variant, a reference parameter binding is defined within the procedure being invoked, with the same name as the parameter, referring to the variable referenced by the argument’s expression. This reference parameter binding is treated as having a declared type of Variant, except when used as the <l-expression> within Let-assignment or Set-assignment, in which case it is treated as having the declared type of the argument’s referenced variable.

  • For each unmapped optional parameter, a local variable is defined with procedure extent within the procedure being invoked with the same name value and declared type as the parameter, and has its value assigned as follows:

    • If the parameter has a specified default value other than Nothing, this default value is Let-assigned to the new local variable.

    • If the parameter has a specified default value of Nothing, this default value is Set-assigned to the new local variable.

    • If the parameter has no specified default value, the new local variables is initialized to the default value for its declared type.

    There can be implementation-specific differences in the semantics of parameter passing during invocation of procedures imported from a library project.