tcgenerics.pas 68 KB

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