tcgenerics.pas 60 KB

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