BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

General FreeBASIC programming questions.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

BUGGED COMPILER ERROR MESSAGE:
"error 202: Illegal member access, UDT.operator.cast" (it is declared private), but on the other hand this cast() operator is not really called if it is declared public.

For a construction with implicit initialization ('Dim As UDT u = v'), the compiler looks for:
- First a matching constructor (for u type).
- Then else a matching cast() operator (for v type).

In the following oversimplified example (with 'Dim As UDT u2 = u1'), there is not a direct match constructor (the copy-constructor), but a cast() operator that matches another constructor (the conversion-constructor via the String datatype), so both are called:

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String)
'        Declare Constructor(Byref t As UDT)
        Declare Constructor()
'    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String)
    Print "Constructor UDT(Byref As String)", @This
End Constructor

'Constructor UDT(Byref t As UDT)
'    Print "Constructor UDT(Byref As UDT)", @This
'End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep

Code: Select all

Constructor UDT()                         6421976

Operator UDT.Cast() As String             6421976
Constructor UDT(Byref As String)          6421968

If the cast() operator is declared private, the "illegal member access" compiler error message is well obtained:

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String)
'        Declare Constructor(Byref t As UDT)
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String)
    Print "Constructor UDT(Byref As String)", @This
End Constructor

'Constructor UDT(Byref t As UDT)
'    Print "Constructor UDT(Byref As UDT)", @This
'End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep
C:\.....\FBIDETEMP.bas(29) error 202: Illegal member access, UDT.operator.cast in 'Dim As UDT u2 = u1'

Now, a direct match constructor (the copy-constructor) is added to the existing code. It is rightly called, instead of the cast() operator + other constructor (previously both called):

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref t As UDT)
        Declare Constructor()
'    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String)
    Print "Constructor UDT(Byref As String)", @This
End Constructor

Constructor UDT(Byref t As UDT)
    Print "Constructor UDT(Byref As UDT)", @This
End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep

Code: Select all

Constructor UDT()                         6421976

Constructor UDT(Byref As UDT)             6421968

But If the cast() operator is again declared private, the "illegal member access" compiler error message is abnormally obtained:

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref t As UDT)
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String)
    Print "Constructor UDT(Byref As String)", @This
End Constructor

Constructor UDT(Byref t As UDT)
    Print "Constructor UDT(Byref As UDT)", @This
End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep
C:\.....\FBIDETEMP.bas(29) error 202: Illegal member access, UDT.operator.cast in 'Dim As UDT u2 = u1'


More generally, this bug also appears if it exists a constructor that has as first parameter type the one of the cast() operator, whatever its other parameters.

In this case, the cast() operator is never called, even without copy-constructor (I suppose implicit construction + implicit copy):

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String, Byval i As Integer)
        Declare Constructor()
'    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String, Byval i As Integer)
    Print "Constructor UDT(Byref As String, Byval As Integer)", @This
End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep

Code: Select all

Constructor UDT()                         6421976


However when the cast() operator is declared private, the same illicit compiler error message is obtained:

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String, Byval i As Integer)
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String, Byval i As Integer)
    Print "Constructor UDT(Byref As String, Byval As Integer)", @This
End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1
Print
Dim As UDT u2 = u1

Sleep
C:\.....\FBIDETEMP.bas(24) error 202: Illegal member access, UDT.operator.cast in 'Dim As UDT u2 = u1'


Note:
I found this bug in much more complex code which I simplified as I went along.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

Same bug for assignment ('u = v') with conversion -> direct

With indirect conversion:

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref s As String)
'        Declare Operator Let(Byref v As TV)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Dim As TU u
Dim As TV v
u = v

Sleep

Code: Select all

Operator TV.Cast() As String
Operator TU.Let(Byref As String)

If The cast() operator is private -> normal compiler error message:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref s As String)
'        Declare Operator Let(Byref v As TV)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Dim As TU u
Dim As TV v
u = v

Sleep
C:\.....\FBIDETEMP.bas(30) error 202: Illegal member access, TV.operator.cast in 'u = v'

