Skip to content

Commit 4033507

Browse files
committed
fbc: sf.net # 948: Duplicated class members inherit from the base class instead of incorrectly from the namespace
Example: namespace M dim as zstring * 32 duplicate = "M.duplicate" end namespace namespace N dim as zstring * 32 duplicate = "N.duplicate" type parent extends object dim as zstring * 32 duplicate = "N.parent.duplicate" end type type child extends parent declare sub proc() end type end namespace sub n.child.proc() using M ? duplicate '' now is "N.parent.duplicate" '' was N.duplicate in fbc-1.08 end sub dim as N.child c c.proc()
1 parent c5edeb1 commit 4033507

File tree

7 files changed

+197
-80
lines changed

7 files changed

+197
-80
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Version 1.09.0
9696
- sf.net #945: regression: Scoping rules have changed inside methods - allow globals to shadow non-explicit enums implicitly imported in to the current namespace
9797
- sf.net #892: Bug when default calling via a pointer to a 'Sub' defined with the only 'Any Ptr' - fbc now differentiates between function pointers that have different numbers and positions of optional parameters
9898
- sf.net #948: Overriding class members doesn't work inside methods of further-extended subclasses
99+
- sf.net #948: Duplicated class members inherit from the base class instead of incorrectly from the namespace
99100

100101

101102
Version 1.08.0

src/compiler/symb.bas

Lines changed: 108 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,100 +1100,128 @@ function symbLookupTypeNS _
11001100
'' Because symbols are added in the order that they are defined,
11011101
'' in some cases we can't just take the first symbol we find.
11021102

1103-
'' keyword?
1104-
hashtb = symb.hashlist.tail
1105-
do
1106-
dim as FBSYMBOL ptr sym = hashLookupEx( @hashtb->tb, id, index )
1107-
while( sym )
1108-
if( sym->class = FB_SYMBCLASS_KEYWORD ) then
1109-
tk = sym->key.id
1110-
tk_class = sym->key.tkclass
1111-
'' return if it's a KEYWORD or a OPERATOR token, they
1112-
'' can't never be redefined, even inside namespaces
1113-
if( tk_class <> FB_TKCLASS_QUIRKWD ) then
1103+
scope
1104+
'' keyword?
1105+
hashtb = symb.hashlist.tail
1106+
do
1107+
dim as FBSYMBOL ptr sym = hashLookupEx( @hashtb->tb, id, index )
1108+
while( sym )
1109+
if( sym->class = FB_SYMBCLASS_KEYWORD ) then
1110+
tk = sym->key.id
1111+
tk_class = sym->key.tkclass
1112+
'' return if it's a KEYWORD or a OPERATOR token, they
1113+
'' can't never be redefined, even inside namespaces
1114+
if( tk_class <> FB_TKCLASS_QUIRKWD ) then
1115+
return symbNewChainpool( sym )
1116+
end if
1117+
end if
1118+
sym = sym->hash.next
1119+
wend
1120+
hashtb = hashtb->prev
1121+
loop while( hashtb <> NULL )
1122+
end scope
1123+
1124+
scope
1125+
'' Search locals - if we are in a procedure, and the symbol can be found
1126+
'' directly, return the first one on the top of the stack
1127+
hashtb = symb.hashlist.tail
1128+
do
1129+
dim as FBSYMBOL ptr sym = hashLookupEx( @hashtb->tb, id, index )
1130+
while( sym )
1131+
if( symbIsLocal( sym ) ) then
11141132
return symbNewChainpool( sym )
11151133
end if
1116-
end if
1117-
sym = sym->hash.next
1118-
wend
1119-
hashtb = hashtb->prev
1120-
loop while( hashtb <> NULL )
1134+
sym = sym->hash.next
1135+
wend
1136+
hashtb = hashtb->prev
1137+
loop while( hashtb <> NULL )
1138+
end scope
11211139

1122-
'' any symbol not in the global namespace or we are already in the global namespace?
1123-
'' check the whole list before we check the imports
1124-
hashtb = symb.hashlist.tail
1125-
do
1126-
dim as FBSYMBOL ptr sym = hashLookupEx( @hashtb->tb, id, index )
1140+
1141+
scope
1142+
'' Search symbols in the UDT's namespace
1143+
dim as FBSYMBOL ptr ns = symbGetCurrentNamespc( )
1144+
1145+
'' search in UDT's (TYPE or CLASS) hash tb first
1146+
dim as FBSYMBOL ptr sym = hashLookupEx( @symbGetCompHashTb( ns ).tb, id, index )
1147+
1148+
'' don't access locals in a TYPE's namespace
11271149
while( sym )
1128-
'' return if it's not the global ns (as in C++, any nested
1129-
'' symbol has precedence over any imported one, even if the
1130-
'' latter was imported in the current ns)
1131-
if( hashtb->owner <> @symbGetGlobalNamespc( ) ) then
1132-
return symbNewChainpool( sym )
1150+
if( symbIsLocal( sym ) ) then
1151+
sym = sym->hash.next
11331152
else
1134-
'' also if we are at the global ns, no need to check the imports
1135-
if( symbGetCurrentNamespc( ) = @symbGetGlobalNamespc( ) ) then
1136-
return symbNewChainpool( sym )
1137-
else
1138-
if( first_ancestor = NULL ) then
1139-
first_ancestor = sym
1140-
end if
1141-
end if
1153+
exit while
11421154
end if
1143-
sym = sym->hash.next
11441155
wend
1145-
hashtb = hashtb->prev
1146-
loop while( hashtb <> NULL )
1147-
1148-
dim as FBSYMBOL ptr ns = symbGetCurrentNamespc( )
11491156

