tcgenerics.pas 34 KB

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