With direct assignment with dedicated Let() operator (cast() operator never called):

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref s As String)
        Declare Operator Let(Byref v As TV)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Dim As TU u
Dim As TV v
u = v

Sleep

Code: Select all

Operator TU.Let(Byref As TV)

But if The cast() operator is private -> abnormal compiler error message:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref s As String)
        Declare Operator Let(Byref v As TV)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Dim As TU u
Dim As TV v
u = v

Sleep
C:\.....\FBIDETEMP.bas(30) error 202: Illegal member access, TV.operator.cast in 'u = v'

Same bug for assignment ('Function = v') with conversion -> direct
By replacing:

Code: Select all

Dim As TU u
Dim As TV v
u = v
with:

Code: Select all

Function test() As TU
    Dim As TV v
    Function = v
End Function

test()
So:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Function test() As TU
    Dim As TV v
    Function = v
End Function

test()

Sleep
C:\.....\FBIDETEMP.bas(30) error 202: Illegal member access, TV.operator.cast in 'Function = v'
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

Same bug for return from function ('Return v') with conversion -> direct

With indirect conversion:

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String)
'        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep

Code: Select all

Operator TV.Cast() As String
Constructor TU(Byref s As String)

If The cast() operator is private -> normal compiler error message:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String)
'        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep
C:\.....\FBIDETEMP.bas(35) error 202: Illegal member access, TV.operator.cast in 'Return v'

With direct assignment with dedicated constructor (cast() operator never called):

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep

Code: Select all

Constructor TU(Byref As TV)

But if The cast() operator is private -> abnormal compiler error message:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep
C:\.....\FBIDETEMP.bas(35) error 202: Illegal member access, TV.operator.cast in 'Return v'


More generally, this bug also appears if it exists a constructor that has as first parameter type the one of the cast() operator, whatever its other parameters.

With cast() operator not private:

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String, Byval i As String)
        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String, Byval i As String)
    Print "Constructor TU(Byref s As String, Byval As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep

Code: Select all

Constructor TU(Byref As TV)

However when the cast() operator is declared private, the same illicit compiler error message is obtained:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref s As String, Byval i As String)
        Declare Constructor(Byref v As TV)
End Type

Constructor TU(Byref s As String, Byval i As String)
    Print "Constructor TU(Byref s As String, Byval As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Function test() As TU
    Dim As TV v
    Return v
End function

test()

Sleep
C:\.....\FBIDETEMP.bas(35) error 202: Illegal member access, TV.operator.cast in 'Return v'


Same bug for implicit copy-construction when passing parameter ('Byval As ...') with conversion -> direct
By replacing:

Code: Select all

Function test() As TU
    Dim As TV v
    Return v
End function

test()
with:

Code: Select all

Sub test(Byval u As TU)
End Sub

Dim As TV v
test(v)
So:

Code: Select all

Type TV
    Public:
        Dim As Integer I
    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
End Type

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Sub test(Byval u As TU)
End Sub

Dim As TV v
test(v)

Sleep
C:\.....\FBIDETEMP.bas(37) error 202: Illegal member access, TV.operator.cast at parameter 1 (u) of TEST() in 'test(v)'
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

I have not found any similar bug with any other conversion operator and especially the Let() operator, except for this cast() operator when private.

@Jeff and others,
I wait a bit for the first potential reactions before filling in a bug report.


A patchwork of the bugged compiler error messages for the future bug report.

With indirect conversions:
- cast() operator + conversion-constructor() matching between them, instead of directly the dedicated constructor(),
- cast() operator + the let() operator matching between them, instead of directly the dedicated let() operator.

Code: Select all

Type TV
    Public:
        Dim As Integer I
        Declare Constructor()
'    Private:
        Declare Operator Cast() As String
End Type

Constructor TV()
    Print "Constructor TV()"
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
'        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval i As Integer)
'        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU(Byref s As String, Byval i As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
End constructor

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Sub s(Byval u As TU)
End Sub

Function f1() As TU
    Dim As TV v
    Return v
End function

Function f2() As TU
    Dim As TV v
    Function = v
End function

Dim As TV v
Print

Dim As TU u = v
Print

u = v
Print