1150-
'' search in UDT's (TYPE or CLASS) hash tb first
1151-
dim as FBSYMBOL ptr sym = hashLookupEx( @symbGetCompHashTb( ns ).tb, id, index )
1152-
1153-
'' don't access local variables in an explicit namespace
1154-
while( sym )
1155-
if( symbIsLocal( sym ) and symbIsVar( sym ) ) then
1156-
sym = sym->hash.next
1157-
else
1158-
exit while
1157+
'' Found the symbol in the type's namespace?
1158+
if( sym ) then
1159+
dim as FBSYMCHAIN ptr chain_ = symbNewChainpool( sym )
1160+
return chain_
11591161
end if
1160-
wend
1162+
end scope
1163+
1164+
scope
1165+
'' Search symbols in the the type's imports, but only if inherieted from
1166+
'' a parent type - don't check imports from a normal namespace
1167+
1168+
'' we already know that the current namespace is a TYPE
1169+
dim as FBSYMBOL ptr ns = symbGetCurrentNamespc( )
1170+
1171+
if( (symbGetCompExt( ns ) <> NULL) and (symbGetCompImportHead( ns ) <> NULL) ) then
1172+
dim as FBSYMCHAIN ptr chain_ = hLookupImportList( ns, id, index )
1173+
dim as FBSYMBOL ptr sym = NULL
1174+
1175+
'' search UDT variables
1176+
while ( chain_ )
1177+
sym = chain_->sym
1178+
while( sym )
1179+
dim as FBSYMBOL ptr parent = symbGetParent( sym )
1180+
if( symbGetType( parent ) = FB_DATATYPE_STRUCT ) then
1181+
if( symbGetUDTBaseLevel( ns, parent ) > 0 ) then
1182+
return symbNewChainpool( chain_->sym )
1183+
end if
1184+
end if
1185+
sym = sym->hash.next
1186+
wend
11611187

1162-
'' Found the symbol in the type's namespace?
1163-
if( sym ) then
1164-
dim as FBSYMCHAIN ptr chain_ = symbNewChainpool( sym )
1165-
return chain_
1166-
end if
1188+
chain_ = symbChainGetNext( chain_ )
1189+
wend
11671190

1168-
'' Search the type's imports
1169-
if( (symbGetCompExt( ns ) <> NULL) and (symbGetCompImportHead( ns ) <> NULL) ) then
1170-
dim as FBSYMCHAIN ptr chain_ = hLookupImportList( ns, id, index )
1171-
if( chain_ ) then
1172-
'' return the first one
1173-
return symbNewChainpool( chain_->sym )
11741191
end if
1175-
end if
1176-
1177-
'' search all the imports?
1178-
dim as FBSYMCHAIN ptr imp_chain = hashLookupEx( @symb.imphashtb, id, index )
1179-
if( imp_chain <> NULL ) then
1192+
end scope
11801193

1181-
if( first_ancestor ) then
1182-
dim as FBSYMCHAIN ptr chain_ = symbNewChainpool( first_ancestor )
1183-
chain_->next = imp_chain
1184-
return chain_
1194+
scope
1195+
'' any symbol not in the global namespace or we are already in the global namespace?
1196+
'' check the whole list before we check the imports
1197+
hashtb = symb.hashlist.tail
1198+
do
1199+
dim as FBSYMBOL ptr sym = hashLookupEx( @hashtb->tb, id, index )
1200+
if( sym ) then
1201+
return symbNewChainpool( sym )
1202+
end if
1203+
hashtb = hashtb->prev
1204+
loop while( hashtb <> NULL )
1205+
end scope
1206+
1207+
scope
1208+
'' search the current namespace
1209+
dim as FBSYMBOL ptr ns = symbGetCurrentNamespc( )
1210+
1211+
if( (symbGetCompExt( ns ) <> NULL) and (symbGetCompImportHead( ns ) <> NULL) ) then
1212+
dim as FBSYMCHAIN ptr chain_ = hLookupImportList( ns, id, index )
1213+
if( chain_ ) then
1214+
'' return the first one
1215+
return symbNewChainpool( chain_->sym )
1216+
end if
11851217
end if
1218+
end scope
11861219

