> On Feb 28, 2019, at 1:44 PM, Sven Barth via fpc-devel > <fpc-devel@lists.freepascal.org> wrote: > > Right now I don't remember your changes, but it might be that you're using > the wrong approach: You shouldn't need to match anything by yourself as the > required infrastructure is already in place. You should extend htypechk > (which does the overload resolution) and defcmp (which compares the defs of > parameter values and parameter declarations in this case) so that > unspecialized generic routines are found (in htypechk) and checked correctly > (in defcmp) and then specialized.
Hmmm, I didn’t extend tcallcandidates even though it did get used. Should tcallcandidates be specializing by itself anyways? I thought it was just for overload resolution. It’s been some months since I looked at this last but this is the function which takes a dummy sym with parsed params and then does a specialization when it finds a match. This looks like a good solution to me except the one issue of strings being arrays instead of the “SHORTSTRING” type. more at: https://github.com/genericptr/freepascal/tree/generic_implicit function try_implicit_specialization(sym:tsym;struct:tabstractrecorddef;is_struct_member:boolean;para: tnode;out spezcontext:tspecializationcontext):tdef; { insert def to front of list (params are processed in reverse order) and only if the param is unique. } procedure add_unique_param(list:tfplist;def:tdef);inline; begin if list.indexof(def)=-1 then list.insert(0,def); end; var i, p: integer; srsym: tsym; srsymtable: TSymtable; ignorevisibility, allowdefaultparas, objcidcall, explicitunit, searchhelpers, anoninherited: boolean; count: integer; bestpd: tabstractprocdef; genname: string; candidates: tcallcandidates; pt: tcallparanode; paraindex: integer; paramtypes: tfplist; begin result:=nil; paramtypes:=nil; candidates:=nil; { count params } paraindex:=0; pt:=tcallparanode(para); while assigned(pt) do begin pt:=tcallparanode(pt.nextpara); paraindex:=paraindex+1; end; { find generic procsyms by param count, starting from number of parsed params. if a procsym is found then validate via tcallcandidates and build list of *unique* types for use when specializing. inferred generic types are evaluated by inserting non-repating types into the list in linear order. (1,'string') = <Integer,String> (1,2,3,4,5,6) = <Integer> ('a','b') = <String> ('string',1) = <String,Integer> ('a',1,'b',2,'c') = <String,Integer> } for i := paraindex downto 1 do begin genname:=sym.name+'$'+tostr(i); if assigned(struct) then searchsym_in_struct(struct,is_struct_member,genname,srsym,srsymtable,[ssf_search_helper]) else searchsym(genname,srsym,srsymtable); if assigned(srsym) then begin ignorevisibility:=false; allowdefaultparas:=true; objcidcall:=false; explicitunit:=false; searchhelpers:=false; anoninherited:=false; spezcontext:=nil; candidates:=tcallcandidates.create(tprocsym(srsym),srsym.owner,para,ignorevisibility, allowdefaultparas,objcidcall,explicitunit, searchhelpers,anoninherited,spezcontext); if candidates.count>0 then begin candidates.get_information; count:=candidates.choose_best(bestpd,false); if count>0 then begin if not assigned(paramtypes) then paramtypes:=tfplist.create; pt:=tcallparanode(para); paraindex:=0; while assigned(pt) do begin case pt.paravalue.nodetype of { types always fail so just block them now } typen: break; { stringconstn resultdef is an arraydef so we need to find the shortstring type to use as the parameter } stringconstn: begin // TODO: is there a better way to get the string typesym? if not searchsym_type('SHORTSTRING',srsym,srsymtable) then internalerror(2019022603); add_unique_param(paramtypes,ttypesym(srsym).typedef); end; else add_unique_param(paramtypes,pt.paravalue.resultdef); end; { next parameter in the call tree } pt:=tcallparanode(pt.nextpara); paraindex:=paraindex+1; end; { no params were found } if paramtypes.count=0 then internalerror(2019022601); { parse generic param string based on param types } result:=generate_implicit_specialization(spezcontext,sym.realname,struct,is_struct_member,paramtypes,i); paramtypes.clear; { found a matching proc } if result<>generrordef then break; end; end; freeandnil(candidates); end; end; freeandnil(paramtypes); freeandnil(candidates); if result=nil then result:=generrordef; end; function generate_implicit_specialization(out context:tspecializationcontext;symname:string;struct:tabstractrecorddef;is_struct_member:boolean;paramtypes:tfplist;paracount:integer):tdef; var parsedpos:tfileposinfo; poslist:tfplist; found: boolean; i: longint; ugenname: string; paramtype: tdef; parampos : pfileposinfo; tmpparampos : tfileposinfo; begin result:=nil; context:=tspecializationcontext.create; fillchar(parsedpos,sizeof(parsedpos),0); poslist:=context.poslist; tmpparampos:=current_filepos; { parse_generic_specialization_types_internal } for i := 0 to min(paramtypes.count,paracount)-1 do begin paramtype:=tdef(paramtypes[i]); { param type def must have a typesym } if not assigned(paramtype.typesym) then internalerror(2019022602); if assigned(poslist) then begin new(parampos); parampos^:=tmpparampos; poslist.add(parampos); end; context.genericdeflist.Add(paramtype); make_prettystring(paramtype,true,context.prettyname,context.specializename); end; { generate_specialization_phase1 } make_genname(context.genericdeflist.Count,symname,nil,context.genname,ugenname); if assigned(struct) then found:=searchsym_in_struct(struct,is_struct_member,ugenname,context.sym,context.symtable,[ssf_search_helper]) else found:=searchsym(ugenname,context.sym,context.symtable); if not found or not (context.sym.typ in [typesym,procsym]) then begin context.free; context:=nil; result:=generrordef; exit; end; { we've found the correct def } if context.sym.typ=typesym then result:=tstoreddef(ttypesym(context.sym).typedef) else begin if tprocsym(context.sym).procdeflist.count=0 then internalerror(2015061203); result:=tstoreddef(tprocsym(context.sym).procdefList[0]); end; end; Regards, Ryan Joseph _______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel