tcgenerics.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. unit TCGenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testregistry,
  6. TCModules, FPPas2Js;
  7. type
  8. { TTestGenerics }
  9. TTestGenerics = class(TCustomTestModule)
  10. Published
  11. // generic record
  12. Procedure TestGen_RecordEmpty;
  13. Procedure TestGen_Record_ClassProc_ObjFPC;
  14. //Procedure TestGen_Record_ClassProc_Delphi;
  15. //Procedure TestGen_Record_ReferGenClass_DelphiFail;
  16. // generic class
  17. Procedure TestGen_ClassEmpty;
  18. Procedure TestGen_Class_EmptyMethod;
  19. Procedure TestGen_Class_TList;
  20. Procedure TestGen_Class_TCustomList;
  21. Procedure TestGen_ClassAncestor;
  22. Procedure TestGen_Class_TypeInfo;
  23. Procedure TestGen_Class_TypeOverload; // ToDo TBird, TBird<T>, TBird<S,T>
  24. Procedure TestGen_Class_ClassProperty;
  25. Procedure TestGen_Class_ClassProc_ObjFPC;
  26. //Procedure TestGen_Class_ClassProc_Delphi;
  27. //Procedure TestGen_Class_ReferGenClass_DelphiFail;
  28. Procedure TestGen_Class_ClassConstructor;
  29. // ToDo: rename local const T
  30. // generic external class
  31. procedure TestGen_ExtClass_Array;
  32. // statements
  33. Procedure TestGen_InlineSpec_Constructor;
  34. Procedure TestGen_CallUnitImplProc;
  35. Procedure TestGen_IntAssignTemplVar;
  36. Procedure TestGen_TypeCastDotField;
  37. // generic helper
  38. procedure TestGen_HelperForArray;
  39. // generic functions
  40. procedure TestGenProc_Function_ObjFPC;
  41. procedure TestGenProc_Function_Delphi;
  42. procedure TestGenProc_Overload;
  43. procedure TestGenProc_Forward;
  44. procedure TestGenProc_Infer_OverloadForward;
  45. procedure TestGenProc_TypeInfo;
  46. procedure TestGenProc_Infer_Widen;
  47. procedure TestGenProc_Infer_PassAsArg;
  48. // ToDo: FuncName:=
  49. // generic methods
  50. procedure TestGenMethod_ObjFPC;
  51. end;
  52. implementation
  53. { TTestGenerics }
  54. procedure TTestGenerics.TestGen_RecordEmpty;
  55. begin
  56. StartProgram(false);
  57. Add([
  58. 'type',
  59. ' generic TRecA<T> = record',
  60. ' end;',
  61. 'var a,b: specialize TRecA<word>;',
  62. 'begin',
  63. ' if a=b then ;']);
  64. ConvertProgram;
  65. CheckSource('TestGen_RecordEmpty',
  66. LinesToStr([ // statements
  67. 'rtl.recNewT($mod, "TRecA$G1", function () {',
  68. ' this.$eq = function (b) {',
  69. ' return true;',
  70. ' };',
  71. ' this.$assign = function (s) {',
  72. ' return this;',
  73. ' };',
  74. '});',
  75. 'this.a = $mod.TRecA$G1.$new();',
  76. 'this.b = $mod.TRecA$G1.$new();',
  77. '']),
  78. LinesToStr([ // $mod.$main
  79. 'if ($mod.a.$eq($mod.b)) ;'
  80. ]));
  81. end;
  82. procedure TTestGenerics.TestGen_Record_ClassProc_ObjFPC;
  83. begin
  84. StartProgram(false);
  85. Add([
  86. '{$modeswitch AdvancedRecords}',
  87. 'type',
  88. ' generic TPoint<T> = record',
  89. ' class var x: T;',
  90. ' class procedure Fly; static;',
  91. ' end;',
  92. 'class procedure Tpoint.Fly;',
  93. 'begin',
  94. ' x:=x+3;',
  95. ' tpoint.x:=tpoint.x+4;',
  96. ' Fly;',
  97. ' tpoint.Fly;',
  98. 'end;',
  99. 'var p: specialize TPoint<word>;',
  100. 'begin',
  101. ' p.x:=p.x+10;',
  102. ' p.Fly;',
  103. ' p.Fly();',
  104. '']);
  105. ConvertProgram;
  106. CheckSource('TestGen_Record_ClassProc',
  107. LinesToStr([ // statements
  108. 'rtl.recNewT($mod, "TPoint$G1", function () {',
  109. ' this.x = 0;',
  110. ' this.$eq = function (b) {',
  111. ' return true;',
  112. ' };',
  113. ' this.$assign = function (s) {',
  114. ' return this;',
  115. ' };',
  116. ' this.Fly = function () {',
  117. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;',
  118. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;',
  119. ' $mod.TPoint$G1.Fly();',
  120. ' $mod.TPoint$G1.Fly();',
  121. ' };',
  122. '}, true);',
  123. 'this.p = $mod.TPoint$G1.$new();',
  124. '']),
  125. LinesToStr([ // $mod.$main
  126. '$mod.TPoint$G1.x = $mod.p.x + 10;',
  127. '$mod.p.Fly();',
  128. '$mod.p.Fly();',
  129. '']));
  130. end;
  131. procedure TTestGenerics.TestGen_ClassEmpty;
  132. begin
  133. StartProgram(false);
  134. Add([
  135. 'type',
  136. ' TObject = class end;',
  137. ' generic TBird<T> = class',
  138. ' end;',
  139. 'var a,b: specialize TBird<word>;',
  140. 'begin',
  141. ' if a=b then ;']);
  142. ConvertProgram;
  143. CheckSource('TestGen_ClassEmpty',
  144. LinesToStr([ // statements
  145. 'rtl.createClass($mod, "TObject", null, function () {',
  146. ' this.$init = function () {',
  147. ' };',
  148. ' this.$final = function () {',
  149. ' };',
  150. '});',
  151. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  152. '});',
  153. 'this.a = null;',
  154. 'this.b = null;',
  155. '']),
  156. LinesToStr([ // $mod.$main
  157. 'if ($mod.a === $mod.b) ;'
  158. ]));
  159. end;
  160. procedure TTestGenerics.TestGen_Class_EmptyMethod;
  161. begin
  162. StartProgram(false);
  163. Add([
  164. 'type',
  165. ' TObject = class end;',
  166. ' generic TBird<T> = class',
  167. ' function Fly(w: T): T;',
  168. ' end;',
  169. 'function TBird.Fly(w: T): T;',
  170. 'begin',
  171. 'end;',
  172. 'var a: specialize TBird<word>;',
  173. 'begin',
  174. ' if a.Fly(3)=4 then ;']);
  175. ConvertProgram;
  176. CheckSource('TestGen_Class_EmptyMethod',
  177. LinesToStr([ // statements
  178. 'rtl.createClass($mod, "TObject", null, function () {',
  179. ' this.$init = function () {',
  180. ' };',
  181. ' this.$final = function () {',
  182. ' };',
  183. '});',
  184. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  185. ' this.Fly = function (w) {',
  186. ' var Result = 0;',
  187. ' return Result;',
  188. ' };',
  189. '});',
  190. 'this.a = null;',
  191. '']),
  192. LinesToStr([ // $mod.$main
  193. ' if ($mod.a.Fly(3) === 4) ;'
  194. ]));
  195. end;
  196. procedure TTestGenerics.TestGen_Class_TList;
  197. begin
  198. StartProgram(false);
  199. Add([
  200. '{$mode objfpc}',
  201. 'type',
  202. ' TObject = class end;',
  203. ' generic TList<T> = class',
  204. ' strict private',
  205. ' FItems: array of T;',
  206. ' function GetItems(Index: longint): T;',
  207. ' procedure SetItems(Index: longint; Value: T);',
  208. ' public',
  209. ' procedure Alter(w: T);',
  210. ' property Items[Index: longint]: T read GetItems write SetItems; default;',
  211. ' end;',
  212. ' TWordList = specialize TList<word>;',
  213. 'function TList.GetItems(Index: longint): T;',
  214. 'begin',
  215. ' Result:=FItems[Index];',
  216. 'end;',
  217. 'procedure TList.SetItems(Index: longint; Value: T);',
  218. 'begin',
  219. ' FItems[Index]:=Value;',
  220. 'end;',
  221. 'procedure TList.Alter(w: T);',
  222. 'begin',
  223. ' SetLength(FItems,length(FItems)+1);',
  224. ' Insert(w,FItems,2);',
  225. ' Delete(FItems,2,3);',
  226. 'end;',
  227. 'var l: TWordList;',
  228. ' w: word;',
  229. 'begin',
  230. ' l[1]:=w;',
  231. ' w:=l[2];',
  232. '']);
  233. ConvertProgram;
  234. CheckSource('TestGen_Class_TList',
  235. LinesToStr([ // statements
  236. 'rtl.createClass($mod, "TObject", null, function () {',
  237. ' this.$init = function () {',
  238. ' };',
  239. ' this.$final = function () {',
  240. ' };',
  241. '});',
  242. 'rtl.createClass($mod, "TList$G1", $mod.TObject, function () {',
  243. ' this.$init = function () {',
  244. ' $mod.TObject.$init.call(this);',
  245. ' this.FItems = [];',
  246. ' };',
  247. ' this.$final = function () {',
  248. ' this.FItems = undefined;',
  249. ' $mod.TObject.$final.call(this);',
  250. ' };',
  251. ' this.GetItems = function (Index) {',
  252. ' var Result = 0;',
  253. ' Result = this.FItems[Index];',
  254. ' return Result;',
  255. ' };',
  256. ' this.SetItems = function (Index, Value) {',
  257. ' this.FItems[Index] = Value;',
  258. ' };',
  259. ' this.Alter = function (w) {',
  260. ' this.FItems = rtl.arraySetLength(this.FItems, 0, rtl.length(this.FItems) + 1);',
  261. ' this.FItems.splice(2, 0, w);',
  262. ' this.FItems.splice(2, 3);',
  263. ' };',
  264. '});',
  265. 'this.l = null;',
  266. 'this.w = 0;',
  267. '']),
  268. LinesToStr([ // $mod.$main
  269. '$mod.l.SetItems(1, $mod.w);',
  270. '$mod.w = $mod.l.GetItems(2);',
  271. '']));
  272. end;
  273. procedure TTestGenerics.TestGen_Class_TCustomList;
  274. begin
  275. StartProgram(false);
  276. Add([
  277. '{$mode delphi}',
  278. 'type',
  279. ' TObject = class end;',
  280. ' TCustomList<T> = class',
  281. ' public',
  282. ' function PrepareAddingItem: word; virtual;',
  283. ' end;',
  284. ' TList<T> = class(TCustomList<T>)',
  285. ' public',
  286. ' function Add: word;',
  287. ' end;',
  288. ' TWordList = TList<word>;',
  289. 'function TCustomList<T>.PrepareAddingItem: word;',
  290. 'begin',
  291. 'end;',
  292. 'function TList<T>.Add: word;',
  293. 'begin',
  294. ' Result:=PrepareAddingItem;',
  295. //' Result:=Self.PrepareAddingItem;',
  296. //' with Self do Result:=PrepareAddingItem;',
  297. 'end;',
  298. 'var l: TWordList;',
  299. 'begin',
  300. '']);
  301. ConvertProgram;
  302. CheckSource('TestGen_Class_TCustomList',
  303. LinesToStr([ // statements
  304. 'rtl.createClass($mod, "TObject", null, function () {',
  305. ' this.$init = function () {',
  306. ' };',
  307. ' this.$final = function () {',
  308. ' };',
  309. '});',
  310. 'rtl.createClass($mod, "TCustomList$G2", $mod.TObject, function () {',
  311. ' this.PrepareAddingItem = function () {',
  312. ' var Result = 0;',
  313. ' return Result;',
  314. ' };',
  315. '});',
  316. 'rtl.createClass($mod, "TList$G1", $mod.TCustomList$G2, function () {',
  317. ' this.Add = function () {',
  318. ' var Result = 0;',
  319. ' Result = this.PrepareAddingItem();',
  320. ' return Result;',
  321. ' };',
  322. '});',
  323. 'this.l = null;',
  324. '']),
  325. LinesToStr([ // $mod.$main
  326. '']));
  327. end;
  328. procedure TTestGenerics.TestGen_ClassAncestor;
  329. begin
  330. StartProgram(false);
  331. Add([
  332. 'type',
  333. ' TObject = class end;',
  334. ' generic TBird<T> = class',
  335. ' end;',
  336. ' generic TEagle<T> = class(specialize TBird<T>)',
  337. ' end;',
  338. 'var a: specialize TEagle<word>;',
  339. 'begin',
  340. '']);
  341. ConvertProgram;
  342. CheckSource('TestGen_ClassAncestor',
  343. LinesToStr([ // statements
  344. 'rtl.createClass($mod, "TObject", null, function () {',
  345. ' this.$init = function () {',
  346. ' };',
  347. ' this.$final = function () {',
  348. ' };',
  349. '});',
  350. 'rtl.createClass($mod, "TBird$G2", $mod.TObject, function () {',
  351. '});',
  352. 'rtl.createClass($mod, "TEagle$G1", $mod.TBird$G2, function () {',
  353. '});',
  354. 'this.a = null;',
  355. '']),
  356. LinesToStr([ // $mod.$main
  357. '']));
  358. end;
  359. procedure TTestGenerics.TestGen_Class_TypeInfo;
  360. begin
  361. Converter.Options:=Converter.Options-[coNoTypeInfo];
  362. StartProgram(false);
  363. Add([
  364. 'type',
  365. ' TObject = class end;',
  366. ' generic TBird<T> = class',
  367. ' published',
  368. ' m: T;',
  369. ' end;',
  370. ' TEagle = specialize TBird<word>;',
  371. 'var',
  372. ' b: specialize TBird<word>;',
  373. ' p: pointer;',
  374. 'begin',
  375. ' p:=typeinfo(TEagle);',
  376. ' p:=typeinfo(b);',
  377. '']);
  378. ConvertProgram;
  379. CheckSource('TestGen_TypeInfo',
  380. LinesToStr([ // statements
  381. 'rtl.createClass($mod, "TObject", null, function () {',
  382. ' this.$init = function () {',
  383. ' };',
  384. ' this.$final = function () {',
  385. ' };',
  386. '});',
  387. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  388. ' this.$init = function () {',
  389. ' $mod.TObject.$init.call(this);',
  390. ' this.m = 0;',
  391. ' };',
  392. ' var $r = this.$rtti;',
  393. ' $r.addField("m", rtl.word);',
  394. '});',
  395. 'this.b = null;',
  396. 'this.p = null;',
  397. '']),
  398. LinesToStr([ // $mod.$main
  399. '$mod.p = $mod.$rtti["TBird$G1"];',
  400. '$mod.p = $mod.b.$rtti;',
  401. '']));
  402. end;
  403. procedure TTestGenerics.TestGen_Class_TypeOverload;
  404. begin
  405. exit;// ToDo
  406. StartProgram(false);
  407. Add([
  408. '{$mode delphi}',
  409. 'type',
  410. ' TObject = class end;',
  411. ' TBird = word;',
  412. ' TBird<T> = class',
  413. ' m: T;',
  414. ' end;',
  415. ' TEagle = TBird<word>;',
  416. 'var',
  417. ' b: TBird<word>;',
  418. ' e: TEagle;',
  419. 'begin',
  420. '']);
  421. ConvertProgram;
  422. CheckSource('TestGen_Class_TypeOverload',
  423. LinesToStr([ // statements
  424. 'rtl.createClass($mod, "TObject", null, function () {',
  425. ' this.$init = function () {',
  426. ' };',
  427. ' this.$final = function () {',
  428. ' };',
  429. '});',
  430. '']),
  431. LinesToStr([ // $mod.$main
  432. '']));
  433. end;
  434. procedure TTestGenerics.TestGen_Class_ClassProperty;
  435. begin
  436. StartProgram(false);
  437. Add([
  438. '{$mode delphi}',
  439. 'type',
  440. ' TObject = class end;',
  441. ' TBird<T> = class',
  442. ' private',
  443. ' class var fSize: T;',
  444. ' public',
  445. ' class property Size: T read fSize write fSize;',
  446. ' end;',
  447. ' TEagle = TBird<word>;',
  448. 'begin',
  449. ' TBird<word>.Size:=3+TBird<word>.Size;',
  450. '']);
  451. ConvertProgram;
  452. CheckSource('TestGen_Class_ClassProperty',
  453. LinesToStr([ // statements
  454. 'rtl.createClass($mod, "TObject", null, function () {',
  455. ' this.$init = function () {',
  456. ' };',
  457. ' this.$final = function () {',
  458. ' };',
  459. '});',
  460. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  461. ' this.fSize = 0;',
  462. '});',
  463. '']),
  464. LinesToStr([ // $mod.$main
  465. '$mod.TBird$G1.fSize = 3 + $mod.TBird$G1.fSize;',
  466. '']));
  467. end;
  468. procedure TTestGenerics.TestGen_Class_ClassProc_ObjFPC;
  469. begin
  470. StartProgram(false);
  471. Add([
  472. 'type',
  473. ' TObject = class end;',
  474. ' generic TPoint<T> = class',
  475. ' class var x: T;',
  476. ' class procedure Fly; static;',
  477. ' class procedure Run;',
  478. ' end;',
  479. 'class procedure Tpoint.Fly;',
  480. 'begin',
  481. ' x:=x+3;',
  482. ' tpoint.x:=tpoint.x+4;',
  483. ' Fly;',
  484. ' tpoint.Fly;',
  485. ' Run;',
  486. ' tpoint.Run;',
  487. 'end;',
  488. 'class procedure TPoint.Run;',
  489. 'begin',
  490. ' x:=x+5;',
  491. ' tpoint.x:=tpoint.x+6;',
  492. ' Fly;',
  493. ' tpoint.Fly;',
  494. ' Run;',
  495. ' tpoint.Run;',
  496. 'end;',
  497. 'var p: specialize TPoint<word>;',
  498. 'begin',
  499. '']);
  500. ConvertProgram;
  501. CheckSource('TestGen_Class_ClassProc',
  502. LinesToStr([ // statements
  503. 'rtl.createClass($mod, "TObject", null, function () {',
  504. ' this.$init = function () {',
  505. ' };',
  506. ' this.$final = function () {',
  507. ' };',
  508. '});',
  509. 'rtl.createClass($mod, "TPoint$G1", $mod.TObject, function () {',
  510. ' this.x = 0;',
  511. ' this.Fly = function () {',
  512. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 3;',
  513. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 4;',
  514. ' $mod.TPoint$G1.Fly();',
  515. ' $mod.TPoint$G1.Fly();',
  516. ' $mod.TPoint$G1.Run();',
  517. ' $mod.TPoint$G1.Run();',
  518. ' };',
  519. ' this.Run = function () {',
  520. ' $mod.TPoint$G1.x = this.x + 5;',
  521. ' $mod.TPoint$G1.x = $mod.TPoint$G1.x + 6;',
  522. ' this.Fly();',
  523. ' $mod.TPoint$G1.Fly();',
  524. ' this.Run();',
  525. ' $mod.TPoint$G1.Run();',
  526. ' };',
  527. '});',
  528. 'this.p = null;',
  529. '']),
  530. LinesToStr([ // $mod.$main
  531. '']));
  532. end;
  533. procedure TTestGenerics.TestGen_Class_ClassConstructor;
  534. begin
  535. StartProgram(false);
  536. Add([
  537. 'type',
  538. ' TObject = class end;',
  539. ' generic TPoint<T> = class',
  540. ' class var x: T;',
  541. ' class procedure Fly; static;',
  542. ' class constructor Init;',
  543. ' end;',
  544. 'var count: word;',
  545. 'class procedure Tpoint.Fly;',
  546. 'begin',
  547. 'end;',
  548. 'class constructor tpoint.init;',
  549. 'begin',
  550. ' count:=count+1;',
  551. ' x:=3;',
  552. ' tpoint.x:=4;',
  553. ' fly;',
  554. ' tpoint.fly;',
  555. 'end;',
  556. 'var',
  557. ' r: specialize TPoint<word>;',
  558. ' s: specialize TPoint<smallint>;',
  559. 'begin',
  560. ' r.x:=10;',
  561. '']);
  562. ConvertProgram;
  563. CheckSource('TestGen_Class_ClassConstructor',
  564. LinesToStr([ // statements
  565. 'rtl.createClass($mod, "TObject", null, function () {',
  566. ' this.$init = function () {',
  567. ' };',
  568. ' this.$final = function () {',
  569. ' };',
  570. '});',
  571. 'rtl.createClass($mod, "TPoint$G1", $mod.TObject, function () {',
  572. ' this.x = 0;',
  573. ' this.Fly = function () {',
  574. ' };',
  575. '});',
  576. 'rtl.createClass($mod, "TPoint$G2", $mod.TObject, function () {',
  577. ' this.x = 0;',
  578. ' this.Fly = function () {',
  579. ' };',
  580. '});',
  581. 'this.count = 0;',
  582. 'this.r = null;',
  583. 'this.s = null;',
  584. '']),
  585. LinesToStr([ // $mod.$main
  586. '(function () {',
  587. ' $mod.count = $mod.count + 1;',
  588. ' $mod.TPoint$G1.x = 3;',
  589. ' $mod.TPoint$G1.x = 4;',
  590. ' $mod.TPoint$G1.Fly();',
  591. ' $mod.TPoint$G1.Fly();',
  592. '})();',
  593. '(function () {',
  594. ' $mod.count = $mod.count + 1;',
  595. ' $mod.TPoint$G2.x = 3;',
  596. ' $mod.TPoint$G2.x = 4;',
  597. ' $mod.TPoint$G2.Fly();',
  598. ' $mod.TPoint$G2.Fly();',
  599. '})();',
  600. '$mod.TPoint$G1.x = 10;',
  601. '']));
  602. end;
  603. procedure TTestGenerics.TestGen_ExtClass_Array;
  604. begin
  605. StartProgram(false);
  606. Add([
  607. '{$mode delphi}',
  608. '{$ModeSwitch externalclass}',
  609. 'type',
  610. ' NativeInt = longint;',
  611. ' TJSGenArray<T> = Class external name ''Array''',
  612. ' private',
  613. ' function GetElements(Index: NativeInt): T; external name ''[]'';',
  614. ' procedure SetElements(Index: NativeInt; const AValue: T); external name ''[]'';',
  615. ' public',
  616. ' type TSelfType = TJSGenArray<T>;',
  617. ' public',
  618. ' FLength : NativeInt; external name ''length'';',
  619. ' constructor new; overload;',
  620. ' constructor new(aLength : NativeInt); overload;',
  621. ' class function _of() : TSelfType; varargs; external name ''of'';',
  622. ' function fill(aValue : T) : TSelfType; overload;',
  623. ' function fill(aValue : T; aStartIndex : NativeInt) : TSelfType; overload;',
  624. ' function fill(aValue : T; aStartIndex,aEndIndex : NativeInt) : TSelfType; overload;',
  625. ' property Length : NativeInt Read FLength Write FLength;',
  626. ' property Elements[Index: NativeInt]: T read GetElements write SetElements; default;',
  627. ' end;',
  628. ' TJSWordArray = TJSGenArray<word>;',
  629. 'var',
  630. ' wa: TJSWordArray;',
  631. ' w: word;',
  632. 'begin',
  633. ' wa:=TJSWordArray.new;',
  634. ' wa:=TJSWordArray.new(3);',
  635. ' wa:=TJSWordArray._of(4,5);',
  636. ' wa:=wa.fill(7);',
  637. ' wa:=wa.fill(7,8,9);',
  638. ' w:=wa.length;',
  639. ' wa.length:=10;',
  640. ' wa[11]:=w;',
  641. ' w:=wa[12];',
  642. '']);
  643. ConvertProgram;
  644. CheckSource('TestGen_ExtClass_Array',
  645. LinesToStr([ // statements
  646. 'this.wa = null;',
  647. 'this.w = 0;',
  648. '']),
  649. LinesToStr([ // $mod.$main
  650. '$mod.wa = new Array();',
  651. '$mod.wa = new Array(3);',
  652. '$mod.wa = Array.of(4, 5);',
  653. '$mod.wa = $mod.wa.fill(7);',
  654. '$mod.wa = $mod.wa.fill(7, 8, 9);',
  655. '$mod.w = $mod.wa.length;',
  656. '$mod.wa.length = 10;',
  657. '$mod.wa[11] = $mod.w;',
  658. '$mod.w = $mod.wa[12];',
  659. '']));
  660. end;
  661. procedure TTestGenerics.TestGen_InlineSpec_Constructor;
  662. begin
  663. StartProgram(false);
  664. Add([
  665. '{$mode objfpc}',
  666. 'type',
  667. ' TObject = class',
  668. ' public',
  669. ' constructor Create;',
  670. ' end;',
  671. ' generic TBird<T> = class',
  672. ' end;',
  673. 'constructor TObject.Create; begin end;',
  674. 'var b: specialize TBird<word>;',
  675. 'begin',
  676. ' b:=specialize TBird<word>.Create;',
  677. '']);
  678. ConvertProgram;
  679. CheckSource('TestGen_InlineSpec_Constructor',
  680. LinesToStr([ // statements
  681. 'rtl.createClass($mod, "TObject", null, function () {',
  682. ' this.$init = function () {',
  683. ' };',
  684. ' this.$final = function () {',
  685. ' };',
  686. ' this.Create = function () {',
  687. ' return this;',
  688. ' };',
  689. '});',
  690. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  691. '});',
  692. 'this.b = null;',
  693. '']),
  694. LinesToStr([ // $mod.$main
  695. '$mod.b = $mod.TBird$G1.$create("Create");',
  696. '']));
  697. end;
  698. procedure TTestGenerics.TestGen_CallUnitImplProc;
  699. begin
  700. AddModuleWithIntfImplSrc('UnitA.pas',
  701. LinesToStr([
  702. 'type',
  703. ' generic TBird<T> = class',
  704. ' procedure Fly;',
  705. ' end;',
  706. 'var b: specialize TBird<boolean>;',
  707. '']),
  708. LinesToStr([
  709. 'procedure DoIt;',
  710. 'var b: specialize TBird<word>;',
  711. 'begin',
  712. ' b:=specialize TBird<word>.Create;',
  713. ' b.Fly;',
  714. 'end;',
  715. 'procedure TBird.Fly;',
  716. 'begin',
  717. ' DoIt;',
  718. 'end;',
  719. '']));
  720. StartProgram(true,[supTObject]);
  721. Add('uses UnitA;');
  722. Add('begin');
  723. ConvertProgram;
  724. CheckUnit('UnitA.pas',
  725. LinesToStr([ // statements
  726. 'rtl.module("UnitA", ["system"], function () {',
  727. ' var $mod = this;',
  728. ' var $impl = $mod.$impl;',
  729. ' rtl.createClass($mod, "TBird$G1", pas.system.TObject, function () {',
  730. ' this.Fly = function () {',
  731. ' $impl.DoIt();',
  732. ' };',
  733. ' });',
  734. ' rtl.createClass($mod, "TBird$G2", pas.system.TObject, function () {',
  735. ' this.Fly = function () {',
  736. ' $impl.DoIt();',
  737. ' };',
  738. ' });',
  739. ' this.b = null;',
  740. '}, null, function () {',
  741. ' var $mod = this;',
  742. ' var $impl = $mod.$impl;',
  743. ' $impl.DoIt = function () {',
  744. ' var b = null;',
  745. ' b = $mod.TBird$G2.$create("Create");',
  746. ' b.Fly();',
  747. ' };',
  748. '});',
  749. '']));
  750. end;
  751. procedure TTestGenerics.TestGen_IntAssignTemplVar;
  752. begin
  753. StartProgram(false);
  754. Add([
  755. 'type',
  756. ' TObject = class end;',
  757. ' generic TBird<T> = class',
  758. ' m: T;',
  759. ' procedure Fly;',
  760. ' end;',
  761. 'var b: specialize TBird<word>;',
  762. 'procedure TBird.Fly;',
  763. 'var i: nativeint;',
  764. 'begin',
  765. ' i:=m;',
  766. 'end;',
  767. 'begin',
  768. '']);
  769. ConvertProgram;
  770. CheckSource('TestGen_IntAssignTemplVar',
  771. LinesToStr([ // statements
  772. 'rtl.createClass($mod, "TObject", null, function () {',
  773. ' this.$init = function () {',
  774. ' };',
  775. ' this.$final = function () {',
  776. ' };',
  777. '});',
  778. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  779. ' this.$init = function () {',
  780. ' $mod.TObject.$init.call(this);',
  781. ' this.m = 0;',
  782. ' };',
  783. ' this.Fly = function () {',
  784. ' var i = 0;',
  785. ' i = this.m;',
  786. ' };',
  787. '});',
  788. 'this.b = null;',
  789. '']),
  790. LinesToStr([ // $mod.$main
  791. '']));
  792. end;
  793. procedure TTestGenerics.TestGen_TypeCastDotField;
  794. begin
  795. StartProgram(false);
  796. Add([
  797. 'type',
  798. ' TObject = class end;',
  799. ' generic TBird<T> = class',
  800. ' Field: T;',
  801. ' procedure Fly;',
  802. ' end;',
  803. 'var',
  804. ' o: TObject;',
  805. ' b: specialize TBird<word>;',
  806. 'procedure TBird.Fly;',
  807. 'begin',
  808. ' specialize TBird<word>(o).Field:=3;',
  809. ' if 4=specialize TBird<word>(o).Field then ;',
  810. 'end;',
  811. 'begin',
  812. ' specialize TBird<word>(o).Field:=5;',
  813. ' if 6=specialize TBird<word>(o).Field then ;',
  814. '']);
  815. ConvertProgram;
  816. CheckSource('TestGen_TypeCastDotField',
  817. LinesToStr([ // statements
  818. 'rtl.createClass($mod, "TObject", null, function () {',
  819. ' this.$init = function () {',
  820. ' };',
  821. ' this.$final = function () {',
  822. ' };',
  823. '});',
  824. 'rtl.createClass($mod, "TBird$G1", $mod.TObject, function () {',
  825. ' this.$init = function () {',
  826. ' $mod.TObject.$init.call(this);',
  827. ' this.Field = 0;',
  828. ' };',
  829. ' this.Fly = function () {',
  830. ' $mod.o.Field = 3;',
  831. ' if (4 === $mod.o.Field) ;',
  832. ' };',
  833. '});',
  834. 'this.o = null;',
  835. 'this.b = null;',
  836. '']),
  837. LinesToStr([ // $mod.$main
  838. '$mod.o.Field = 5;',
  839. 'if (6 === $mod.o.Field) ;',
  840. '']));
  841. end;
  842. procedure TTestGenerics.TestGen_HelperForArray;
  843. begin
  844. StartProgram(false);
  845. Add([
  846. '{$ModeSwitch typehelpers}',
  847. 'type',
  848. ' generic TArr<T> = array[1..2] of T;',
  849. ' TWordArrHelper = type helper for specialize TArr<word>',
  850. ' procedure Fly(w: word);',
  851. ' end;',
  852. 'procedure TWordArrHelper.Fly(w: word);',
  853. 'begin',
  854. 'end;',
  855. 'var',
  856. ' a: specialize TArr<word>;',
  857. 'begin',
  858. ' a.Fly(3);',
  859. '']);
  860. ConvertProgram;
  861. CheckSource('TestGen_HelperForArray',
  862. LinesToStr([ // statements
  863. 'rtl.createHelper($mod, "TWordArrHelper", null, function () {',
  864. ' this.Fly = function (w) {',
  865. ' };',
  866. '});',
  867. 'this.a = rtl.arraySetLength(null, 0, 2);',
  868. '']),
  869. LinesToStr([ // $mod.$main
  870. '$mod.TWordArrHelper.Fly.call({',
  871. ' p: $mod,',
  872. ' get: function () {',
  873. ' return this.p.a;',
  874. ' },',
  875. ' set: function (v) {',
  876. ' this.p.a = v;',
  877. ' }',
  878. '}, 3);',
  879. '']));
  880. end;
  881. procedure TTestGenerics.TestGenProc_Function_ObjFPC;
  882. begin
  883. StartProgram(false);
  884. Add([
  885. 'generic function Run<T>(a: T): T;',
  886. 'var i: T;',
  887. 'begin',
  888. ' a:=i;',
  889. ' Result:=a;',
  890. 'end;',
  891. 'var w: word;',
  892. 'begin',
  893. ' w:=specialize Run<word>(3);',
  894. '']);
  895. ConvertProgram;
  896. CheckSource('TestGenProc_Function_ObjFPC',
  897. LinesToStr([ // statements
  898. 'this.Run$s0 = function (a) {',
  899. ' var Result = 0;',
  900. ' var i = 0;',
  901. ' a = i;',
  902. ' Result = a;',
  903. ' return Result;',
  904. '};',
  905. 'this.w = 0;',
  906. '']),
  907. LinesToStr([ // $mod.$main
  908. '$mod.w = $mod.Run$s0(3);',
  909. '']));
  910. end;
  911. procedure TTestGenerics.TestGenProc_Function_Delphi;
  912. begin
  913. StartProgram(false);
  914. Add([
  915. '{$mode delphi}',
  916. 'function Run<T>(a: T): T;',
  917. 'var i: T;',
  918. 'begin',
  919. ' a:=i;',
  920. ' Result:=a;',
  921. 'end;',
  922. 'var w: word;',
  923. 'begin',
  924. ' w:=Run<word>(3);',
  925. '']);
  926. ConvertProgram;
  927. CheckSource('TestGenProc_Function_Delphi',
  928. LinesToStr([ // statements
  929. 'this.Run$s0 = function (a) {',
  930. ' var Result = 0;',
  931. ' var i = 0;',
  932. ' a = i;',
  933. ' Result = a;',
  934. ' return Result;',
  935. '};',
  936. 'this.w = 0;',
  937. '']),
  938. LinesToStr([ // $mod.$main
  939. '$mod.w = $mod.Run$s0(3);',
  940. '']));
  941. end;
  942. procedure TTestGenerics.TestGenProc_Overload;
  943. begin
  944. StartProgram(false);
  945. Add([
  946. 'generic procedure DoIt<T>(a: T; w: word); overload;',
  947. 'begin',
  948. 'end;',
  949. 'generic procedure DoIt<T>(a: T; b: boolean); overload;',
  950. 'begin',
  951. 'end;',
  952. 'begin',
  953. ' specialize DoIt<word>(3,4);',
  954. ' specialize DoIt<boolean>(false,5);',
  955. ' specialize DoIt<word>(6,true);',
  956. ' specialize DoIt<double>(7.3,true);',
  957. '']);
  958. ConvertProgram;
  959. CheckSource('TestGenProc_Overload',
  960. LinesToStr([ // statements
  961. 'this.DoIt$s0 = function (a, w) {',
  962. '};',
  963. 'this.DoIt$s1 = function (a, w) {',
  964. '};',
  965. 'this.DoIt$1s0 = function (a, b) {',
  966. '};',
  967. 'this.DoIt$1s1 = function (a, b) {',
  968. '};',
  969. '']),
  970. LinesToStr([ // $mod.$main
  971. '$mod.DoIt$s0(3, 4);',
  972. '$mod.DoIt$s1(false, 5);',
  973. '$mod.DoIt$1s0(6, true);',
  974. '$mod.DoIt$1s1(7.3, true);',
  975. '']));
  976. end;
  977. procedure TTestGenerics.TestGenProc_Forward;
  978. begin
  979. StartProgram(false);
  980. Add([
  981. '{$mode delphi}',
  982. 'procedure Run<S>(a: S; b: boolean); forward;',
  983. 'procedure Run<S>(a: S; b: boolean);',
  984. 'begin',
  985. ' Run<word>(1,true);',
  986. 'end;',
  987. 'begin',
  988. ' Run(1.3,true);',
  989. '']);
  990. ConvertProgram;
  991. CheckSource('TestGenProc_infer_OverloadForward',
  992. LinesToStr([ // statements
  993. 'this.Run$s0 = function (a, b) {',
  994. ' $mod.Run$s0(1, true);',
  995. '};',
  996. 'this.Run$s1 = function (a, b) {',
  997. ' $mod.Run$s0(1, true);',
  998. '};',
  999. '']),
  1000. LinesToStr([ // $mod.$main
  1001. '$mod.Run$s1(1.3, true);',
  1002. '']));
  1003. end;
  1004. procedure TTestGenerics.TestGenProc_Infer_OverloadForward;
  1005. begin
  1006. StartProgram(false);
  1007. Add([
  1008. '{$mode delphi}',
  1009. 'procedure {#A}Run<S>(a: S; b: boolean); forward; overload;',
  1010. 'procedure {#B}Run<T>(a: T; w: word); forward; overload;',
  1011. 'procedure {#C}Run<U>(a: U; b: U); forward; overload;',
  1012. 'procedure {#A2}Run<S>(a: S; b: boolean); overload;',
  1013. 'begin',
  1014. ' {@A}Run(1,true);', // non generic take precedence
  1015. ' {@B}Run(2,word(3));', // non generic take precedence
  1016. ' {@C}Run(''foo'',''bar'');',
  1017. 'end;',
  1018. 'procedure {#B2}Run<T>(a: T; w: word); overload;',
  1019. 'begin',
  1020. 'end;',
  1021. 'procedure {#C2}Run<U>(a: U; b: U); overload;',
  1022. 'begin',
  1023. 'end;',
  1024. 'begin',
  1025. ' {@A}Run(1,true);', // non generic take precedence
  1026. ' {@B}Run(2,word(3));', // non generic take precedence
  1027. ' {@C}Run(''foo'',''bar'');',
  1028. '']);
  1029. ConvertProgram;
  1030. CheckSource('TestGenProc_infer_OverloadForward',
  1031. LinesToStr([ // statements
  1032. 'this.Run$s0 = function (a, b) {',
  1033. ' $mod.Run$s0(1, true);',
  1034. ' $mod.Run$1s0(2, 3);',
  1035. ' $mod.Run$2s0("foo", "bar");',
  1036. '};',
  1037. 'this.Run$1s0 = function (a, w) {',
  1038. '};',
  1039. 'this.Run$2s0 = function (a, b) {',
  1040. '};',
  1041. '']),
  1042. LinesToStr([ // $mod.$main
  1043. '$mod.Run$s0(1, true);',
  1044. '$mod.Run$1s0(2, 3);',
  1045. '$mod.Run$2s0("foo", "bar");',
  1046. '']));
  1047. end;
  1048. procedure TTestGenerics.TestGenProc_TypeInfo;
  1049. begin
  1050. Converter.Options:=Converter.Options-[coNoTypeInfo];
  1051. StartProgram(true,[supTypeInfo]);
  1052. Add([
  1053. '{$modeswitch implicitfunctionspecialization}',
  1054. 'generic procedure Run<S>(a: S);',
  1055. 'var',
  1056. ' p: TTypeInfo;',
  1057. 'begin',
  1058. ' p:=TypeInfo(S);',
  1059. ' p:=TypeInfo(a);',
  1060. 'end;',
  1061. 'begin',
  1062. ' Run(word(3));',
  1063. ' Run(''foo'');',
  1064. '']);
  1065. ConvertProgram;
  1066. CheckSource('TestGenProc_TypeInfo',
  1067. LinesToStr([ // statements
  1068. 'this.Run$s0 = function (a) {',
  1069. ' var p = null;',
  1070. ' p = rtl.word;',
  1071. ' p = rtl.word;',
  1072. '};',
  1073. 'this.Run$s1 = function (a) {',
  1074. ' var p = null;',
  1075. ' p = rtl.string;',
  1076. ' p = rtl.string;',
  1077. '};',
  1078. '']),
  1079. LinesToStr([ // $mod.$main
  1080. '$mod.Run$s0(3);',
  1081. '$mod.Run$s1("foo");',
  1082. '']));
  1083. end;
  1084. procedure TTestGenerics.TestGenProc_Infer_Widen;
  1085. begin
  1086. StartProgram(false);
  1087. Add([
  1088. '{$mode delphi}',
  1089. 'procedure Run<S>(a: S; b: S);',
  1090. 'begin',
  1091. 'end;',
  1092. 'begin',
  1093. ' Run(word(1),longint(2));',
  1094. ' Run(byte(2),smallint(2));',
  1095. ' Run(longword(3),longint(2));',
  1096. ' Run(nativeint(4),longint(2));',
  1097. ' Run(nativeint(5),nativeuint(2));',
  1098. ' Run(''a'',''foo'');',
  1099. ' Run(''bar'',''c'');',
  1100. '']);
  1101. ConvertProgram;
  1102. CheckSource('TestGenProc_Infer_Widen',
  1103. LinesToStr([ // statements
  1104. 'this.Run$s0 = function (a, b) {',
  1105. '};',
  1106. 'this.Run$s1 = function (a, b) {',
  1107. '};',
  1108. 'this.Run$s2 = function (a, b) {',
  1109. '};',
  1110. '']),
  1111. LinesToStr([ // $mod.$main
  1112. '$mod.Run$s0(1, 2);',
  1113. '$mod.Run$s0(2, 2);',
  1114. '$mod.Run$s1(3, 2);',
  1115. '$mod.Run$s1(4, 2);',
  1116. '$mod.Run$s1(5, 2);',
  1117. '$mod.Run$s2("a", "foo");',
  1118. '$mod.Run$s2("bar", "c");',
  1119. '']));
  1120. end;
  1121. procedure TTestGenerics.TestGenProc_Infer_PassAsArg;
  1122. begin
  1123. StartProgram(false);
  1124. Add([
  1125. '{$mode delphi}',
  1126. 'function Run<T>(a: T): T;',
  1127. 'var b: T;',
  1128. 'begin',
  1129. ' Run(Run<word>(3));',
  1130. ' Run(Run(word(4)));',
  1131. 'end;',
  1132. 'begin',
  1133. ' Run(Run<word>(5));',
  1134. ' Run(Run(word(6)));',
  1135. '']);
  1136. ConvertProgram;
  1137. CheckSource('TestGenProc_Infer_PassAsArg',
  1138. LinesToStr([ // statements
  1139. 'this.Run$s0 = function (a) {',
  1140. ' var Result = 0;',
  1141. ' var b = 0;',
  1142. ' $mod.Run$s0($mod.Run$s0(3));',
  1143. ' $mod.Run$s0($mod.Run$s0(4));',
  1144. ' return Result;',
  1145. '};',
  1146. '']),
  1147. LinesToStr([ // $mod.$main
  1148. '$mod.Run$s0($mod.Run$s0(5));',
  1149. '$mod.Run$s0($mod.Run$s0(6));',
  1150. '']));
  1151. end;
  1152. procedure TTestGenerics.TestGenMethod_ObjFPC;
  1153. begin
  1154. StartProgram(false);
  1155. Add([
  1156. '{$mode objfpc}',
  1157. '{$ModeSwitch implicitfunctionspecialization}',
  1158. 'type',
  1159. ' TObject = class',
  1160. ' generic procedure {#A}Run<S>(a: S; b: boolean); overload;',
  1161. ' generic procedure {#B}Run<T>(a: T; w: word); overload;',
  1162. ' generic procedure {#C}Run<U>(a: U; b: U); overload;',
  1163. ' end; ',
  1164. 'generic procedure {#A2}TObject.Run<S>(a: S; b: boolean); overload;',
  1165. 'begin',
  1166. ' {@A}Run(1,true);', // non generic take precedence
  1167. ' {@B}Run(2,word(3));', // non generic take precedence
  1168. ' {@C}Run(''foo'',''bar'');',
  1169. 'end;',
  1170. 'generic procedure {#B2}TObject.Run<T>(a: T; w: word); overload;',
  1171. 'begin',
  1172. 'end;',
  1173. 'generic procedure {#C2}TObject.Run<U>(a: U; b: U); overload;',
  1174. 'begin',
  1175. 'end;',
  1176. 'var o: TObject;',
  1177. 'begin',
  1178. ' o.{@A}Run(1,true);', // non generic take precedence
  1179. ' o.{@B}Run(2,word(3));', // non generic take precedence
  1180. ' o.{@C}Run(''foo'',''bar'');',
  1181. '']);
  1182. ConvertProgram;
  1183. CheckSource('TestGenMethod_ObjFPC',
  1184. LinesToStr([ // statements
  1185. 'rtl.createClass($mod, "TObject", null, function () {',
  1186. ' this.$init = function () {',
  1187. ' };',
  1188. ' this.$final = function () {',
  1189. ' };',
  1190. ' this.Run$s0 = function (a, b) {',
  1191. ' this.Run$s0(1, true);',
  1192. ' this.Run$1s0(2, 3);',
  1193. ' this.Run$2s0("foo", "bar");',
  1194. ' };',
  1195. ' this.Run$1s0 = function (a, w) {',
  1196. ' };',
  1197. ' this.Run$2s0 = function (a, b) {',
  1198. ' };',
  1199. '});',
  1200. 'this.o = null;',
  1201. '']),
  1202. LinesToStr([ // $mod.$main
  1203. '$mod.o.Run$s0(1, true);',
  1204. '$mod.o.Run$1s0(2, 3);',
  1205. '$mod.o.Run$2s0("foo", "bar");',
  1206. '']));
  1207. end;
  1208. Initialization
  1209. RegisterTests([TTestGenerics]);
  1210. end.