1187-
return imp_chain
1188-
end if
1189-
1190-
'' no imports? return only first ancestor (if we already found it)
1191-
if( first_ancestor ) then
1192-
return symbNewChainpool( first_ancestor )
1193-
end if
1220+
'' search all the imports
1221+
dim as FBSYMCHAIN ptr imp_chain = hashLookupEx( @symb.imphashtb, id, index )
11941222

11951223
'' never found
1196-
return NULL
1224+
return imp_chain
11971225

11981226
end function
11991227

@@ -1345,6 +1373,9 @@ function symbLookupAt _
13451373
'' search in UDT's (NAMESPACE, TYPE, CLASS or ENUM) hash tb first
13461374
dim as FBSYMBOL ptr sym = hashLookupEx( @symbGetCompHashTb( ns ).tb, id, index )
13471375

1376+
'' !!!TODO!!! some imports won't make sense in an explicit namespace
1377+
'' for example this.proc() where proc() is imported from a plain old namespace
1378+
13481379
'' don't access local variables in an explicit namespace
13491380
while( sym )
13501381
if( symbIsLocal( sym ) and symbIsVar( sym ) ) then

src/compiler/symb.bi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ type FB_STRUCTEXT
512512
end type
513513

514514
type FBS_STRUCT
515-
'' extends FBNAMESCP
515+
'' extends FBNAMESPC
516516
ns as FBNAMESPC
517517

518518
base as FBSYMBOL_ ptr '' base class

tests/structs/inherit-type-1.bas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private sub module_proc()
131131

132132
scope
133133
dim x as N.A3.C
134-
checkCall( x.method(), "N.PROC" )
134+
checkCall( x.method(), "N.P.PROC" )
135135
end scope
136136

137137
end sub

tests/structs/inherit-type-3.bas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ namespace N
144144
end type
145145

146146
sub C.method()
147-
proc() '' << ambiguous N.P.PROC, B.PROC, E.PROC
147+
proc()
148148
end sub
149149

150150
sub method2()

tests/structs/inherit-type-4.bas

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include once "fbcunit.bi"
2+
3+
'' define namespace names to allow short names
4+
'' in this source but avoid namespace collisions
5+
'' in other sources
6+
7+
#define M iherit_type_4_M
8+
#define N iherit_type_4_N
9+
10+
dim shared as zstring * 32 duplicate = "..duplicate"
11+
12+
namespace M
13+
dim as zstring * 32 duplicate = "M.duplicate"
14+
end namespace
15+
16+
namespace N
17+
dim as zstring * 32 duplicate = "N.duplicate"
18+
type parent extends object
19+
dim as zstring * 32 duplicate = "N.parent.duplicate"
20+
end type
21+
type child extends parent
22+
declare sub proc()
23+
end type
24+
end namespace
25+
26+
sub n.child.proc()
27+
using M
28+
CU_ASSERT_EQUAL( duplicate, "N.parent.duplicate" )
29+
end sub
30+
31+
private sub module_proc
32+
dim as N.child c
33+
c.proc()
34+
end sub
35+
36+
SUITE( fbc_tests.structs.inherit_type_4 )
37+
TEST( default )
38+
module_proc()
39+
END_TEST
40+
END_SUITE

tests/structs/inherit-type-5.bas

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include once "fbcunit.bi"
2+
3+
'' define namespace names to allow short names
4+
'' in this source but avoid namespace collisions
5+
'' in other sources
6+
7+
#define M iherit_type_5_M
8+
#define N iherit_type_5_N
9+
10+
dim shared as zstring * 32 duplicate = "..duplicate"
11+
12+
namespace M
13+
dim as zstring * 32 duplicate = "M.duplicate"
14+
end namespace
15+
16+
namespace N
17+
type parent extends object
18+
declare sub proc()
19+
end type
20+
type child extends parent
21+
declare sub proc()
22+
end type
23+
end namespace
24+
25+
sub N.parent.proc()
26+
using M
27+
CU_ASSERT_EQUAL( duplicate, "..duplicate" )
28+
end sub
29+
30+
sub N.child.proc()
31+
using M
32+
CU_ASSERT_EQUAL( duplicate, "..duplicate" )
33+
end sub
34+
35+
private sub module_proc
36+
dim as n.child c
37+
c.proc()
38+
cast(n.parent,c).proc()
39+
end sub
40+
41+
SUITE( fbc_tests.structs.inherit_type_5 )
42+
TEST( default )
43+
module_proc()
44+
END_TEST
45+
END_SUITE

0 commit comments

Comments
 (0)