s(v)
Print

f1()
Print

f2()
Print

Sleep

Code: Select all

Constructor TV()

Operator TV.Cast() As String
Constructor TU(Byref s As String)

Operator TV.Cast() As String
Operator TU.Let(Byref As String)

Operator TV.Cast() As String
Constructor TU(Byref s As String)

Constructor TV()
Operator TV.Cast() As String
Constructor TU(Byref s As String)

Constructor TU()
Constructor TV()
Operator TV.Cast() As String
Operator TU.Let(Byref As String)

If The cast() operator is private -> normal compiler error messages:

Code: Select all

Type TV
    Public:
        Dim As Integer I
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor TV()
    Print "Constructor TV()"
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
'        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval i As Integer)
'        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU(Byref s As String, Byval i As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
End constructor

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Sub s(Byval u As TU)
End Sub

Function f1() As TU
    Dim As TV v
    Return v
End function

Function f2() As TU
    Dim As TV v
    Function = v
End function

Dim As TV v
Print

Dim As TU u = v
Print

u = v
Print

s(v)
Print

f1()
Print

f2()
Print

Sleep
C:\.....\FBIDETEMP.bas(58) error 202: Illegal member access, TV.operator.cast in 'Return v'
C:\.....\FBIDETEMP.bas(63) error 202: Illegal member access, TV.operator.cast in 'Function = v'
C:\.....\FBIDETEMP.bas(67) error 202: Illegal member access, TV.operator.cast in 'Dim As TU u = v'
C:\.....\FBIDETEMP.bas(70) error 202: Illegal member access, TV.operator.cast in 'u = v'
C:\.....\FBIDETEMP.bas(73) error 202: Illegal member access, TV.operator.cast at parameter 1 (u) of S() in 's(v)'

With direct assignment added to the existing code:
+ dedicated constructor(),
+ dedicated let() operator.
=> cast() operator no longer called (its definition remains).

Code: Select all

Type TV
    Public:
        Dim As Integer I
        Declare Constructor()
'    Private:
        Declare Operator Cast() As String
End Type

