2.4.4 Deferred Types
The RD-VBA type system defines a category of deferred data types.
Note
Not implemented. Deferred types are not in use.
Deferred types address late-bound and other cases where MS-VBA would fail to resolve a valid compile-time data type.
Using late binding and duck typing to introduce and surface inherent deferred types to design-time symbols is a valid language core extension. Surfacing deferred types to design-time symbols enables LSP-level enhanced capabilities, notably around auto-completion lists; see RD-VBAL §1.1.2 Language Core Extensions.
A deferred type is a valid RD-VBA data type representing an undefined type. An undefined type is a workspace-defined data type that does not have any associated source code.
A deferred type may statically be one of the following data types:
Unresolved Names
The static-semantics layer consumes ModuleDirectives to decide whether an unresolved simple name is a deferred VBUnknownType or a VBC09302 Variable not defined compile-time error; see RD-VBAL §2.3.1.3 Name Resolution.
RD-VBA defers the actual type guess for an unresolved name to a later type-inference pass (IVBInferableType), rather than deciding it in the simple-name-expression rule; see RD-VBAL §5.6.10 Simple Name Expressions.
Deferred Names
| Deferred symbol | Name |
|---|---|
| Deferred type | A candidate name. The candidate name can change depending on how the deferred type is being used. |
| Deferred member | The identifier name identifying the member in the workspace source code. |
| Deferred parameter | Arg followed by its 1-based position in the deferred member signature: the first parameter is Arg1, the second is Arg2, and so on. |
Deferred members resolve as follows:
- Any two symbols should be resolved to the same deferred member if the resolved qualifying module is the same for both symbols.
- Without a qualifier, a deferred symbol is deemed to be an undeclared local variable, as per MS-VBAL scoping rules.
- If a global-scope deferred symbol with the same identifier name exists, an unqualified deferred symbol (an undeclared local variable) should resolve to the global-scope deferred symbol (RD-VBAL §2.3.1.3 Name Resolution).
Deferred parameters are also defined from named arguments:
- If a call site supplies a named argument that is not a defined deferred parameter, a deferred parameter with that name is defined at the end of the deferred member signature.
- Multiple deferred parameters defined from unmatched named arguments are materialized in alphabetical order.
- A deferred parameter defined from an unmatched named argument is deemed
Optional.
Member Ownership
Deferred types cannot implement IVBMemberOwnerType, because the related symbols are unbound.
Deferred types implement IVBInferableType instead of IVBMemberOwnerType. IVBInferableType exposes an immutable hashset of candidate types that would be legal to materialize the deferred type with.
2.4.4.1 VBDeferredModuleType
VBDeferredModuleType represents a deferred VBStdModuleType.
A deferred member is presumed to belong to a deferred module, unless the deferred member is qualified:
| Deferred member | Owner |
|---|---|
| Unqualified | A deferred module. |
| Qualified; the resolved module has a bound symbol | The resolved module type's IVBMemberOwnerType.DeferredMembers array. |
| Qualified; the qualifying module symbol is unbound | The named deferred module the qualifier denotes. |
Only one unnamed deferred module may be semantically (but not statically) defined at any given time in a source project.
2.4.4.2 VBDeferredClassType
VBDeferredClassType represents a deferred VBClassType.
👉 Deferred class types cannot be presumed to have a default instance. A default instance is set by a VB_PredeclaredId module attribute with the value True; see RD-VBAL §3.1.1 Attributes and RD-VBAL §5.2.4 Class Module Declarations.
A deferred class is semantically defined when an unbound member call is made against an object variable of a class type that may or may not be defined in the workspace source code.
The default name of a deferred class is the word Class followed by a number, taken in numerical order until the class name is unique in the workspace: Class1, unless a Class1 module already exists in the workspace, in which case Class2, and so on.
Warning
The names of any deferred type defined in workspace source code must be considered "in use" for all operations involving the naming of a module, including the addition of new (bound) modules to the workspace or project.
2.4.4.3 VBDeferredTypeDesc
VBDeferredTypeDesc represents (describes) a VBDeferredType within the type system.
👉 A value of the VBDeferredTypeDesc meta type, a VBDeferredTypeDescValue, is used in the implementation of the Is relational operator; see RD-VBAL §5.6.9.7 Is Operator. The Is operator uses a deferred type descriptor value because its semantics demand knowledge of a data type where a value is normally required.
Note
Not implemented. None of the other deferred descriptor types are in use.
All deferred descriptor types inherit the corresponding non-deferred descriptor type (RD-VBAL §2.4.3 Meta and Advanced Types). A deferred descriptor type that describes a type explicitly shadows (hides) the static TypeInfo property of the non-deferred descriptor type it inherits.
2.4.4.4 VBDeferredMemberDesc
VBDeferredMemberDesc is a descriptor that represents (describes) any VBDeferredTypeMemberSymbol.
RD-VBAL groups the following descriptors under VBDeferredMemberDesc:
| Section | Descriptor |
|---|---|
| §2.4.4.4.1 | VBDeferredProcedureMemberDesc |
| §2.4.4.4.2 | VBDeferredPropertyLetProcedureDesc |
| §2.4.4.4.3 | VBDeferredPropertySetProcedureDesc |
| §2.4.4.4.4 | VBDeferredFunctionProcedureDesc |
| §2.4.4.4.5 | VBDeferredPropertyGetProcedureDesc |
| §2.4.4.4.6 | VBDeferredParameterDesc |
2.4.4.4.1 VBDeferredProcedureMemberDesc
VBDeferredProcedureMemberDesc is a descriptor that represents (describes) a non-returning deferred procedure member symbol (a VBDeferredTypeMemberSymbol).
2.4.4.4.2 VBDeferredPropertyLetProcedureDesc
VBDeferredPropertyLetProcedureDesc is a descriptor that represents (describes) a deferred Property Let member.
2.4.4.4.3 VBDeferredPropertySetProcedureDesc
VBDeferredPropertySetProcedureDesc is a descriptor that represents (describes) a deferred Property Set member.
2.4.4.4.4 VBDeferredFunctionProcedureDesc
VBDeferredFunctionProcedureDesc is a descriptor that represents (describes) a deferred Function member.
2.4.4.4.5 VBDeferredPropertyGetProcedureDesc
VBDeferredPropertyGetProcedureDesc is a descriptor that represents (describes) a deferred Property Get member.
2.4.4.4.6 VBDeferredParameterDesc
VBDeferredParameterDesc is a descriptor that represents (describes) a single parameter of a deferred member.
👉 Deferred parameters are inferred from the arguments provided at the call sites of deferred members.
The data type of a deferred parameter depends on how many call sites supply an argument for the parameter. It also depends on the data types of the arguments supplied for it at the call sites:
| Call-site arguments | Deferred parameter data type | Parameter |
|---|---|---|
| Only VBBooleanValue arguments | VBBooleanType | ByVal |
| Only VBObjectValue arguments | VBObjectType |
ByVal |
Only VBObjectValue arguments whose class type is resolvable (whether deferred or not) |
That specific class type | ByVal |
Any number of VBStringType (string) arguments |
VBStringType | ByVal |
Any number of VBEnumType (enum) arguments |
VBIntegerType | ByVal |
Any number of IIntegralNumericType arguments |
The largest of the candidate types | ByVal |
Any number of IFixedPointNumericType arguments |
VBCurrencyType | ByVal |
Any number of IFloatingPointNumericType arguments |
VBDoubleType | ByVal |
| A specific VBUserDefinedTypeValue | The data type of the specified UDT | ByRef |
| Any number of VBArrayValue arguments | Variant |
ByRef |
| Mixed-bag (heterogeneous) arguments | Variant |
ByRef |
A deferred ByVal parameter is passed by value. A deferred ByRef parameter must be passed by reference.
Note
A deferred parameter inferred as Variant (from array or heterogeneous arguments) may not be materializable.
A deferred parameter inferred as Variant should issue semantic flags as appropriate, to signal the case to any listening language-level extensions; see RD-VBAL §1.1.3 Core Semantic Flags.
⏮️ RD-VBAL §2.4.3 Meta and Advanced Types | ⏭️ RD-VBAL §2.5 Runtime Values