Table of Contents

5.5.1.2 Runtime semantics

Note

This section describes the implementation of MS-VBAL §5.5.1.2 Runtime semantics.

Let-coercion is the implicit conversion applied to an operand, or to an assignment RHS, so that its value fits a required destination declared type.

In the operator evaluation pipeline, the validation step let-coerces all non-null operands (non-VBNullValue) to the determined effective type of the operation (RD-VBAL §5.6.9.2 Simple Data Operators).

Let-coercion provider

Let-coercion is driven by a let-coercion provider, LetCoercionRuntimeSemanticsProvider. The provider uses provider/strategy dispatch: it dispatches to a per-destination-type let-coercion strategy, selected by the destination type.

LetCoercionRuntimeSemanticsProvider.EvaluateLetCoercionSemantics evaluates a let-coercion in this order:

  1. When the source value is a Variant, the provider unwraps it before dispatching to a strategy. The unwrap is performed once, by the provider, on behalf of every strategy. It is recursive, because a Variant may wrap another Variant.
  2. The provider resolves the strategy by walking the base-type chain of the destination VBType. One strategy keyed on VBNumericType serves every concrete numeric type (RD-VBAL §5.5.1.2.1 Let-coercion between numeric types).

Every let-coercion strategy casts frame.SourceValue directly to its own concrete value type. The provider unwraps a Variant source before dispatch so that the direct cast of every strategy sees the wrapped value rather than the VBVariantValue.

Strategy dispatch is keyed on the destination type. It selects the right strategy for a Variant source as well, because the Variant's TypeInfo mirrors its wrapped value's (RD-VBAL §5.5.1.2.12 Let-coercion to Variant).

Coercion frame stack

The let-coercion provider maintains a coercion frame stack (see LetCoercionStackFrame).

A recursive let-coercion is a strategy that must coerce through an intermediate type, e.g. Date → Double → Integer. The coercion frame stack detects a recursive let-coercion and reports it as OutOfStackSpace (VBRuntimeErrorId) rather than overflowing the call stack.

A VBTypeDescValue is used in the implementation of let-coercion, where semantics demand knowledge of a data type where a value is normally required (RD-VBAL §2.4.3 Meta and Advanced Types).

Let-coercion result

Each let-coercion step yields a LetCoercionResult:

Result Carries
Success The coerced VBTypedValue.
Error A run-time error, such as TypeMismatch or Overflow (VBRuntimeErrorId).
NotApplicable —

Let-coercion strategies

The let-coercion strategy contract is ILetCoercionRuntimeSemantics. ILetCoercionRuntimeSemantics.EvaluateLetCoercion and ILetCoercionRuntimeSemantics.Analyze take the coerced value's own ExpressionNode rather than a VBOperatorExpression.

Every let-coercion strategy treats the node parameter as opaque: it reads only the node's identity and location, for error reporting. No strategy therefore depends on the narrower VBOperatorExpression type.

RD-VBA rules out the fabrication of synthetic nodes for let-coercion: a construct that has no operator node of its own in source passes its own expression (RD-VBAL §5.5.1.2.2 Let-coercion to and from Boolean). The node parameter of the operator runtime semantics follows the same rule (RD-VBAL §5.6.9.2 Simple Data Operators).

5.5.1.2.1 Let-coercion between numeric types

Note

This section describes the implementation of MS-VBAL §5.5.1.2.1 Let-coercion between numeric types.

One let-coercion strategy keyed on VBNumericType, VBNumericLetCoercionTypeRuntimeSemantics, serves every concrete numeric type.

Let-coercion between numeric types validates that the source value is within the destination's representable range. When the source value is outside that range, it raises Overflow. Otherwise:

Conversion Result
Widening The value is copied, converted to the destination's representation.
Narrowing to a wider-or-equal integral type The value is copied, converted to the destination's representation.
Floating-point or fixed-point value → integral type (narrowing) The value is rounded to the nearest integer (RD-VBAL §5.5.1.2.1.1 Banker's rounding) before conversion.
Integral → floating-point 🎯 A plain widening copy (see the divergence note below).

A Date source let-coerced to a numeric destination reports ConversionSemanticFlags.DateSerial (ConversionSemanticFlags). VBNumericLetCoercionTypeRuntimeSemantics.DateSerialFlagsOf computes the DateSerial flag for a Date source.

Note

🎯 RD-VBAL diverges from MS-VBAL in the integral → floating-point block of MS-VBAL §5.5.1.2.1.

MS-VBAL specifies that block as a verbatim copy of the preceding (narrowing) block, including the finite-value and banker's-rounding checks. No integer value can meet the finite-value and banker's-rounding conditions, and integral → floating-point is an unambiguously widening conversion.

RD-VBAL treats integral → floating-point let-coercion as a plain widening copy.

MS-VBAL divergence principle

RDCore implements the MS-VBAL type-coercion rules verbatim, except for the resolved specification errors noted in this section (RD-VBAL §5.0 Semantics).

  • Divergences from MS-VBAL caused by obvious copy/paste and transcription errors in the MS specification are resolved in favour of the evident intent.
  • Anything in MS-VBAL that implicitly depends on the Windows Registry, ActiveX, or MSForms is out of scope for the RD-VBA run-time. MS-VBAL requirements with such an implicit dependency are resolved in favour of the evident intent.

5.5.1.2.1.1 Banker's rounding

Note

This section describes the implementation of MS-VBAL §5.5.1.2.1.1 Banker's rounding.

The rounding used when narrowing a floating-point or fixed-point value to an integral type is round-half-to-even ("banker's rounding").

5.5.1.2.2 Let-coercion to and from Boolean

Note

This section describes the implementation of MS-VBAL §5.5.1.2.2 Let-coercion to and from Boolean.

A Date source let-coerced to a Boolean destination reports ConversionSemanticFlags.DateSerial. VBBooleanLetCoercionRuntimeSemantics reuses VBNumericLetCoercionTypeRuntimeSemantics.DateSerialFlagsOf for it (RD-VBAL §5.5.1.2.1 Let-coercion between numeric types).

A condition passes its own expression through to the Boolean let-coercion strategy, with no synthetic node standing in for an operator that is not present in source (RD-VBAL §3.5.4 Execution).

5.5.1.2.3 Let-coercion to and from Date

Note

This section describes the implementation of MS-VBAL §5.5.1.2.3 Let-coercion to and from Date.

VBDateLetCoercionRuntimeSemantics runs only when Date is the destination type.

👉 A Date source let-coerced to a numeric or Boolean destination is handled by the numeric or Boolean strategy, which reports its DateSerial flag (RD-VBAL §5.5.1.2.1 Let-coercion between numeric types, RD-VBAL §5.5.1.2.2 Let-coercion to and from Boolean).

5.5.1.2.4 Let-coercion to and from String

Note

This section describes the implementation of MS-VBAL §5.5.1.2.4 Let-coercion to and from String.

Floating-point types define a SignificantIntegerDigits constant, declared on the VBType. It is used to represent floating-point values correctly as VBStringValue in conversions and coercions to String (RD-VBAL §2.5.2.1.1 Numeric Values):

Value type VBType Significant digits (SignificantIntegerDigits)
VBSingleValue VBSingleType 7
VBDoubleValue VBDoubleType 15

5.5.1.2.5 Let-coercion to String * length (fixed-length strings)

This section corresponds to MS-VBAL §5.5.1.2.5 Let-coercion to String * length (fixed-length strings).

Note

Reserved. This section has no content yet.

5.5.1.2.6 Let-coercion to and from resizable Byte()

Note

This section describes the implementation of MS-VBAL §5.5.1.2.6 Let-coercion to and from resizable Byte().

VBResizableByteArrayType has its own let-coercion semantics, which allow implicit conversion to and from VBStringType (RD-VBAL §2.4.1 Intrinsic Types).

5.5.1.2.7 Let-coercion to and from non-Byte arrays

This section corresponds to MS-VBAL §5.5.1.2.7 Let-coercion to and from non-Byte arrays.

Note

Reserved. This section has no content yet.

5.5.1.2.8 Let-coercion to and from a UDT

This section corresponds to MS-VBAL §5.5.1.2.8 Let-coercion to and from a UDT.

Note

Reserved. This section has no content yet.

5.5.1.2.9 Let-coercion to and from Error

This section corresponds to MS-VBAL §5.5.1.2.9 Let-coercion to and from Error.

Note

Reserved. This section has no content yet.

5.5.1.2.10 Let-coercion from Null

This section corresponds to MS-VBAL §5.5.1.2.10 Let-coercion from Null.

Note

Reserved. This section has no content yet.

5.5.1.2.11 Let-coercion from Empty

This section corresponds to MS-VBAL §5.5.1.2.11 Let-coercion from Empty.

Note

Reserved. This section has no content yet.

5.5.1.2.12 Let-coercion to Variant

Note

This section describes the implementation of MS-VBAL §5.5.1.2.12 Let-coercion to Variant: Variant let-coercion and storage.

Any value except a class or Nothing let-coerces to Variant as a copy. A value let-coerced to Variant is wrapped in a VBVariantValue (RD-VBAL §2.5.2.1.5 Variant Values).

Type information

A VBVariantValue's own TypeInfo mirrors its wrapped value's TypeInfo, so that ordinary destination-type dispatch, in let-coercion and in operator and effective-type determination, picks the same strategy it would for the unwrapped value.

  • The runtime (C#) instance of a let-coerced Variant value remains a VBVariantValue, not the wrapped value's concrete type.
  • A VBVariantValue wraps the whole value, whether or not that value is a scalar.
  • A Variant may wrap another Variant.

Storage

Storage holds a VBVariantValue as a VBRuntimeVariantValue box, and reads it back as a VBVariantValue. The box holds the wrapped VBTypedValue of the Variant itself.

The VBRuntimeVariantValue box follows the same pattern a VBArrayValue uses via VBRuntimeArrayValue (RD-VBAL §2.5.2.1.2 Array Values).

👉 A Variant read back from a variable, array element, or field carries the exact value that was stored in it, rather than a new, unrelated Empty.

Unwrapping

Because TypeInfo mirrors the wrapped value:

  • Any code that short-circuits on a TypeInfo match must unwrap a VBVariantValue first.
  • Any code that pattern-matches a VBTypedValue operand against a concrete value type directly must unwrap a VBVariantValue first.
  • Unwrapping a VBVariantValue must be recursive, because a Variant may wrap another Variant.

Code that does not unwrap a VBVariantValue sees the box instead of the value.

Site Variant handling See
LetCoercionRuntimeSemanticsProvider.EvaluateLetCoercionSemantics Unwraps a VBVariantValue source once, in the provider, for every let-coercion. Let-coercion provider
OperatorRuntimeSemantics.LetCoerceNonNullOperand Does not take its "already the right type" short-circuit for a Variant operand: the operand is let-coerced through the provider, which unwraps it. RD-VBAL §5.6.9.2 Simple Data Operators
SetCoercionRuntimeSemantics Unwraps a VBVariantValue before its own object pattern-match. RD-VBAL §5.5.2.2 Runtime semantics
RuntimeExpressionEvaluator.EvaluateIndex Unwraps a VBVariantValue before matching a wrapped array. RD-VBAL §5.6.13 Index Expressions
ProcedureExecutor.ExecuteForEachOpener Unwraps a VBVariantValue before matching a wrapped array. RD-VBAL §5.4.2.4 For Each Statement
BinaryConcatOperatorRuntimeSemantics.IsByteArray Unwraps a VBVariantValue before matching a wrapped array. RD-VBAL §5.6.9.4 & Operator

5.5.1.2.13 Let-coercion to and from a class or Object or Nothing

Note

This section describes the implementation of MS-VBAL §5.5.1.2.13 Let-coercion to and from a class or Object or Nothing.

The default member of a class type can be implicitly invoked through let-coercion, yielding the data value of the object (RD-VBAL §2.4.2 Non-intrinsic Types; RD-VBAL §5.6.2 Expression Evaluation).


⏮️ RD-VBAL §5.5.1.1 Static semantics | ⏭️ RD-VBAL §5.5.2 Set-coercion