Constructor TV()
    Print "Constructor TV()"
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval i As Integer)
        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU(Byref s As String, Byval i As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
End constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Sub s(Byval u As TU)
End Sub

Function f1() As TU
    Dim As TV v
    Return v
End function

Function f2() As TU
    Dim As TV v
    Function = v
End function

Dim As TV v
Print

Dim As TU u = v
Print

u = v
Print

s(v)
Print

f1()
Print

f2()
Print

Sleep

Code: Select all

Constructor TV()

Constructor TU(Byref As TV)

Operator TU.Let(Byref As TV)

Constructor TU(Byref As TV)

Constructor TV()
Constructor TU(Byref As TV)

Constructor TU()
Constructor TV()
Operator TU.Let(Byref As TV)

But if the cast() operator is declared private, illicit compiler error messages are obtained:

Code: Select all

Type TV
    Public:
        Dim As Integer I
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor TV()
    Print "Constructor TV()"
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End operator

Type TU
    Public:
        Dim As Integer I
        Declare Constructor()
        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval i As Integer)
        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Constructor TU(Byref s As String, Byval i As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
End constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Sub s(Byval u As TU)
End Sub

Function f1() As TU
    Dim As TV v
    Return v
End function

Function f2() As TU
    Dim As TV v
    Function = v
End function

Dim As TV v
Print

Dim As TU u = v
Print

u = v
Print

s(v)
Print

f1()
Print

f2()
Print

Sleep
C:\.....\FBIDETEMP.bas(58) error 202: Illegal member access, TV.operator.cast in 'Return v'
C:\.....\FBIDETEMP.bas(63) error 202: Illegal member access, TV.operator.cast in 'Function = v'
C:\.....\FBIDETEMP.bas(67) error 202: Illegal member access, TV.operator.cast in 'Dim As TU u = v'
C:\.....\FBIDETEMP.bas(70) error 202: Illegal member access, TV.operator.cast in 'u = v'
C:\.....\FBIDETEMP.bas(73) error 202: Illegal member access, TV.operator.cast at parameter 1 (u) of S() in 's(v)'
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

For those interested, an excerpt from the Coercion and Conversion (Variables and Datatypes) documentation page of the Programmer's Guide:
  • .....
Conversions using User Data Type constructors and operators
  • For conversion between built-in types (among standard types like between numeric types as above or between string types), the compiler knows what to do without the need for instructions from user.
    This is called the implicit internal conversion (or coercion).

    When one of the two types is at least a UDT (User Defined Type), the user has to code some UDT procedures to define how do the conversion.
    Then, the conversion execution can be explicit if the user specifies what UDT procedure must be used, or implicit if the user leaves the choice to compiler.

    In the world of UDTs, conversions can be controlled by means of three member procedures:
    • - Single-argument constructor: allow conversion from a particular type to initialize an object.
      - Assignment operator: allow conversion from a particular type on assignment.
      - Type-cast operator: allow conversion to a particular type.
    For a construction with implicit initialization ('Dim As UDT u = v'), the compiler usually searches:
    • - Firstly a matched constructor (for u type from v type).
      - Secondly a cast operator (for v type to special type (*)) and its matching conversion-constructor (for u type from special type (*)).
      - Thirdly finally a matched cast operator (for v type to u type).
      (a matched let operator (for u type from v type) is not searched by compiler on a construction with implicit initialization)
    For an implicit copy-construction ('Byval As u_type') when passing a v type parameter, the compiler usually searches:
    • - Firstly a matched cast operator (for v type to u type).
      - Secondly a matched constructor (for u type from v type).
      - Thirdly finally a cast operator (for v type to special type (*)) and its matching conversion-constructor (for u type from special type (*)).
      (a matched let operator (for u type from v type) is not searched by compiler on a construction with implicit initialization)
    For an implicit assignment ('u = v'), or an implicit return from function by assigning ('Function = v') with function returning u type, the compiler usually searches:
    • - Firstly a matched let operator (for u type from v type).
      - Secondly a cast operator (for v type to special type (*)) and its matching let operator (for u type from special type (*)).
      - Thirdly a matched cast operator (for v type to u type).
      - Fourthly finally a matched constructor (for u type from v type) and an explicit copy-let operator (u type).
    For an implicit return from function by exiting immediately ('Return v') with function returning u type, the compiler usually searches:
    • - Firstly a matched constructor (for u type from v type).
      - Secondly a cast operator (for v type to special type (*)) and its matching conversion-constructor (for u type from special type (*)).
      If an explicit copy-constructor (u type) exists:
      - Thirdly a matched cast operator (for v type to u type).
      - Fourthly finally a matched let operator (for u type from v type).
      Else (an explicit copy-constructor (u type) does not exist):
      - Thirdly a matched let operator (for u type from v type).
      - Fourthly finally a matched cast operator (for v type to u type).
    special type (*) : pointer or string, or UDT if there is no explicit copy-constructor / explicit copy-assignment operator for u type
.....

As I took advantage of this analysis to redo and complete all the conversion cases relating to UDTs, I also updated and completed the above paragraph of the documentation.
Last edited by fxm on Nov 08, 2022 7:33, edited 2 times in total.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by coderJeff »

fxm wrote: Nov 04, 2022 7:21 But if the cast() operator is declared private, illicit compiler error messages are obtained:
Thank-you. With the test cases you provided, I found the cause of the bug in like 5 seconds. Fixing it however requires some rework to the compiler internals. fbc is immediately throwing an error while checking the member procedure visibility access instead of continuing to search for a member procedure that would work. So even if there is a matching composition, fbc errors out early.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

What seems surprising is that this behavior that we see with the 'Operator Cast() As String' (when it is private) does not apply to the 'Operator Let(Byref As String'), while both are used in the following conversion:

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
'        Declare Operator Let(Byref v As TV)
'    Private:
        Declare Operator Let(Byref s As String)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Dim As TU u
Dim As TV v
u = v

Sleep

Code: Select all

Operator TV.Cast() As String
Operator TU.Let(Byref As String)

