tcgenerics.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. unit tcgenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, pastree, testregistry, pscanner, tctypeparser;
  6. Type
  7. { TTestGenerics - for resolver see unit tcresolvegenerics }
  8. TTestGenerics = Class(TBaseTestTypeParser)
  9. Published
  10. // generic types
  11. Procedure TestObjectGenerics;
  12. Procedure TestRecordGenerics;
  13. Procedure TestArrayGenerics;
  14. Procedure TestArrayGenericsDelphi;
  15. Procedure TestProcTypeGenerics;
  16. Procedure TestDeclarationDelphi;
  17. Procedure TestDeclarationFPC;
  18. Procedure TestDeclarationFPCNoSpaces;
  19. Procedure TestMethodImplementation;
  20. // generic constraints
  21. Procedure TestGenericConstraint;
  22. Procedure TestGenericInterfaceConstraint;
  23. Procedure TestDeclarationConstraint;
  24. // specialize type
  25. Procedure TestSpecializationDelphi;
  26. Procedure TestDeclarationDelphiSpecialize;
  27. Procedure TestInlineSpecializationInArgument;
  28. Procedure TestSpecializeNested;
  29. Procedure TestInlineSpecializeInStatement;
  30. Procedure TestInlineSpecializeInStatementDelphi;
  31. // generic functions
  32. Procedure TestGenericFunction_Program;
  33. Procedure TestGenericFunction_Unit;
  34. // generic method
  35. Procedure TestGenericMethod_Program;
  36. end;
  37. implementation
  38. procedure TTestGenerics.TestObjectGenerics;
  39. begin
  40. Add([
  41. 'Type',
  42. 'Generic TSomeClass<T> = Object',
  43. ' b : T;',
  44. 'end;',
  45. '']);
  46. ParseDeclarations;
  47. end;
  48. procedure TTestGenerics.TestRecordGenerics;
  49. begin
  50. Add([
  51. 'Type',
  52. ' Generic TSome<T> = Record',
  53. ' b : T;',
  54. ' end;',
  55. '']);
  56. ParseDeclarations;
  57. end;
  58. procedure TTestGenerics.TestArrayGenerics;
  59. begin
  60. Add([
  61. 'Type',
  62. ' Generic TSome<T> = array of T;',
  63. ' Generic TStatic<R,T> = array[R] of T;',
  64. '']);
  65. ParseDeclarations;
  66. end;
  67. procedure TTestGenerics.TestArrayGenericsDelphi;
  68. begin
  69. Add([
  70. '{$mode delphi}',
  71. 'Type',
  72. ' TSome<T> = array of T;',
  73. ' TStatic<R,T> = array[R] of T;',
  74. '']);
  75. ParseDeclarations;
  76. end;
  77. procedure TTestGenerics.TestProcTypeGenerics;
  78. begin
  79. Add([
  80. 'Type',
  81. ' Generic TSome<T> = procedure(v: T);',
  82. ' Generic TFunc<R,T> = function(b: R): T;',
  83. '']);
  84. ParseDeclarations;
  85. end;
  86. procedure TTestGenerics.TestDeclarationDelphi;
  87. Var
  88. T : TPasClassType;
  89. begin
  90. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  91. Source.Add('Type');
  92. Source.Add(' TSomeClass<T,T2> = Class(TObject)');
  93. Source.Add(' b : T;');
  94. Source.Add(' b2 : T2;');
  95. Source.Add(' end;');
  96. ParseDeclarations;
  97. AssertNotNull('have generic definition',Declarations.Classes);
  98. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  99. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  100. T:=TPasClassType(Declarations.Classes[0]);
  101. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  102. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  103. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  104. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  105. end;
  106. procedure TTestGenerics.TestDeclarationFPC;
  107. Var
  108. T : TPasClassType;
  109. begin
  110. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches;
  111. Source.Add('Type');
  112. Source.Add(' TSomeClass<T;T2> = Class(TObject)');
  113. Source.Add(' b : T;');
  114. Source.Add(' b2 : T2;');
  115. Source.Add(' end;');
  116. ParseDeclarations;
  117. AssertNotNull('have generic definition',Declarations.Classes);
  118. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  119. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  120. T:=TPasClassType(Declarations.Classes[0]);
  121. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  122. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  123. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  124. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  125. end;
  126. procedure TTestGenerics.TestDeclarationFPCNoSpaces;
  127. Var
  128. T : TPasClassType;
  129. begin
  130. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches;
  131. Source.Add('Type');
  132. Source.Add(' TSomeClass<T;T2>=Class(TObject)');
  133. Source.Add(' b : T;');
  134. Source.Add(' b2 : T2;');
  135. Source.Add(' end;');
  136. ParseDeclarations;
  137. AssertNotNull('have generic definition',Declarations.Classes);
  138. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  139. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  140. T:=TPasClassType(Declarations.Classes[0]);
  141. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  142. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  143. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  144. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  145. end;
  146. procedure TTestGenerics.TestMethodImplementation;
  147. begin
  148. With source do
  149. begin
  150. Add('unit afile;');
  151. Add('{$MODE DELPHI}');
  152. Add('interface');
  153. Add('type');
  154. Add(' TTest<T> = object');
  155. Add(' procedure foo(v:T);');
  156. Add(' procedure bar<Y>(v:T);');
  157. Add(' type');
  158. Add(' TSub = class');
  159. Add(' procedure DoIt<Y>(v:T);');
  160. Add(' end;');
  161. Add(' end;');
  162. Add('implementation');
  163. Add('procedure TTest<T>.foo;');
  164. Add('begin');
  165. Add('end;');
  166. Add('procedure TTest<T>.bar<Y>;');
  167. Add('begin');
  168. Add('end;');
  169. Add('procedure TTest<T>.TSub.DoIt<Y>;');
  170. Add('begin');
  171. Add('end;');
  172. end;
  173. ParseModule;
  174. end;
  175. procedure TTestGenerics.TestGenericConstraint;
  176. begin
  177. Add([
  178. 'Type',
  179. 'Generic TSomeClass<T: TObject> = class',
  180. ' b : T;',
  181. 'end;',
  182. 'Generic TBird<T: class> = class',
  183. ' c : specialize TBird<T>;',
  184. 'end;',
  185. 'Generic TEagle<T: record> = class',
  186. 'end;',
  187. 'Generic TEagle<T: constructor> = class',
  188. 'end;',
  189. '']);
  190. ParseDeclarations;
  191. end;
  192. procedure TTestGenerics.TestGenericInterfaceConstraint;
  193. begin
  194. Add([
  195. 'Type',
  196. 'TIntfA = interface end;',
  197. 'TIntfB = interface end;',
  198. 'TBird = class(TInterfacedObject,TIntfA,TIntfB) end;',
  199. 'Generic TAnt<T: TIntfA, TIntfB> = class',
  200. ' b: T;',
  201. ' c: specialize TAnt<T>;',
  202. 'end;',
  203. 'Generic TFly<T: TIntfA, TIntfB; S> = class',
  204. ' b: S;',
  205. ' c: specialize TFly<T>;',
  206. 'end;',
  207. '']);
  208. ParseDeclarations;
  209. end;
  210. procedure TTestGenerics.TestDeclarationConstraint;
  211. Var
  212. T : TPasClassType;
  213. begin
  214. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  215. Source.Add('Type');
  216. Source.Add(' TSomeClass<T: T2> = Class(TObject)');
  217. Source.Add(' b : T;');
  218. Source.Add(' end;');
  219. ParseDeclarations;
  220. AssertNotNull('have generic definition',Declarations.Classes);
  221. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  222. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  223. T:=TPasClassType(Declarations.Classes[0]);
  224. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  225. AssertEquals('1 template types',1,T.GenericTemplateTypes.Count);
  226. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  227. AssertEquals('Type constraint is recorded','T2',TPasGenericTemplateType(T.GenericTemplateTypes[0]).TypeConstraint);
  228. end;
  229. procedure TTestGenerics.TestSpecializationDelphi;
  230. begin
  231. Add('{$mode delphi}');
  232. ParseType('TFPGList<integer>',TPasSpecializeType,'');
  233. end;
  234. procedure TTestGenerics.TestDeclarationDelphiSpecialize;
  235. Var
  236. T : TPasClassType;
  237. begin
  238. Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
  239. Source.Add('Type');
  240. Source.Add(' TSomeClass<T,T2> = Class(TSomeGeneric<Integer,Integer>)');
  241. Source.Add(' b : T;');
  242. Source.Add(' b2 : T2;');
  243. Source.Add(' end;');
  244. ParseDeclarations;
  245. AssertNotNull('have generic definition',Declarations.Classes);
  246. AssertEquals('have generic definition',1,Declarations.Classes.Count);
  247. AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType);
  248. T:=TPasClassType(Declarations.Classes[0]);
  249. AssertEquals('Name is correct','TSomeClass',T.Name);
  250. AssertNotNull('have generic templates',T.GenericTemplateTypes);
  251. AssertEquals('2 template types',2,T.GenericTemplateTypes.Count);
  252. AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent);
  253. AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent);
  254. end;
  255. procedure TTestGenerics.TestInlineSpecializationInArgument;
  256. begin
  257. With source do
  258. begin
  259. Add('unit afile;');
  260. Add('{$MODE DELPHI}');
  261. Add('interface');
  262. Add('type');
  263. Add(' TFoo=class');
  264. Add(' procedure foo(var Node:TSomeGeneric<TBoundingBox>;const index:Integer);');
  265. Add(' end;');
  266. Add('implementation');
  267. end;
  268. ParseModule;
  269. end;
  270. procedure TTestGenerics.TestSpecializeNested;
  271. begin
  272. Add([
  273. 'Type',
  274. ' generic TSomeClass<A,B> = class(specialize TOther<A,specialize TAnother<B>>) end;',
  275. '']);
  276. ParseDeclarations;
  277. end;
  278. procedure TTestGenerics.TestInlineSpecializeInStatement;
  279. begin
  280. Add([
  281. '{$mode objfpc}',
  282. 'begin',
  283. ' vec:=specialize TVector<double>.create;',
  284. ' t:=specialize a<b>;',
  285. //' t:=specialize a<b.specialize c<d,e.f>>;',
  286. //' t:=a.specialize b<c>;',
  287. ' t:=specialize a<b>.c;',
  288. '']);
  289. ParseModule;
  290. end;
  291. procedure TTestGenerics.TestInlineSpecializeInStatementDelphi;
  292. begin
  293. Add([
  294. '{$mode delphi}',
  295. 'begin',
  296. ' vec:=TVector<double>.create;',
  297. ' b:=a<b;',
  298. ' t:=a<b.c<d,e.f>>;',
  299. ' t:=a.b<c>;',
  300. ' t:=a<b>.c;',
  301. // forbidden:' t:=a<b<c>.d>;',
  302. '']);
  303. ParseModule;
  304. end;
  305. procedure TTestGenerics.TestGenericFunction_Program;
  306. begin
  307. Add([
  308. 'generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;',
  309. 'begin',
  310. 'end;',
  311. 'begin',
  312. ' specialize IfThen<word>(true,2,3);',
  313. '']);
  314. ParseModule;
  315. end;
  316. procedure TTestGenerics.TestGenericFunction_Unit;
  317. begin
  318. Add([
  319. 'unit afile;',
  320. 'interface',
  321. 'generic function Get<T>(val: T) :T;',
  322. 'implementation',
  323. 'generic function Get<T>(val: T) :T;',
  324. 'begin',
  325. 'end;',
  326. 'initialization',
  327. ' specialize GetIt<word>(2);',
  328. '']);
  329. ParseModule;
  330. end;
  331. procedure TTestGenerics.TestGenericMethod_Program;
  332. begin
  333. Add([
  334. '{$mode objfpc}',
  335. 'type',
  336. ' TObject = class',
  337. ' generic function Get<T>(val: T) :T;',
  338. ' type TBird = word;',
  339. ' generic procedure Fly<T>;',
  340. ' const C = 1;',
  341. ' generic procedure Run<T>;',
  342. ' end;',
  343. 'generic function TObject.Get<T>(val: T) :T;',
  344. 'begin',
  345. 'end;',
  346. 'begin',
  347. ' TObject.specialize GetIt<word>(2);',
  348. '']);
  349. ParseModule;
  350. end;
  351. initialization
  352. RegisterTest(TTestGenerics);
  353. end.