Another example of "regression" with fbc 1.10.0 when evaluating 'u <> v' ('u' being a TU instance and 'v' a TV instance), with conversion possible via a String for example:
#define TU_ctor_from_TV '' A
#define TU_ctor_from_string '' B
#define TV_cast_to_TU '' C
#define TV_cast_to_string '' D
#define op_inequal_from_TU_from_TU '' E
#define op_inequal_from_TU_from_TV '' F
'' fbc version 1.09.0 1.10.0
'' Priority 1 F F
'' Priority 2 C+E C+E
'' Priority 3 A+E A+E
'' Priority 4 D+B+E
Type _TV As TV
Type TU
Dim As Integer I
Declare Constructor()
#ifdef TU_ctor_from_TV
Declare Constructor(Byref v As _TV)
#endif
#ifdef TU_ctor_from_string
Declare Constructor(Byref s As String)
#endif
Declare Destructor()
End Type
Type TV
Dim As Integer I
#ifdef TV_cast_to_TU
Declare Operator Cast() Byref As TU
#endif
#ifdef TV_cast_to_string
Declare Operator Cast() As string
#endif
End Type
Dim Shared As TU u
Dim Shared As TV v
Constructor TU()
If @This <> @u Then
Print " Constructor UDT()"
End If
End Constructor
#ifdef TU_ctor_from_TV
Constructor TU(Byref v As TV)
Print " Constructor TU(Byref As TV)"
End Constructor
#endif
#ifdef TU_ctor_from_string
Constructor TU(Byref s As string)
Print " Constructor TU(Byref As string)"
End Constructor
#endif
Destructor TU()
If @This <> @u Then
Print " Destructor TU()"
End If
End Destructor
#ifdef TV_cast_to_TU
Operator TV.Cast() Byref As TU
Print " Operator TV.Cast() Byref As TU"
Return u
End Operator
#endif
#ifdef TV_cast_to_string
Operator TV.Cast() As string
Print " Operator TV.Cast() Byref As String"
Return ""
End Operator
#endif
#ifdef op_inequal_from_TU_from_TU
Operator <>(Byref ul As TU, Byref ur As TU) As Integer
Print " Operator <>(Byref As TU, Byref As TU) As Integer"
Return 0
End Operator
#endif
#ifdef op_inequal_from_TU_from_TV
Operator <>(Byref ul As TU, Byref vr As TV) As Integer
Print " Operator <>(Byref As TU, Byref As TV) As Integer"
Return 0
End Operator
#endif
Print "'u <> v':"
If u <> v Then End If
Sleep
I have studied this for a couple of days and I have a fix. It is not what I expected so there is probably a little bit more here to understand. But I am going to push the changes soon anyway. It's a one line change that should give the same behaviour as fbc 1.09.0 for this context. And I have added the most recent tests from this topic. thank-you fxm for the code to build the "regression" tests.
For the comparison operator (actually, any binary operator, I think), at least one parameter of the two should (needs to?) match the UDT type to start with. But constructors and casts are allowed to help give a matching argument to the binary operator call. It looks like the intent is that we don't want to allow multiple constructors or casts to be chained together - at most one of each. A single constructor and/or cast to get the needed arguments to make the comparison. I know, that description is lacking and shows that I still do not have the full understanding of what currently exists in compiler logic.
Regardless of my lack of understanding, best and most efficient code generation will result when the comparison operator (or any binary operator I think) is explicitly defined. Invoking constructors and/or casts result in allocation of temporary instances and variables. For the comparison operator which should be access only (i.e. read-only), ideally an exact matching comparison operator is declared and defined by the user to avoid any temporary allocations thus improving the size and speed of the end program.
'' This code allows to check the precedence of the constructors/operators (among the eleven)
'' for each conversion/inheritance case (among the seventeen)
'' by commenting or not the #define lines only.
'' test cases selected:
#define dim_as_TU_from_TV
#define byval_as_TU_from_TV
#define byref_as_TU_from_TV
#define equal_as_TU_from_TV
#define function_equal_from_TV_to_TU
#define return_from_TV_to_TU
#define inequal_from_TU_from_TV
#define dim_as_TW_from_TW
#define byval_as_TW_from_TW
#define equal_as_TW_from_TW
#define function_equal_from_TW_to_TW
#define return_from_TW_to_TW
#define dim_as_TU_from_TW
#define byval_as_TU_from_TW
#define equal_as_TU_from_TW
#define function_equal_from_TW_to_TU
#define return_from_TW_to_TU
'' constructors/operators defined:
#define TU_ctor_from_TU
#define TU_ctor_from_TV
#define TU_ctor_from_TX
#define TU_let_from_TU
#define TU_let_from_TV
#define TU_let_from_TX
#define TU_dtor
#define TV_cast_to_TU
#define TV_cast_to_TX
#define op_inequal_from_TU_from_TU
#define op_inequal_from_TU_from_TV
'' TX type defined:
'#define TX_as_integer
'#define TX_as_integer_ptr
#define TX_as_string
'#define TX_as_UDT_with_integer
'#define TX_as_UDT_with_string
#ifdef TX_as_integer
Type TX As Integer
#endif
#ifdef TX_as_integer_ptr
Type TX As Integer Ptr
#endif
#ifdef TX_as_string
Type TX As String
#endif
#ifdef TX_as_UDT_with_integer
Type TX
Dim As Integer I
End Type
#endif
#ifdef TX_as_UDT_with_string
Type TX
Dim As String s
End Type
#endif
Type _TV As TV
Type TU
Dim As Integer I
Declare Constructor()
#ifdef TU_ctor_from_TU
Declare Constructor(Byref u As TU)
#endif
#ifdef TU_ctor_from_TV
Declare Constructor(Byref v As _TV)
#endif
#ifdef TU_ctor_from_TX
Declare Constructor(Byref s As TX)
#endif
#ifdef TU_let_from_TU
Declare Operator Let(Byref u As TU)
#endif
#ifdef TU_let_from_TV
Declare Operator Let(Byref v As _TV)
#endif
#ifdef TU_let_from_TX
Declare Operator Let(Byref s As TX)
#endif
#ifdef TU_dtor
Declare Destructor()
#endif
End Type
Type TV
Dim As Integer I
#ifdef TV_cast_to_TU
Declare Operator Cast() Byref As TU
#endif
#ifdef TV_cast_to_TX
Declare Operator Cast() Byref As TX
#endif
End Type
Type TW Extends TU
End Type
Dim Shared As TX x0
Dim Shared As TU u0
Dim Shared As TV v0
Dim Shared As TW w0, w1
Constructor TU()
If (@This <> @u0) And (@This <> @w0) And (@This <> @w1) Then
Print " Constructor TU()"
End If
End Constructor
#ifdef TU_ctor_from_TU
Constructor TU(Byref u As TU)
Print " Constructor TU(Byref As TU)"
End Constructor
#endif
#ifdef TU_ctor_from_TV
Constructor TU(Byref v As TV)
Print " Constructor TU(Byref As TV)"
End Constructor
#endif
#ifdef TU_ctor_from_TX
Constructor TU(Byref s As TX)
Print " Constructor TU(Byref As TX)"
End Constructor
#endif
#ifdef TU_let_from_TU
Operator TU.Let(Byref u As TU)
Print " Operator TU.Let(Byref As TU)"
End Operator
#endif
#ifdef TU_let_from_TV
Operator TU.Let(Byref v As TV)
Print " Operator TU.Let(Byref As TV)"
End Operator
#endif
#ifdef TU_let_from_TX
Operator TU.Let(Byref s As TX)
Print " Operator TU.Let(Byref As TX)"
End Operator
#endif
#ifdef TU_dtor
Destructor TU()
If (@This <> @u0) And (@This <> @w0) And (@This <> @w1) Then
Print " Destructor TU()"
End If
End Destructor
#endif
#ifdef TV_cast_to_TU
Operator TV.Cast() Byref As TU
Print " Operator TV.Cast() Byref As TU"
Return u0
End Operator
#endif
#ifdef TV_cast_to_TX
Operator TV.Cast() Byref As TX
Print " Operator TV.Cast() Byref As TX"
Return x0
End Operator
#endif
#ifdef op_inequal_from_TU_from_TU
Operator <>(Byref ul As TU, Byref ur As TU) As Integer
Print " Operator <>(Byref As TU, Byref As TU) As Integer"
Return 0
End Operator
#endif
#ifdef op_inequal_from_TU_from_TV
Operator <>(Byref ul As TU, Byref vr As TV) As Integer
Print " Operator <>(Byref As TU, Byref As TV) As Integer"
Return 0
End Operator
#endif
#ifdef byval_as_TU_from_TV
Sub s1(Byval u As TU)
End Sub
#endif
#ifdef byref_as_TU_from_TV
Sub s2(Byref u As TU)
End Sub
#endif
#ifdef function_equal_from_TV_to_TU
Function f11() As TU
Function = v0
End function
#endif
#ifdef return_from_TV_to_TU
Function f12() As TU
Return v0
End function
#endif
#ifdef byval_as_TW_from_TW
Sub s21(Byval w As TW)
End Sub
#endif
#ifdef function_equal_from_TW_to_TW
Function f21() As TW
Function = w0
End function
#endif
#ifdef return_from_TW_to_TW
Function f22() As TW
Return w0
End function
#endif
#ifdef byval_as_TU_from_TW
Sub s31(Byval u As TU)
End Sub
#endif
#ifdef function_equal_from_TW_to_TU
Function f31() As TU
Function = w0
End function
#endif
#ifdef return_from_TW_to_TU
Function f32() As TU
Return w0
End function
#endif
Print "-------------------- Conversion (v -> u) ---------------------"
Print
#ifdef dim_as_TU_from_TV
Scope
Print "'Dim As TU u = v':"
Dim As TU u = v0
End Scope
Print
#endif
#ifdef byval_as_TU_from_TV
Scope
Print "'Byval As TU' (from TV):"
s1(v0)
End Scope
Print
#endif
#ifdef byref_as_TU_from_TV
Scope
Print "'Byref As TU' (from TV):"
s2(v0)
End Scope
Print
#endif
#ifdef equal_as_TU_from_TV
Scope
Print "'u = v':"
u0 = v0
End Scope
Print
#endif
#ifdef function_equal_from_TV_to_TU
Scope
Print "'Function = v' to TU:"
f11()
End Scope
Print
#endif
#ifdef return_from_TV_to_TU
Scope
Print "'Return v' to TU:"
f12()
End Scope
Print
#endif
#ifdef inequal_from_TU_from_TV
Scope
Print "'u <> v':"
If u0 <> v0 Then End If
End Scope
Print
#endif
Print "------------------- Inheritance (TU <- TW) -------------------"
Print
#ifdef dim_as_TW_from_TW
Scope
Print "'Dim As TW w = w0':"
Dim As TW w = w0
End Scope
Print
#endif
#ifdef byval_as_TW_from_TW
Scope
Print "'Byval As TW' (from TW):"
s21(w0)
End Scope
Print
#endif
#ifdef equal_as_TW_from_TW
Scope
Print "'w = w0':"
w1 = w0
End Scope
Print
#endif
#ifdef function_equal_from_TW_to_TW
Scope
Print "'Function = w' to TW:"
f21()
End Scope
Print
#endif
#ifdef return_from_TW_to_TW
Scope
Print "'Return w' to TW:"
f22()
End Scope
Print
#endif
Print "----- Conversion with Inheritance (w -> u with TU <- TW) -----"
Print
#ifdef dim_as_TU_from_TW
Scope
Print "'Dim As TU u = w':"
Dim As TU u = w0
End Scope
Print
#endif
#ifdef byval_as_TU_from_TW
Scope
Print "'Byval As TU' (from TW):"
s31(w0)
End Scope
Print
#endif
#ifdef equal_as_TU_from_TW
Scope
Print "'u = w':"
u0 = w0
End Scope
Print
#endif
#ifdef function_equal_from_TW_to_TU
Scope
Print "'Function = w' to TU:"
f31()
End Scope
Print
#endif
#ifdef return_from_TW_to_TU
Scope
Print "'Return w' to TU:"
f32()
End Scope
Print
#endif
Sleep
I took the opportunity to add the visualization of the call to the TU_dtor.