When the only 'Operator Cast() As String' is declared private, a normal compiler error message is obtained:

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
'        Declare Operator Let(Byref v As TV)
    Private:
        Declare Operator Let(Byref s As String)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Dim As TU u
Dim As TV v
u = v

Sleep
C:\.....\FBIDETEMP.bas(31) error 202: Illegal member access, TU.operator.let in 'u = v'

But no more error when the 'Operator Let(Byref As TV)' is added to the above code ('Operator Let(Byref As String)' always private):

Code: Select all

Type TV
    Public:
        Dim As Integer I
'    Private:
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return " "
End Operator

Type TU
    Public:
        Dim As Integer I
        Declare Operator Let(Byref v As TV)
    Private:
        Declare Operator Let(Byref s As String)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Dim As TU u
Dim As TV v
u = v

Sleep

Code: Select all

Operator TU.Let(Byref As TV)
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

coderJeff wrote: Nov 05, 2022 16:57 fbc is immediately throwing an error while checking the member procedure visibility access instead of continuing to search for a member procedure that would work. So even if there is a matching composition, fbc errors out early.
OK, simple and clear summary of the bug.

For the 'Return ...' keyword in a function body, it may be 4 different possible conversions tested in the following order:
1. exists a matching conversion-constructor,
2. exists a cast operator and its matching constructor,
3. exists either a matched let operator, or a matching cast operator if also exists an explicit copy-constructor,
4. exists either a matching cast operator, or a matching let operator if also exists an explicit copy-constructor.

- Example 1 (4 possibilities):
1. exists a matching conversion-constructor,
2. exists a cast operator and its matching constructor,
3. exists either a matched let operator, or a matching cast operator if also exists an explicit copy-constructor,
4. exists either a matching cast operator, or a matching let operator if also exists an explicit copy-constructor.

Code: Select all

Type _TV As TV

Type TU
    Dim As Integer I
    Declare Constructor()
    Declare Constructor(Byref v As _TV)
    Declare Constructor(Byref s As String)
    Declare Operator Let(Byref v As _TV)
End Type

Type TV
    Dim As Integer I
    Declare Constructor()
    Declare Operator Cast() As String
    Declare Operator Cast() As TU
End Type

Constructor TU()
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Constructor TV()
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return ""
End operator

Operator TV.Cast() As TU
    Print "Operator TV.Cast() As TU"
    Dim As TU u
    Return u
End operator

Function f1() As TU
    Dim As TV v
    Return v
End function

f1()
Print

Sleep

Code: Select all

Constructor TU(Byref As TV)

- Example 2 (3 possibilities):
1. exists a matching conversion-constructor,
2. exists a cast operator and its matching constructor,
3. exists either a matched let operator, or a matching cast operator if also exists an explicit copy-constructor,
4. exists either a matching cast operator, or a matching let operator if also exists an explicit copy-constructor.

Code: Select all

Type _TV As TV

Type TU
    Dim As Integer I
    Declare Constructor()
'    Declare Constructor(Byref v As _TV)
    Declare Constructor(Byref s As String)
    Declare Operator Let(Byref v As _TV)
End Type

Type TV
    Dim As Integer I
    Declare Constructor()
    Declare Operator Cast() As String
    Declare Operator Cast() As TU
End Type

Constructor TU()
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
End Constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Constructor TV()
End Constructor

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return ""
End operator

Operator TV.Cast() As TU
    Print "Operator TV.Cast() As TU"
    Dim As TU u
    Return u
End operator

Function f1() As TU
    Dim As TV v
    Return v
End function

f1()
Print

Sleep

Code: Select all

Operator TV.Cast() As String
Constructor TU(Byref s As String)

- Example 3 (2 possibilities):
1. exists a matching conversion-constructor,
2. exists a cast operator and its matching constructor,

3. exists either a matched let operator, or a matching cast operator if also exists an explicit copy-constructor,
4. exists either a matching cast operator, or a matching let operator if also exists an explicit copy-constructor.

Code: Select all

Type _TV As TV

Type TU
    Dim As Integer I
    Declare Constructor()
'    Declare Constructor(Byref v As _TV)
'    Declare Constructor(Byref s As String)
    Declare Operator Let(Byref v As _TV)
