From 9d48bc0baf6b8db5908be90ffbcfb2079ede4ac4 Mon Sep 17 00:00:00 2001 From: svenbarth <pascaldragon@googlemail.com> Date: Wed, 18 Sep 2013 14:28:46 +0000 Subject: [PATCH] Implement cross unit type overloading of generics. This fixes the regression introduced with revision 25498. symtable.pas: + add new tsymbol_search_flag type which can be passed to various searchsym* routines + add support to not call "addsymref" + add new searchsym_with_flags function that calls searchsym_maybe_with_symoption * adjust searchsym_maybe_with_symoption, searchsym_in_class & searchsym_in_helper to use new flag type instead of Boolean arguments * adjust searchsym & searchsym_with_symoption which call the modified functions nutils.pas, handle_staticfield_access: * adjust searchsym_in_class call pexpr.pas, handle_factor_typenode, postfixoperators, factor: * adjust searchsym_in_helper and searchsym_in_class calls pinline.pas, new_function: * adjust searchsym_in_class call scanner.pas, try_consume_nestedsym: * adjust searchsym_in_class call fmodule.pas, tmodule: + add genericdummysyms field which is a TFPHashObjectList that contains TFPObjectList instances per generic dummy that in turn contains tgenericdummysyms instances pgenutil.pas: + add function split_generic_name to split a generic name into non-generic name and count value of type parameters + add function resolve_generic_dummysym which tries to use the new genericdummysyms field to find the real symbol of a dummy sym * generate_specialization: adjust searchsym_in_class call * specialization_init/specialization_done: save/restore genericdummysyms of module symdef.pas, tdefawaresymtablestack: + add new intermediate method pushcommon which is used by both push and pushafter + add new intermediate method remove_helpers_and_generics (which calls remove_generics and remove_helpers if necessary) * rename removehelpers to remove_helpers * rename addhelpers to add_helpers_and_generics and extend it to correctly fill current_module.genericdummysyms * call remove_helpers_and_generics from pop instead of remove_helpers ptype.pas, single_type, read_named_type.expr_type, read_named_type: * try to resolve symbols with sp_generic_dummy with resolve_generic_dummysym + added test git-svn-id: trunk@25519 - --- .gitattributes | 5 ++ compiler/fmodule.pas | 7 ++ compiler/nutils.pas | 2 +- compiler/pexpr.pas | 16 ++--- compiler/pgenutil.pas | 41 +++++++++++- compiler/pinline.pas | 2 +- compiler/ptype.pas | 59 +++++++++++++++-- compiler/scanner.pas | 2 +- compiler/symdef.pas | 136 ++++++++++++++++++++++++++++++++------ compiler/symtable.pas | 69 +++++++++++++------ tests/test/tgeneric96.pp | 11 +++ tests/test/ugeneric96a.pp | 21 ++++++ tests/test/ugeneric96b.pp | 21 ++++++ tests/test/ugeneric96c.pp | 14 ++++ tests/test/ugeneric96d.pp | 14 ++++ 15 files changed, 360 insertions(+), 60 deletions(-) create mode 100644 tests/test/tgeneric96.pp create mode 100644 tests/test/ugeneric96a.pp create mode 100644 tests/test/ugeneric96b.pp create mode 100644 tests/test/ugeneric96c.pp create mode 100644 tests/test/ugeneric96d.pp diff --git a/.gitattributes b/.gitattributes index f3cdc3ecef..f90bbca35e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11310,6 +11310,7 @@ tests/test/tgeneric92.pp svneol=native#text/pascal tests/test/tgeneric93.pp svneol=native#text/pascal tests/test/tgeneric94.pp svneol=native#text/pascal tests/test/tgeneric95.pp svneol=native#text/pascal +tests/test/tgeneric96.pp svneol=native#text/pascal tests/test/tgoto.pp svneol=native#text/plain tests/test/theap.pp svneol=native#text/plain tests/test/theapthread.pp svneol=native#text/plain @@ -11937,6 +11938,10 @@ tests/test/ugeneric91a.pp svneol=native#text/pascal tests/test/ugeneric91b.pp svneol=native#text/pascal tests/test/ugeneric93a.pp svneol=native#text/pascal tests/test/ugeneric93b.pp svneol=native#text/pascal +tests/test/ugeneric96a.pp svneol=native#text/pascal +tests/test/ugeneric96b.pp svneol=native#text/pascal +tests/test/ugeneric96c.pp svneol=native#text/pascal +tests/test/ugeneric96d.pp svneol=native#text/pascal tests/test/uhintdir.pp svneol=native#text/plain tests/test/uhlp3.pp svneol=native#text/pascal tests/test/uhlp31.pp svneol=native#text/pascal diff --git a/compiler/fmodule.pas b/compiler/fmodule.pas index d4b3aaf325..f146ddfab6 100644 --- a/compiler/fmodule.pas +++ b/compiler/fmodule.pas @@ -184,6 +184,11 @@ interface the full name of the type and the data is a TFPObjectList of tobjectdef instances (the helper defs) } extendeddefs: TFPHashObjectList; + { contains a list of the current topmost non-generic symbol for a + typename of which at least one generic exists; the key is the + non-generic typename and the data is a TFPObjectList of tgenericdummyentry + instances whereby the last one is the current top most one } + genericdummysyms: TFPHashObjectList; { this contains a list of units that needs to be waited for until the unit can be finished (code generated, etc.); this is needed to handle @@ -547,6 +552,7 @@ implementation wpoinfo:=nil; checkforwarddefs:=TFPObjectList.Create(false); extendeddefs:=TFPHashObjectList.Create(true); + genericdummysyms:=tfphashobjectlist.create(true); waitingforunit:=tfpobjectlist.create(false); waitingunits:=tfpobjectlist.create(false); globalsymtable:=nil; @@ -636,6 +642,7 @@ implementation stringdispose(mainname); FImportLibraryList.Free; extendeddefs.Free; + genericdummysyms.free; waitingforunit.free; waitingunits.free; stringdispose(asmprefix); diff --git a/compiler/nutils.pas b/compiler/nutils.pas index 74c01b1600..f6d9667ac1 100644 --- a/compiler/nutils.pas +++ b/compiler/nutils.pas @@ -1042,7 +1042,7 @@ implementation else static_name:=lower(generate_nested_name(sym.owner,'_'))+'_'+sym.name; if sym.owner.defowner.typ=objectdef then - searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable,true) + searchsym_in_class(tobjectdef(sym.owner.defowner),tobjectdef(sym.owner.defowner),static_name,sym,srsymtable,[ssf_search_helper]) else searchsym_in_record(trecorddef(sym.owner.defowner),static_name,sym,srsymtable); if assigned(sym) then diff --git a/compiler/pexpr.pas b/compiler/pexpr.pas index b0fbf80aea..b56fc6f05a 100644 --- a/compiler/pexpr.pas +++ b/compiler/pexpr.pas @@ -1382,7 +1382,7 @@ implementation result:=ctypenode.create(hdef); ttypenode(result).typesym:=sym; { search also in inherited methods } - searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable,true); + searchsym_in_class(tobjectdef(hdef),tobjectdef(current_structdef),pattern,srsym,srsymtable,[ssf_search_helper]); if assigned(srsym) then check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); consume(_ID); @@ -2197,7 +2197,7 @@ implementation if token=_ID then begin structh:=tobjectdef(tclassrefdef(p1.resultdef).pointeddef); - searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true); + searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]); if assigned(srsym) then begin check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); @@ -2221,7 +2221,7 @@ implementation if token=_ID then begin structh:=tobjectdef(p1.resultdef); - searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,true); + searchsym_in_class(tobjectdef(structh),tobjectdef(structh),pattern,srsym,srsymtable,[ssf_search_helper]); if assigned(srsym) then begin check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg); @@ -2920,9 +2920,9 @@ implementation else { helpers have their own ways of dealing with inherited } if is_objectpascal_helper(current_structdef) then - searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,true) + searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,[ssf_has_inherited]) else - searchsym_in_class(hclassdef,current_structdef,hs,srsym,srsymtable,true); + searchsym_in_class(hclassdef,current_structdef,hs,srsym,srsymtable,[ssf_search_helper]); end else begin @@ -2932,9 +2932,9 @@ implementation anon_inherited:=false; { helpers have their own ways of dealing with inherited } if is_objectpascal_helper(current_structdef) then - searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,true) + searchsym_in_helper(tobjectdef(current_structdef),tobjectdef(current_structdef),hs,srsym,srsymtable,[ssf_has_inherited]) else - searchsym_in_class(hclassdef,current_structdef,hs,srsym,srsymtable,true); + searchsym_in_class(hclassdef,current_structdef,hs,srsym,srsymtable,[ssf_search_helper]); end; if assigned(srsym) then begin @@ -2992,7 +2992,7 @@ implementation if (po_msgint in pd.procoptions) or (po_msgstr in pd.procoptions) then begin - searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable,true); + searchsym_in_class(hclassdef,hclassdef,'DEFAULTHANDLER',srsym,srsymtable,[ssf_search_helper]); if not assigned(srsym) or (srsym.typ<>procsym) then internalerror(200303171); diff --git a/compiler/pgenutil.pas b/compiler/pgenutil.pas index af6f34ba94..97bbb20c89 100644 --- a/compiler/pgenutil.pas +++ b/compiler/pgenutil.pas @@ -41,11 +41,14 @@ uses procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList); procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist); function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring; + procedure split_generic_name(const name:tidstring;out nongeneric:string;out count:longint); + function resolve_generic_dummysym(const name:tidstring):tsym; type tspecializationstate = record oldsymtablestack : tsymtablestack; oldextendeddefs : TFPHashObjectList; + oldgenericdummysyms: tfphashobjectlist; end; procedure specialization_init(genericdef:tdef;var state:tspecializationstate); @@ -566,7 +569,7 @@ uses if assigned(genericdef) and (genericdef.owner.symtabletype in [objectsymtable,recordsymtable]) then begin if genericdef.owner.symtabletype = objectsymtable then - found:=searchsym_in_class(tobjectdef(genericdef.owner.defowner),tobjectdef(genericdef.owner.defowner),ugenname,srsym,st,false) + found:=searchsym_in_class(tobjectdef(genericdef.owner.defowner),tobjectdef(genericdef.owner.defowner),ugenname,srsym,st,[]) else found:=searchsym_in_record(tabstractrecorddef(genericdef.owner.defowner),ugenname,srsym,st); end @@ -1102,6 +1105,38 @@ uses result:=name+'$crc'+hexstr(crc,8); end; + procedure split_generic_name(const name:tidstring;out nongeneric:string;out count:longint); + var + i,code : longint; + countstr : string; + begin + for i:=length(name) downto 1 do + if name[i]='$' then + begin + nongeneric:=copy(name,1,i-1); + countstr:=copy(name,i+1,length(name)-i); + val(countstr,count,code); + if code<>0 then + internalerror(2013091605); + exit; + end; + nongeneric:=name; + count:=0; + end; + + + function resolve_generic_dummysym(const name:tidstring):tsym; + var + list : tfpobjectlist; + begin + list:=tfpobjectlist(current_module.genericdummysyms.find(name)); + if assigned(list) and (list.count>0) then + result:=tgenericdummyentry(list.last).resolvedsym + else + result:=nil; + end; + + procedure specialization_init(genericdef:tdef;var state: tspecializationstate); var pu : tused_unit; @@ -1117,7 +1152,9 @@ uses the resolved symbols } state.oldsymtablestack:=symtablestack; state.oldextendeddefs:=current_module.extendeddefs; + state.oldgenericdummysyms:=current_module.genericdummysyms; current_module.extendeddefs:=TFPHashObjectList.create(true); + current_module.genericdummysyms:=tfphashobjectlist.create(true); symtablestack:=tdefawaresymtablestack.create; hmodule:=find_module_from_symtable(genericdef.owner); if hmodule=nil then @@ -1169,6 +1206,8 @@ uses { Restore symtablestack } current_module.extendeddefs.free; current_module.extendeddefs:=state.oldextendeddefs; + current_module.genericdummysyms.free; + current_module.genericdummysyms:=state.oldgenericdummysyms; symtablestack.free; symtablestack:=state.oldsymtablestack; { clear the state record to be on the safe side } diff --git a/compiler/pinline.pas b/compiler/pinline.pas index 7cf7899df3..322fc53696 100644 --- a/compiler/pinline.pas +++ b/compiler/pinline.pas @@ -472,7 +472,7 @@ implementation { search the constructor also in the symbol tables of the parents } afterassignment:=false; - searchsym_in_class(classh,classh,pattern,srsym,srsymtable,true); + searchsym_in_class(classh,classh,pattern,srsym,srsymtable,[ssf_search_helper]); consume(_ID); do_member_read(classh,false,srsym,p1,again,[cnf_new_call]); { we need to know which procedure is called } diff --git a/compiler/ptype.pas b/compiler/ptype.pas index 5cc93d7d7f..210faf35ee 100644 --- a/compiler/ptype.pas +++ b/compiler/ptype.pas @@ -493,8 +493,16 @@ implementation ) then begin - Message(parser_e_no_generics_as_types); - def:=generrordef; + srsym:=resolve_generic_dummysym(srsym.name); + if assigned(srsym) and + not (sp_generic_dummy in srsym.symoptions) and + (srsym.typ=typesym) then + def:=ttypesym(srsym).typedef + else + begin + Message(parser_e_no_generics_as_types); + def:=generrordef; + end; end else if (def.typ=undefineddef) and (sp_generic_dummy in srsym.symoptions) and @@ -504,8 +512,16 @@ implementation begin if m_delphi in current_settings.modeswitches then begin - Message(parser_e_no_generics_as_types); - def:=generrordef; + srsym:=resolve_generic_dummysym(srsym.name); + if assigned(srsym) and + not (sp_generic_dummy in srsym.symoptions) and + (srsym.typ=typesym) then + def:=ttypesym(srsym).typedef + else + begin + Message(parser_e_no_generics_as_types); + def:=generrordef; + end; end else def:=current_genericdef; @@ -887,6 +903,9 @@ implementation old_block_type : tblock_type; dospecialize : boolean; newdef : tdef; + sym : tsym; + genstr : string; + gencount : longint; begin old_block_type:=block_type; dospecialize:=false; @@ -1031,8 +1050,26 @@ implementation ) then begin - Message(parser_e_no_generics_as_types); - def:=generrordef; + if assigned(def.typesym) then + begin + if ttypesym(def.typesym).typedef.typ<>undefineddef then + { non-Delphi modes... } + split_generic_name(def.typesym.name,genstr,gencount) + else + genstr:=def.typesym.name; + sym:=resolve_generic_dummysym(genstr); + end + else + sym:=nil; + if assigned(sym) and + not (sp_generic_dummy in sym.symoptions) and + (sym.typ=typesym) then + def:=ttypesym(sym).typedef + else + begin + Message(parser_e_no_generics_as_types); + def:=generrordef; + end; end else if is_classhelper(def) then begin @@ -1515,7 +1552,15 @@ implementation (tt2.typ=undefineddef) and assigned(tt2.typesym) and (sp_generic_dummy in tt2.typesym.symoptions) then - Message(parser_e_no_generics_as_types); + begin + sym:=resolve_generic_dummysym(tt2.typesym.name); + if assigned(sym) and + not (sp_generic_dummy in sym.symoptions) and + (sym.typ=typesym) then + tt2:=ttypesym(sym).typedef + else + Message(parser_e_no_generics_as_types); + end; { don't use getpointerdef() here, since this is a type declaration (-> must create new typedef) } def:=tpointerdef.create(tt2); diff --git a/compiler/scanner.pas b/compiler/scanner.pas index c9eb11cd20..6bdaf98d3c 100644 --- a/compiler/scanner.pas +++ b/compiler/scanner.pas @@ -1390,7 +1390,7 @@ type preproc_consume(_POINT); current_scanner.skipspace; if def.typ=objectdef then - found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,true) + found:=searchsym_in_class(tobjectdef(def),tobjectdef(def),current_scanner.preproc_pattern,srsym,srsymtable,[ssf_search_helper]) else found:=searchsym_in_record(trecorddef(def),current_scanner.preproc_pattern,srsym,srsymtable); if not found then diff --git a/compiler/symdef.pas b/compiler/symdef.pas index a4a6b61c35..6cc61ab040 100644 --- a/compiler/symdef.pas +++ b/compiler/symdef.pas @@ -825,16 +825,27 @@ interface function is_publishable : boolean;override; end; + + tgenericdummyentry = class + dummysym : tsym; + resolvedsym : tsym; + end; + + tdefawaresymtablestack = class(TSymtablestack) private - procedure addhelpers(st: TSymtable); - procedure removehelpers(st: TSymtable); + procedure add_helpers_and_generics(st:tsymtable;addgenerics:boolean); + procedure remove_helpers_and_generics(st:tsymtable);inline; + procedure remove_helpers(st:tsymtable); + procedure remove_generics(st:tsymtable); + procedure pushcommon(st:tsymtable);inline; public procedure push(st: TSymtable); override; procedure pushafter(st,afterst:TSymtable); override; procedure pop(st: TSymtable); override; end; + var current_structdef: tabstractrecorddef; { used for private functions check !! } current_genericdef: tstoreddef; { used to reject declaration of generic class inside generic class } @@ -1080,6 +1091,8 @@ implementation {$ifdef jvm} jvmdef, {$endif} + { parser } + pgenutil, { module } fmodule, { other } @@ -1316,12 +1329,15 @@ implementation the pushed/popped symtables) ****************************************************************************} - procedure tdefawaresymtablestack.addhelpers(st: TSymtable); + procedure tdefawaresymtablestack.add_helpers_and_generics(st:tsymtable;addgenerics:boolean); var i: integer; s: string; list: TFPObjectList; def: tdef; + sym,srsym : tsym; + srsymtable : tsymtable; + entry : tgenericdummyentry; begin { search the symtable from first to last; the helper to use will be the last one in the list } @@ -1330,6 +1346,7 @@ implementation if not (st.symlist[i] is ttypesym) then continue; def:=ttypesym(st.SymList[i]).typedef; + sym:=tsym(st.symlist[i]); if is_objectpascal_helper(def) then begin s:=generate_objectpascal_helper_key(tobjectdef(def).extendeddef); @@ -1343,13 +1360,62 @@ implementation list.Add(def); end else - { add nested helpers as well } - if def.typ in [recorddef,objectdef] then - addhelpers(tabstractrecorddef(def).symtable); + begin + if addgenerics and + (sp_generic_dummy in sym.symoptions) + then + begin + { did we already search for a generic with that name? } + list:=tfpobjectlist(current_module.genericdummysyms.find(sym.name)); + if not assigned(list) then + begin + list:=tfpobjectlist.create(true); + current_module.genericdummysyms.add(sym.name,list); + end; + { is the dummy sym still "dummy"? } + if (sym.typ=typesym) and + ( + { dummy sym defined in mode Delphi } + (ttypesym(sym).typedef.typ=undefineddef) or + { dummy sym defined in non-Delphi mode } + (tstoreddef(ttypesym(sym).typedef).is_generic) + ) then + begin + { do we have a non-generic type of the same name + available? } + if not searchsym_with_flags(sym.name,srsym,srsymtable,[ssf_no_addsymref]) then + srsym:=nil; + end + else + { dummy symbol is already not so dummy anymore } + srsym:=nil; + if assigned(srsym) then + begin + entry:=tgenericdummyentry.create; + entry.resolvedsym:=srsym; + entry.dummysym:=sym; + list.add(entry); + end; + end; + { add nested helpers as well } + if (def.typ in [recorddef,objectdef]) and + (sto_has_helper in tabstractrecorddef(def).symtable.tableoptions) then + add_helpers_and_generics(tabstractrecorddef(def).symtable,false); + end; end; end; - procedure tdefawaresymtablestack.removehelpers(st: TSymtable); + + procedure tdefawaresymtablestack.remove_helpers_and_generics(st:tsymtable); + begin + if sto_has_helper in st.tableoptions then + remove_helpers(st); + if sto_has_generic in st.tableoptions then + remove_generics(st); + end; + + + procedure tdefawaresymtablestack.remove_helpers(st:TSymtable); var i, j: integer; tmpst: TSymtable; @@ -1383,31 +1449,63 @@ implementation end; end; + + procedure tdefawaresymtablestack.remove_generics(st:tsymtable); + var + i,j : longint; + entry : tgenericdummyentry; + list : tfpobjectlist; + begin + for i:=current_module.genericdummysyms.count-1 downto 0 do + begin + list:=tfpobjectlist(current_module.genericdummysyms[i]); + if not assigned(list) then + continue; + for j:=list.count-1 downto 0 do + begin + entry:=tgenericdummyentry(list[j]); + if entry.dummysym.owner=st then + list.delete(j); + end; + if list.count=0 then + current_module.genericdummysyms.delete(i); + end; + end; + + + procedure tdefawaresymtablestack.pushcommon(st:tsymtable); + begin + if (sto_has_generic in st.tableoptions) or + ( + (st.symtabletype in [globalsymtable,staticsymtable]) and + (sto_has_helper in st.tableoptions) + ) then + { nested helpers will be added as well } + add_helpers_and_generics(st,true); + end; + procedure tdefawaresymtablestack.push(st: TSymtable); begin - { nested helpers will be added as well } - if (st.symtabletype in [globalsymtable,staticsymtable]) and - (sto_has_helper in st.tableoptions) then - addhelpers(st); + pushcommon(st); inherited push(st); end; procedure tdefawaresymtablestack.pushafter(st,afterst:TSymtable); begin - { nested helpers will be added as well } - if (st.symtabletype in [globalsymtable,staticsymtable]) and - (sto_has_helper in st.tableoptions) then - addhelpers(st); + pushcommon(st); inherited pushafter(st,afterst); end; procedure tdefawaresymtablestack.pop(st: TSymtable); begin inherited pop(st); - { nested helpers will be removed as well } - if (st.symtabletype in [globalsymtable,staticsymtable]) and - (sto_has_helper in st.tableoptions) then - removehelpers(st); + if (sto_has_generic in st.tableoptions) or + ( + (st.symtabletype in [globalsymtable,staticsymtable]) and + (sto_has_helper in st.tableoptions) + ) then + { nested helpers will be removed as well } + remove_helpers_and_generics(st); end; diff --git a/compiler/symtable.pas b/compiler/symtable.pas index 3f08b1c8df..cd1ba82683 100644 --- a/compiler/symtable.pas +++ b/compiler/symtable.pas @@ -206,6 +206,15 @@ interface var systemunit : tglobalsymtable; { pointer to the system unit } + type + tsymbol_search_flag = ( + ssf_search_option, + ssf_search_helper, + ssf_has_inherited, + ssf_no_addsymref + ); + tsymbol_search_flags = set of tsymbol_search_flag; + {**************************************************************************** Functions @@ -233,19 +242,20 @@ interface function is_visible_for_object(pd:tprocdef;contextobjdef:tabstractrecorddef):boolean; function is_visible_for_object(sym:tsym;contextobjdef:tabstractrecorddef):boolean; function searchsym(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; - function searchsym_maybe_with_symoption(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchoption:boolean;option:tsymoption):boolean; + function searchsym_with_flags(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; + function searchsym_maybe_with_symoption(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags;option:tsymoption):boolean; { searches for a symbol with the given name that has the given option in symoptions set } function searchsym_with_symoption(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;option:tsymoption):boolean; function searchsym_type(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_module(pm:pointer;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_named_module(const unitname, symname: TIDString; out srsym: tsym; out srsymtable: tsymtable): boolean; - function searchsym_in_class(classh: tobjectdef; contextclassh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:boolean):boolean; + function searchsym_in_class(classh: tobjectdef; contextclassh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; function searchsym_in_record(recordh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_class_by_msgint(classh:tobjectdef;msgid:longint;out srdef : tdef;out srsym:tsym;out srsymtable:TSymtable):boolean; function searchsym_in_class_by_msgstr(classh:tobjectdef;const s:string;out srsym:tsym;out srsymtable:TSymtable):boolean; { searches symbols inside of a helper's implementation } - function searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;aHasInherited:boolean):boolean; + function searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; function search_system_type(const s: TIDString): ttypesym; function try_search_system_type(const s: TIDString): ttypesym; function search_system_proc(const s: TIDString): tprocdef; @@ -2313,10 +2323,17 @@ implementation function searchsym(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; begin - result:=searchsym_maybe_with_symoption(s,srsym,srsymtable,false,sp_none); + result:=searchsym_maybe_with_symoption(s,srsym,srsymtable,[],sp_none); end; - function searchsym_maybe_with_symoption(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchoption:boolean;option:tsymoption):boolean; + + function searchsym_with_flags(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; + begin + result:=searchsym_maybe_with_symoption(s,srsym,srsymtable,flags,sp_none); + end; + + + function searchsym_maybe_with_symoption(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags;option:tsymoption):boolean; var hashedid : THashedIDString; contextstructdef : tabstractrecorddef; @@ -2331,12 +2348,12 @@ implementation if (srsymtable.symtabletype=objectsymtable) then begin { TODO : implement the search for an option in classes as well } - if searchoption then + if ssf_search_option in flags then begin result:=false; exit; end; - if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable,true) then + if searchsym_in_class(tobjectdef(srsymtable.defowner),tobjectdef(srsymtable.defowner),s,srsym,srsymtable,flags+[ssf_search_helper]) then begin result:=true; exit; @@ -2360,7 +2377,7 @@ implementation contextstructdef:=current_structdef; if not (srsym.owner.symtabletype in [objectsymtable,recordsymtable]) or is_visible_for_object(srsym,contextstructdef) and - (not searchoption or (option in srsym.symoptions)) then + (not (ssf_search_option in flags) or (option in srsym.symoptions)) then begin { we need to know if a procedure references symbols in the static symtable, because then it can't be @@ -2368,7 +2385,8 @@ implementation if assigned(current_procinfo) and (srsym.owner.symtabletype=staticsymtable) then include(current_procinfo.flags,pi_uses_static_symtable); - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; @@ -2383,7 +2401,7 @@ implementation function searchsym_with_symoption(const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;option:tsymoption):boolean; begin - result:=searchsym_maybe_with_symoption(s,srsym,srsymtable,true,option); + result:=searchsym_maybe_with_symoption(s,srsym,srsymtable,[ssf_search_option],option); end; function searchsym_type(const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean; @@ -2615,7 +2633,7 @@ implementation end; - function searchsym_in_class(classh: tobjectdef;contextclassh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;searchhelper:boolean):boolean; + function searchsym_in_class(classh: tobjectdef;contextclassh:tabstractrecorddef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; var hashedid : THashedIDString; orgclass : tobjectdef; @@ -2651,13 +2669,14 @@ implementation if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then begin - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; for i:=0 to classh.ImplementedInterfaces.count-1 do begin - if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable,false) then + if searchsym_in_class(TImplementedInterface(classh.ImplementedInterfaces[i]).intfdef,contextclassh,s,srsym,srsymtable,flags-[ssf_search_helper]) then begin result:=true; exit; @@ -2668,7 +2687,7 @@ implementation if is_objectpascal_helper(classh) then begin { helpers have their own obscure search logic... } - result:=searchsym_in_helper(classh,tobjectdef(contextclassh),s,srsym,srsymtable,false); + result:=searchsym_in_helper(classh,tobjectdef(contextclassh),s,srsym,srsymtable,flags-[ssf_has_inherited]); if result then exit; end @@ -2680,7 +2699,9 @@ implementation begin { search for a class helper method first if this is an Object Pascal class and we haven't yet found a helper symbol } - if is_class(classh) and searchhelper and not assigned(hlpsrsym) then + if is_class(classh) and + (ssf_search_helper in flags) and + not assigned(hlpsrsym) then begin result:=search_objectpascal_helper(classh,contextclassh,s,srsym,srsymtable); if result then @@ -2703,7 +2724,8 @@ implementation if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then begin - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; @@ -2840,7 +2862,7 @@ implementation srsymtable:=nil; end; - function searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;aHasInherited:boolean):boolean; + function searchsym_in_helper(classh,contextclassh:tobjectdef;const s: TIDString;out srsym:tsym;out srsymtable:TSymtable;flags:tsymbol_search_flags):boolean; var hashedid : THashedIDString; parentclassh : tobjectdef; @@ -2855,7 +2877,7 @@ implementation 3. search the symbol in the parent helpers 4. only classes: search the symbol in the parents of the extended type } - if not aHasInherited then + if not (ssf_has_inherited in flags) then begin { search in the helper itself } srsymtable:=classh.symtable; @@ -2863,7 +2885,8 @@ implementation if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then begin - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; @@ -2876,7 +2899,8 @@ implementation if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then begin - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; @@ -2890,7 +2914,8 @@ implementation if assigned(srsym) and is_visible_for_object(srsym,contextclassh) then begin - addsymref(srsym); + if not (ssf_no_addsymref in flags) then + addsymref(srsym); result:=true; exit; end; @@ -2898,7 +2923,7 @@ implementation end; if is_class(classh.extendeddef) then { now search in the parents of the extended class (with helpers!) } - result:=searchsym_in_class(tobjectdef(classh.extendeddef).childof,contextclassh,s,srsym,srsymtable,true); + result:=searchsym_in_class(tobjectdef(classh.extendeddef).childof,contextclassh,s,srsym,srsymtable,flags+[ssf_search_helper]); { addsymref is already called by searchsym_in_class } end; diff --git a/tests/test/tgeneric96.pp b/tests/test/tgeneric96.pp new file mode 100644 index 0000000000..8a030c8fd7 --- /dev/null +++ b/tests/test/tgeneric96.pp @@ -0,0 +1,11 @@ +{ %NORUN } + +program tgeneric96; + +uses + ugeneric96a, + ugeneric96b; + +begin + +end. diff --git a/tests/test/ugeneric96a.pp b/tests/test/ugeneric96a.pp new file mode 100644 index 0000000000..1eb19da880 --- /dev/null +++ b/tests/test/ugeneric96a.pp @@ -0,0 +1,21 @@ +unit ugeneric96a; + +{$mode objfpc} + +interface + +uses + // difference to ugeneric96b: order of uses + ugeneric96c, // contains non-generic TTest + ugeneric96d; // contains generic TTest<> + +type + TLongIntTest = specialize TTest<LongInt>; + +var + lt: TLongIntTest; + t: TTest; + +implementation + +end. diff --git a/tests/test/ugeneric96b.pp b/tests/test/ugeneric96b.pp new file mode 100644 index 0000000000..53826c214a --- /dev/null +++ b/tests/test/ugeneric96b.pp @@ -0,0 +1,21 @@ +unit ugeneric96b; + +{$mode objfpc} + +interface + +uses + // difference to ugeneric96a: order of uses + ugeneric96d, // contains generic TTest<> + ugeneric96c; // contains non-generic TTest + +type + TLongIntTest = specialize TTest<LongInt>; + +var + lt: TLongIntTest; + t: TTest; + +implementation + +end. diff --git a/tests/test/ugeneric96c.pp b/tests/test/ugeneric96c.pp new file mode 100644 index 0000000000..8daa493105 --- /dev/null +++ b/tests/test/ugeneric96c.pp @@ -0,0 +1,14 @@ +unit ugeneric96c; + +{$mode objfpc} + +interface + +type + TTest = class + + end; + +implementation + +end. diff --git a/tests/test/ugeneric96d.pp b/tests/test/ugeneric96d.pp new file mode 100644 index 0000000000..650f869541 --- /dev/null +++ b/tests/test/ugeneric96d.pp @@ -0,0 +1,14 @@ +unit ugeneric96d; + +{$mode objfpc} + +interface + +type + generic TTest<T> = class + + end; + +implementation + +end.