tcgenerics.pas 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818
  1. unit TCGenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testregistry,
  6. TCModules, FPPas2Js, PScanner, PasResolveEval;
  7. type
  8. { TTestGenerics }
  9. TTestGenerics = class(TCustomTestModule)
  10. Published
  11. // generic record
  12. Procedure TestGen_RecordEmpty;
  13. Procedure TestGen_Record_ClassProc;
  14. Procedure TestGen_Record_ClassVarRecord_Program;
  15. Procedure TestGen_Record_ClassVarRecord_UnitImpl;
  16. Procedure TestGen_Record_RTTI_UnitImpl;
  17. procedure TestGen_Record_Delay_UsedByImplUses;
  18. // ToDo: type alias type as parameter, TBird = type word;
  19. // generic class
  20. Procedure TestGen_ClassEmpty;
  21. Procedure TestGen_Class_EmptyMethod;
  22. Procedure TestGen_Class_TList;
  23. Procedure TestGen_Class_TCustomList; // ToDo: with Self do Result:=Method()
  24. Procedure TestGen_ClassAncestor;
  25. Procedure TestGen_Class_TypeInfo;
  26. Procedure TestGen_Class_TypeOverload; // ToDo TBird, TBird<T>, TBird<S,T>
  27. Procedure TestGen_Class_ClassProperty;
  28. Procedure TestGen_Class_ClassProc;
  29. //Procedure TestGen_Record_ReferGenClass_DelphiFail; TBird<T> = class x:TBird; end;
  30. Procedure TestGen_Class_ClassConstructor;
  31. Procedure TestGen_Class_TypeCastSpecializesWarn;
  32. Procedure TestGen_Class_TypeCastSpecializesJSValueNoWarn;
  33. procedure TestGen_Class_OverloadsInUnit;
  34. procedure TestGen_ClassForward_CircleRTTI;
  35. procedure TestGen_Class_Nested_RTTI;
  36. Procedure TestGen_Class_ClassVarRecord_UnitImpl;
  37. // generic external class
  38. procedure TestGen_ExtClass_VarArgsOfType;
  39. procedure TestGen_ExtClass_Array;
  40. procedure TestGen_ExtClass_GenJSValueAssign;
  41. procedure TestGen_ExtClass_AliasMemberType;
  42. Procedure TestGen_ExtClass_RTTI;
  43. procedure TestGen_ExtClass_UnitImplRec;
  44. // class interfaces
  45. procedure TestGen_ClassInterface_Corba;
  46. procedure TestGen_ClassInterface_InterfacedObject;
  47. procedure TestGen_ClassInterface_COM_RTTI;
  48. procedure TestGen_ClassInterface_Helper;
  49. procedure TestGen_ClassInterface_DelayedInitSpec;
  50. // statements
  51. Procedure TestGen_InlineSpec_Constructor;
  52. Procedure TestGen_CallUnitImplProc;
  53. Procedure TestGen_IntAssignTemplVar;
  54. Procedure TestGen_TypeCastDotField;
  55. Procedure TestGen_Except;
  56. // generic helper
  57. procedure TestGen_HelperForArray;
  58. // generic functions
  59. procedure TestGenProc_Function_ObjFPC;
  60. procedure TestGenProc_Function_Delphi;
  61. procedure TestGenProc_Overload;
  62. procedure TestGenProc_Forward;
  63. procedure TestGenProc_Infer_OverloadForward;
  64. procedure TestGenProc_TypeInfo;
  65. procedure TestGenProc_Infer_Widen;
  66. procedure TestGenProc_Infer_PassAsArg;
  67. procedure TestGenProc_AnonymousProc;
  68. // ToDo: FuncName:= instead of Result:=
  69. // generic methods
  70. procedure TestGenMethod_ImplicitSpec_ObjFPC;
  71. procedure TestGenMethod_Delphi;
  72. // generic array
  73. procedure TestGen_Array_OtherUnit;
  74. procedure TestGen_ArrayOfUnitImplRec;
  75. procedure TestGen_Array_TypecastJSValueResultToArg;
  76. // generic procedure type
  77. procedure TestGen_ProcType_ProcLocal;
  78. procedure TestGen_ProcType_Local_RTTI_Fail;
  79. procedure TestGen_ProcType_ParamUnitImpl;
  80. end;
  81. implementation
  82. { TTestGenerics }
  83. procedure TTestGenerics.TestGen_RecordEmpty;
  84. begin
  85. StartProgram(false);
  86. Add([
  87. 'type',
  88. ' generic TRecA<T> = record',
  89. ' end;',
  90. 'var a,b: specialize TRecA<word>;',
  91. 'begin',
  92. ' if a=b then ;']);
  93. ConvertProgram;
  94. CheckSource('TestGen_RecordEmpty',
  95. LinesToStr([ // statements
  96. 'rtl.recNewT(this, "TRecA$G1", function () {',
  97. ' this.$eq = function (b) {',
  98. ' return true;',
  99. ' };',
  100. ' this.$assign = function (s) {',
  101. ' return this;',
  102. ' };',
  103. '});',
  104. 'this.a = this.TRecA$G1.$new();',
  105. 'this.b = this.TRecA$G1.$new();',
  106. '']),
  107. LinesToStr([ // $mod.$main
  108. 'if ($mod.a.$eq($mod.b)) ;'
  109. ]));
  110. end;
  111. procedure TTestGenerics.TestGen_Record_ClassProc;
  112. begin
  113. StartProgram(false);
  114. Add([
  115. '{$modeswitch AdvancedRecords}',
  116. 'type',
  117. ' generic TPoint<T> = record',
  118. ' class var x: T;',
  119. ' class procedure Fly; static;',
  120. ' end;',
  121. 'class procedure Tpoint.Fly;',
  122. 'begin',
  123. ' x:=x+3;',
  124. ' tpoint.x:=tpoint.x+4;',
  125. ' Fly;',
  126. ' tpoint.Fly;',
  127. 'end;',
  128. 'var p: specialize TPoint<word>;',
  129. 'begin',
  130. ' p.x:=p.x+10;',
  131. ' p.Fly;',
  132. ' p.Fly();',
  133. '']);
  134. ConvertProgram;
  135. CheckSource('TestGen_Record_ClassProc',
  136. LinesToStr([ // statements
  137. 'rtl.recNewT(this, "TPoint$G1", function () {',
  138. ' this.x = 0;',
  139. ' this.$eq = function (b) {',
  140. ' return true;',
  141. ' };',
  142. ' this.$assign = function (s) {',
  143. ' return this;',
  144. ' };',
  145. ' this.Fly = function () {',
  146. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;',
  147. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;',
  148. ' $mod.TPoint$G1.Fly();',
  149. ' $mod.TPoint$G1.Fly();',
  150. ' };',
  151. '}, true);',
  152. 'this.p = this.TPoint$G1.$new();',
  153. '']),
  154. LinesToStr([ // $mod.$main
  155. '$mod.TPoint$G1.x = $mod.p.x + 10;',
  156. '$mod.TPoint$G1.Fly();',
  157. '$mod.TPoint$G1.Fly();',
  158. '']));
  159. end;
  160. procedure TTestGenerics.TestGen_Record_ClassVarRecord_Program;
  161. begin
  162. StartProgram(false);
  163. Add([
  164. '{$modeswitch AdvancedRecords}',
  165. 'type',
  166. ' generic TAnt<T> = record',
  167. ' class var x: T;',
  168. ' end;',
  169. ' TBird = record',
  170. ' b: word;',
  171. ' end;',
  172. 'var f: specialize TAnt<TBird>;',
  173. 'begin',
  174. ' f.x.b:=f.x.b+10;',
  175. '']);
  176. ConvertProgram;
  177. CheckSource('TestGen_Record_ClassVarRecord_Program',
  178. LinesToStr([ // statements
  179. 'rtl.recNewT(this, "TBird", function () {',
  180. ' this.b = 0;',
  181. ' this.$eq = function (b) {',
  182. ' return this.b === b.b;',
  183. ' };',
  184. ' this.$assign = function (s) {',
  185. ' this.b = s.b;',
  186. ' return this;',
  187. ' };',
  188. '});',
  189. 'rtl.recNewT(this, "TAnt$G1", function () {',
  190. ' this.x = $mod.TBird.$new();',
  191. ' this.$eq = function (b) {',
  192. ' return true;',
  193. ' };',
  194. ' this.$assign = function (s) {',
  195. ' return this;',
  196. ' };',
  197. '}, true);',
  198. 'this.f = this.TAnt$G1.$new();',
  199. '']),
  200. LinesToStr([ // $mod.$main
  201. '$mod.f.x.b = $mod.f.x.b + 10;',
  202. '']));
  203. end;
  204. procedure TTestGenerics.TestGen_Record_ClassVarRecord_UnitImpl;
  205. begin
  206. StartProgram(true,[supTObject]);
  207. AddModuleWithIntfImplSrc('UnitA.pas',
  208. LinesToStr([
  209. '{$modeswitch AdvancedRecords}',
  210. 'type',
  211. ' generic TAnt<T> = record',
  212. ' class var x: T;',
  213. ' class var a: array[1..2] of T;',
  214. ' end;',
  215. '']),
  216. LinesToStr([
  217. 'type',
  218. ' TBird = record',
  219. ' b: word;',
  220. ' end;',
  221. 'var f: specialize TAnt<TBird>;',
  222. 'begin',
  223. ' f.x.b:=f.x.b+10;',
  224. '']));
  225. Add([
  226. 'uses UnitA;',
  227. 'begin',
  228. 'end.']);
  229. ConvertProgram;
  230. CheckUnit('UnitA.pas',
  231. LinesToStr([ // statements
  232. 'rtl.module("UnitA", ["system"], function () {',
  233. ' var $mod = this;',
  234. ' var $impl = $mod.$impl;',
  235. ' rtl.recNewT(this, "TAnt$G1", function () {',
  236. ' this.$initSpec = function () {',
  237. ' this.x = $impl.TBird.$new();',
  238. ' this.a = rtl.arraySetLength(null, $impl.TBird, 2);',
  239. ' };',
  240. ' this.a$a$clone = function (a) {',
  241. ' var b = [];',
  242. ' b.length = 2;',
  243. ' for (var c = 0; c < 2; c++) b[c] = $impl.TBird.$clone(a[c]);',
  244. ' return b;',
  245. ' };',
  246. ' this.$eq = function (b) {',
  247. ' return true;',
  248. ' };',
  249. ' this.$assign = function (s) {',
  250. ' return this;',
  251. ' };',
  252. ' }, true);',
  253. ' $mod.$implcode = function () {',
  254. ' rtl.recNewT($impl, "TBird", function () {',
  255. ' this.b = 0;',
  256. ' this.$eq = function (b) {',
  257. ' return this.b === b.b;',
  258. ' };',
  259. ' this.$assign = function (s) {',
  260. ' this.b = s.b;',
  261. ' return this;',
  262. ' };',
  263. ' });',
  264. ' $impl.f = $mod.TAnt$G1.$new();',
  265. ' };',
  266. ' $mod.$init = function () {',
  267. ' $impl.f.x.b = $impl.f.x.b + 10;',
  268. ' };',
  269. '}, []);']));
  270. CheckSource('TestGen_Record_ClassVarRecord_UnitImpl',
  271. LinesToStr([ // statements
  272. '$mod.$implcode = function () {',
  273. ' pas.UnitA.TAnt$G1.$initSpec();',
  274. '};',
  275. '']),
  276. LinesToStr([ // $mod.$main
  277. '']));
  278. end;
  279. procedure TTestGenerics.TestGen_Record_RTTI_UnitImpl;
  280. begin
  281. WithTypeInfo:=true;
  282. StartUnit(true);
  283. Add([
  284. 'interface',
  285. '{$modeswitch AdvancedRecords}',
  286. 'type',
  287. ' generic TAnt<T> = record',
  288. ' class var x: T;',
  289. //' class var a,b: array of T;',
  290. ' end;',
  291. 'implementation',
  292. 'type',
  293. ' TBird = record',
  294. ' b: word;',
  295. ' end;',
  296. 'var f: specialize TAnt<TBird>;',
  297. ' p: pointer;',
  298. 'begin',
  299. ' p:=typeinfo(f);',
  300. '']);
  301. ConvertUnit;
  302. CheckSource('TestGen_Record_RTTI_UnitImpl',
  303. LinesToStr([ // statements
  304. 'var $impl = $mod.$impl;',
  305. 'rtl.recNewT(this, "TAnt$G1", function () {',
  306. ' var $r = $mod.$rtti.$Record("TAnt<Test1.TBird>", {});',
  307. ' this.$initSpec = function () {',
  308. ' this.x = $impl.TBird.$new();',
  309. ' $r.addField("x", $mod.$rtti["TBird"]);',
  310. ' };',
  311. ' this.$eq = function (b) {',
  312. ' return true;',
  313. ' };',
  314. ' this.$assign = function (s) {',
  315. ' return this;',
  316. ' };',
  317. '}, true);',
  318. '']),
  319. LinesToStr([ // $mod.$init
  320. '$impl.p = $mod.$rtti["TAnt<Test1.TBird>"];',
  321. '']),
  322. LinesToStr([ // statements
  323. 'rtl.recNewT($impl, "TBird", function () {',
  324. ' this.b = 0;',
  325. ' this.$eq = function (b) {',
  326. ' return this.b === b.b;',
  327. ' };',
  328. ' this.$assign = function (s) {',
  329. ' this.b = s.b;',
  330. ' return this;',
  331. ' };',
  332. ' var $r = $mod.$rtti.$Record("TBird", {});',
  333. ' $r.addField("b", rtl.word);',
  334. '});',
  335. '$impl.f = $mod.TAnt$G1.$new();',
  336. '$impl.p = null;',
  337. '']));
  338. end;
  339. procedure TTestGenerics.TestGen_Record_Delay_UsedByImplUses;
  340. begin
  341. WithTypeInfo:=true;
  342. StartProgram(true,[supTObject]);
  343. AddModuleWithIntfImplSrc('UnitA.pas',
  344. LinesToStr([
  345. '{$modeswitch AdvancedRecords}',
  346. 'type',
  347. ' generic TBird<T> = record',
  348. ' class var a: T;',
  349. ' end;',
  350. '']),
  351. LinesToStr([
  352. '']));
  353. AddModuleWithIntfImplSrc('UnitB.pas',
  354. LinesToStr([
  355. 'procedure Fly;',
  356. '']),
  357. LinesToStr([
  358. 'uses UnitA;',
  359. 'type',
  360. ' TFox = record',
  361. ' B: word;',
  362. ' end;',
  363. 'procedure Fly;',
  364. 'var Bird: specialize TBird<TFox>;',
  365. 'begin',
  366. ' if typeinfo(Bird)<>nil then ;',
  367. ' Bird.a:=Bird.a;',
  368. 'end;',
  369. '']));
  370. Add([
  371. 'uses UnitB;',
  372. 'begin',
  373. ' Fly;']);
  374. ConvertProgram;
  375. CheckSource('TestGen_Record_Delay_UsedByImplUses',
  376. LinesToStr([ // statements
  377. '$mod.$implcode = function () {',
  378. ' pas.UnitA.TBird$G1.$initSpec();',
  379. '};',
  380. '']),
  381. LinesToStr([ // $mod.$main
  382. 'pas.UnitB.Fly();'
  383. ]));
  384. end;
  385. procedure TTestGenerics.TestGen_ClassEmpty;
  386. begin
  387. StartProgram(false);
  388. Add([
  389. 'type',
  390. ' TObject = class end;',
  391. ' generic TBird<T> = class',
  392. ' end;',
  393. 'var a,b: specialize TBird<word>;',
  394. 'begin',
  395. ' if a=b then ;']);
  396. ConvertProgram;
  397. CheckSource('TestGen_ClassEmpty',
  398. LinesToStr([ // statements
  399. 'rtl.createClass(this, "TObject", null, function () {',
  400. ' this.$init = function () {',
  401. ' };',
  402. ' this.$final = function () {',
  403. ' };',
  404. '});',
  405. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  406. '}, "TBird<System.Word>");',
  407. 'this.a = null;',
  408. 'this.b = null;',
  409. '']),
  410. LinesToStr([ // $mod.$main
  411. 'if ($mod.a === $mod.b) ;'
  412. ]));
  413. end;
  414. procedure TTestGenerics.TestGen_Class_EmptyMethod;
  415. begin
  416. StartProgram(false);
  417. Add([
  418. 'type',
  419. ' TObject = class end;',
  420. ' generic TBird<T> = class',
  421. ' function Fly(w: T): T;',
  422. ' end;',
  423. 'function TBird.Fly(w: T): T;',
  424. 'begin',
  425. 'end;',
  426. 'var a: specialize TBird<word>;',
  427. 'begin',
  428. ' if a.Fly(3)=4 then ;']);
  429. ConvertProgram;
  430. CheckSource('TestGen_Class_EmptyMethod',
  431. LinesToStr([ // statements
  432. 'rtl.createClass(this, "TObject", null, function () {',
  433. ' this.$init = function () {',
  434. ' };',
  435. ' this.$final = function () {',
  436. ' };',
  437. '});',
  438. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  439. ' this.Fly = function (w) {',
  440. ' var Result = 0;',
  441. ' return Result;',
  442. ' };',
  443. '}, "TBird<System.Word>");',
  444. 'this.a = null;',
  445. '']),
  446. LinesToStr([ // $mod.$main
  447. ' if ($mod.a.Fly(3) === 4) ;'
  448. ]));
  449. end;
  450. procedure TTestGenerics.TestGen_Class_TList;
  451. begin
  452. StartProgram(false);
  453. Add([
  454. '{$mode objfpc}',
  455. 'type',
  456. ' TObject = class end;',
  457. ' generic TList<T> = class',
  458. ' strict private',
  459. ' FItems: array of T;',
  460. ' function GetItems(Index: longint): T;',
  461. ' procedure SetItems(Index: longint; Value: T);',
  462. ' public',
  463. ' procedure Alter(w: T);',
  464. ' property Items[Index: longint]: T read GetItems write SetItems; default;',
  465. ' end;',
  466. ' TWordList = specialize TList<word>;',
  467. 'function TList.GetItems(Index: longint): T;',
  468. 'begin',
  469. ' Result:=FItems[Index];',
  470. 'end;',
  471. 'procedure TList.SetItems(Index: longint; Value: T);',
  472. 'begin',
  473. ' FItems[Index]:=Value;',
  474. 'end;',
  475. 'procedure TList.Alter(w: T);',
  476. 'begin',
  477. ' SetLength(FItems,length(FItems)+1);',
  478. ' Insert(w,FItems,2);',
  479. ' Delete(FItems,2,3);',
  480. 'end;',
  481. 'var l: TWordList;',
  482. ' w: word;',
  483. 'begin',
  484. ' l[1]:=w;',
  485. ' w:=l[2];',
  486. '']);
  487. ConvertProgram;
  488. CheckSource('TestGen_Class_TList',
  489. LinesToStr([ // statements
  490. 'rtl.createClass(this, "TObject", null, function () {',
  491. ' this.$init = function () {',
  492. ' };',
  493. ' this.$final = function () {',
  494. ' };',
  495. '});',
  496. 'rtl.createClass(this, "TList$G1", this.TObject, function () {',
  497. ' this.$init = function () {',
  498. ' $mod.TObject.$init.call(this);',
  499. ' this.FItems = [];',
  500. ' };',
  501. ' this.$final = function () {',
  502. ' this.FItems = undefined;',
  503. ' $mod.TObject.$final.call(this);',
  504. ' };',
  505. ' this.GetItems = function (Index) {',
  506. ' var Result = 0;',
  507. ' Result = this.FItems[Index];',
  508. ' return Result;',
  509. ' };',
  510. ' this.SetItems = function (Index, Value) {',
  511. ' this.FItems[Index] = Value;',
  512. ' };',
  513. ' this.Alter = function (w) {',
  514. ' this.FItems = rtl.arraySetLength(this.FItems, 0, rtl.length(this.FItems) + 1);',
  515. ' this.FItems = rtl.arrayInsert(w, this.FItems, 2);',
  516. ' this.FItems.splice(2, 3);',
  517. ' };',
  518. '}, "TList<System.Word>");',
  519. 'this.l = null;',
  520. 'this.w = 0;',
  521. '']),
  522. LinesToStr([ // $mod.$main
  523. '$mod.l.SetItems(1, $mod.w);',
  524. '$mod.w = $mod.l.GetItems(2);',
  525. '']));
  526. end;
  527. procedure TTestGenerics.TestGen_Class_TCustomList;
  528. begin
  529. StartProgram(false);
  530. Add([
  531. '{$mode delphi}',
  532. 'type',
  533. ' TObject = class end;',
  534. ' TCustomList<T> = class',
  535. ' public',
  536. ' function PrepareAddingItem: word; virtual;',
  537. ' end;',
  538. ' TList<T> = class(TCustomList<T>)',
  539. ' public',
  540. ' function Add: word;',
  541. ' end;',
  542. ' TWordList = TList<word>;',
  543. 'function TCustomList<T>.PrepareAddingItem: word;',
  544. 'begin',
  545. 'end;',
  546. 'function TList<T>.Add: word;',
  547. 'begin',
  548. ' Result:=PrepareAddingItem;',
  549. ' Result:=Self.PrepareAddingItem;',
  550. //' with Self do Result:=PrepareAddingItem;',
  551. 'end;',
  552. 'var l: TWordList;',
  553. 'begin',
  554. '']);
  555. ConvertProgram;
  556. CheckSource('TestGen_Class_TCustomList',
  557. LinesToStr([ // statements
  558. 'rtl.createClass(this, "TObject", null, function () {',
  559. ' this.$init = function () {',
  560. ' };',
  561. ' this.$final = function () {',
  562. ' };',
  563. '});',
  564. 'rtl.createClass(this, "TCustomList$G2", this.TObject, function () {',
  565. ' this.PrepareAddingItem = function () {',
  566. ' var Result = 0;',
  567. ' return Result;',
  568. ' };',
  569. '}, "TCustomList<System.Word>");',
  570. 'rtl.createClass(this, "TList$G1", this.TCustomList$G2, function () {',
  571. ' this.Add = function () {',
  572. ' var Result = 0;',
  573. ' Result = this.PrepareAddingItem();',
  574. ' Result = this.PrepareAddingItem();',
  575. ' return Result;',
  576. ' };',
  577. '}, "TList<System.Word>");',
  578. 'this.l = null;',
  579. '']),
  580. LinesToStr([ // $mod.$main
  581. '']));
  582. end;
  583. procedure TTestGenerics.TestGen_ClassAncestor;
  584. begin
  585. StartProgram(false);
  586. Add([
  587. 'type',
  588. ' TObject = class end;',
  589. ' generic TBird<T> = class',
  590. ' end;',
  591. ' generic TEagle<T> = class(specialize TBird<T>)',
  592. ' end;',
  593. 'var a: specialize TEagle<word>;',
  594. 'begin',
  595. '']);
  596. ConvertProgram;
  597. CheckSource('TestGen_ClassAncestor',
  598. LinesToStr([ // statements
  599. 'rtl.createClass(this, "TObject", null, function () {',
  600. ' this.$init = function () {',
  601. ' };',
  602. ' this.$final = function () {',
  603. ' };',
  604. '});',
  605. 'rtl.createClass(this, "TBird$G2", this.TObject, function () {',
  606. '}, "TBird<System.Word>");',
  607. 'rtl.createClass(this, "TEagle$G1", this.TBird$G2, function () {',
  608. '}, "TEagle<System.Word>");',
  609. 'this.a = null;',
  610. '']),
  611. LinesToStr([ // $mod.$main
  612. '']));
  613. end;
  614. procedure TTestGenerics.TestGen_Class_TypeInfo;
  615. begin
  616. WithTypeInfo:=true;
  617. StartProgram(false);
  618. Add([
  619. 'type',
  620. ' TObject = class end;',
  621. ' generic TBird<T> = class',
  622. ' published',
  623. ' m: T;',
  624. ' end;',
  625. ' TEagle = specialize TBird<word>;',
  626. 'var',
  627. ' b: specialize TBird<word>;',
  628. ' p: pointer;',
  629. 'begin',
  630. ' p:=typeinfo(TEagle);',
  631. ' p:=typeinfo(b);',
  632. '']);
  633. ConvertProgram;
  634. CheckSource('TestGen_Class_TypeInfo',
  635. LinesToStr([ // statements
  636. '$mod.$rtti.$Class("TBird<System.Word>");',
  637. 'rtl.createClass(this, "TObject", null, function () {',
  638. ' this.$init = function () {',
  639. ' };',
  640. ' this.$final = function () {',
  641. ' };',
  642. '});',
  643. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  644. ' this.$init = function () {',
  645. ' $mod.TObject.$init.call(this);',
  646. ' this.m = 0;',
  647. ' };',
  648. ' var $r = this.$rtti;',
  649. ' $r.addField("m", rtl.word);',
  650. '}, "TBird<System.Word>");',
  651. 'this.b = null;',
  652. 'this.p = null;',
  653. '']),
  654. LinesToStr([ // $mod.$main
  655. '$mod.p = $mod.$rtti["TBird<System.Word>"];',
  656. '$mod.p = $mod.b.$rtti;',
  657. '']));
  658. end;
  659. procedure TTestGenerics.TestGen_Class_TypeOverload;
  660. begin
  661. exit;// ToDo
  662. StartProgram(false);
  663. Add([
  664. '{$mode delphi}',
  665. 'type',
  666. ' TObject = class end;',
  667. ' TBird = word;',
  668. ' TBird<T> = class',
  669. ' m: T;',
  670. ' end;',
  671. ' TEagle = TBird<word>;',
  672. 'var',
  673. ' b: TBird<word>;',
  674. ' e: TEagle;',
  675. 'begin',
  676. '']);
  677. ConvertProgram;
  678. CheckSource('TestGen_Class_TypeOverload',
  679. LinesToStr([ // statements
  680. 'rtl.createClass(this, "TObject", null, function () {',
  681. ' this.$init = function () {',
  682. ' };',
  683. ' this.$final = function () {',
  684. ' };',
  685. '});',
  686. '']),
  687. LinesToStr([ // $mod.$main
  688. '']));
  689. end;
  690. procedure TTestGenerics.TestGen_Class_ClassProperty;
  691. begin
  692. StartProgram(false);
  693. Add([
  694. '{$mode delphi}',
  695. 'type',
  696. ' TObject = class end;',
  697. ' TBird<T> = class',
  698. ' private',
  699. ' class var fSize: T;',
  700. ' public',
  701. ' class property Size: T read fSize write fSize;',
  702. ' end;',
  703. ' TEagle = TBird<word>;',
  704. 'begin',
  705. ' TBird<word>.Size:=3+TBird<word>.Size;',
  706. '']);
  707. ConvertProgram;
  708. CheckSource('TestGen_Class_ClassProperty',
  709. LinesToStr([ // statements
  710. 'rtl.createClass(this, "TObject", null, function () {',
  711. ' this.$init = function () {',
  712. ' };',
  713. ' this.$final = function () {',
  714. ' };',
  715. '});',
  716. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  717. ' this.fSize = 0;',
  718. '}, "TBird<System.Word>");',
  719. '']),
  720. LinesToStr([ // $mod.$main
  721. '$mod.TBird$G1.fSize = 3 + $mod.TBird$G1.fSize;',
  722. '']));
  723. end;
  724. procedure TTestGenerics.TestGen_Class_ClassProc;
  725. begin
  726. StartProgram(false);
  727. Add([
  728. 'type',
  729. ' TObject = class end;',
  730. ' generic TPoint<T> = class',
  731. ' class var x: T;',
  732. ' class procedure Fly; static;',
  733. ' class procedure Run;',
  734. ' end;',
  735. 'class procedure Tpoint.Fly;',
  736. 'begin',
  737. ' x:=x+3;',
  738. ' tpoint.x:=tpoint.x+4;',
  739. ' Fly;',
  740. ' tpoint.Fly;',
  741. ' Run;',
  742. ' tpoint.Run;',
  743. 'end;',
  744. 'class procedure TPoint.Run;',
  745. 'begin',
  746. ' x:=x+5;',
  747. ' tpoint.x:=tpoint.x+6;',
  748. ' Fly;',
  749. ' tpoint.Fly;',
  750. ' Run;',
  751. ' tpoint.Run;',
  752. 'end;',
  753. 'var p: specialize TPoint<word>;',
  754. 'begin',
  755. '']);
  756. ConvertProgram;
  757. CheckSource('TestGen_Class_ClassProc',
  758. LinesToStr([ // statements
  759. 'rtl.createClass(this, "TObject", null, function () {',
  760. ' this.$init = function () {',
  761. ' };',
  762. ' this.$final = function () {',
  763. ' };',
  764. '});',
  765. 'rtl.createClass(this, "TPoint$G1", this.TObject, function () {',
  766. ' this.x = 0;',
  767. ' this.Fly = function () {',
  768. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;',
  769. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;',
  770. ' $mod.TPoint$G1.Fly();',
  771. ' $mod.TPoint$G1.Fly();',
  772. ' $mod.TPoint$G1.Run();',
  773. ' $mod.TPoint$G1.Run();',
  774. ' };',
  775. ' this.Run = function () {',
  776. ' $mod.TPoint$G1.x = this.x + 5;',
  777. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 6;',
  778. ' this.Fly();',
  779. ' this.Fly();',
  780. ' this.Run();',
  781. ' $mod.TPoint$G1.Run();',
  782. ' };',
  783. '}, "TPoint<System.Word>");',
  784. 'this.p = null;',
  785. '']),
  786. LinesToStr([ // $mod.$main
  787. '']));
  788. end;
  789. procedure TTestGenerics.TestGen_Class_ClassConstructor;
  790. begin
  791. StartProgram(false);
  792. Add([
  793. 'type',
  794. ' TObject = class end;',
  795. ' generic TPoint<T> = class',
  796. ' class var x: T;',
  797. ' class procedure Fly; static;',
  798. ' class constructor Init;',
  799. ' end;',
  800. 'var count: word;',
  801. 'class procedure Tpoint.Fly;',
  802. 'begin',
  803. 'end;',
  804. 'class constructor tpoint.init;',
  805. 'begin',
  806. ' count:=count+1;',
  807. ' x:=3;',
  808. ' tpoint.x:=4;',
  809. ' fly;',
  810. ' tpoint.fly;',
  811. 'end;',
  812. 'var',
  813. ' r: specialize TPoint<word>;',
  814. ' s: specialize TPoint<smallint>;',
  815. 'begin',
  816. ' r.x:=10;',
  817. '']);
  818. ConvertProgram;
  819. CheckSource('TestGen_Class_ClassConstructor',
  820. LinesToStr([ // statements
  821. 'rtl.createClass(this, "TObject", null, function () {',
  822. ' this.$init = function () {',
  823. ' };',
  824. ' this.$final = function () {',
  825. ' };',
  826. '});',
  827. 'this.count = 0;',
  828. 'rtl.createClass(this, "TPoint$G1", this.TObject, function () {',
  829. ' this.x = 0;',
  830. ' this.Fly = function () {',
  831. ' };',
  832. '}, "TPoint<System.Word>");',
  833. 'this.r = null;',
  834. 'rtl.createClass(this, "TPoint$G2", this.TObject, function () {',
  835. ' this.x = 0;',
  836. ' this.Fly = function () {',
  837. ' };',
  838. '}, "TPoint<System.SmallInt>");',
  839. 'this.s = null;',
  840. '']),
  841. LinesToStr([ // $mod.$main
  842. '(function () {',
  843. ' $mod.count = $mod.count + 1;',
  844. ' $mod.TPoint$G1.x = 3;',
  845. ' $mod.TPoint$G1.x = 4;',
  846. ' $mod.TPoint$G1.Fly();',
  847. ' $mod.TPoint$G1.Fly();',
  848. '})();',
  849. '(function () {',
  850. ' $mod.count = $mod.count + 1;',
  851. ' $mod.TPoint$G2.x = 3;',
  852. ' $mod.TPoint$G2.x = 4;',
  853. ' $mod.TPoint$G2.Fly();',
  854. ' $mod.TPoint$G2.Fly();',
  855. '})();',
  856. '$mod.TPoint$G1.x = 10;',
  857. '']));
  858. end;
  859. procedure TTestGenerics.TestGen_Class_TypeCastSpecializesWarn;
  860. begin
  861. StartProgram(false);
  862. Add([
  863. '{$mode delphi}',
  864. 'type',
  865. ' TObject = class end;',
  866. ' TBird<T> = class F: T; end;',
  867. ' TBirdWord = TBird<Word>;',
  868. ' TBirdChar = TBird<Char>;',
  869. 'var',
  870. ' w: TBirdWord;',
  871. ' c: TBirdChar;',
  872. 'begin',
  873. ' w:=TBirdWord(c);',
  874. '']);
  875. ConvertProgram;
  876. CheckSource('TestGen_Class_TypeCastSpecializesWarn',
  877. LinesToStr([ // statements
  878. 'rtl.createClass(this, "TObject", null, function () {',
  879. ' this.$init = function () {',
  880. ' };',
  881. ' this.$final = function () {',
  882. ' };',
  883. '});',
  884. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  885. ' this.$init = function () {',
  886. ' $mod.TObject.$init.call(this);',
  887. ' this.F = 0;',
  888. ' };',
  889. '}, "TBird<System.Word>");',
  890. 'rtl.createClass(this, "TBird$G2", this.TObject, function () {',
  891. ' this.$init = function () {',
  892. ' $mod.TObject.$init.call(this);',
  893. ' this.F = "";',
  894. ' };',
  895. '}, "TBird<System.Char>");',
  896. 'this.w = null;',
  897. 'this.c = null;',
  898. '']),
  899. LinesToStr([ // $mod.$main
  900. '$mod.w = $mod.c;',
  901. '']));
  902. CheckHint(mtWarning,nClassTypesAreNotRelatedXY,'Class types "TBird<System.Char>" and "TBird<System.Word>" are not related');
  903. CheckResolverUnexpectedHints();
  904. end;
  905. procedure TTestGenerics.TestGen_Class_TypeCastSpecializesJSValueNoWarn;
  906. begin
  907. StartProgram(false);
  908. Add([
  909. '{$mode delphi}',
  910. 'type',
  911. ' TObject = class end;',
  912. ' TBird<T> = class F: T; end;',
  913. ' TBirdWord = TBird<Word>;',
  914. ' TBirdAny = TBird<JSValue>;',
  915. 'var',
  916. ' w: TBirdWord;',
  917. ' a: TBirdAny;',
  918. 'begin',
  919. ' w:=TBirdWord(a);',
  920. ' a:=TBirdAny(w);',
  921. '']);
  922. ConvertProgram;
  923. CheckSource('TestGen_Class_TypeCastSpecializesJSValueNoWarn',
  924. LinesToStr([ // statements
  925. 'rtl.createClass(this, "TObject", null, function () {',
  926. ' this.$init = function () {',
  927. ' };',
  928. ' this.$final = function () {',
  929. ' };',
  930. '});',
  931. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  932. ' this.$init = function () {',
  933. ' $mod.TObject.$init.call(this);',
  934. ' this.F = 0;',
  935. ' };',
  936. '}, "TBird<System.Word>");',
  937. 'rtl.createClass(this, "TBird$G2", this.TObject, function () {',
  938. ' this.$init = function () {',
  939. ' $mod.TObject.$init.call(this);',
  940. ' this.F = undefined;',
  941. ' };',
  942. '}, "TBird<System.JSValue>");',
  943. 'this.w = null;',
  944. 'this.a = null;',
  945. '']),
  946. LinesToStr([ // $mod.$main
  947. '$mod.w = $mod.a;',
  948. '$mod.a = $mod.w;',
  949. '']));
  950. CheckResolverUnexpectedHints();
  951. end;
  952. procedure TTestGenerics.TestGen_Class_OverloadsInUnit;
  953. begin
  954. StartProgram(true,[supTObject]);
  955. AddModuleWithIntfImplSrc('UnitA.pas',
  956. LinesToStr([
  957. 'type',
  958. ' generic TBird<T> = class',
  959. ' const c = 13;',
  960. ' constructor Create(w: T);',
  961. ' constructor Create(b: boolean);',
  962. ' end;',
  963. '']),
  964. LinesToStr([
  965. 'constructor TBird.Create(w: T);',
  966. 'const c = 14;',
  967. 'begin',
  968. 'end;',
  969. 'constructor TBird.Create(b: boolean);',
  970. 'const c = 15;',
  971. 'begin',
  972. 'end;',
  973. '']));
  974. Add([
  975. 'uses UnitA;',
  976. 'type',
  977. ' TWordBird = specialize TBird<word>;',
  978. ' TDoubleBird = specialize TBird<double>;',
  979. 'var',
  980. ' wb: TWordBird;',
  981. ' db: TDoubleBird;',
  982. 'begin',
  983. ' wb:=TWordBird.Create(3);',
  984. ' wb:=TWordBird.Create(true);',
  985. ' db:=TDoubleBird.Create(1.3);',
  986. ' db:=TDoubleBird.Create(true);',
  987. '']);
  988. ConvertProgram;
  989. CheckUnit('UnitA.pas',
  990. LinesToStr([ // statements
  991. 'rtl.module("UnitA", ["system"], function () {',
  992. ' var $mod = this;',
  993. ' rtl.createClass(this, "TBird$G1", pas.system.TObject, function () {',
  994. ' this.c = 13;',
  995. ' var c$1 = 14;',
  996. ' this.Create$1 = function (w) {',
  997. ' return this;',
  998. ' };',
  999. ' var c$2 = 15;',
  1000. ' this.Create$2 = function (b) {',
  1001. ' return this;',
  1002. ' };',
  1003. ' }, "TBird<System.Word>");',
  1004. ' rtl.createClass(this, "TBird$G2", pas.system.TObject, function () {',
  1005. ' this.c = 13;',
  1006. ' var c$1 = 14;',
  1007. ' this.Create$1 = function (w) {',
  1008. ' return this;',
  1009. ' };',
  1010. ' var c$2 = 15;',
  1011. ' this.Create$2 = function (b) {',
  1012. ' return this;',
  1013. ' };',
  1014. ' }, "TBird<System.Double>");',
  1015. '});',
  1016. '']));
  1017. CheckSource('TestGen_Class_OverloadsInUnit',
  1018. LinesToStr([ // statements
  1019. 'this.wb = null;',
  1020. 'this.db = null;',
  1021. '']),
  1022. LinesToStr([ // $mod.$main
  1023. '$mod.wb = pas.UnitA.TBird$G1.$create("Create$1", [3]);',
  1024. '$mod.wb = pas.UnitA.TBird$G1.$create("Create$2", [true]);',
  1025. '$mod.db = pas.UnitA.TBird$G2.$create("Create$1", [1.3]);',
  1026. '$mod.db = pas.UnitA.TBird$G2.$create("Create$2", [true]);',
  1027. '']));
  1028. end;
  1029. procedure TTestGenerics.TestGen_ClassForward_CircleRTTI;
  1030. begin
  1031. WithTypeInfo:=true;
  1032. StartProgram(false);
  1033. Add([
  1034. '{$mode objfpc}',
  1035. 'type',
  1036. ' TObject = class end;',
  1037. ' {$M+}',
  1038. ' TPersistent = class end;',
  1039. ' {$M-}',
  1040. ' generic TAnt<T> = class;',
  1041. ' generic TFish<U> = class(TPersistent)',
  1042. ' private type AliasU = U;',
  1043. ' published',
  1044. ' a: specialize TAnt<AliasU>;',
  1045. ' end;',
  1046. ' generic TAnt<T> = class(TPersistent)',
  1047. ' private type AliasT = T;',
  1048. ' published',
  1049. ' f: specialize TFish<AliasT>;',
  1050. ' end;',
  1051. 'var',
  1052. ' WordFish: specialize TFish<word>;',
  1053. ' p: pointer;',
  1054. 'begin',
  1055. ' p:=typeinfo(specialize TAnt<word>);',
  1056. ' p:=typeinfo(specialize TFish<word>);',
  1057. '']);
  1058. ConvertProgram;
  1059. CheckSource('TestGen_ClassForward_CircleRTTI',
  1060. LinesToStr([ // statements
  1061. '$mod.$rtti.$Class("TAnt<System.Word>");',
  1062. '$mod.$rtti.$Class("TFish<System.Word>");',
  1063. 'rtl.createClass(this, "TObject", null, function () {',
  1064. ' this.$init = function () {',
  1065. ' };',
  1066. ' this.$final = function () {',
  1067. ' };',
  1068. '});',
  1069. 'rtl.createClass(this, "TPersistent", this.TObject, function () {',
  1070. '});',
  1071. 'rtl.createClass(this, "TAnt$G2", this.TPersistent, function () {',
  1072. ' this.$init = function () {',
  1073. ' $mod.TPersistent.$init.call(this);',
  1074. ' this.f = null;',
  1075. ' };',
  1076. ' this.$final = function () {',
  1077. ' this.f = undefined;',
  1078. ' $mod.TPersistent.$final.call(this);',
  1079. ' };',
  1080. ' var $r = this.$rtti;',
  1081. ' $r.addField("f", $mod.$rtti["TFish<System.Word>"]);',
  1082. '}, "TAnt<System.Word>");',
  1083. 'rtl.createClass(this, "TFish$G2", this.TPersistent, function () {',
  1084. ' this.$init = function () {',
  1085. ' $mod.TPersistent.$init.call(this);',
  1086. ' this.a = null;',
  1087. ' };',
  1088. ' this.$final = function () {',
  1089. ' this.a = undefined;',
  1090. ' $mod.TPersistent.$final.call(this);',
  1091. ' };',
  1092. ' var $r = this.$rtti;',
  1093. ' $r.addField("a", $mod.$rtti["TAnt<System.Word>"]);',
  1094. '}, "TFish<System.Word>");',
  1095. 'this.WordFish = null;',
  1096. 'this.p = null;',
  1097. '']),
  1098. LinesToStr([ // $mod.$main
  1099. '$mod.p = $mod.$rtti["TAnt<System.Word>"];',
  1100. '$mod.p = $mod.$rtti["TFish<System.Word>"];',
  1101. '']));
  1102. end;
  1103. procedure TTestGenerics.TestGen_Class_Nested_RTTI;
  1104. begin
  1105. WithTypeInfo:=true;
  1106. StartProgram(true,[supTObject]);
  1107. AddModuleWithIntfImplSrc('UnitA.pas',
  1108. LinesToStr([
  1109. 'type',
  1110. ' generic TAnt<T> = class',
  1111. ' type',
  1112. ' TLeg = class',
  1113. ' published',
  1114. ' Size: T;',
  1115. ' end;',
  1116. ' end;',
  1117. ' TBoolAnt = specialize TAnt<boolean>;',
  1118. '']),
  1119. LinesToStr([
  1120. '']));
  1121. Add([
  1122. 'uses UnitA;',
  1123. 'var',
  1124. ' BoolLeg: TBoolAnt.TLeg;',
  1125. 'begin',
  1126. ' if typeinfo(TBoolAnt.TLeg)=nil then ;',
  1127. '']);
  1128. ConvertProgram;
  1129. CheckUnit('UnitA.pas',
  1130. LinesToStr([ // statements
  1131. 'rtl.module("UnitA", ["system"], function () {',
  1132. ' var $mod = this;',
  1133. ' $mod.$rtti.$Class("TAnt<System.Boolean>");',
  1134. ' rtl.createClass(this, "TAnt$G1", pas.system.TObject, function () {',
  1135. ' rtl.createClass(this, "TLeg", pas.system.TObject, function () {',
  1136. ' this.$init = function () {',
  1137. ' pas.system.TObject.$init.call(this);',
  1138. ' this.Size = false;',
  1139. ' };',
  1140. ' var $r = this.$rtti;',
  1141. ' $r.addField("Size", rtl.boolean);',
  1142. ' }, "TAnt<System.Boolean>.TLeg");',
  1143. ' }, "TAnt<System.Boolean>");',
  1144. '});']));
  1145. CheckSource('TestGen_Class_Nested_RTTI',
  1146. LinesToStr([ // statements
  1147. 'this.BoolLeg = null;',
  1148. '']),
  1149. LinesToStr([ // $mod.$main
  1150. 'if (pas.UnitA.$rtti["TAnt<System.Boolean>.TLeg"] === null) ;',
  1151. '']));
  1152. end;
  1153. procedure TTestGenerics.TestGen_Class_ClassVarRecord_UnitImpl;
  1154. begin
  1155. StartProgram(true,[supTObject]);
  1156. AddModuleWithIntfImplSrc('UnitA.pas',
  1157. LinesToStr([
  1158. 'type',
  1159. ' generic TAnt<T> = class',
  1160. ' public',
  1161. ' class var x: T;',
  1162. ' class var a: array[1..2] of T;',
  1163. ' end;',
  1164. '']),
  1165. LinesToStr([
  1166. 'type',
  1167. ' TBird = record',
  1168. ' b: word;',
  1169. ' end;',
  1170. 'var f: specialize TAnt<TBird>;',
  1171. 'begin',
  1172. ' f.x.b:=f.x.b+10;',
  1173. '']));
  1174. Add([
  1175. 'uses UnitA;',
  1176. 'begin',
  1177. 'end.']);
  1178. ConvertProgram;
  1179. CheckUnit('UnitA.pas',
  1180. LinesToStr([ // statements
  1181. 'rtl.module("UnitA", ["system"], function () {',
  1182. ' var $mod = this;',
  1183. ' var $impl = $mod.$impl;',
  1184. ' rtl.createClass(this, "TAnt$G1", pas.system.TObject, function () {',
  1185. ' this.$initSpec = function () {',
  1186. ' this.x = $impl.TBird.$new();',
  1187. ' this.a = rtl.arraySetLength(null, $impl.TBird, 2);',
  1188. ' };',
  1189. ' this.a$a$clone = function (a) {',
  1190. ' var b = [];',
  1191. ' b.length = 2;',
  1192. ' for (var c = 0; c < 2; c++) b[c] = $impl.TBird.$clone(a[c]);',
  1193. ' return b;',
  1194. ' };',
  1195. ' }, "TAnt<UnitA.TBird>");',
  1196. ' $mod.$implcode = function () {',
  1197. ' rtl.recNewT($impl, "TBird", function () {',
  1198. ' this.b = 0;',
  1199. ' this.$eq = function (b) {',
  1200. ' return this.b === b.b;',
  1201. ' };',
  1202. ' this.$assign = function (s) {',
  1203. ' this.b = s.b;',
  1204. ' return this;',
  1205. ' };',
  1206. ' });',
  1207. ' $impl.f = null;',
  1208. ' };',
  1209. ' $mod.$init = function () {',
  1210. ' $impl.f.x.b = $impl.f.x.b + 10;',
  1211. ' };',
  1212. '}, []);',
  1213. '']));
  1214. CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
  1215. LinesToStr([ // statements
  1216. '$mod.$implcode = function () {',
  1217. ' pas.UnitA.TAnt$G1.$initSpec();',
  1218. '};',
  1219. '']),
  1220. LinesToStr([ // $mod.$main
  1221. '']));
  1222. end;
  1223. procedure TTestGenerics.TestGen_ExtClass_VarArgsOfType;
  1224. begin
  1225. StartProgram(false);
  1226. Add([
  1227. '{$mode objfpc}',
  1228. '{$modeswitch externalclass}',
  1229. 'type',
  1230. ' TJSObject = class external name ''Object''',
  1231. ' end;',
  1232. ' generic TGJSSet<T> = class external name ''Set''',
  1233. ' constructor new(aElement1: T); varargs of T; overload;',
  1234. ' function bind(thisArg: TJSObject): T; varargs of T;',
  1235. ' end;',
  1236. ' TJSWordSet = specialize TGJSSet<word>;',
  1237. 'var',
  1238. ' s: TJSWordSet;',
  1239. ' w: word;',
  1240. 'begin',
  1241. ' s:=TJSWordSet.new(3);',
  1242. ' s:=TJSWordSet.new(3,5);',
  1243. ' w:=s.bind(nil);',
  1244. ' w:=s.bind(nil,6);',
  1245. ' w:=s.bind(nil,7,8);',
  1246. '']);
  1247. ConvertProgram;
  1248. CheckSource('TestGen_ExtClass_VarArgsOfType',
  1249. LinesToStr([ // statements
  1250. 'this.s = null;',
  1251. 'this.w = 0;',
  1252. '']),
  1253. LinesToStr([ // $mod.$main
  1254. '$mod.s = new Set(3);',
  1255. '$mod.s = new Set(3, 5);',
  1256. '$mod.w = $mod.s.bind(null);',
  1257. '$mod.w = $mod.s.bind(null, 6);',
  1258. '$mod.w = $mod.s.bind(null, 7, 8);',
  1259. '']));
  1260. end;
  1261. procedure TTestGenerics.TestGen_ExtClass_Array;
  1262. begin
  1263. StartProgram(false);
  1264. Add([
  1265. '{$mode delphi}',
  1266. '{$ModeSwitch externalclass}',
  1267. 'type',
  1268. ' NativeInt = longint;',
  1269. ' TJSGenArray<T> = Class external name ''Array''',
  1270. ' private',
  1271. ' function GetElements(Index: NativeInt): T; external name ''[]'';',
  1272. ' procedure SetElements(Index: NativeInt; const AValue: T); external name ''[]'';',
  1273. ' public',
  1274. ' type TSelfType = TJSGenArray<T>;',
  1275. ' public',
  1276. ' FLength : NativeInt; external name ''length'';',
  1277. ' constructor new; overload;',
  1278. ' constructor new(aLength : NativeInt); overload;',
  1279. ' class function _of() : TSelfType; varargs; external name ''of'';',
  1280. ' function fill(aValue : T) : TSelfType; overload;',
  1281. ' function fill(aValue : T; aStartIndex : NativeInt) : TSelfType; overload;',
  1282. ' function fill(aValue : T; aStartIndex,aEndIndex : NativeInt) : TSelfType; overload;',
  1283. ' property Length : NativeInt Read FLength Write FLength;',
  1284. ' property Elements[Index: NativeInt]: T read GetElements write SetElements; default;',
  1285. ' end;',
  1286. ' TJSWordArray = TJSGenArray<word>;',
  1287. 'var',
  1288. ' wa: TJSWordArray;',
  1289. ' w: word;',
  1290. 'begin',
  1291. ' wa:=TJSWordArray.new;',
  1292. ' wa:=TJSWordArray.new(3);',
  1293. ' wa:=TJSWordArray._of(4,5);',
  1294. ' wa:=wa.fill(7);',
  1295. ' wa:=wa.fill(7,8,9);',
  1296. ' w:=wa.length;',
  1297. ' wa.length:=10;',
  1298. ' wa[11]:=w;',
  1299. ' w:=wa[12];',
  1300. '']);
  1301. ConvertProgram;
  1302. CheckSource('TestGen_ExtClass_Array',
  1303. LinesToStr([ // statements
  1304. 'this.wa = null;',
  1305. 'this.w = 0;',
  1306. '']),
  1307. LinesToStr([ // $mod.$main
  1308. '$mod.wa = new Array();',
  1309. '$mod.wa = new Array(3);',
  1310. '$mod.wa = Array.of(4, 5);',
  1311. '$mod.wa = $mod.wa.fill(7);',
  1312. '$mod.wa = $mod.wa.fill(7, 8, 9);',
  1313. '$mod.w = $mod.wa.length;',
  1314. '$mod.wa.length = 10;',
  1315. '$mod.wa[11] = $mod.w;',
  1316. '$mod.w = $mod.wa[12];',
  1317. '']));
  1318. end;
  1319. procedure TTestGenerics.TestGen_ExtClass_GenJSValueAssign;
  1320. begin
  1321. StartProgram(false);
  1322. Add([
  1323. '{$mode delphi}',
  1324. '{$modeswitch externalclass}',
  1325. 'type',
  1326. ' TExt<T> = class external name ''Ext''',
  1327. ' F: T;',
  1328. ' end;',
  1329. ' TExtWord = TExt<Word>;',
  1330. ' TExtAny = TExt<JSValue>;',
  1331. 'procedure Run(e: TExtAny);',
  1332. 'begin end;',
  1333. 'var',
  1334. ' w: TExtWord;',
  1335. ' a: TExtAny;',
  1336. 'begin',
  1337. ' a:=w;',
  1338. ' Run(w);',
  1339. '']);
  1340. ConvertProgram;
  1341. CheckSource('TestGen_ExtClass_GenJSValueAssign',
  1342. LinesToStr([ // statements
  1343. 'this.Run = function (e) {',
  1344. '};',
  1345. 'this.w = null;',
  1346. 'this.a = null;',
  1347. '']),
  1348. LinesToStr([ // $mod.$main
  1349. '$mod.a = $mod.w;',
  1350. '$mod.Run($mod.w);',
  1351. '']));
  1352. CheckResolverUnexpectedHints();
  1353. end;
  1354. procedure TTestGenerics.TestGen_ExtClass_AliasMemberType;
  1355. begin
  1356. StartProgram(false);
  1357. Add([
  1358. '{$mode objfpc}',
  1359. '{$modeswitch externalclass}',
  1360. 'type',
  1361. ' generic TExt<T> = class external name ''Ext''',
  1362. ' public type TRun = reference to function(a: T): T;',
  1363. ' end;',
  1364. ' TExtWord = specialize TExt<word>;',
  1365. ' TExtWordRun = TExtWord.TRun;',
  1366. 'begin',
  1367. '']);
  1368. ConvertProgram;
  1369. CheckSource('TestGen_ExtClass_AliasMemberType',
  1370. LinesToStr([ // statements
  1371. '']),
  1372. LinesToStr([ // $mod.$main
  1373. '']));
  1374. end;
  1375. procedure TTestGenerics.TestGen_ExtClass_RTTI;
  1376. begin
  1377. WithTypeInfo:=true;
  1378. StartProgram(false);
  1379. Add([
  1380. '{$mode objfpc}',
  1381. '{$modeswitch externalclass}',
  1382. 'type',
  1383. ' generic TGJSSET<T> = class external name ''SET''',
  1384. ' A: T;',
  1385. ' end;',
  1386. ' TJSSet = specialize TGJSSET<JSValue>;',
  1387. ' TJSSetEventProc = reference to procedure(value : JSValue; key: NativeInt; set_: TJSSet);',
  1388. 'var p: Pointer;',
  1389. 'begin',
  1390. ' p:=typeinfo(TJSSetEventProc);',
  1391. '']);
  1392. ConvertProgram;
  1393. CheckSource('TestGen_ExtClass_RTTI',
  1394. LinesToStr([ // statements
  1395. 'this.$rtti.$ExtClass("TGJSSET<System.JSValue>", {',
  1396. ' jsclass: "SET"',
  1397. '});',
  1398. 'this.$rtti.$RefToProcVar("TJSSetEventProc", {',
  1399. ' procsig: rtl.newTIProcSig([["value", rtl.jsvalue], ["key", rtl.nativeint], ["set_", this.$rtti["TGJSSET<System.JSValue>"]]])',
  1400. '});',
  1401. 'this.p = null;',
  1402. '']),
  1403. LinesToStr([ // $mod.$main
  1404. '$mod.p = $mod.$rtti["TJSSetEventProc"];',
  1405. '']));
  1406. end;
  1407. procedure TTestGenerics.TestGen_ExtClass_UnitImplRec;
  1408. begin
  1409. WithTypeInfo:=true;
  1410. StartProgram(true,[supTObject]);
  1411. AddModuleWithIntfImplSrc('UnitA.pas',
  1412. LinesToStr([
  1413. '{$mode objfpc}',
  1414. '{$modeswitch externalclass}',
  1415. 'type',
  1416. ' generic TAnt<T> = class external name ''SET''',
  1417. ' x: T;',
  1418. ' end;',
  1419. '']),
  1420. LinesToStr([
  1421. 'type',
  1422. ' TBird = record',
  1423. ' b: word;',
  1424. ' end;',
  1425. 'var',
  1426. ' f: specialize TAnt<TBird>;',
  1427. 'begin',
  1428. ' f.x.b:=f.x.b+10;',
  1429. '']));
  1430. Add([
  1431. 'uses UnitA;',
  1432. 'begin',
  1433. 'end.']);
  1434. ConvertProgram;
  1435. CheckUnit('UnitA.pas',
  1436. LinesToStr([ // statements
  1437. 'rtl.module("UnitA", ["system"], function () {',
  1438. ' var $mod = this;',
  1439. ' var $impl = $mod.$impl;',
  1440. ' this.$rtti.$ExtClass("TAnt<UnitA.TBird>", {',
  1441. ' jsclass: "SET"',
  1442. ' });',
  1443. ' $mod.$implcode = function () {',
  1444. ' rtl.recNewT($impl, "TBird", function () {',
  1445. ' this.b = 0;',
  1446. ' this.$eq = function (b) {',
  1447. ' return this.b === b.b;',
  1448. ' };',
  1449. ' this.$assign = function (s) {',
  1450. ' this.b = s.b;',
  1451. ' return this;',
  1452. ' };',
  1453. ' var $r = $mod.$rtti.$Record("TBird", {});',
  1454. ' $r.addField("b", rtl.word);',
  1455. ' });',
  1456. ' $impl.f = null;',
  1457. ' };',
  1458. ' $mod.$init = function () {',
  1459. ' $impl.f.x.b = $impl.f.x.b + 10;',
  1460. ' };',
  1461. '}, []);']));
  1462. CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
  1463. LinesToStr([ // statements
  1464. '']),
  1465. LinesToStr([ // $mod.$main
  1466. '']));
  1467. end;
  1468. procedure TTestGenerics.TestGen_ClassInterface_Corba;
  1469. begin
  1470. StartProgram(false);
  1471. Add([
  1472. '{$interfaces corba}',
  1473. 'type',
  1474. ' IUnknown = interface;',
  1475. ' IUnknown = interface',
  1476. ' [''{00000000-0000-0000-C000-000000000046}'']',
  1477. ' end;',
  1478. ' IInterface = IUnknown;',
  1479. ' generic IBird<T> = interface(IInterface)',
  1480. ' function GetSize: T;',
  1481. ' procedure SetSize(i: T);',
  1482. ' property Size: T read GetSize write SetSize;',
  1483. ' procedure DoIt(i: T);',
  1484. ' end;',
  1485. ' TObject = class',
  1486. ' end;',
  1487. ' generic TBird<T> = class(TObject,specialize IBird<T>)',
  1488. ' function GetSize: T; virtual; abstract;',
  1489. ' procedure SetSize(i: T); virtual; abstract;',
  1490. ' procedure DoIt(i: T); virtual; abstract;',
  1491. ' end;',
  1492. ' IWordBird = specialize IBird<Word>;',
  1493. ' TWordBird = specialize TBird<Word>;',
  1494. 'var',
  1495. ' BirdIntf: IWordBird;',
  1496. 'begin',
  1497. ' BirdIntf.Size:=BirdIntf.Size;',
  1498. '']);
  1499. ConvertProgram;
  1500. CheckSource('TestGen_ClassInterface_Corba',
  1501. LinesToStr([ // statements
  1502. 'rtl.createInterface(this, "IUnknown", "{00000000-0000-0000-C000-000000000046}", [], null);',
  1503. 'rtl.createClass(this, "TObject", null, function () {',
  1504. ' this.$init = function () {',
  1505. ' };',
  1506. ' this.$final = function () {',
  1507. ' };',
  1508. '});',
  1509. 'rtl.createInterface(',
  1510. ' this,',
  1511. ' "IBird$G2",',
  1512. ' "{33AB51C6-6240-3BDF-B4B0-D48A593EAB0A}",',
  1513. ' ["GetSize", "SetSize", "DoIt"],',
  1514. ' this.IUnknown,',
  1515. ' "IBird<System.Word>"',
  1516. ');',
  1517. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  1518. ' rtl.addIntf(this, $mod.IBird$G2);',
  1519. '}, "TBird<System.Word>");',
  1520. 'this.BirdIntf = null;',
  1521. '']),
  1522. LinesToStr([ // $mod.$main
  1523. '$mod.BirdIntf.SetSize($mod.BirdIntf.GetSize());',
  1524. '']));
  1525. end;
  1526. procedure TTestGenerics.TestGen_ClassInterface_InterfacedObject;
  1527. begin
  1528. StartProgram(true,[supTInterfacedObject]);
  1529. Add([
  1530. '{$mode delphi}',
  1531. 'type',
  1532. ' IComparer<T> = interface [''{505778ED-F783-4456-9691-32F419CC5E18}'']',
  1533. ' function Compare(const Left, Right: T): Integer; overload;',
  1534. ' end;',
  1535. ' TComparer<T> = class(TInterfacedObject, IComparer<T>)',
  1536. ' function Compare(const Left, Right: T): Integer;',
  1537. ' end;',
  1538. 'function TComparer<T>.Compare(const Left, Right: T): Integer; begin end;',
  1539. 'var',
  1540. ' aComparer : IComparer<Integer>;',
  1541. 'begin',
  1542. ' aComparer:=TComparer<Integer>.Create;',
  1543. '']);
  1544. ConvertProgram;
  1545. CheckSource('TestGen_ClassInterface_InterfacedObject',
  1546. LinesToStr([ // statements
  1547. 'rtl.createInterface(',
  1548. ' this,',
  1549. ' "IComparer$G2",',
  1550. ' "{505778ED-F783-4456-9691-32F419CC5E18}",',
  1551. ' ["Compare"],',
  1552. ' pas.system.IUnknown,',
  1553. ' "IComparer<System.Longint>"',
  1554. ');',
  1555. 'this.aComparer = null;',
  1556. 'rtl.createClass(this, "TComparer$G1", pas.system.TInterfacedObject, function () {',
  1557. ' this.Compare = function (Left, Right) {',
  1558. ' var Result = 0;',
  1559. ' return Result;',
  1560. ' };',
  1561. ' rtl.addIntf(this, $mod.IComparer$G2);',
  1562. ' rtl.addIntf(this, pas.system.IUnknown);',
  1563. '}, "TComparer<System.Longint>");',
  1564. '']),
  1565. LinesToStr([ // $mod.$main
  1566. 'rtl.setIntfP($mod, "aComparer", rtl.queryIntfT($mod.TComparer$G1.$create("Create"), $mod.IComparer$G2), true);',
  1567. '']));
  1568. end;
  1569. procedure TTestGenerics.TestGen_ClassInterface_COM_RTTI;
  1570. begin
  1571. StartProgram(true,[supTInterfacedObject]);
  1572. Add([
  1573. '{$mode delphi}',
  1574. 'type',
  1575. ' TBird = class',
  1576. ' function Fly<T: IInterface>: T;',
  1577. ' end;',
  1578. ' IAnt = interface',
  1579. ' procedure InterfaceProc;',
  1580. ' end;',
  1581. 'function TBird.Fly<T>: T;',
  1582. 'begin',
  1583. ' if TypeInfo(T)=nil then ;',
  1584. 'end;',
  1585. 'var Bird: TBird;',
  1586. ' Ant: IAnt;',
  1587. 'begin',
  1588. ' Ant := Bird.Fly<IAnt>;',
  1589. '']);
  1590. ConvertProgram;
  1591. CheckSource('TestGen_ClassInterface_COM_RTTI',
  1592. LinesToStr([ // statements
  1593. 'rtl.createClass(this, "TBird", pas.system.TObject, function () {',
  1594. ' this.Fly$G1 = function () {',
  1595. ' var Result = null;',
  1596. ' if ($mod.$rtti["IAnt"] === null) ;',
  1597. ' return Result;',
  1598. ' };',
  1599. '});',
  1600. 'rtl.createInterface(this, "IAnt", "{B9D0FF27-A446-3A1B-AA85-F167837AA297}", ["InterfaceProc"], pas.system.IUnknown);',
  1601. 'this.Bird = null;',
  1602. 'this.Ant = null;',
  1603. '']),
  1604. LinesToStr([ // $mod.$main
  1605. 'rtl.setIntfP($mod, "Ant", $mod.Bird.Fly$G1(), true);',
  1606. '']));
  1607. end;
  1608. procedure TTestGenerics.TestGen_ClassInterface_Helper;
  1609. begin
  1610. StartProgram(true,[supTInterfacedObject]);
  1611. Add([
  1612. '{$mode objfpc}',
  1613. '{$ModeSwitch typehelpers}',
  1614. 'type',
  1615. ' IAnt = interface',
  1616. ' procedure InterfaceProc;',
  1617. ' end;',
  1618. ' TBird = type helper for IAnt',
  1619. ' generic procedure Fly<T>(a: T);',
  1620. ' end;',
  1621. 'generic procedure TBird.Fly<T>(a: T);',
  1622. 'begin',
  1623. 'end;',
  1624. 'var ',
  1625. ' Ant: IAnt;',
  1626. 'begin',
  1627. ' Ant.specialize Fly<word>(3);',
  1628. '']);
  1629. ConvertProgram;
  1630. CheckSource('TestGen_ClassInterface_COM_RTTI',
  1631. LinesToStr([ // statements
  1632. 'rtl.createInterface(this, "IAnt", "{B9D0FF27-A446-3A1B-AA85-F167837AA297}", ["InterfaceProc"], pas.system.IUnknown);',
  1633. 'rtl.createHelper(this, "TBird", null, function () {',
  1634. ' this.Fly$G1 = function (a) {',
  1635. ' };',
  1636. '});',
  1637. 'this.Ant = null;',
  1638. '']),
  1639. LinesToStr([ // $mod.$main
  1640. '$mod.TBird.Fly$G1.call({',
  1641. ' p: $mod,',
  1642. ' get: function () {',
  1643. ' return this.p.Ant;',
  1644. ' },',
  1645. ' set: function (v) {',
  1646. ' rtl.setIntfP(this.p, "Ant", v);',
  1647. ' }',
  1648. '}, 3);',
  1649. '']));
  1650. end;
  1651. procedure TTestGenerics.TestGen_ClassInterface_DelayedInitSpec;
  1652. begin
  1653. WithTypeInfo:=true;
  1654. StartProgram(true,[supTObject,supTInterfacedObject]);
  1655. AddModuleWithIntfImplSrc('UnitA.pas',
  1656. LinesToStr([
  1657. '{$mode delphi}',
  1658. 'type',
  1659. ' TAnt<T> = interface',
  1660. ' procedure Run(x: T);',
  1661. ' end;',
  1662. '']),
  1663. LinesToStr([
  1664. '']));
  1665. Add([
  1666. '{$mode delphi}',
  1667. 'uses UnitA;',
  1668. 'type',
  1669. ' TArrWord = array of word;',
  1670. ' TMyIntf = TAnt<TArrWord>;',
  1671. ' TBird = class(TInterfacedObject,TMyIntf)',
  1672. ' procedure Run(a: TArrWord); external name ''Run'';',
  1673. ' end;',
  1674. 'var',
  1675. ' i: TMyIntf;',
  1676. 'begin',
  1677. ' i:=TBird.Create;',
  1678. ' i.Run([3,4]);',
  1679. 'end.']);
  1680. ConvertProgram;
  1681. CheckUnit('UnitA.pas',
  1682. LinesToStr([ // statements
  1683. 'rtl.module("UnitA", ["system"], function () {',
  1684. ' var $mod = this;',
  1685. ' $mod.$rtti.$Interface("TAnt<test1.TArrWord>");',
  1686. ' rtl.createInterface(',
  1687. ' this,',
  1688. ' "TAnt$G1",',
  1689. ' "{B145F21B-2696-32D5-87A5-F16C037A2D45}",',
  1690. ' ["Run"],',
  1691. ' pas.system.IUnknown,',
  1692. ' function () {',
  1693. ' this.$initSpec = function () {',
  1694. ' var $r = this.$rtti;',
  1695. ' $r.addMethod("Run", 0, [["x", pas.program.$rtti["TArrWord"]]]);',
  1696. ' };',
  1697. ' },',
  1698. ' "TAnt<test1.TArrWord>"',
  1699. ' );',
  1700. '});']));
  1701. CheckSource('TestGen_ClassInterface_DelayedInitSpec',
  1702. LinesToStr([ // statements
  1703. 'this.$rtti.$DynArray("TArrWord", {',
  1704. ' eltype: rtl.word',
  1705. '});',
  1706. 'rtl.createClass(this, "TBird", pas.system.TInterfacedObject, function () {',
  1707. ' rtl.addIntf(this, pas.UnitA.TAnt$G1);',
  1708. ' rtl.addIntf(this, pas.system.IUnknown);',
  1709. '});',
  1710. 'this.i = null;',
  1711. '$mod.$implcode = function () {',
  1712. ' pas.UnitA.TAnt$G1.$initSpec();',
  1713. '};',
  1714. '']),
  1715. LinesToStr([ // $mod.$main
  1716. 'rtl.setIntfP($mod, "i", rtl.queryIntfT($mod.TBird.$create("Create"), pas.UnitA.TAnt$G1), true);',
  1717. '$mod.i.Run([3, 4]);',
  1718. '']));
  1719. end;
  1720. procedure TTestGenerics.TestGen_InlineSpec_Constructor;
  1721. begin
  1722. StartProgram(false);
  1723. Add([
  1724. '{$mode objfpc}',
  1725. 'type',
  1726. ' TObject = class',
  1727. ' public',
  1728. ' constructor Create;',
  1729. ' end;',
  1730. ' generic TBird<T> = class',
  1731. ' end;',
  1732. 'constructor TObject.Create; begin end;',
  1733. 'var b: specialize TBird<word>;',
  1734. 'begin',
  1735. ' b:=specialize TBird<word>.Create;',
  1736. '']);
  1737. ConvertProgram;
  1738. CheckSource('TestGen_InlineSpec_Constructor',
  1739. LinesToStr([ // statements
  1740. 'rtl.createClass(this, "TObject", null, function () {',
  1741. ' this.$init = function () {',
  1742. ' };',
  1743. ' this.$final = function () {',
  1744. ' };',
  1745. ' this.Create = function () {',
  1746. ' return this;',
  1747. ' };',
  1748. '});',
  1749. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  1750. '}, "TBird<System.Word>");',
  1751. 'this.b = null;',
  1752. '']),
  1753. LinesToStr([ // $mod.$main
  1754. '$mod.b = $mod.TBird$G1.$create("Create");',
  1755. '']));
  1756. end;
  1757. procedure TTestGenerics.TestGen_CallUnitImplProc;
  1758. begin
  1759. AddModuleWithIntfImplSrc('UnitA.pas',
  1760. LinesToStr([
  1761. 'type',
  1762. ' generic TBird<T> = class',
  1763. ' procedure Fly;',
  1764. ' end;',
  1765. 'var b: specialize TBird<boolean>;',
  1766. '']),
  1767. LinesToStr([
  1768. 'procedure DoIt;',
  1769. 'var b: specialize TBird<word>;',
  1770. 'begin',
  1771. ' b:=specialize TBird<word>.Create;',
  1772. ' b.Fly;',
  1773. 'end;',
  1774. 'procedure TBird.Fly;',
  1775. 'begin',
  1776. ' DoIt;',
  1777. 'end;',
  1778. '']));
  1779. StartProgram(true,[supTObject]);
  1780. Add('uses UnitA;');
  1781. Add('begin');
  1782. ConvertProgram;
  1783. CheckUnit('UnitA.pas',
  1784. LinesToStr([ // statements
  1785. 'rtl.module("UnitA", ["system"], function () {',
  1786. ' var $mod = this;',
  1787. ' var $impl = $mod.$impl;',
  1788. ' rtl.createClass(this, "TBird$G1", pas.system.TObject, function () {',
  1789. ' this.Fly = function () {',
  1790. ' $impl.DoIt();',
  1791. ' };',
  1792. ' }, "TBird<System.Boolean>");',
  1793. ' this.b = null;',
  1794. ' rtl.createClass(this, "TBird$G2", pas.system.TObject, function () {',
  1795. ' this.Fly = function () {',
  1796. ' $impl.DoIt();',
  1797. ' };',
  1798. ' }, "TBird<System.Word>");',
  1799. ' $mod.$implcode = function () {',
  1800. ' $impl.DoIt = function () {',
  1801. ' var b = null;',
  1802. ' b = $mod.TBird$G2.$create("Create");',
  1803. ' b.Fly();',
  1804. ' };',
  1805. ' };',
  1806. '}, []);',
  1807. '']));
  1808. end;
  1809. procedure TTestGenerics.TestGen_IntAssignTemplVar;
  1810. begin
  1811. StartProgram(false);
  1812. Add([
  1813. 'type',
  1814. ' TObject = class end;',
  1815. ' generic TBird<T> = class',
  1816. ' m: T;',
  1817. ' procedure Fly;',
  1818. ' end;',
  1819. 'var b: specialize TBird<word>;',
  1820. 'procedure TBird.Fly;',
  1821. 'var i: nativeint;',
  1822. 'begin',
  1823. ' i:=m;',
  1824. 'end;',
  1825. 'begin',
  1826. '']);
  1827. ConvertProgram;
  1828. CheckSource('TestGen_IntAssignTemplVar',
  1829. LinesToStr([ // statements
  1830. 'rtl.createClass(this, "TObject", null, function () {',
  1831. ' this.$init = function () {',
  1832. ' };',
  1833. ' this.$final = function () {',
  1834. ' };',
  1835. '});',
  1836. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  1837. ' this.$init = function () {',
  1838. ' $mod.TObject.$init.call(this);',
  1839. ' this.m = 0;',
  1840. ' };',
  1841. ' this.Fly = function () {',
  1842. ' var i = 0;',
  1843. ' i = this.m;',
  1844. ' };',
  1845. '}, "TBird<System.Word>");',
  1846. 'this.b = null;',
  1847. '']),
  1848. LinesToStr([ // $mod.$main
  1849. '']));
  1850. end;
  1851. procedure TTestGenerics.TestGen_TypeCastDotField;
  1852. begin
  1853. StartProgram(false);
  1854. Add([
  1855. 'type',
  1856. ' TObject = class end;',
  1857. ' generic TBird<T> = class',
  1858. ' Field: T;',
  1859. ' procedure Fly;',
  1860. ' end;',
  1861. 'var',
  1862. ' o: TObject;',
  1863. ' b: specialize TBird<word>;',
  1864. 'procedure TBird.Fly;',
  1865. 'begin',
  1866. ' specialize TBird<word>(o).Field:=3;',
  1867. ' if 4=specialize TBird<word>(o).Field then ;',
  1868. 'end;',
  1869. 'begin',
  1870. ' specialize TBird<word>(o).Field:=5;',
  1871. ' if 6=specialize TBird<word>(o).Field then ;',
  1872. '']);
  1873. ConvertProgram;
  1874. CheckSource('TestGen_TypeCastDotField',
  1875. LinesToStr([ // statements
  1876. 'rtl.createClass(this, "TObject", null, function () {',
  1877. ' this.$init = function () {',
  1878. ' };',
  1879. ' this.$final = function () {',
  1880. ' };',
  1881. '});',
  1882. 'this.o = null;',
  1883. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  1884. ' this.$init = function () {',
  1885. ' $mod.TObject.$init.call(this);',
  1886. ' this.Field = 0;',
  1887. ' };',
  1888. ' this.Fly = function () {',
  1889. ' $mod.o.Field = 3;',
  1890. ' if (4 === $mod.o.Field) ;',
  1891. ' };',
  1892. '}, "TBird<System.Word>");',
  1893. 'this.b = null;',
  1894. '']),
  1895. LinesToStr([ // $mod.$main
  1896. '$mod.o.Field = 5;',
  1897. 'if (6 === $mod.o.Field) ;',
  1898. '']));
  1899. end;
  1900. procedure TTestGenerics.TestGen_Except;
  1901. begin
  1902. StartProgram(false);
  1903. Add([
  1904. 'type',
  1905. ' TObject = class end;',
  1906. ' generic TBird<T> = class',
  1907. ' Field: T;',
  1908. ' procedure Fly;',
  1909. ' end;',
  1910. ' Exception = class',
  1911. ' end;',
  1912. ' generic EBird<T> = class(Exception)',
  1913. ' Id: T;',
  1914. ' end;',
  1915. 'var',
  1916. ' b: specialize TBird<word>;',
  1917. 'procedure TBird.Fly;',
  1918. 'begin',
  1919. ' try',
  1920. ' except',
  1921. ' on E: Exception do Fly;',
  1922. ' on EBird: specialize EBird<word> do EBird.Id:=3;',
  1923. ' else',
  1924. ' Fly;',
  1925. ' end;',
  1926. 'end;',
  1927. 'begin',
  1928. '']);
  1929. ConvertProgram;
  1930. CheckSource('TestGen_Except',
  1931. LinesToStr([ // statements
  1932. 'rtl.createClass(this, "TObject", null, function () {',
  1933. ' this.$init = function () {',
  1934. ' };',
  1935. ' this.$final = function () {',
  1936. ' };',
  1937. '});',
  1938. 'rtl.createClass(this, "Exception", this.TObject, function () {',
  1939. '});',
  1940. 'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
  1941. ' this.$init = function () {',
  1942. ' $mod.TObject.$init.call(this);',
  1943. ' this.Field = 0;',
  1944. ' };',
  1945. ' this.Fly = function () {',
  1946. ' try {} catch ($e) {',
  1947. ' if ($mod.Exception.isPrototypeOf($e)) {',
  1948. ' var E = $e;',
  1949. ' this.Fly();',
  1950. ' } else if ($mod.EBird$G1.isPrototypeOf($e)) {',
  1951. ' var EBird = $e;',
  1952. ' EBird.Id = 3;',
  1953. ' } else {',
  1954. ' this.Fly();',
  1955. ' }',
  1956. ' };',
  1957. ' };',
  1958. '}, "TBird<System.Word>");',
  1959. 'this.b = null;',
  1960. 'rtl.createClass(this, "EBird$G1", this.Exception, function () {',
  1961. ' this.$init = function () {',
  1962. ' $mod.Exception.$init.call(this);',
  1963. ' this.Id = 0;',
  1964. ' };',
  1965. '}, "EBird<System.Word>");',
  1966. '']),
  1967. LinesToStr([ // $mod.$main
  1968. '']));
  1969. end;
  1970. procedure TTestGenerics.TestGen_HelperForArray;
  1971. begin
  1972. StartProgram(false);
  1973. Add([
  1974. '{$ModeSwitch typehelpers}',
  1975. 'type',
  1976. ' generic TArr<T> = array[1..2] of T;',
  1977. ' TWordArrHelper = type helper for specialize TArr<word>',
  1978. ' procedure Fly(w: word);',
  1979. ' end;',
  1980. 'procedure TWordArrHelper.Fly(w: word);',
  1981. 'begin',
  1982. 'end;',
  1983. 'var',
  1984. ' a: specialize TArr<word>;',
  1985. 'begin',
  1986. ' a.Fly(3);',
  1987. '']);
  1988. ConvertProgram;
  1989. CheckSource('TestGen_HelperForArray',
  1990. LinesToStr([ // statements
  1991. 'rtl.createHelper(this, "TWordArrHelper", null, function () {',
  1992. ' this.Fly = function (w) {',
  1993. ' };',
  1994. '});',
  1995. 'this.a = rtl.arraySetLength(null, 0, 2);',
  1996. '']),
  1997. LinesToStr([ // $mod.$main
  1998. '$mod.TWordArrHelper.Fly.call({',
  1999. ' p: $mod,',
  2000. ' get: function () {',
  2001. ' return this.p.a;',
  2002. ' },',
  2003. ' set: function (v) {',
  2004. ' this.p.a = v;',
  2005. ' }',
  2006. '}, 3);',
  2007. '']));
  2008. end;
  2009. procedure TTestGenerics.TestGenProc_Function_ObjFPC;
  2010. begin
  2011. StartProgram(false);
  2012. Add([
  2013. 'generic function Run<T>(a: T): T;',
  2014. 'var i: T;',
  2015. 'begin',
  2016. ' a:=i;',
  2017. ' Result:=a;',
  2018. 'end;',
  2019. 'var w: word;',
  2020. 'begin',
  2021. ' w:=specialize Run<word>(3);',
  2022. '']);
  2023. ConvertProgram;
  2024. CheckSource('TestGenProc_Function_ObjFPC',
  2025. LinesToStr([ // statements
  2026. 'this.w = 0;',
  2027. 'this.Run$G1 = function (a) {',
  2028. ' var Result = 0;',
  2029. ' var i = 0;',
  2030. ' a = i;',
  2031. ' Result = a;',
  2032. ' return Result;',
  2033. '};',
  2034. '']),
  2035. LinesToStr([ // $mod.$main
  2036. '$mod.w = $mod.Run$G1(3);',
  2037. '']));
  2038. end;
  2039. procedure TTestGenerics.TestGenProc_Function_Delphi;
  2040. begin
  2041. StartProgram(false);
  2042. Add([
  2043. '{$mode delphi}',
  2044. 'function Run<T>(a: T): T;',
  2045. 'var i: T;',
  2046. 'begin',
  2047. ' a:=i;',
  2048. ' Result:=a;',
  2049. 'end;',
  2050. 'var w: word;',
  2051. 'begin',
  2052. ' w:=Run<word>(3);',
  2053. '']);
  2054. ConvertProgram;
  2055. CheckSource('TestGenProc_Function_Delphi',
  2056. LinesToStr([ // statements
  2057. 'this.w = 0;',
  2058. 'this.Run$G1 = function (a) {',
  2059. ' var Result = 0;',
  2060. ' var i = 0;',
  2061. ' a = i;',
  2062. ' Result = a;',
  2063. ' return Result;',
  2064. '};',
  2065. '']),
  2066. LinesToStr([ // $mod.$main
  2067. '$mod.w = $mod.Run$G1(3);',
  2068. '']));
  2069. end;
  2070. procedure TTestGenerics.TestGenProc_Overload;
  2071. begin
  2072. StartProgram(false);
  2073. Add([
  2074. 'generic procedure DoIt<T>(a: T; w: word); overload;',
  2075. 'begin',
  2076. 'end;',
  2077. 'generic procedure DoIt<T>(a: T; b: boolean); overload;',
  2078. 'begin',
  2079. 'end;',
  2080. 'begin',
  2081. ' specialize DoIt<word>(3,4);',
  2082. ' specialize DoIt<boolean>(false,5);',
  2083. ' specialize DoIt<word>(6,true);',
  2084. ' specialize DoIt<double>(7.3,true);',
  2085. '']);
  2086. ConvertProgram;
  2087. CheckSource('TestGenProc_Overload',
  2088. LinesToStr([ // statements
  2089. 'this.DoIt$G1 = function (a, w) {',
  2090. '};',
  2091. 'this.DoIt$G2 = function (a, w) {',
  2092. '};',
  2093. 'this.DoIt$1G1 = function (a, b) {',
  2094. '};',
  2095. 'this.DoIt$1G2 = function (a, b) {',
  2096. '};',
  2097. '']),
  2098. LinesToStr([ // $mod.$main
  2099. '$mod.DoIt$G1(3, 4);',
  2100. '$mod.DoIt$G2(false, 5);',
  2101. '$mod.DoIt$1G1(6, true);',
  2102. '$mod.DoIt$1G2(7.3, true);',
  2103. '']));
  2104. end;
  2105. procedure TTestGenerics.TestGenProc_Forward;
  2106. begin
  2107. StartProgram(false);
  2108. Add([
  2109. '{$mode delphi}',
  2110. 'procedure Run<S>(a: S; b: boolean); forward;',
  2111. 'procedure Run<S>(a: S; b: boolean);',
  2112. 'begin',
  2113. ' Run<word>(1,true);',
  2114. 'end;',
  2115. 'begin',
  2116. ' Run(1.3,true);',
  2117. '']);
  2118. ConvertProgram;
  2119. CheckSource('TestGenProc_infer_OverloadForward',
  2120. LinesToStr([ // statements
  2121. 'this.Run$G1 = function (a, b) {',
  2122. ' $mod.Run$G1(1, true);',
  2123. '};',
  2124. 'this.Run$G2 = function (a, b) {',
  2125. ' $mod.Run$G1(1, true);',
  2126. '};',
  2127. '']),
  2128. LinesToStr([ // $mod.$main
  2129. '$mod.Run$G2(1.3, true);',
  2130. '']));
  2131. end;
  2132. procedure TTestGenerics.TestGenProc_Infer_OverloadForward;
  2133. begin
  2134. StartProgram(false);
  2135. Add([
  2136. '{$mode delphi}',
  2137. 'procedure {#A}Run<S>(a: S; b: boolean); forward; overload;',
  2138. 'procedure {#B}Run<T>(a: T; w: word); forward; overload;',
  2139. 'procedure {#C}Run<U>(a: U; b: U); forward; overload;',
  2140. 'procedure {#A2}Run<S>(a: S; b: boolean); overload;',
  2141. 'begin',
  2142. ' {@A}Run(1,true);', // non generic take precedence
  2143. ' {@B}Run(2,word(3));', // non generic take precedence
  2144. ' {@C}Run(''foo'',''bar'');',
  2145. 'end;',
  2146. 'procedure {#B2}Run<T>(a: T; w: word); overload;',
  2147. 'begin',
  2148. 'end;',
  2149. 'procedure {#C2}Run<U>(a: U; b: U); overload;',
  2150. 'begin',
  2151. 'end;',
  2152. 'begin',
  2153. ' {@A}Run(1,true);', // non generic take precedence
  2154. ' {@B}Run(2,word(3));', // non generic take precedence
  2155. ' {@C}Run(''foo'',''bar'');',
  2156. '']);
  2157. ConvertProgram;
  2158. CheckSource('TestGenProc_infer_OverloadForward',
  2159. LinesToStr([ // statements
  2160. 'this.Run$G1 = function (a, b) {',
  2161. ' $mod.Run$G1(1, true);',
  2162. ' $mod.Run$1G1(2, 3);',
  2163. ' $mod.Run$2G1("foo", "bar");',
  2164. '};',
  2165. 'this.Run$1G1 = function (a, w) {',
  2166. '};',
  2167. 'this.Run$2G1 = function (a, b) {',
  2168. '};',
  2169. '']),
  2170. LinesToStr([ // $mod.$main
  2171. '$mod.Run$G1(1, true);',
  2172. '$mod.Run$1G1(2, 3);',
  2173. '$mod.Run$2G1("foo", "bar");',
  2174. '']));
  2175. end;
  2176. procedure TTestGenerics.TestGenProc_TypeInfo;
  2177. begin
  2178. WithTypeInfo:=true;
  2179. StartProgram(true,[supTypeInfo]);
  2180. Add([
  2181. '{$modeswitch implicitfunctionspecialization}',
  2182. 'generic procedure Run<S>(a: S);',
  2183. 'var',
  2184. ' p: TTypeInfo;',
  2185. 'begin',
  2186. ' p:=TypeInfo(S);',
  2187. ' p:=TypeInfo(a);',
  2188. 'end;',
  2189. 'begin',
  2190. ' Run(word(3));',
  2191. ' Run(''foo'');',
  2192. '']);
  2193. ConvertProgram;
  2194. CheckSource('TestGenProc_TypeInfo',
  2195. LinesToStr([ // statements
  2196. 'this.Run$G1 = function (a) {',
  2197. ' var p = null;',
  2198. ' p = rtl.word;',
  2199. ' p = rtl.word;',
  2200. '};',
  2201. 'this.Run$G2 = function (a) {',
  2202. ' var p = null;',
  2203. ' p = rtl.string;',
  2204. ' p = rtl.string;',
  2205. '};',
  2206. '']),
  2207. LinesToStr([ // $mod.$main
  2208. '$mod.Run$G1(3);',
  2209. '$mod.Run$G2("foo");',
  2210. '']));
  2211. end;
  2212. procedure TTestGenerics.TestGenProc_Infer_Widen;
  2213. begin
  2214. StartProgram(false);
  2215. Add([
  2216. '{$mode delphi}',
  2217. 'procedure Run<S>(a: S; b: S);',
  2218. 'begin',
  2219. 'end;',
  2220. 'begin',
  2221. ' Run(word(1),longint(2));',
  2222. ' Run(byte(2),smallint(2));',
  2223. ' Run(longword(3),longint(2));',
  2224. ' Run(nativeint(4),longint(2));',
  2225. ' Run(nativeint(5),nativeuint(2));',
  2226. ' Run(''a'',''foo'');',
  2227. ' Run(''bar'',''c'');',
  2228. '']);
  2229. ConvertProgram;
  2230. CheckSource('TestGenProc_Infer_Widen',
  2231. LinesToStr([ // statements
  2232. 'this.Run$G1 = function (a, b) {',
  2233. '};',
  2234. 'this.Run$G2 = function (a, b) {',
  2235. '};',
  2236. 'this.Run$G3 = function (a, b) {',
  2237. '};',
  2238. '']),
  2239. LinesToStr([ // $mod.$main
  2240. '$mod.Run$G1(1, 2);',
  2241. '$mod.Run$G1(2, 2);',
  2242. '$mod.Run$G2(3, 2);',
  2243. '$mod.Run$G2(4, 2);',
  2244. '$mod.Run$G2(5, 2);',
  2245. '$mod.Run$G3("a", "foo");',
  2246. '$mod.Run$G3("bar", "c");',
  2247. '']));
  2248. end;
  2249. procedure TTestGenerics.TestGenProc_Infer_PassAsArg;
  2250. begin
  2251. StartProgram(false);
  2252. Add([
  2253. '{$mode delphi}',
  2254. 'function Run<T>(a: T): T;',
  2255. 'var b: T;',
  2256. 'begin',
  2257. ' Run(Run<word>(3));',
  2258. ' Run(Run(word(4)));',
  2259. 'end;',
  2260. 'begin',
  2261. ' Run(Run<word>(5));',
  2262. ' Run(Run(word(6)));',
  2263. '']);
  2264. ConvertProgram;
  2265. CheckSource('TestGenProc_Infer_PassAsArg',
  2266. LinesToStr([ // statements
  2267. 'this.Run$G1 = function (a) {',
  2268. ' var Result = 0;',
  2269. ' var b = 0;',
  2270. ' $mod.Run$G1($mod.Run$G1(3));',
  2271. ' $mod.Run$G1($mod.Run$G1(4));',
  2272. ' return Result;',
  2273. '};',
  2274. '']),
  2275. LinesToStr([ // $mod.$main
  2276. '$mod.Run$G1($mod.Run$G1(5));',
  2277. '$mod.Run$G1($mod.Run$G1(6));',
  2278. '']));
  2279. end;
  2280. procedure TTestGenerics.TestGenProc_AnonymousProc;
  2281. begin
  2282. StartProgram(false);
  2283. Add([
  2284. '{$mode delphi}',
  2285. 'type',
  2286. ' TProc = reference to procedure;',
  2287. ' TFunc = reference to function(Value: JSValue): JSValue;',
  2288. 'function Run<T>(a: T; p: TProc): T;',
  2289. 'var b: T;',
  2290. ' f: TFunc;',
  2291. 'begin',
  2292. ' Result:=Run(a,procedure()begin end);',
  2293. ' f:=function(b: JSValue): JSValue begin end;',
  2294. ' f:=function(b: JSValue): JSValue',
  2295. ' function Sub(c: JSValue): JSValue;',
  2296. ' begin',
  2297. ' Result:=c;',
  2298. ' end;',
  2299. ' begin',
  2300. ' Result:=Sub(b);',
  2301. ' end;',
  2302. 'end;',
  2303. 'begin',
  2304. ' Run<word>(3,procedure() begin end);',
  2305. '']);
  2306. ConvertProgram;
  2307. CheckSource('TestGenProc_AnonymousProc',
  2308. LinesToStr([ // statements
  2309. 'this.Run$G1 = function (a, p) {',
  2310. ' var Result = 0;',
  2311. ' var b = 0;',
  2312. ' var f = null;',
  2313. ' Result = $mod.Run$G1(a, function () {',
  2314. ' });',
  2315. ' f = function (b) {',
  2316. ' var Result = undefined;',
  2317. ' return Result;',
  2318. ' };',
  2319. ' f = function (b) {',
  2320. ' var Result = undefined;',
  2321. ' function Sub(c) {',
  2322. ' var Result = undefined;',
  2323. ' Result = c;',
  2324. ' return Result;',
  2325. ' };',
  2326. ' Result = Sub(b);',
  2327. ' return Result;',
  2328. ' };',
  2329. ' return Result;',
  2330. '};',
  2331. '']),
  2332. LinesToStr([ // $mod.$main
  2333. '$mod.Run$G1(3, function () {',
  2334. '});',
  2335. '']));
  2336. end;
  2337. procedure TTestGenerics.TestGenMethod_ImplicitSpec_ObjFPC;
  2338. begin
  2339. StartProgram(false);
  2340. Add([
  2341. '{$mode objfpc}',
  2342. '{$ModeSwitch implicitfunctionspecialization}',
  2343. 'type',
  2344. ' TObject = class',
  2345. ' generic procedure {#A}Run<S>(a: S; b: boolean); overload;',
  2346. ' generic procedure {#B}Run<T>(a: T; w: word); overload;',
  2347. ' generic procedure {#C}Run<U>(a: U; b: U); overload;',
  2348. ' end; ',
  2349. 'generic procedure {#A2}TObject.Run<S>(a: S; b: boolean); overload;',
  2350. 'begin',
  2351. ' {@A}Run(1,true);', // non generic take precedence
  2352. ' {@B}Run(2,word(3));', // non generic take precedence
  2353. ' {@C}Run(''foo'',''bar'');',
  2354. 'end;',
  2355. 'generic procedure {#B2}TObject.Run<T>(a: T; w: word); overload;',
  2356. 'begin',
  2357. 'end;',
  2358. 'generic procedure {#C2}TObject.Run<U>(a: U; b: U); overload;',
  2359. 'begin',
  2360. 'end;',
  2361. 'var o: TObject;',
  2362. 'begin',
  2363. ' o.{@A}Run(1,true);', // non generic take precedence
  2364. ' o.{@B}Run(2,word(3));', // non generic take precedence
  2365. ' o.{@C}Run(''foo'',''bar'');',
  2366. '']);
  2367. ConvertProgram;
  2368. CheckSource('TestGenMethod_ImplicitSpec_ObjFPC',
  2369. LinesToStr([ // statements
  2370. 'rtl.createClass(this, "TObject", null, function () {',
  2371. ' this.$init = function () {',
  2372. ' };',
  2373. ' this.$final = function () {',
  2374. ' };',
  2375. ' this.Run$G1 = function (a, b) {',
  2376. ' this.Run$G1(1, true);',
  2377. ' this.Run$1G1(2, 3);',
  2378. ' this.Run$2G1("foo", "bar");',
  2379. ' };',
  2380. ' this.Run$1G1 = function (a, w) {',
  2381. ' };',
  2382. ' this.Run$2G1 = function (a, b) {',
  2383. ' };',
  2384. '});',
  2385. 'this.o = null;',
  2386. '']),
  2387. LinesToStr([ // $mod.$main
  2388. '$mod.o.Run$G1(1, true);',
  2389. '$mod.o.Run$1G1(2, 3);',
  2390. '$mod.o.Run$2G1("foo", "bar");',
  2391. '']));
  2392. end;
  2393. procedure TTestGenerics.TestGenMethod_Delphi;
  2394. begin
  2395. StartProgram(false);
  2396. Add([
  2397. '{$mode delphi}',
  2398. 'type',
  2399. ' TObject = class',
  2400. ' procedure Run<S>;',
  2401. ' end; ',
  2402. 'procedure TObject.Run<S>;',
  2403. 'begin',
  2404. 'end;',
  2405. 'var o: TObject;',
  2406. 'begin',
  2407. ' o.Run<word>;',
  2408. ' o.Run<word>();',
  2409. ' with o do begin',
  2410. ' Run<word>;',
  2411. ' Run<word>();',
  2412. ' end;',
  2413. '']);
  2414. ConvertProgram;
  2415. CheckSource('TestGenMethod_Delphi',
  2416. LinesToStr([ // statements
  2417. 'rtl.createClass(this, "TObject", null, function () {',
  2418. ' this.$init = function () {',
  2419. ' };',
  2420. ' this.$final = function () {',
  2421. ' };',
  2422. ' this.Run$G1 = function () {',
  2423. ' };',
  2424. '});',
  2425. 'this.o = null;',
  2426. '']),
  2427. LinesToStr([ // $mod.$main
  2428. '$mod.o.Run$G1();',
  2429. '$mod.o.Run$G1();',
  2430. 'var $with = $mod.o;',
  2431. '$with.Run$G1();',
  2432. '$with.Run$G1();',
  2433. '']));
  2434. end;
  2435. procedure TTestGenerics.TestGen_Array_OtherUnit;
  2436. begin
  2437. WithTypeInfo:=true;
  2438. StartProgram(true,[supTObject]);
  2439. AddModuleWithIntfImplSrc('UnitA.pas',
  2440. LinesToStr([
  2441. 'type',
  2442. ' generic TDyn<T> = array of T;',
  2443. ' generic TStatic<T> = array[1..2] of T;',
  2444. '']),
  2445. '');
  2446. AddModuleWithIntfImplSrc('UnitB.pas',
  2447. LinesToStr([
  2448. 'uses UnitA;',
  2449. 'type',
  2450. ' TAnt = class end;',
  2451. ' TAntArray = specialize TDyn<TAnt>;',
  2452. 'procedure Run;',
  2453. '']),
  2454. LinesToStr([
  2455. 'procedure Run;',
  2456. 'begin',
  2457. ' if typeinfo(TAntArray)=nil then ;',
  2458. 'end;',
  2459. '']));
  2460. Add([
  2461. 'uses UnitB;',
  2462. 'begin',
  2463. ' Run;',
  2464. '']);
  2465. ConvertProgram;
  2466. CheckUnit('UnitA.pas',
  2467. LinesToStr([ // statements
  2468. 'rtl.module("UnitA", ["system"], function () {',
  2469. ' var $mod = this;',
  2470. ' this.$rtti.$DynArray("TDyn<UnitB.TAnt>", {});',
  2471. '});']));
  2472. CheckUnit('UnitB.pas',
  2473. LinesToStr([ // statements
  2474. 'rtl.module("UnitB", ["system", "UnitA"], function () {',
  2475. ' var $mod = this;',
  2476. ' rtl.createClass(this, "TAnt", pas.system.TObject, function () {',
  2477. ' });',
  2478. ' this.Run = function () {',
  2479. ' if (pas.UnitA.$rtti["TDyn<UnitB.TAnt>"] === null) ;',
  2480. ' };',
  2481. '});']));
  2482. CheckSource('TestGen_Array_OtherUnit',
  2483. LinesToStr([ // statements
  2484. '$mod.$implcode = function () {',
  2485. ' pas.UnitA.$rtti["TDyn<UnitB.TAnt>"].eltype = pas.UnitB.$rtti["TAnt"];',
  2486. '};',
  2487. '']),
  2488. LinesToStr([ // $mod.$main
  2489. ' pas.UnitB.Run();',
  2490. '']));
  2491. end;
  2492. procedure TTestGenerics.TestGen_ArrayOfUnitImplRec;
  2493. begin
  2494. WithTypeInfo:=true;
  2495. StartProgram(true,[supTObject]);
  2496. AddModuleWithIntfImplSrc('UnitA.pas',
  2497. LinesToStr([
  2498. 'type',
  2499. ' generic TDyn<T> = array of T;',
  2500. ' generic TStatic<T> = array[1..2] of T;',
  2501. '']),
  2502. LinesToStr([
  2503. 'type',
  2504. ' TBird = record',
  2505. ' b: word;',
  2506. ' end;',
  2507. ' TAnt = class end;',
  2508. ' TAntArray = specialize TDyn<TAnt>;',
  2509. 'var',
  2510. ' d: specialize TDyn<TBird>;',
  2511. ' s: specialize TStatic<TBird>;',
  2512. ' p: pointer;',
  2513. 'begin',
  2514. ' d[0].b:=s[1].b;',
  2515. ' s:=s;',
  2516. ' p:=typeinfo(TAntArray);',
  2517. '']));
  2518. Add([
  2519. 'uses UnitA;',
  2520. 'begin',
  2521. '']);
  2522. ConvertProgram;
  2523. CheckUnit('UnitA.pas',
  2524. LinesToStr([ // statements
  2525. 'rtl.module("UnitA", ["system"], function () {',
  2526. ' var $mod = this;',
  2527. ' var $impl = $mod.$impl;',
  2528. ' this.$rtti.$DynArray("TDyn<UnitA.TAnt>", {});',
  2529. ' this.$rtti.$DynArray("TDyn<UnitA.TBird>", {});',
  2530. ' this.TStatic$G1$clone = function (a) {',
  2531. ' var b = [];',
  2532. ' b.length = 2;',
  2533. ' for (var c = 0; c < 2; c++) b[c] = $impl.TBird.$clone(a[c]);',
  2534. ' return b;',
  2535. ' };',
  2536. ' this.$rtti.$StaticArray("TStatic<UnitA.TBird>", {',
  2537. ' dims: [2]',
  2538. ' });',
  2539. ' $mod.$implcode = function () {',
  2540. ' rtl.recNewT($impl, "TBird", function () {',
  2541. ' this.b = 0;',
  2542. ' this.$eq = function (b) {',
  2543. ' return this.b === b.b;',
  2544. ' };',
  2545. ' this.$assign = function (s) {',
  2546. ' this.b = s.b;',
  2547. ' return this;',
  2548. ' };',
  2549. ' var $r = $mod.$rtti.$Record("TBird", {});',
  2550. ' $r.addField("b", rtl.word);',
  2551. ' });',
  2552. ' rtl.createClass($impl, "TAnt", pas.system.TObject, function () {',
  2553. ' });',
  2554. ' $impl.d = [];',
  2555. ' $impl.s = rtl.arraySetLength(null, $impl.TBird, 2);',
  2556. ' $impl.p = null;',
  2557. ' };',
  2558. ' $mod.$init = function () {',
  2559. ' $impl.d[0].b = $impl.s[0].b;',
  2560. ' $impl.s = $mod.TStatic$G1$clone($impl.s);',
  2561. ' $impl.p = $mod.$rtti["TDyn<UnitA.TAnt>"];',
  2562. ' };',
  2563. '}, []);']));
  2564. CheckSource('TestGen_ArrayOfUnitImplRec',
  2565. LinesToStr([ // statements
  2566. '$mod.$implcode = function () {',
  2567. ' pas.UnitA.$rtti["TDyn<UnitA.TAnt>"].eltype = pas.UnitA.$rtti["TAnt"];',
  2568. ' pas.UnitA.$rtti["TDyn<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
  2569. ' pas.UnitA.$rtti["TStatic<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
  2570. '};',
  2571. '']),
  2572. LinesToStr([ // $mod.$main
  2573. '']));
  2574. end;
  2575. procedure TTestGenerics.TestGen_Array_TypecastJSValueResultToArg;
  2576. begin
  2577. StartProgram(false);
  2578. Add([
  2579. '{$mode delphi}',
  2580. 'type',
  2581. ' TArray<T> = array of T;',
  2582. ' TFunc = function: JSValue of object;',
  2583. ' TObject = class',
  2584. ' f: TFunc;',
  2585. ' function Run: jsvalue; virtual; abstract;',
  2586. ' end;',
  2587. 'procedure Sit(Arr: TArray<TObject>);',
  2588. 'begin',
  2589. 'end;',
  2590. 'procedure Fly(o: TObject);',
  2591. 'begin',
  2592. ' Sit(TArray<TObject>(o.f()));',
  2593. ' Sit(TArray<TObject>(o.Run));',
  2594. ' Sit(TArray<TObject>(o.Run()));',
  2595. 'end;',
  2596. 'begin']);
  2597. ConvertProgram;
  2598. CheckSource('TestGen_Array_TypecastJSValueResultToArg',
  2599. LinesToStr([ // statements
  2600. 'rtl.createClass(this, "TObject", null, function () {',
  2601. ' this.$init = function () {',
  2602. ' this.f = null;',
  2603. ' };',
  2604. ' this.$final = function () {',
  2605. ' this.f = undefined;',
  2606. ' };',
  2607. '});',
  2608. 'this.Sit = function (Arr) {',
  2609. '};',
  2610. 'this.Fly = function (o) {',
  2611. ' $mod.Sit(o.f());',
  2612. ' $mod.Sit(o.Run());',
  2613. ' $mod.Sit(o.Run());',
  2614. '};',
  2615. '']),
  2616. LinesToStr([ // $mod.$main
  2617. '']));
  2618. end;
  2619. procedure TTestGenerics.TestGen_ProcType_ProcLocal;
  2620. begin
  2621. StartProgram(false);
  2622. Add([
  2623. 'procedure Fly(w: word);',
  2624. 'begin',
  2625. 'end;',
  2626. 'procedure Run(w: word);',
  2627. 'type generic TProc<T> = procedure(a: T);',
  2628. 'var p: specialize TProc<word>;',
  2629. 'begin',
  2630. ' p:=@Fly;',
  2631. ' p(w);',
  2632. 'end;',
  2633. 'begin',
  2634. 'end.']);
  2635. ConvertProgram;
  2636. CheckSource('TestGen_ProcType_ProcLocal',
  2637. LinesToStr([ // statements
  2638. 'this.Fly = function (w) {',
  2639. '};',
  2640. 'this.Run = function (w) {',
  2641. ' var p = null;',
  2642. ' p = $mod.Fly;',
  2643. ' p(w);',
  2644. '};',
  2645. '']),
  2646. LinesToStr([ // $mod.$main
  2647. '']));
  2648. end;
  2649. procedure TTestGenerics.TestGen_ProcType_Local_RTTI_Fail;
  2650. begin
  2651. WithTypeInfo:=true;
  2652. StartProgram(false);
  2653. Add([
  2654. 'procedure Fly(w: word);',
  2655. 'begin',
  2656. 'end;',
  2657. 'procedure Run(w: word);',
  2658. 'type generic TProc<T> = procedure(a: T);',
  2659. 'var',
  2660. ' p: specialize TProc<word>;',
  2661. ' t: Pointer;',
  2662. 'begin',
  2663. ' p:=@Fly;',
  2664. ' p(w);',
  2665. ' t:=typeinfo(p);',
  2666. 'end;',
  2667. 'begin',
  2668. 'end.']);
  2669. SetExpectedPasResolverError(sSymbolCannotBePublished,nSymbolCannotBePublished);
  2670. ConvertProgram;
  2671. end;
  2672. procedure TTestGenerics.TestGen_ProcType_ParamUnitImpl;
  2673. begin
  2674. WithTypeInfo:=true;
  2675. StartProgram(true,[supTObject]);
  2676. AddModuleWithIntfImplSrc('UnitA.pas',
  2677. LinesToStr([
  2678. 'type',
  2679. ' generic TAnt<T> = function(const a: T): T;',
  2680. '']),
  2681. LinesToStr([
  2682. 'type',
  2683. ' TBird = record',
  2684. ' b: word;',
  2685. ' end;',
  2686. 'var',
  2687. ' f: specialize TAnt<TBird>;',
  2688. ' b: TBird;',
  2689. ' p: pointer;',
  2690. 'begin',
  2691. ' b:=f(b);',
  2692. ' p:=typeinfo(f);',
  2693. '']));
  2694. Add([
  2695. 'uses UnitA;',
  2696. 'begin',
  2697. 'end.']);
  2698. ConvertProgram;
  2699. CheckUnit('UnitA.pas',
  2700. LinesToStr([ // statements
  2701. 'rtl.module("UnitA", ["system"], function () {',
  2702. ' var $mod = this;',
  2703. ' var $impl = $mod.$impl;',
  2704. ' this.$rtti.$ProcVar("TAnt<UnitA.TBird>", {',
  2705. ' init: function () {',
  2706. ' this.procsig = rtl.newTIProcSig([["a", $mod.$rtti["TBird"], 2]], $mod.$rtti["TBird"]);',
  2707. ' }',
  2708. ' });',
  2709. ' $mod.$implcode = function () {',
  2710. ' rtl.recNewT($impl, "TBird", function () {',
  2711. ' this.b = 0;',
  2712. ' this.$eq = function (b) {',
  2713. ' return this.b === b.b;',
  2714. ' };',
  2715. ' this.$assign = function (s) {',
  2716. ' this.b = s.b;',
  2717. ' return this;',
  2718. ' };',
  2719. ' var $r = $mod.$rtti.$Record("TBird", {});',
  2720. ' $r.addField("b", rtl.word);',
  2721. ' });',
  2722. ' $impl.f = null;',
  2723. ' $impl.b = $impl.TBird.$new();',
  2724. ' $impl.p = null;',
  2725. ' };',
  2726. ' $mod.$init = function () {',
  2727. ' $impl.b.$assign($impl.f($impl.b));',
  2728. ' $impl.p = $mod.$rtti["TAnt<UnitA.TBird>"];',
  2729. ' };',
  2730. '}, []);']));
  2731. CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
  2732. LinesToStr([ // statements
  2733. '$mod.$implcode = function () {',
  2734. ' pas.UnitA.$rtti["TAnt<UnitA.TBird>"].init();',
  2735. '};',
  2736. '']),
  2737. LinesToStr([ // $mod.$main
  2738. '']));
  2739. end;
  2740. Initialization
  2741. RegisterTests([TTestGenerics]);
  2742. end.