End Type

Type TV
    Dim As Integer I
    Declare Constructor()
'    Declare Operator Cast() As String
    Declare Operator Cast() As TU
End Type

Constructor TU()
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

'Constructor TU(Byref s As String)
'    Print "Constructor TU(Byref s As String)"
'End Constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
End Operator

Constructor TV()
End Constructor

'Operator TV.Cast() As String
'    Print "Operator TV.Cast() As String"
'    Return ""
'End operator

Operator TV.Cast() As TU
    Print "Operator TV.Cast() As TU"
    Dim As TU u
    Return u
End operator

Function f1() As TU
    Dim As TV v
    Return v
End function

f1()
Print

Sleep

Code: Select all

Operator TU.Let(Byref As TV)

- Example 4 (1 possibility):
1. exists a matching conversion-constructor,
2. exists a cast operator and its matching constructor,
3. exists either a matched let operator, or a matching cast operator if also exists an explicit copy-constructor,

4. exists either a matching cast operator, or a matching let operator if also exists an explicit copy-constructor.

Code: Select all

Type _TV As TV

Type TU
    Dim As Integer I
    Declare Constructor()
'    Declare Constructor(Byref v As _TV)
'    Declare Constructor(Byref s As String)
'    Declare Operator Let(Byref v As _TV)
End Type

Type TV
    Dim As Integer I
    Declare Constructor()
'    Declare Operator Cast() As String
    Declare Operator Cast() As TU
End Type

Constructor TU()
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'End constructor

'Constructor TU(Byref s As String)
'    Print "Constructor TU(Byref s As String)"
'End Constructor

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'End Operator

Constructor TV()
End Constructor

'Operator TV.Cast() As String
'    Print "Operator TV.Cast() As String"
'    Return ""
'End operator

Operator TV.Cast() As TU
    Print "Operator TV.Cast() As TU"
    Dim As TU u
    Return u
End operator

Function f1() As TU
    Dim As TV v
    Return v
End function

f1()
Print

Sleep

Code: Select all

Operator TV.Cast() As TU

Consequently, the first failing conversion and only it must be memorized in order to be able to output it in the end if necessary.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by coderJeff »

I've sat down a few times over last weeks to try and make some progress on this. It's a tricky one.

Briefly:
- compiler searches for possible matches to call a member procedure
- compiler checks if parameter conversions would allow matching a call to a member procedure
- exact matches rank higher than conversions
- errors when checking conversions are reported at the wrong time, so the whole lookup fails when it should succeed
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by coderJeff »

I've made some progress, but it always makes me nervous to push updates of changes deep in the compiler logic:

Consider example (from earlier in the thread):

Code: Select all

Type UDT
    Public:
        Dim As Integer i
        Declare Constructor(Byref s As String)
        Declare Constructor()
    Private:
        Declare Operator Cast() As String
End Type

Constructor UDT()
    Print "Constructor UDT()",, @This
End Constructor

Constructor UDT(Byref s As String)
    Print "Constructor UDT(Byref As String)", @This
End Constructor

Operator UDT.Cast() As String
    Print "Operator UDT.Cast() As String", @This
    Return ""
End Operator

Dim As UDT u1

'' fbc 1.09.0 fails with illegal access
'' fbc 1.10.0 succeeds by shallow copy initialization
Dim As UDT u2 = u1
The last few lines are:

Code: Select all

'' fbc 1.09.0 fails with illegal access
'' fbc 1.10.0 succeeds by shallow copy initialization
Dim As UDT u2 = u1
The main behaviour that has to be fixed is that 'private: operator cast' was generating an error even if only testing that it could be used. The compiler considers a number of constructions and chooses the best one.

The result of fixing this behaviour, is that other constructions now succeed. In theory that shouldn't break user code since things that were previously in error are now allowed. But it is a change in behaviour and could cause some confusion if the user expected some syntax to error in certain uses.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

coderJeff wrote: Nov 28, 2022 16:06 But it is a change in behaviour and could cause some confusion if the user expected some syntax to error in certain uses.

