pgenutil.pas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. {
  2. Copyright (c) 2011
  3. Contains different functions that are used in the context of
  4. parsing generics.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit pgenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. { common }
  23. cclasses,
  24. { global }
  25. globtype,
  26. { symtable }
  27. symtype,symdef,symbase;
  28. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo);
  29. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string);
  30. function parse_generic_parameters(allowconstraints:boolean):TFPObjectList;
  31. function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean;
  32. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  33. procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist);
  34. function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring;
  35. type
  36. tspecializationstate = record
  37. oldsymtablestack : tsymtablestack;
  38. oldextendeddefs : TFPHashObjectList;
  39. end;
  40. procedure specialization_init(genericdef:tdef;var state:tspecializationstate);
  41. procedure specialization_done(var state:tspecializationstate);
  42. implementation
  43. uses
  44. { common }
  45. cutils,fpccrc,
  46. { global }
  47. globals,tokens,verbose,finput,
  48. { symtable }
  49. symconst,symsym,symtable,
  50. { modules }
  51. fmodule,
  52. { pass 1 }
  53. htypechk,
  54. node,nobj,nmem,
  55. { parser }
  56. scanner,
  57. pbase,pexpr,pdecsub,ptype;
  58. procedure maybe_add_waiting_unit(tt:tdef);
  59. var
  60. hmodule : tmodule;
  61. begin
  62. if not assigned(tt) or
  63. not (df_generic in tt.defoptions) then
  64. exit;
  65. hmodule:=find_module_from_symtable(tt.owner);
  66. if not assigned(hmodule) then
  67. internalerror(2012092401);
  68. if hmodule=current_module then
  69. exit;
  70. if hmodule.state<>ms_compiled then
  71. begin
  72. {$ifdef DEBUG_UNITWAITING}
  73. Writeln('Unit ', current_module.modulename^,
  74. ' waiting for ', hmodule.modulename^);
  75. {$endif DEBUG_UNITWAITING}
  76. if current_module.waitingforunit.indexof(hmodule)<0 then
  77. current_module.waitingforunit.add(hmodule);
  78. if hmodule.waitingunits.indexof(current_module)<0 then
  79. hmodule.waitingunits.add(current_module);
  80. end;
  81. end;
  82. function check_generic_constraints(genericdef:tstoreddef;paradeflist:tfpobjectlist;poslist:tfplist):boolean;
  83. var
  84. i,j,
  85. intfcount : longint;
  86. formaldef,
  87. paradef : tstoreddef;
  88. objdef,
  89. paraobjdef,
  90. formalobjdef : tobjectdef;
  91. intffound : boolean;
  92. filepos : tfileposinfo;
  93. begin
  94. { check whether the given specialization parameters fit to the eventual
  95. constraints of the generic }
  96. if not assigned(genericdef.genericparas) or (genericdef.genericparas.count=0) then
  97. internalerror(2012101001);
  98. if genericdef.genericparas.count<>paradeflist.count then
  99. internalerror(2012101002);
  100. if paradeflist.count<>poslist.count then
  101. internalerror(2012120801);
  102. result:=true;
  103. for i:=0 to genericdef.genericparas.count-1 do
  104. begin
  105. filepos:=pfileposinfo(poslist[i])^;
  106. formaldef:=tstoreddef(ttypesym(genericdef.genericparas[i]).typedef);
  107. if formaldef.typ=undefineddef then
  108. { the parameter is of unspecified type, so no need to check }
  109. continue;
  110. if not (df_genconstraint in formaldef.defoptions) or
  111. not assigned(formaldef.genconstraintdata) then
  112. internalerror(2013021602);
  113. paradef:=tstoreddef(paradeflist[i]);
  114. { undefineddef is compatible with anything }
  115. if formaldef.typ=undefineddef then
  116. continue;
  117. if paradef.typ<>formaldef.typ then
  118. begin
  119. case formaldef.typ of
  120. recorddef:
  121. MessagePos(filepos,type_e_record_type_expected);
  122. objectdef:
  123. case tobjectdef(formaldef).objecttype of
  124. odt_class,
  125. odt_javaclass:
  126. MessagePos1(filepos,type_e_class_type_expected,paradef.typename);
  127. odt_interfacecom,
  128. odt_interfacecorba,
  129. odt_dispinterface,
  130. odt_interfacejava:
  131. MessagePos1(filepos,type_e_interface_type_expected,paradef.typename);
  132. else
  133. internalerror(2012101003);
  134. end;
  135. errordef:
  136. { ignore }
  137. ;
  138. else
  139. internalerror(2012101004);
  140. end;
  141. result:=false;
  142. end
  143. else
  144. begin
  145. { the paradef types are the same, so do special checks for the
  146. cases in which they are needed }
  147. if formaldef.typ=objectdef then
  148. begin
  149. paraobjdef:=tobjectdef(paradef);
  150. formalobjdef:=tobjectdef(formaldef);
  151. if not (formalobjdef.objecttype in [odt_class,odt_javaclass,odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_dispinterface]) then
  152. internalerror(2012101102);
  153. if formalobjdef.objecttype in [odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_dispinterface] then
  154. begin
  155. { this is either a concerete interface or class type (the
  156. latter without specific implemented interfaces) }
  157. case paraobjdef.objecttype of
  158. odt_interfacecom,
  159. odt_interfacecorba,
  160. odt_interfacejava,
  161. odt_dispinterface:
  162. if not paraobjdef.is_related(formalobjdef.childof) then
  163. begin
  164. MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.childof.typename);
  165. result:=false;
  166. end;
  167. odt_class,
  168. odt_javaclass:
  169. begin
  170. objdef:=paraobjdef;
  171. intffound:=false;
  172. while assigned(objdef) do
  173. begin
  174. for j:=0 to objdef.implementedinterfaces.count-1 do
  175. if timplementedinterface(objdef.implementedinterfaces[j]).intfdef=formalobjdef.childof then
  176. begin
  177. intffound:=true;
  178. break;
  179. end;
  180. if intffound then
  181. break;
  182. objdef:=objdef.childof;
  183. end;
  184. result:=intffound;
  185. if not result then
  186. MessagePos2(filepos,parser_e_class_doesnt_implement_interface,paraobjdef.typename,formalobjdef.childof.typename);
  187. end;
  188. else
  189. begin
  190. MessagePos1(filepos,type_e_class_or_interface_type_expected,paraobjdef.typename);
  191. result:=false;
  192. end;
  193. end;
  194. end
  195. else
  196. begin
  197. { this is either a "class" or a concrete instance with
  198. or without implemented interfaces }
  199. if not (paraobjdef.objecttype in [odt_class,odt_javaclass]) then
  200. begin
  201. MessagePos1(filepos,type_e_class_type_expected,paraobjdef.typename);
  202. result:=false;
  203. continue;
  204. end;
  205. if assigned(formalobjdef.childof) and
  206. not paradef.is_related(formalobjdef.childof) then
  207. begin
  208. MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.childof.typename);
  209. result:=false;
  210. end;
  211. intfcount:=0;
  212. for j:=0 to formalobjdef.implementedinterfaces.count-1 do
  213. begin
  214. objdef:=paraobjdef;
  215. while assigned(objdef) do
  216. begin
  217. intffound:=assigned(
  218. objdef.find_implemented_interface(
  219. timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef
  220. )
  221. );
  222. if intffound then
  223. break;
  224. objdef:=objdef.childof;
  225. end;
  226. if intffound then
  227. inc(intfcount)
  228. else
  229. MessagePos2(filepos,parser_e_class_doesnt_implement_interface,paraobjdef.typename,timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef.typename);
  230. end;
  231. if intfcount<>formalobjdef.implementedinterfaces.count then
  232. result:=false;
  233. end;
  234. end;
  235. end;
  236. end;
  237. end;
  238. function parse_generic_specialization_types_internal(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring;parsedtype:tdef;parsedpos:tfileposinfo):boolean;
  239. var
  240. old_block_type : tblock_type;
  241. first : boolean;
  242. typeparam : tnode;
  243. parampos : pfileposinfo;
  244. tmpparampos : tfileposinfo;
  245. begin
  246. result:=true;
  247. if genericdeflist=nil then
  248. internalerror(2012061401);
  249. { set the block type to type, so that the parsed type are returned as
  250. ttypenode (e.g. classes are in non type-compatible blocks returned as
  251. tloadvmtaddrnode) }
  252. old_block_type:=block_type;
  253. { if parsedtype is set, then the first type identifer was already parsed
  254. (happens in inline specializations) and thus we only need to parse
  255. the remaining types and do as if the first one was already given }
  256. first:=not assigned(parsedtype);
  257. if assigned(parsedtype) then
  258. begin
  259. genericdeflist.Add(parsedtype);
  260. specializename:='$'+parsedtype.typename;
  261. prettyname:=parsedtype.typesym.prettyname;
  262. if assigned(poslist) then
  263. begin
  264. New(parampos);
  265. parampos^:=parsedpos;
  266. poslist.add(parampos);
  267. end;
  268. end
  269. else
  270. begin
  271. specializename:='';
  272. prettyname:='';
  273. end;
  274. while not (token in [_GT,_RSHARPBRACKET]) do
  275. begin
  276. { "first" is set to false at the end of the loop! }
  277. if not first then
  278. consume(_COMMA);
  279. block_type:=bt_type;
  280. tmpparampos:=current_filepos;
  281. typeparam:=factor(false,true);
  282. if typeparam.nodetype=typen then
  283. begin
  284. if df_generic in typeparam.resultdef.defoptions then
  285. Message(parser_e_no_generics_as_params);
  286. if assigned(poslist) then
  287. begin
  288. New(parampos);
  289. parampos^:=tmpparampos;
  290. poslist.add(parampos);
  291. end;
  292. genericdeflist.Add(typeparam.resultdef);
  293. if not assigned(typeparam.resultdef.typesym) then
  294. message(type_e_generics_cannot_reference_itself)
  295. else
  296. begin
  297. specializename:=specializename+'$'+typeparam.resultdef.typename;
  298. if first then
  299. prettyname:=prettyname+typeparam.resultdef.typesym.prettyname
  300. else
  301. prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname;
  302. end;
  303. end
  304. else
  305. begin
  306. Message(type_e_type_id_expected);
  307. result:=false;
  308. end;
  309. typeparam.free;
  310. first:=false;
  311. end;
  312. block_type:=old_block_type;
  313. end;
  314. function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean;
  315. var
  316. dummypos : tfileposinfo;
  317. begin
  318. FillChar(dummypos, SizeOf(tfileposinfo), 0);
  319. result:=parse_generic_specialization_types_internal(genericdeflist,poslist,prettyname,specializename,nil,dummypos);
  320. end;
  321. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string);
  322. var
  323. dummypos : tfileposinfo;
  324. begin
  325. FillChar(dummypos, SizeOf(tfileposinfo), 0);
  326. generate_specialization(tt,parse_class_parent,_prettyname,nil,'',dummypos);
  327. end;
  328. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo);
  329. var
  330. st : TSymtable;
  331. srsym : tsym;
  332. pt2 : tnode;
  333. errorrecovery,
  334. found,
  335. first,
  336. err : boolean;
  337. errval,
  338. i,
  339. gencount : longint;
  340. genericdef,def : tstoreddef;
  341. generictype : ttypesym;
  342. genericdeflist : TFPObjectList;
  343. generictypelist : TFPObjectList;
  344. prettyname,specializename : ansistring;
  345. ufinalspecializename,
  346. countstr,genname,ugenname,finalspecializename : string;
  347. vmtbuilder : TVMTBuilder;
  348. specializest : tsymtable;
  349. item : tobject;
  350. old_current_structdef : tabstractrecorddef;
  351. old_current_genericdef,old_current_specializedef : tstoreddef;
  352. tempst : tglobalsymtable;
  353. old_block_type: tblock_type;
  354. hashedid: thashedidstring;
  355. state : tspecializationstate;
  356. hmodule : tmodule;
  357. oldcurrent_filepos : tfileposinfo;
  358. poslist : tfplist;
  359. begin
  360. { retrieve generic def that we are going to replace }
  361. genericdef:=tstoreddef(tt);
  362. tt:=nil;
  363. { either symname must be given or genericdef needs to be valid }
  364. errorrecovery:=false;
  365. if (symname='') and
  366. (not assigned(genericdef) or
  367. not assigned(genericdef.typesym) or
  368. (genericdef.typesym.typ<>typesym)) then
  369. begin
  370. errorrecovery:=true;
  371. tt:=generrordef;
  372. end;
  373. { Only parse the parameters for recovery or
  374. for recording in genericbuf }
  375. if parse_generic or errorrecovery then
  376. begin
  377. first:=assigned(parsedtype);
  378. if not first and not try_to_consume(_LT) then
  379. consume(_LSHARPBRACKET);
  380. gencount:=0;
  381. { handle "<>" }
  382. if not first and ((token=_RSHARPBRACKET) or (token=_GT)) then
  383. Message(type_e_type_id_expected)
  384. else
  385. repeat
  386. if not first then
  387. begin
  388. pt2:=factor(false,true);
  389. pt2.free;
  390. end;
  391. first:=false;
  392. inc(gencount);
  393. until not try_to_consume(_COMMA);
  394. if not try_to_consume(_GT) then
  395. consume(_RSHARPBRACKET);
  396. { we need to return a def that can later pass some checks like
  397. whether it's an interface or not }
  398. if not errorrecovery and
  399. (not assigned(tt) or (tt.typ=undefineddef)) then
  400. begin
  401. if (symname='') and (df_generic in genericdef.defoptions) then
  402. { this happens in non-Delphi modes }
  403. tt:=genericdef
  404. else
  405. begin
  406. { find the corresponding generic symbol so that any checks
  407. done on the returned def will be handled correctly }
  408. str(gencount,countstr);
  409. if symname='' then
  410. genname:=ttypesym(genericdef.typesym).realname
  411. else
  412. genname:=symname;
  413. genname:=genname+'$'+countstr;
  414. ugenname:=upper(genname);
  415. { first check whether the found name is the same as that of
  416. the current def or one of its (generic) surrounding defs;
  417. this is necessary as the symbol of the generic can not yet
  418. be used for lookup as it still contains a reference to an
  419. errordef) }
  420. def:=current_genericdef;
  421. repeat
  422. if def.typ in [objectdef,recorddef] then
  423. if tabstractrecorddef(def).objname^=ugenname then
  424. begin
  425. tt:=def;
  426. break;
  427. end;
  428. def:=tstoreddef(def.owner.defowner);
  429. until not assigned(def) or not (df_generic in def.defoptions);
  430. { it's not part of the current object hierarchy, so search
  431. for the symbol }
  432. if not assigned(tt) then
  433. begin
  434. if not searchsym(ugenname,srsym,st) or
  435. (srsym.typ<>typesym) then
  436. begin
  437. identifier_not_found(genname);
  438. tt:=generrordef;
  439. exit;
  440. end;
  441. tt:=ttypesym(srsym).typedef;
  442. { this happens in non-Delphi modes if we encounter a
  443. specialization of the generic class or record we're
  444. currently parsing }
  445. if (tt.typ=errordef) and assigned(current_structdef) and
  446. (current_structdef.objname^=ugenname) then
  447. tt:=current_structdef;
  448. end;
  449. end;
  450. end;
  451. exit;
  452. end;
  453. if not assigned(parsedtype) and not try_to_consume(_LT) then
  454. begin
  455. consume(_LSHARPBRACKET);
  456. { handle "<>" }
  457. if (token=_GT) or (token=_RSHARPBRACKET) then
  458. begin
  459. Message(type_e_type_id_expected);
  460. if not try_to_consume(_GT) then
  461. try_to_consume(_RSHARPBRACKET);
  462. tt:=generrordef;
  463. exit;
  464. end;
  465. end;
  466. genericdeflist:=TFPObjectList.Create(false);
  467. poslist:=tfplist.create;
  468. { Parse type parameters }
  469. err:=not parse_generic_specialization_types_internal(genericdeflist,poslist,prettyname,specializename,parsedtype,parsedpos);
  470. if err then
  471. begin
  472. if not try_to_consume(_GT) then
  473. try_to_consume(_RSHARPBRACKET);
  474. genericdeflist.free;
  475. for i:=0 to poslist.count-1 do
  476. dispose(pfileposinfo(poslist[i]));
  477. poslist.free;
  478. tt:=generrordef;
  479. exit;
  480. end;
  481. { use the name of the symbol as procvars return a user friendly version
  482. of the name }
  483. if symname='' then
  484. genname:=ttypesym(genericdef.typesym).realname
  485. else
  486. genname:=symname;
  487. { in case of non-Delphi mode the type name could already be a generic
  488. def (but maybe the wrong one) }
  489. if assigned(genericdef) and
  490. ([df_generic,df_specialization]*genericdef.defoptions<>[]) then
  491. begin
  492. { remove the type count suffix from the generic's name }
  493. for i:=Length(genname) downto 1 do
  494. if genname[i]='$' then
  495. begin
  496. genname:=copy(genname,1,i-1);
  497. break;
  498. end;
  499. { in case of a specialization we've only reached the specialization
  500. checksum yet }
  501. if df_specialization in genericdef.defoptions then
  502. for i:=length(genname) downto 1 do
  503. if genname[i]='$' then
  504. begin
  505. genname:=copy(genname,1,i-1);
  506. break;
  507. end;
  508. end
  509. else
  510. { search for a potential suffix }
  511. for i:=length(genname) downto 1 do
  512. if genname[i]='$' then
  513. begin
  514. { if the part right of the $ is a number we assume that the left
  515. part is the name of the generic, otherwise we assume that the
  516. complete name is the name of the generic }
  517. countstr:=copy(genname,i+1,length(genname)-i);
  518. gencount:=0;
  519. val(countstr,gencount,errval);
  520. if errval=0 then
  521. genname:=copy(genname,1,i-1);
  522. break;
  523. end;
  524. { search a generic with the given count of params }
  525. countstr:='';
  526. str(genericdeflist.Count,countstr);
  527. genname:=genname+'$'+countstr;
  528. ugenname:=upper(genname);
  529. if assigned(genericdef) and (genericdef.owner.symtabletype in [objectsymtable,recordsymtable]) then
  530. begin
  531. if genericdef.owner.symtabletype = objectsymtable then
  532. found:=searchsym_in_class(tobjectdef(genericdef.owner.defowner),tobjectdef(genericdef.owner.defowner),ugenname,srsym,st,false)
  533. else
  534. found:=searchsym_in_record(tabstractrecorddef(genericdef.owner.defowner),ugenname,srsym,st);
  535. end
  536. else
  537. found:=searchsym(ugenname,srsym,st);
  538. if not found or (srsym.typ<>typesym) then
  539. begin
  540. identifier_not_found(genname);
  541. if not try_to_consume(_GT) then
  542. try_to_consume(_RSHARPBRACKET);
  543. for i:=0 to poslist.count-1 do
  544. dispose(pfileposinfo(poslist[i]));
  545. poslist.free;
  546. genericdeflist.Free;
  547. tt:=generrordef;
  548. exit;
  549. end;
  550. { we've found the correct def }
  551. genericdef:=tstoreddef(ttypesym(srsym).typedef);
  552. if not check_generic_constraints(genericdef,genericdeflist,poslist) then
  553. begin
  554. { the parameters didn't fit the constraints, so don't continue with the
  555. specialization }
  556. genericdeflist.free;
  557. for i:=0 to poslist.count-1 do
  558. dispose(pfileposinfo(poslist[i]));
  559. poslist.free;
  560. tt:=generrordef;
  561. if not try_to_consume(_GT) then
  562. try_to_consume(_RSHARPBRACKET);
  563. exit;
  564. end;
  565. { build the new type's name }
  566. finalspecializename:=generate_generic_name(genname,specializename);
  567. ufinalspecializename:=upper(finalspecializename);
  568. prettyname:=genericdef.typesym.prettyname+'<'+prettyname+'>';
  569. { select the symtable containing the params }
  570. case genericdef.typ of
  571. procdef:
  572. st:=genericdef.GetSymtable(gs_para);
  573. objectdef,
  574. recorddef:
  575. st:=genericdef.GetSymtable(gs_record);
  576. arraydef:
  577. st:=tarraydef(genericdef).symtable;
  578. procvardef:
  579. st:=genericdef.GetSymtable(gs_para);
  580. else
  581. internalerror(200511182);
  582. end;
  583. generictypelist:=tfpobjectlist.create(false);
  584. { build the list containing the types for the generic params }
  585. gencount:=0;
  586. for i:=0 to st.SymList.Count-1 do
  587. begin
  588. srsym:=tsym(st.SymList[i]);
  589. if sp_generic_para in srsym.symoptions then
  590. begin
  591. if gencount=genericdeflist.Count then
  592. internalerror(2011042702);
  593. generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
  594. generictypelist.add(generictype);
  595. inc(gencount);
  596. end;
  597. end;
  598. { Special case if we are referencing the current defined object }
  599. if assigned(current_structdef) and
  600. (current_structdef.objname^=ufinalspecializename) then
  601. tt:=current_structdef;
  602. { decide in which symtable to put the specialization }
  603. if current_module.is_unit and current_module.in_interface then
  604. specializest:=current_module.globalsymtable
  605. else
  606. specializest:=current_module.localsymtable;
  607. { Can we reuse an already specialized type? }
  608. { for this first check whether we are currently specializing a nested
  609. type of the current (main) specialization (this is necessary, because
  610. during that time the symbol of the main specialization will still
  611. contain a reference to an errordef) }
  612. if not assigned(tt) and assigned(current_specializedef) then
  613. begin
  614. def:=current_specializedef;
  615. repeat
  616. if def.typ in [objectdef,recorddef] then
  617. if tabstractrecorddef(def).objname^=ufinalspecializename then begin
  618. tt:=def;
  619. break;
  620. end;
  621. def:=tstoreddef(def.owner.defowner);
  622. until not assigned(def) or not (df_specialization in def.defoptions);
  623. end;
  624. { now check whether there is a specialization somewhere else }
  625. if not assigned(tt) then
  626. begin
  627. hashedid.id:=ufinalspecializename;
  628. srsym:=tsym(specializest.findwithhash(hashedid));
  629. if assigned(srsym) then
  630. begin
  631. if srsym.typ<>typesym then
  632. internalerror(200710171);
  633. tt:=ttypesym(srsym).typedef;
  634. end
  635. else
  636. { the generic could have been specialized in the globalsymtable
  637. already, so search there as well }
  638. if (specializest<>current_module.globalsymtable) and assigned(current_module.globalsymtable) then
  639. begin
  640. srsym:=tsym(current_module.globalsymtable.findwithhash(hashedid));
  641. if assigned(srsym) then
  642. begin
  643. if srsym.typ<>typesym then
  644. internalerror(2011121101);
  645. tt:=ttypesym(srsym).typedef;
  646. end;
  647. end;
  648. end;
  649. if not assigned(tt) then
  650. begin
  651. specialization_init(genericdef,state);
  652. { push a temporary global symtable so that the specialization is
  653. added to the correct symtable; this symtable does not contain
  654. any other symbols, so that the type resolution can not be
  655. influenced by symbols in the current unit }
  656. tempst:=tspecializesymtable.create(current_module.modulename^,current_module.moduleid);
  657. symtablestack.push(tempst);
  658. { Reparse the original type definition }
  659. if not err then
  660. begin
  661. if parse_class_parent then
  662. begin
  663. old_current_structdef:=current_structdef;
  664. old_current_genericdef:=current_genericdef;
  665. old_current_specializedef:=current_specializedef;
  666. if genericdef.owner.symtabletype in [recordsymtable,objectsymtable] then
  667. current_structdef:=tabstractrecorddef(genericdef.owner.defowner)
  668. else
  669. current_structdef:=nil;
  670. current_genericdef:=nil;
  671. current_specializedef:=nil;
  672. end;
  673. maybe_add_waiting_unit(genericdef);
  674. { First a new typesym so we can reuse this specialization and
  675. references to this specialization can be handled }
  676. srsym:=ttypesym.create(finalspecializename,generrordef);
  677. specializest.insert(srsym);
  678. { specializations are declarations as such it is the wisest to
  679. declare set the blocktype to "type"; otherwise we'll
  680. experience unexpected side effects like the addition of
  681. classrefdefs if we have a generic that's derived from another
  682. generic }
  683. old_block_type:=block_type;
  684. block_type:=bt_type;
  685. if not assigned(genericdef.generictokenbuf) then
  686. internalerror(200511171);
  687. hmodule:=find_module_from_symtable(genericdef.owner);
  688. if hmodule=nil then
  689. internalerror(2012051202);
  690. oldcurrent_filepos:=current_filepos;
  691. { use the index the module got from the current compilation process }
  692. current_filepos.moduleindex:=hmodule.unit_index;
  693. current_tokenpos:=current_filepos;
  694. current_scanner.startreplaytokens(genericdef.generictokenbuf);
  695. read_named_type(tt,srsym,genericdef,generictypelist,false,false);
  696. current_filepos:=oldcurrent_filepos;
  697. ttypesym(srsym).typedef:=tt;
  698. tt.typesym:=srsym;
  699. if _prettyname<>'' then
  700. ttypesym(tt.typesym).fprettyname:=_prettyname
  701. else
  702. ttypesym(tt.typesym).fprettyname:=prettyname;
  703. { Note regarding hint directives:
  704. There is no need to remove the flags for them from the
  705. specialized generic symbol, because hint directives that
  706. follow the specialization are handled by the code in
  707. pdecl.types_dec and added to the type symbol.
  708. E.g.: TFoo = TBar<Blubb> deprecated;
  709. Here the symbol TBar$1$Blubb will contain the
  710. "sp_hint_deprecated" flag while the TFoo symbol won't.}
  711. case tt.typ of
  712. { Build VMT indexes for classes and read hint directives }
  713. objectdef:
  714. begin
  715. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  716. consume(_SEMICOLON);
  717. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  718. vmtbuilder.generate_vmt;
  719. vmtbuilder.free;
  720. end;
  721. { handle params, calling convention, etc }
  722. procvardef:
  723. begin
  724. if not check_proc_directive(true) then
  725. begin
  726. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  727. consume(_SEMICOLON);
  728. end;
  729. parse_var_proc_directives(ttypesym(srsym));
  730. handle_calling_convention(tprocvardef(tt));
  731. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  732. consume(_SEMICOLON);
  733. end;
  734. else
  735. { parse hint directives for records and arrays }
  736. begin
  737. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  738. consume(_SEMICOLON);
  739. end;
  740. end;
  741. { Consume the semicolon if it is also recorded }
  742. try_to_consume(_SEMICOLON);
  743. block_type:=old_block_type;
  744. if parse_class_parent then
  745. begin
  746. current_structdef:=old_current_structdef;
  747. current_genericdef:=old_current_genericdef;
  748. current_specializedef:=old_current_specializedef;
  749. end;
  750. end;
  751. { extract all created symbols and defs from the temporary symtable
  752. and add them to the specializest }
  753. for i:=tempst.SymList.Count-1 downto 0 do
  754. begin
  755. item:=tempst.SymList.Items[i];
  756. { using changeowner the symbol is automatically added to the
  757. new symtable }
  758. tsym(item).ChangeOwner(specializest);
  759. end;
  760. for i:=tempst.DefList.Count-1 downto 0 do
  761. begin
  762. item:=tempst.DefList.Items[i];
  763. { using changeowner the def is automatically added to the new
  764. symtable }
  765. tdef(item).ChangeOwner(specializest);
  766. end;
  767. { if a generic was declared during the specialization we need to
  768. flag the specialize symtable accordingly }
  769. if sto_has_generic in tempst.tableoptions then
  770. specializest.includeoption(sto_has_generic);
  771. tempst.free;
  772. specialization_done(state);
  773. end;
  774. if not (token in [_GT, _RSHARPBRACKET]) then
  775. begin
  776. consume(_RSHARPBRACKET);
  777. exit;
  778. end
  779. else
  780. consume(token);
  781. genericdeflist.free;
  782. generictypelist.free;
  783. if assigned(genericdef) then
  784. begin
  785. { check the hints of the found generic symbol }
  786. srsym:=genericdef.typesym;
  787. check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
  788. end;
  789. end;
  790. function parse_generic_parameters(allowconstraints:boolean):TFPObjectList;
  791. var
  792. generictype : ttypesym;
  793. i,firstidx : longint;
  794. srsymtable : tsymtable;
  795. basedef,def : tdef;
  796. defname : tidstring;
  797. allowconstructor,
  798. doconsume : boolean;
  799. constraintdata : tgenericconstraintdata;
  800. old_block_type : tblock_type;
  801. begin
  802. result:=TFPObjectList.Create(false);
  803. firstidx:=0;
  804. old_block_type:=block_type;
  805. block_type:=bt_type;
  806. repeat
  807. if token=_ID then
  808. begin
  809. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  810. include(generictype.symoptions,sp_generic_para);
  811. result.add(generictype);
  812. end;
  813. consume(_ID);
  814. if try_to_consume(_COLON) then
  815. begin
  816. if not allowconstraints then
  817. { TODO }
  818. Message(parser_e_illegal_expression{ parser_e_generic_constraints_not_allowed_here});
  819. { construct a name which can be used for a type specification }
  820. constraintdata:=tgenericconstraintdata.create;
  821. defname:='';
  822. str(current_module.deflist.count,defname);
  823. defname:='$gendef'+defname;
  824. allowconstructor:=m_delphi in current_settings.modeswitches;
  825. basedef:=generrordef;
  826. repeat
  827. doconsume:=true;
  828. case token of
  829. _CONSTRUCTOR:
  830. begin
  831. if not allowconstructor or (gcf_constructor in constraintdata.flags) then
  832. Message(parser_e_illegal_expression);
  833. include(constraintdata.flags,gcf_constructor);
  834. allowconstructor:=false;
  835. end;
  836. _CLASS:
  837. begin
  838. if gcf_class in constraintdata.flags then
  839. Message(parser_e_illegal_expression);
  840. if basedef=generrordef then
  841. include(constraintdata.flags,gcf_class)
  842. else
  843. Message(parser_e_illegal_expression);
  844. end;
  845. _RECORD:
  846. begin
  847. if ([gcf_constructor,gcf_class]*constraintdata.flags<>[])
  848. or (constraintdata.interfaces.count>0) then
  849. Message(parser_e_illegal_expression)
  850. else
  851. begin
  852. srsymtable:=trecordsymtable.create(defname,0);
  853. basedef:=trecorddef.create(defname,srsymtable);
  854. include(constraintdata.flags,gcf_record);
  855. allowconstructor:=false;
  856. end;
  857. end;
  858. else
  859. begin
  860. { after single_type "token" is the trailing ",", ";" or
  861. ">"! }
  862. doconsume:=false;
  863. { def is already set to a class or record }
  864. if gcf_record in constraintdata.flags then
  865. Message(parser_e_illegal_expression);
  866. single_type(def, [stoAllowSpecialization]);
  867. { only types that are inheritable are allowed }
  868. if (def.typ<>objectdef) or
  869. not (tobjectdef(def).objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_javaclass]) then
  870. Message1(type_e_class_or_interface_type_expected,def.typename)
  871. else
  872. case tobjectdef(def).objecttype of
  873. odt_class,
  874. odt_javaclass:
  875. begin
  876. if gcf_class in constraintdata.flags then
  877. { "class" + concrete class is not allowed }
  878. Message(parser_e_illegal_expression)
  879. else
  880. { do we already have a concrete class? }
  881. if basedef<>generrordef then
  882. Message(parser_e_illegal_expression)
  883. else
  884. basedef:=def;
  885. end;
  886. odt_interfacecom,
  887. odt_interfacecorba,
  888. odt_interfacejava,
  889. odt_dispinterface:
  890. constraintdata.interfaces.add(def);
  891. end;
  892. end;
  893. end;
  894. if doconsume then
  895. consume(token);
  896. until not try_to_consume(_COMMA);
  897. if ([gcf_class,gcf_constructor]*constraintdata.flags<>[]) or
  898. (constraintdata.interfaces.count>1) or
  899. (
  900. (basedef.typ=objectdef) and
  901. (tobjectdef(basedef).objecttype in [odt_javaclass,odt_class])
  902. ) then
  903. begin
  904. if basedef.typ=errordef then
  905. { don't pass an errordef as a parent to a tobjectdef }
  906. basedef:=class_tobject
  907. else
  908. if (basedef.typ<>objectdef) or
  909. not (tobjectdef(basedef).objecttype in [odt_javaclass,odt_class]) then
  910. internalerror(2012101101);
  911. basedef:=tobjectdef.create(tobjectdef(basedef).objecttype,defname,tobjectdef(basedef));
  912. for i:=0 to constraintdata.interfaces.count-1 do
  913. tobjectdef(basedef).implementedinterfaces.add(
  914. timplementedinterface.create(tobjectdef(constraintdata.interfaces[i])));
  915. end
  916. else
  917. if constraintdata.interfaces.count=1 then
  918. begin
  919. if basedef.typ<>errordef then
  920. internalerror(2013021601);
  921. def:=tdef(constraintdata.interfaces[0]);
  922. basedef:=tobjectdef.create(tobjectdef(def).objecttype,defname,tobjectdef(def));
  923. constraintdata.interfaces.delete(0);
  924. end;
  925. if basedef.typ<>errordef then
  926. with tstoreddef(basedef) do
  927. begin
  928. genconstraintdata:=tgenericconstraintdata.create;
  929. genconstraintdata.flags:=constraintdata.flags;
  930. genconstraintdata.interfaces.assign(constraintdata.interfaces);
  931. include(defoptions,df_genconstraint);
  932. end;
  933. for i:=firstidx to result.count-1 do
  934. ttypesym(result[i]).typedef:=basedef;
  935. firstidx:=result.count;
  936. constraintdata.free;
  937. end;
  938. until not (try_to_consume(_COMMA) or try_to_consume(_SEMICOLON));
  939. block_type:=old_block_type;
  940. end;
  941. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  942. var
  943. i: longint;
  944. generictype: ttypesym;
  945. st: tsymtable;
  946. begin
  947. def.genericdef:=genericdef;
  948. if not assigned(genericlist) then
  949. exit;
  950. if assigned(genericdef) then
  951. include(def.defoptions,df_specialization)
  952. else
  953. if genericlist.count>0 then
  954. include(def.defoptions,df_generic);
  955. case def.typ of
  956. recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
  957. arraydef: st:=tarraydef(def).symtable;
  958. procvardef,procdef: st:=tabstractprocdef(def).parast;
  959. else
  960. internalerror(201101020);
  961. end;
  962. if (genericlist.count>0) and not assigned(def.genericparas) then
  963. def.genericparas:=tfphashobjectlist.create(false);
  964. for i:=0 to genericlist.count-1 do
  965. begin
  966. generictype:=ttypesym(genericlist[i]);
  967. st.insert(generictype);
  968. include(generictype.symoptions,sp_generic_para);
  969. def.genericparas.add(generictype.name,generictype);
  970. end;
  971. end;
  972. procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist);
  973. var
  974. gensym : ttypesym;
  975. begin
  976. { for generics in non-Delphi modes we insert a private type symbol
  977. that has the same base name as the currently parsed generic and
  978. that references this defs }
  979. if not (m_delphi in current_settings.modeswitches) and
  980. (
  981. (
  982. parse_generic and
  983. assigned(genericlist) and
  984. (genericlist.count>0)
  985. ) or
  986. (
  987. assigned(current_specializedef) and
  988. assigned(current_structdef.genericdef) and
  989. (current_structdef.genericdef.typ in [objectdef,recorddef]) and
  990. (pos('$',name)>0)
  991. )
  992. ) then
  993. begin
  994. { we need to pass nil as def here, because the constructor wants
  995. to set the typesym of the def which is not what we want }
  996. gensym:=ttypesym.create(copy(name,1,pos('$',name)-1),nil);
  997. gensym.typedef:=current_structdef;
  998. include(gensym.symoptions,sp_internal);
  999. { the symbol should be only visible to the generic class
  1000. itself }
  1001. gensym.visibility:=vis_strictprivate;
  1002. symtablestack.top.insert(gensym);
  1003. end;
  1004. end;
  1005. function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring;
  1006. var
  1007. crc : cardinal;
  1008. begin
  1009. if specializename='' then
  1010. internalerror(2012061901);
  1011. { build the new type's name }
  1012. crc:=UpdateCrc32(0,specializename[1],length(specializename));
  1013. result:=name+'$crc'+hexstr(crc,8);
  1014. end;
  1015. procedure specialization_init(genericdef:tdef;var state: tspecializationstate);
  1016. var
  1017. pu : tused_unit;
  1018. hmodule : tmodule;
  1019. unitsyms : TFPHashObjectList;
  1020. sym : tsym;
  1021. i : Integer;
  1022. begin
  1023. if not assigned(genericdef) then
  1024. internalerror(200705151);
  1025. { Setup symtablestack at definition time
  1026. to get types right, however this is not perfect, we should probably record
  1027. the resolved symbols }
  1028. state.oldsymtablestack:=symtablestack;
  1029. state.oldextendeddefs:=current_module.extendeddefs;
  1030. current_module.extendeddefs:=TFPHashObjectList.create(true);
  1031. symtablestack:=tdefawaresymtablestack.create;
  1032. hmodule:=find_module_from_symtable(genericdef.owner);
  1033. if hmodule=nil then
  1034. internalerror(200705152);
  1035. { collect all unit syms in the generic's unit as we need to establish
  1036. their unitsym.module link again so that unit identifiers can be used }
  1037. unitsyms:=tfphashobjectlist.create(false);
  1038. if (hmodule<>current_module) and assigned(hmodule.globalsymtable) then
  1039. for i:=0 to hmodule.globalsymtable.symlist.count-1 do
  1040. begin
  1041. sym:=tsym(hmodule.globalsymtable.symlist[i]);
  1042. if sym.typ=unitsym then
  1043. unitsyms.add(upper(sym.realname),sym);
  1044. end;
  1045. { add all units if we are specializing inside the current unit (as the
  1046. generic could have been declared in the implementation part), but load
  1047. only interface units, if we are in a different unit as then the generic
  1048. needs to be in the interface section }
  1049. pu:=tused_unit(hmodule.used_units.first);
  1050. while assigned(pu) do
  1051. begin
  1052. if not assigned(pu.u.globalsymtable) then
  1053. { in certain circular, but valid unit constellations it can happen
  1054. that we specialize a generic in a different unit that was used
  1055. in the implementation section of the generic's unit and were the
  1056. interface is still being parsed and thus the localsymtable is in
  1057. reality the global symtable }
  1058. if pu.u.in_interface then
  1059. symtablestack.push(pu.u.localsymtable)
  1060. else
  1061. internalerror(200705153)
  1062. else
  1063. symtablestack.push(pu.u.globalsymtable);
  1064. sym:=tsym(unitsyms.find(pu.u.modulename^));
  1065. if assigned(sym) and not assigned(tunitsym(sym).module) then
  1066. tunitsym(sym).module:=pu.u;
  1067. pu:=tused_unit(pu.next);
  1068. end;
  1069. unitsyms.free;
  1070. if assigned(hmodule.globalsymtable) then
  1071. symtablestack.push(hmodule.globalsymtable);
  1072. { push the localsymtable if needed }
  1073. if (hmodule<>current_module) or not current_module.in_interface then
  1074. symtablestack.push(hmodule.localsymtable);
  1075. end;
  1076. procedure specialization_done(var state: tspecializationstate);
  1077. begin
  1078. { Restore symtablestack }
  1079. current_module.extendeddefs.free;
  1080. current_module.extendeddefs:=state.oldextendeddefs;
  1081. symtablestack.free;
  1082. symtablestack:=state.oldsymtablestack;
  1083. { clear the state record to be on the safe side }
  1084. fillchar(state, sizeof(state), 0);
  1085. end;
  1086. end.