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:
- 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 aVariantmay wrap anotherVariant. - The provider resolves the strategy by walking the base-type chain of the destination
VBType. One strategy keyed on
VBNumericTypeserves 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
Datesource let-coerced to a numeric orBooleandestination is handled by the numeric orBooleanstrategy, which reports itsDateSerialflag (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
Variantvalue remains aVBVariantValue, not the wrapped value's concrete type. - A
VBVariantValuewraps the whole value, whether or not that value is a scalar. - A
Variantmay wrap anotherVariant.
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
Variantread back from a variable, array element, or field carries the exact value that was stored in it, rather than a new, unrelatedEmpty.
Unwrapping
Because TypeInfo mirrors the wrapped value:
- Any code that short-circuits on a
TypeInfomatch must unwrap aVBVariantValuefirst. - Any code that pattern-matches a
VBTypedValueoperand against a concrete value type directly must unwrap aVBVariantValuefirst. - Unwrapping a
VBVariantValuemust be recursive, because aVariantmay wrap anotherVariant.
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