Referring to the above example, if the user wants to prohibit the implicit copy-construction by imposing only construction by conversion, the easiest way is to declare a private copy-constructor, and not to knowingly take advantage of an existing bug by declaring a private cast operator matching the conversion type.

I do not think we should hesitate to fix this bug (as we did for many others that did not prohibit the execution of code), as on the contrary we could do it exceptionally for this other bug:
#811 *(ptr).field should give an error
where the user uses it involuntarily by being mistaken about the precedence of the operators.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

@Jeff,

Thanks for the fix for #970.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by fxm »

Okay, but a little thing bothers me:
In case of third-part conversion, where two operators are chained, these two operators do not cause a symmetric error message when one of them is declared private.

Example for assignment TV -> string -> TU, with a TV.cast operator to string, and a TU.let operator from string:

Code: Select all

'#define Private_TU_let_from_string
'#define Private_TV_cast_to_string

Type TU
    Public:
        Dim As Integer I
    #ifdef Private_TU_let_from_string
    Private:
    #endif
        Declare Operator Let(Byref s As String)
End Type

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
End Operator

Type TV
    Public:
        Dim As Integer I
    #ifdef Private_TV_cast_to_string
    Private:
    #endif
        Declare Operator Cast() As String
End Type

Operator TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return ""
End Operator

Dim As TU u
Dim As TV v
u = v

Sleep

Code: Select all

Operator TV.Cast() As String
Operator TU.Let(Byref As String)

- If only the operator let is private:

Code: Select all

#define Private_TU_let_from_string
'#define Private_TV_cast_to_string
C:\.....\FBIDETEMP.bas(33) error 202: Illegal member access, TU.operator.let in 'u = v'
OK

- If only the operator cast is private:

Code: Select all

'#define Private_TU_let_from_string
#define Private_TV_cast_to_string
C:\.....\FBIDETEMP.bas(33) error 181: Invalid assignment/conversion in 'u = v'
NOK : rather "error 202: Illegal member access, TV.operator.cast in 'u = v'" instead ?

- If The Two operators are private:

Code: Select all

#define Private_TU_let_from_string
#define Private_TV_cast_to_string
C:\.....\FBIDETEMP.bas(33) error 181: Invalid assignment/conversion in 'u = v'
OK ?
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message

Post by coderJeff »

fxm wrote: Nov 30, 2022 13:55 Okay, but a little thing bothers me:
In case of third-part conversion, where two operators are chained, these two operators do not cause a symmetric error message when one of them is declared private.
I understand what you are saying. I noticed this while developing the changes. I'm afraid that it's best that we can do at the moment unless we make more major changes to fbc internals. Currently, fbc ranks possible procedure matches and tries to choose the best. But currently there is no way to rank a procedure call as a possible match while at the same time tracking that it can't match because unable to access a conversion / CAST.

The logic kind of works like this:

Code: Select all

u = v                            '' typeof(u) <> typeof(v), Invalid assignment
u = cast(string, v)              '' cast(string, v) is not typeof(u), Invalid assignment
u.let(string) = v                '' typeof(v) is not string, Invalid assignment
u.let(string) = cast(string, v)  '' ok, but only if both let and cast accessible
Then we should expect one of the following scenarios depending on private / public:

Code: Select all

public:let public:cast
u.let(string) = cast(string, v)  '' public CAST is something we can use and access
                                 '' public LET is something we can use and access
                                 '' result: OK 

private:let public:cast
u.let(string) = cast(string, v)  '' public CAST is something we can use and access
                                 '' private LET is something we can use but NOT access
                                 '' result: Illegal member access on private LET

public:let private:cast
u.let(string) = cast(string, v)  '' private CAST is something we can not access and therefore not use
                                 '' no checks made on public LET
                                 '' result: Invalid assignment

private:let private:cast
u.let(string) = cast(string, v)  '' private cast is something we can not access and therefore not use
                                 '' no checks made on private LET
                                 '' result: Invalid assignment
We know that the assignment should fail, but getting more refined detailed reason why it fails would require another major change to the internals and internal information tracking. So, this is probably as best as we can do for now.

EDIT: fixed up my incorrect uses of CAN and NOT in the scenarios. :)
Post Reply