tcgenerics.pp 9.5 KB

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