tcresolvegenerics.pas 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. unit tcresolvegenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, testregistry, tcresolver, PasResolveEval, PParser;
  6. type
  7. { TTestResolveGenerics }
  8. TTestResolveGenerics = Class(TCustomTestResolver)
  9. Published
  10. // generic types
  11. procedure TestGen_MissingTemplateFail;
  12. procedure TestGen_VarTypeWithoutSpecializeFail;
  13. procedure TestGen_GenTypeWithWrongParamCountFail;
  14. procedure TestGen_GenericNotFoundFail;
  15. procedure TestGen_SameNameSameParamCountFail;
  16. procedure TestGen_TypeAliasWithoutSpecializeFail;
  17. // constraints
  18. procedure TestGen_ConstraintStringFail;
  19. procedure TestGen_ConstraintMultiClassFail;
  20. procedure TestGen_ConstraintRecordExpectedFail;
  21. procedure TestGen_ConstraintClassRecordFail;
  22. procedure TestGen_ConstraintRecordClassFail;
  23. procedure TestGen_ConstraintArrayFail;
  24. // ToDo: constraint constructor
  25. // ToDo: constraint T:Unit2.TBird
  26. // ToDo: constraint T:Unit2.TGen<word>
  27. procedure TestGen_TemplNameEqTypeNameFail;
  28. procedure TestGen_ConstraintInheritedMissingRecordFail;
  29. procedure TestGen_ConstraintInheritedMissingClassTypeFail;
  30. // generic record
  31. procedure TestGen_RecordLocalNameDuplicateFail;
  32. procedure TestGen_Record;
  33. procedure TestGen_RecordDelphi;
  34. procedure TestGen_RecordNestedSpecialized;
  35. procedure TestGen_Record_SpecializeSelfInsideFail;
  36. procedure TestGen_RecordAnoArray;
  37. // ToDo: unitname.specialize TBird<word>.specialize
  38. procedure TestGen_RecordNestedSpecialize;
  39. // generic class
  40. procedure TestGen_Class;
  41. procedure TestGen_ClassDelphi;
  42. procedure TestGen_ClassForward;
  43. procedure TestGen_ClassForwardConstraints;
  44. procedure TestGen_ClassForwardConstraintNameMismatch;
  45. procedure TestGen_ClassForwardConstraintKeywordMismatch;
  46. procedure TestGen_ClassForwardConstraintTypeMismatch;
  47. procedure TestGen_ClassForward_Circle;
  48. procedure TestGen_Class_RedeclareInUnitImplFail;
  49. procedure TestGen_Class_AnotherInUnitImpl;
  50. procedure TestGen_Class_Method;
  51. procedure TestGen_Class_MethodOverride;
  52. procedure TestGen_Class_MethodDelphi;
  53. // ToDo: procedure TestGen_Class_MethodDelphiTypeParamMissing;
  54. // ToDo: procedure TestGen_Class_MethodImplConstraintFail;
  55. procedure TestGen_Class_SpecializeSelfInside;
  56. procedure TestGen_Class_GenAncestor;
  57. procedure TestGen_Class_AncestorSelfFail;
  58. procedure TestGen_ClassOfSpecializeFail;
  59. // ToDo: UnitA.impl uses UnitB.intf uses UnitA.intf, UnitB has specialize of UnitA
  60. procedure TestGen_Class_NestedType;
  61. procedure TestGen_Class_NestedRecord;
  62. procedure TestGen_Class_NestedClass;
  63. procedure TestGen_Class_Enums_NotPropagating;
  64. procedure TestGen_Class_List;
  65. // generic external class
  66. procedure TestGen_ExtClass_Array;
  67. // generic interface
  68. procedure TestGen_ClassInterface;
  69. procedure TestGen_ClassInterface_Method;
  70. // generic array
  71. procedure TestGen_Array;
  72. // ToDo: anonymous array type
  73. // generic procedure type
  74. procedure TestGen_ProcType;
  75. // pointer of generic
  76. procedure TestGen_PointerDirectSpecializeFail;
  77. // ToDo: helpers for generics
  78. // generic functions
  79. procedure TestGen_GenericFunction; // ToDo
  80. // ToDo: generic class method overload <T> <S,T>
  81. // ToDo: procedure TestGen_GenMethod_ClassConstructorFail;
  82. // generic statements
  83. procedure TestGen_LocalVar;
  84. procedure TestGen_Statements;
  85. procedure TestGen_InlineSpecializeExpr;
  86. // ToDo: for-in
  87. procedure TestGen_TryExcept;
  88. // ToDo: call
  89. // ToDo: dot
  90. // ToDo: is as
  91. // ToDo: typecast
  92. // ToTo: nested proc
  93. end;
  94. implementation
  95. { TTestResolveGenerics }
  96. procedure TTestResolveGenerics.TestGen_MissingTemplateFail;
  97. begin
  98. StartProgram(false);
  99. Add([
  100. 'type generic g< > = array of word;',
  101. 'begin',
  102. '']);
  103. CheckParserException('Expected "Identifier"',nParserExpectTokenError);
  104. end;
  105. procedure TTestResolveGenerics.TestGen_VarTypeWithoutSpecializeFail;
  106. begin
  107. StartProgram(false);
  108. Add([
  109. 'type generic TBird<T> = record end;',
  110. 'var b: TBird;',
  111. 'begin',
  112. '']);
  113. CheckResolverException('Generics without specialization cannot be used as a type for a variable',
  114. nGenericsWithoutSpecializationAsType);
  115. end;
  116. procedure TTestResolveGenerics.TestGen_GenTypeWithWrongParamCountFail;
  117. begin
  118. StartProgram(false);
  119. Add([
  120. 'type generic TBird<T> = record end;',
  121. 'var b: TBird<word, byte>;',
  122. 'begin',
  123. '']);
  124. CheckResolverException('identifier not found "TBird<,>"',
  125. nIdentifierNotFound);
  126. end;
  127. procedure TTestResolveGenerics.TestGen_GenericNotFoundFail;
  128. begin
  129. StartProgram(false);
  130. Add([
  131. '{$mode objfpc}',
  132. 'type',
  133. ' TBird = specialize TAnimal<word>;',
  134. 'begin',
  135. '']);
  136. CheckResolverException('identifier not found "TAnimal<>"',
  137. nIdentifierNotFound);
  138. end;
  139. procedure TTestResolveGenerics.TestGen_SameNameSameParamCountFail;
  140. begin
  141. StartProgram(false);
  142. Add([
  143. '{$mode delphi}',
  144. 'type',
  145. ' TBird<S,T> = record w: T; end;',
  146. ' TBird<X,Y> = record f: X; end;',
  147. 'begin',
  148. '']);
  149. CheckResolverException('Duplicate identifier "TBird" at afile.pp(4,8)',
  150. nDuplicateIdentifier);
  151. end;
  152. procedure TTestResolveGenerics.TestGen_TypeAliasWithoutSpecializeFail;
  153. begin
  154. StartProgram(false);
  155. Add([
  156. '{$mode delphi}',
  157. 'type',
  158. ' TBird<T> = record w: T; end;',
  159. ' TBirdAlias = TBird;',
  160. 'begin',
  161. '']);
  162. CheckResolverException('type expected, but TBird<> found',
  163. nXExpectedButYFound);
  164. end;
  165. procedure TTestResolveGenerics.TestGen_ConstraintStringFail;
  166. begin
  167. StartProgram(false);
  168. Add([
  169. 'generic function DoIt<T:string>(a: T): T;',
  170. 'begin',
  171. ' Result:=a;',
  172. 'end;',
  173. 'begin',
  174. '']);
  175. CheckResolverException('"String" is not a valid constraint',
  176. nXIsNotAValidConstraint);
  177. end;
  178. procedure TTestResolveGenerics.TestGen_ConstraintMultiClassFail;
  179. begin
  180. StartProgram(false);
  181. Add([
  182. '{$mode objfpc}',
  183. 'type',
  184. ' TObject = class end;',
  185. ' TBird = class end;',
  186. ' TBear = class end;',
  187. 'generic function DoIt<T: TBird, TBear>(a: T): T;',
  188. 'begin',
  189. ' Result:=a;',
  190. 'end;',
  191. 'begin',
  192. '']);
  193. CheckResolverException('"TBird" constraint and "TBear" constraint cannot be specified together',
  194. nConstraintXAndConstraintYCannotBeTogether);
  195. end;
  196. procedure TTestResolveGenerics.TestGen_ConstraintRecordExpectedFail;
  197. begin
  198. StartProgram(false);
  199. Add([
  200. '{$mode objfpc}',
  201. 'type',
  202. ' generic TBird<T:record> = record v: T; end;',
  203. 'var r: specialize TBird<word>;',
  204. 'begin',
  205. '']);
  206. CheckResolverException('record type expected, but Word found',
  207. nXExpectedButYFound);
  208. end;
  209. procedure TTestResolveGenerics.TestGen_ConstraintClassRecordFail;
  210. begin
  211. StartProgram(false);
  212. Add([
  213. '{$mode objfpc}',
  214. 'type',
  215. ' TRec = record end;',
  216. ' generic TBird<T:class> = record v: T; end;',
  217. 'var r: specialize TBird<TRec>;',
  218. 'begin',
  219. '']);
  220. CheckResolverException('class type expected, but TRec found',
  221. nXExpectedButYFound);
  222. end;
  223. procedure TTestResolveGenerics.TestGen_ConstraintRecordClassFail;
  224. begin
  225. StartProgram(false);
  226. Add([
  227. '{$mode objfpc}',
  228. 'type',
  229. ' TObject = class end;',
  230. ' generic TBird<T:record> = record v: T; end;',
  231. 'var r: specialize TBird<TObject>;',
  232. 'begin',
  233. '']);
  234. CheckResolverException('record type expected, but TObject found',
  235. nXExpectedButYFound);
  236. end;
  237. procedure TTestResolveGenerics.TestGen_ConstraintArrayFail;
  238. begin
  239. StartProgram(false);
  240. Add([
  241. '{$mode objfpc}',
  242. 'type',
  243. ' TArr = array of word;',
  244. ' generic TBird<T:TArr> = record v: T; end;',
  245. 'begin',
  246. '']);
  247. CheckResolverException('"array of Word" is not a valid constraint',
  248. nXIsNotAValidConstraint);
  249. end;
  250. procedure TTestResolveGenerics.TestGen_TemplNameEqTypeNameFail;
  251. begin
  252. StartProgram(false);
  253. Add([
  254. '{$mode objfpc}',
  255. 'type',
  256. ' generic TBird<TBird> = record v: T; end;',
  257. 'var r: specialize TBird<word>;',
  258. 'begin',
  259. '']);
  260. CheckResolverException('Duplicate identifier "TBird" at afile.pp(4,16)',
  261. nDuplicateIdentifier);
  262. end;
  263. procedure TTestResolveGenerics.TestGen_ConstraintInheritedMissingRecordFail;
  264. begin
  265. StartProgram(false);
  266. Add([
  267. '{$mode objfpc}',
  268. 'type',
  269. ' TObject = class end;',
  270. ' generic TBird<T: record> = class v: T; end;',
  271. ' generic TEagle<U> = class(TBird<U>)',
  272. ' end;',
  273. 'begin',
  274. '']);
  275. CheckResolverException('Type parameter "U" is missing constraint "record"',
  276. nTypeParamXIsMissingConstraintY);
  277. end;
  278. procedure TTestResolveGenerics.TestGen_ConstraintInheritedMissingClassTypeFail;
  279. begin
  280. StartProgram(false);
  281. Add([
  282. '{$mode objfpc}',
  283. 'type',
  284. ' TObject = class end;',
  285. ' TAnt = class end;',
  286. ' generic TBird<T: TAnt> = class v: T; end;',
  287. ' generic TEagle<U> = class(TBird<U>)',
  288. ' end;',
  289. 'begin',
  290. '']);
  291. CheckResolverException('Type parameter "U" is not compatible with type "TAnt"',
  292. nTypeParamXIsNotCompatibleWithY);
  293. end;
  294. procedure TTestResolveGenerics.TestGen_RecordLocalNameDuplicateFail;
  295. begin
  296. StartProgram(false);
  297. Add([
  298. '{$mode objfpc}',
  299. 'type',
  300. ' generic TBird<T> = record T: word; end;',
  301. 'begin',
  302. '']);
  303. CheckResolverException('Duplicate identifier "T" at afile.pp(4,18)',
  304. nDuplicateIdentifier);
  305. end;
  306. procedure TTestResolveGenerics.TestGen_Record;
  307. begin
  308. StartProgram(false);
  309. Add([
  310. '{$mode objfpc}',
  311. 'type',
  312. ' {#Typ}T = word;',
  313. ' generic TRec<{#Templ}T> = record',
  314. ' {=Templ}v: T;',
  315. ' end;',
  316. 'var',
  317. ' r: specialize TRec<word>;',
  318. ' {=Typ}w: T;',
  319. 'begin',
  320. ' r.v:=w;',
  321. '']);
  322. ParseProgram;
  323. end;
  324. procedure TTestResolveGenerics.TestGen_RecordDelphi;
  325. begin
  326. StartProgram(false);
  327. Add([
  328. '{$mode delphi}',
  329. 'type',
  330. ' {#Typ}T = word;',
  331. ' TRec<{#Templ}T> = record',
  332. ' {=Templ}v: T;',
  333. ' end;',
  334. 'var',
  335. ' r: TRec<word>;',
  336. ' {=Typ}w: T;',
  337. 'begin',
  338. ' r.v:=w;',
  339. '']);
  340. ParseProgram;
  341. end;
  342. procedure TTestResolveGenerics.TestGen_RecordNestedSpecialized;
  343. begin
  344. StartProgram(false);
  345. Add([
  346. '{$mode objfpc}',
  347. 'type',
  348. ' TObject = class end;',
  349. ' generic TBird<T> = class v: T; end;',
  350. ' generic TFish<T:class> = record v: T; end;',
  351. 'var f: specialize TFish<specialize TBird<word>>;',
  352. 'begin',
  353. '']);
  354. ParseProgram;
  355. end;
  356. procedure TTestResolveGenerics.TestGen_Record_SpecializeSelfInsideFail;
  357. begin
  358. StartProgram(false);
  359. Add([
  360. '{$mode objfpc}',
  361. 'type',
  362. ' generic TBird<T> = record',
  363. ' v: specialize TBird<word>;',
  364. ' end;',
  365. 'begin',
  366. '']);
  367. CheckResolverException('type "TBird<>" is not yet completely defined',
  368. nTypeXIsNotYetCompletelyDefined);
  369. end;
  370. procedure TTestResolveGenerics.TestGen_RecordAnoArray;
  371. begin
  372. StartProgram(false);
  373. Add([
  374. '{$mode objfpc}',
  375. 'type',
  376. ' generic TBird<T> = record v: T; end;',
  377. 'var',
  378. ' a: specialize TBird<array of word>;',
  379. ' b: specialize TBird<array of word>;',
  380. 'begin',
  381. ' a:=b;',
  382. '']);
  383. ParseProgram;
  384. end;
  385. procedure TTestResolveGenerics.TestGen_RecordNestedSpecialize;
  386. begin
  387. StartProgram(false);
  388. Add([
  389. '{$mode objfpc}',
  390. 'type',
  391. ' generic TBird<T> = record v: T; end;',
  392. 'var',
  393. ' a: specialize TBird<specialize TBird<word>>;',
  394. 'begin',
  395. ' a.v.v:=3;',
  396. '']);
  397. ParseProgram;
  398. end;
  399. procedure TTestResolveGenerics.TestGen_Class;
  400. begin
  401. StartProgram(false);
  402. Add([
  403. '{$mode objfpc}',
  404. 'type',
  405. ' TObject = class end;',
  406. ' {#Typ}T = word;',
  407. ' generic TBird<{#Templ}T> = class',
  408. ' {=Templ}v: T;',
  409. ' end;',
  410. 'var',
  411. ' b: specialize TBird<word>;',
  412. ' {=Typ}w: T;',
  413. 'begin',
  414. ' b.v:=w;',
  415. '']);
  416. ParseProgram;
  417. end;
  418. procedure TTestResolveGenerics.TestGen_ClassDelphi;
  419. begin
  420. StartProgram(false);
  421. Add([
  422. '{$mode delphi}',
  423. 'type',
  424. ' TObject = class end;',
  425. ' {#Typ}T = word;',
  426. ' TBird<{#Templ}T> = class',
  427. ' {=Templ}v: T;',
  428. ' end;',
  429. 'var',
  430. ' b: TBird<word>;',
  431. ' {=Typ}w: T;',
  432. 'begin',
  433. ' b.v:=w;',
  434. '']);
  435. ParseProgram;
  436. end;
  437. procedure TTestResolveGenerics.TestGen_ClassForward;
  438. begin
  439. StartProgram(false);
  440. Add([
  441. '{$mode objfpc}',
  442. 'type',
  443. ' TObject = class end;',
  444. ' {#Typ}T = word;',
  445. ' generic TBird<{#Templ_Forward}T> = class;',
  446. ' TRec = record',
  447. ' b: specialize TBird<T>;',
  448. ' end;',
  449. ' generic TBird<{#Templ}T> = class',
  450. ' {=Templ}v: T;',
  451. ' r: TRec;',
  452. ' end;',
  453. 'var',
  454. ' s: TRec;',
  455. ' {=Typ}w: T;',
  456. 'begin',
  457. ' s.b.v:=w;',
  458. ' s.b.r:=s;',
  459. '']);
  460. ParseProgram;
  461. end;
  462. procedure TTestResolveGenerics.TestGen_ClassForwardConstraints;
  463. begin
  464. StartProgram(false);
  465. Add([
  466. '{$mode objfpc}',
  467. 'type',
  468. ' TObject = class end;',
  469. ' TAnt = class end;',
  470. ' generic TBird<T: class; U; V: TAnt> = class;',
  471. ' TRec = record',
  472. ' b: specialize TBird<TAnt,word,TAnt>;',
  473. ' end;',
  474. ' generic TBird<T: class; U; V: TAnt> = class',
  475. ' i: U;',
  476. ' r: TRec;',
  477. ' end;',
  478. 'var',
  479. ' s: TRec;',
  480. ' w: word;',
  481. 'begin',
  482. ' s.b.i:=w;',
  483. ' s.b.r:=s;',
  484. '']);
  485. ParseProgram;
  486. end;
  487. procedure TTestResolveGenerics.TestGen_ClassForwardConstraintNameMismatch;
  488. begin
  489. StartProgram(false);
  490. Add([
  491. '{$mode objfpc}',
  492. 'type',
  493. ' TObject = class end;',
  494. ' generic TBird<T> = class;',
  495. ' generic TBird<U> = class',
  496. ' i: U;',
  497. ' end;',
  498. 'begin',
  499. '']);
  500. CheckResolverException('Declaration of "U" differs from previous declaration at afile.pp(5,18)',
  501. nDeclOfXDiffersFromPrevAtY);
  502. end;
  503. procedure TTestResolveGenerics.TestGen_ClassForwardConstraintKeywordMismatch;
  504. begin
  505. StartProgram(false);
  506. Add([
  507. '{$mode objfpc}',
  508. 'type',
  509. ' TObject = class end;',
  510. ' generic TBird<T: class, constructor> = class;',
  511. ' generic TBird<U: class> = class',
  512. ' i: U;',
  513. ' end;',
  514. 'begin',
  515. '']);
  516. CheckResolverException('Declaration of "U" differs from previous declaration at afile.pp(5,18)',
  517. nDeclOfXDiffersFromPrevAtY);
  518. end;
  519. procedure TTestResolveGenerics.TestGen_ClassForwardConstraintTypeMismatch;
  520. begin
  521. StartProgram(false);
  522. Add([
  523. '{$mode objfpc}',
  524. 'type',
  525. ' TObject = class end;',
  526. ' TAnt = class end;',
  527. ' TFish = class end;',
  528. ' generic TBird<T: TAnt> = class;',
  529. ' generic TBird<T: TFish> = class',
  530. ' i: U;',
  531. ' end;',
  532. 'begin',
  533. '']);
  534. CheckResolverException('Declaration of "T" differs from previous declaration at afile.pp(7,20)',
  535. nDeclOfXDiffersFromPrevAtY);
  536. end;
  537. procedure TTestResolveGenerics.TestGen_ClassForward_Circle;
  538. begin
  539. StartProgram(false);
  540. Add([
  541. '{$mode objfpc}',
  542. 'type',
  543. ' TObject = class end;',
  544. ' generic TAnt<T> = class;',
  545. ' generic TFish<U> = class',
  546. ' private type AliasU = U;',
  547. ' var a: TAnt<AliasU>;',
  548. ' Size: AliasU;',
  549. ' end;',
  550. ' generic TAnt<T> = class',
  551. ' private type AliasT = T;',
  552. ' var f: TFish<AliasT>;',
  553. ' Speed: AliasT;',
  554. ' end;',
  555. 'var',
  556. ' WordFish: specialize TFish<word>;',
  557. ' BoolAnt: specialize TAnt<boolean>;',
  558. ' w: word;',
  559. ' b: boolean;',
  560. 'begin',
  561. ' WordFish.Size:=w;',
  562. ' WordFish.a.Speed:=w;',
  563. ' WordFish.a.f.Size:=w;',
  564. ' BoolAnt.Speed:=b;',
  565. ' BoolAnt.f.Size:=b;',
  566. ' BoolAnt.f.a.Speed:=b;',
  567. '']);
  568. ParseProgram;
  569. end;
  570. procedure TTestResolveGenerics.TestGen_Class_RedeclareInUnitImplFail;
  571. begin
  572. StartUnit(false);
  573. Add([
  574. 'interface',
  575. 'type',
  576. ' TObject = class end;',
  577. ' generic TBird<T> = class v: T; end;',
  578. 'implementation',
  579. 'type generic TBird<T> = record v: T; end;',
  580. '']);
  581. CheckResolverException('Duplicate identifier "TBird" at afile.pp(5,16)',
  582. nDuplicateIdentifier);
  583. end;
  584. procedure TTestResolveGenerics.TestGen_Class_AnotherInUnitImpl;
  585. begin
  586. StartUnit(false);
  587. Add([
  588. 'interface',
  589. 'type',
  590. ' TObject = class end;',
  591. ' generic TBird<T> = class v: T; end;',
  592. 'implementation',
  593. 'type generic TBird<T,U> = record x: T; y: U; end;',
  594. '']);
  595. ParseUnit;
  596. end;
  597. procedure TTestResolveGenerics.TestGen_Class_Method;
  598. begin
  599. StartProgram(false);
  600. Add([
  601. '{$mode objfpc}',
  602. 'type',
  603. ' TObject = class end;',
  604. ' {#Typ}T = word;',
  605. ' generic TBird<{#Templ}T> = class',
  606. ' function Fly(p:T): T; virtual; abstract;',
  607. ' function Run(p:T): T;',
  608. ' end;',
  609. 'function TBird.Run(p:T): T;',
  610. 'begin',
  611. 'end;',
  612. 'var',
  613. ' b: specialize TBird<word>;',
  614. ' {=Typ}w: T;',
  615. 'begin',
  616. ' w:=b.Fly(w);',
  617. ' w:=b.Run(w);',
  618. '']);
  619. ParseProgram;
  620. end;
  621. procedure TTestResolveGenerics.TestGen_Class_MethodOverride;
  622. begin
  623. StartProgram(false);
  624. Add([
  625. '{$mode objfpc}',
  626. 'type',
  627. ' TObject = class end;',
  628. ' generic TBird<T> = class',
  629. ' function Fly(p:T): T; virtual; abstract;',
  630. ' end;',
  631. ' generic TEagle<S> = class(specialize TBird<S>)',
  632. ' function Fly(p:S): S; override;',
  633. ' end;',
  634. 'function TEagle.Fly(p:S): S;',
  635. 'begin',
  636. 'end;',
  637. 'var',
  638. ' e: specialize TEagle<word>;',
  639. ' w: word;',
  640. 'begin',
  641. ' w:=e.Fly(w);',
  642. '']);
  643. ParseProgram;
  644. end;
  645. procedure TTestResolveGenerics.TestGen_Class_MethodDelphi;
  646. begin
  647. StartProgram(false);
  648. Add([
  649. '{$mode delphi}',
  650. 'type',
  651. ' TObject = class end;',
  652. ' {#Typ}T = word;',
  653. ' TBird<{#Templ}T> = class',
  654. ' function Fly(p:T): T; virtual; abstract;',
  655. ' function Run(p:T): T;',
  656. ' end;',
  657. 'function TBird<T>.Run(p:T): T;',
  658. 'begin',
  659. 'end;',
  660. 'var',
  661. ' b: TBird<word>;',
  662. ' {=Typ}w: T;',
  663. 'begin',
  664. ' w:=b.Fly(w);',
  665. ' w:=b.Run(w);',
  666. '']);
  667. ParseProgram;
  668. end;
  669. procedure TTestResolveGenerics.TestGen_Class_SpecializeSelfInside;
  670. begin
  671. StartProgram(false);
  672. Add([
  673. '{$mode objfpc}',
  674. 'type',
  675. ' TObject = class end;',
  676. ' generic TBird<T> = class',
  677. ' e: T;',
  678. ' v: TBird<boolean>;',
  679. ' end;',
  680. 'var',
  681. ' b: specialize TBird<word>;',
  682. ' w: word;',
  683. 'begin',
  684. ' b.e:=w;',
  685. ' if b.v.e then ;',
  686. '']);
  687. ParseProgram;
  688. end;
  689. procedure TTestResolveGenerics.TestGen_Class_GenAncestor;
  690. begin
  691. StartProgram(false);
  692. Add([
  693. '{$mode objfpc}',
  694. 'type',
  695. ' TObject = class end;',
  696. ' generic TBird<T> = class',
  697. ' i: T;',
  698. ' end;',
  699. ' generic TEagle<T> = class(TBird<T>)',
  700. ' j: T;',
  701. ' end;',
  702. 'var',
  703. ' e: specialize TEagle<word>;',
  704. 'begin',
  705. ' e.i:=e.j;',
  706. '']);
  707. ParseProgram;
  708. end;
  709. procedure TTestResolveGenerics.TestGen_Class_AncestorSelfFail;
  710. begin
  711. StartProgram(false);
  712. Add([
  713. '{$mode objfpc}',
  714. 'type',
  715. ' TObject = class end;',
  716. ' generic TBird<T> = class(TBird<word>)',
  717. ' e: T;',
  718. ' end;',
  719. 'var',
  720. ' b: specialize TBird<word>;',
  721. 'begin',
  722. '']);
  723. CheckResolverException('type "TBird<>" is not yet completely defined',nTypeXIsNotYetCompletelyDefined);
  724. end;
  725. procedure TTestResolveGenerics.TestGen_ClassOfSpecializeFail;
  726. begin
  727. StartProgram(false);
  728. Add([
  729. '{$mode objfpc}',
  730. 'type',
  731. ' TObject = class end;',
  732. ' generic TBird<T> = class',
  733. ' e: T;',
  734. ' end;',
  735. ' TBirdClass = class of specialize TBird<word>;',
  736. 'begin',
  737. '']);
  738. CheckParserException('Expected "Identifier" at token "specialize" in file afile.pp at line 8 column 25',nParserExpectTokenError);
  739. end;
  740. procedure TTestResolveGenerics.TestGen_Class_NestedType;
  741. begin
  742. StartProgram(false);
  743. Add([
  744. '{$mode objfpc}',
  745. 'type',
  746. ' TObject = class end;',
  747. ' generic TBird<T> = class',
  748. ' public type',
  749. ' TArrayEvent = reference to procedure(El: T);',
  750. ' public',
  751. ' p: TArrayEvent;',
  752. ' end;',
  753. ' TBirdWord = specialize TBird<word>;',
  754. 'var',
  755. ' b: TBirdWord;',
  756. 'begin',
  757. ' b.p:=procedure(El: word) begin end;']);
  758. ParseProgram;
  759. end;
  760. procedure TTestResolveGenerics.TestGen_Class_NestedRecord;
  761. begin
  762. StartProgram(false);
  763. Add([
  764. '{$mode objfpc}',
  765. '{$modeswitch advancedrecords}',
  766. 'type',
  767. ' TObject = class end;',
  768. ' generic TBird<T> = class',
  769. ' public type TWing = record',
  770. ' s: T;',
  771. ' function GetIt: T;',
  772. ' end;',
  773. ' public',
  774. ' w: TWing;',
  775. ' end;',
  776. ' TBirdWord = specialize TBird<word>;',
  777. 'function TBird.TWing.GetIt: T;',
  778. 'begin',
  779. 'end;',
  780. 'var',
  781. ' b: TBirdWord;',
  782. ' i: word;',
  783. 'begin',
  784. ' b.w.s:=i;',
  785. ' i:=b.w.GetIt;',
  786. '']);
  787. ParseProgram;
  788. end;
  789. procedure TTestResolveGenerics.TestGen_Class_NestedClass;
  790. begin
  791. StartProgram(false);
  792. Add([
  793. '{$mode objfpc}',
  794. 'type',
  795. ' TObject = class end;',
  796. ' generic TBird<T> = class',
  797. ' public type TWing = class',
  798. ' s: T;',
  799. ' function GetIt: T;',
  800. ' end;',
  801. ' public',
  802. ' w: TWing;',
  803. ' end;',
  804. ' TBirdWord = specialize TBird<word>;',
  805. 'function TBird.TWing.GetIt: T;',
  806. 'begin',
  807. 'end;',
  808. 'var',
  809. ' b: TBirdWord;',
  810. ' i: word;',
  811. 'begin',
  812. ' b.w.s:=3;',
  813. ' i:=b.w.GetIt;',
  814. '']);
  815. ParseProgram;
  816. end;
  817. procedure TTestResolveGenerics.TestGen_Class_Enums_NotPropagating;
  818. begin
  819. StartProgram(false);
  820. Add([
  821. '{$mode objfpc}',
  822. 'type',
  823. ' TObject = class end;',
  824. ' generic TBird<T> = class',
  825. ' public type',
  826. ' TEnum = (red, blue);',
  827. ' const',
  828. ' e = blue;',
  829. ' end;',
  830. 'const',
  831. ' r = red;',
  832. 'begin']);
  833. CheckResolverException('identifier not found "red"',nIdentifierNotFound);
  834. end;
  835. procedure TTestResolveGenerics.TestGen_Class_List;
  836. begin
  837. StartProgram(false);
  838. Add([
  839. '{$mode objfpc}',
  840. 'type',
  841. ' TObject = class end;',
  842. ' generic TList<T> = class',
  843. ' strict private',
  844. ' FItems: array of T;',
  845. ' function GetItems(Index: longint): T;',
  846. ' procedure SetItems(Index: longint; Value: T);',
  847. ' public',
  848. ' procedure Alter(w: T);',
  849. ' property Items[Index: longint]: T read GetItems write SetItems; default;',
  850. ' end;',
  851. ' TWordList = specialize TList<word>;',
  852. 'function TList.GetItems(Index: longint): T;',
  853. 'begin',
  854. ' Result:=FItems[Index];',
  855. 'end;',
  856. 'procedure TList.SetItems(Index: longint; Value: T);',
  857. 'begin',
  858. ' FItems[Index]:=Value;',
  859. 'end;',
  860. 'procedure TList.Alter(w: T);',
  861. 'begin',
  862. ' SetLength(FItems,length(FItems)+1);',
  863. ' Insert(w,FItems,2);',
  864. ' Delete(FItems,2,3);',
  865. 'end;',
  866. 'var l: TWordList;',
  867. ' w: word;',
  868. 'begin',
  869. ' l[1]:=w;',
  870. ' w:=l[2];']);
  871. ParseProgram;
  872. end;
  873. procedure TTestResolveGenerics.TestGen_ExtClass_Array;
  874. begin
  875. StartProgram(false);
  876. Add([
  877. '{$mode delphi}',
  878. '{$ModeSwitch externalclass}',
  879. 'type',
  880. ' NativeInt = longint;',
  881. ' TJSGenArray<T> = Class external name ''Array''',
  882. ' private',
  883. ' function GetElements(Index: NativeInt): T; external name ''[]'';',
  884. ' procedure SetElements(Index: NativeInt; const AValue: T); external name ''[]'';',
  885. ' public',
  886. ' type TSelfType = TJSGenArray<T>;',
  887. ' TArrayEvent = reference to function(El: T; Arr: TSelfType): Boolean;',
  888. ' TArrayCallback = TArrayEvent;',
  889. ' public',
  890. ' FLength : NativeInt; external name ''length'';',
  891. ' constructor new; overload;',
  892. ' constructor new(aLength : NativeInt); overload;',
  893. ' class function _of() : TSelfType; varargs; external name ''of'';',
  894. ' function every(const aCallback: TArrayCallBack): boolean; overload;',
  895. ' function fill(aValue : T) : TSelfType; overload;',
  896. ' function fill(aValue : T; aStartIndex : NativeInt) : TSelfType; overload;',
  897. ' function fill(aValue : T; aStartIndex,aEndIndex : NativeInt) : TSelfType; overload;',
  898. ' property Length : NativeInt Read FLength Write FLength;',
  899. ' property Elements[Index: NativeInt]: T read GetElements write SetElements; default;',
  900. ' end;',
  901. ' TJSWordArray = TJSGenArray<word>;',
  902. 'var',
  903. ' wa: TJSWordArray;',
  904. ' w: word;',
  905. 'begin',
  906. ' wa:=TJSWordArray.new;',
  907. ' wa:=TJSWordArray.new(3);',
  908. ' wa:=TJSWordArray._of(4,5);',
  909. ' wa:=wa.fill(7);',
  910. ' wa:=wa.fill(7,8,9);',
  911. ' w:=wa.length;',
  912. ' wa.length:=10;',
  913. ' wa[11]:=w;',
  914. ' w:=wa[12];',
  915. ' wa.every(function(El: word; Arr: TJSWordArray): Boolean',
  916. ' begin',
  917. ' end',
  918. ' );',
  919. '']);
  920. ParseProgram;
  921. end;
  922. procedure TTestResolveGenerics.TestGen_ClassInterface;
  923. begin
  924. StartProgram(false);
  925. Add([
  926. 'type',
  927. ' {$interfaces corba}',
  928. ' generic ICorbaIntf<T> = interface',
  929. ' procedure Fly(a: T);',
  930. ' end;',
  931. ' {$interfaces com}',
  932. ' IUnknown = interface',
  933. ' end;',
  934. ' IInterface = IUnknown;',
  935. ' generic IComIntf<T> = interface',
  936. ' procedure Run(b: T);',
  937. ' end;',
  938. 'begin']);
  939. ParseProgram;
  940. end;
  941. procedure TTestResolveGenerics.TestGen_ClassInterface_Method;
  942. begin
  943. StartProgram(false);
  944. Add([
  945. 'type',
  946. ' {$interfaces corba}',
  947. ' generic IBird<T> = interface',
  948. ' procedure Fly(a: T);',
  949. ' end;',
  950. ' TObject = class end;',
  951. ' generic TBird<U> = class(IBird<U>)',
  952. ' procedure Fly(a: U);',
  953. ' end;',
  954. 'procedure TBird.Fly(a: U);',
  955. 'begin',
  956. 'end;',
  957. 'var b: specialize IBird<word>;',
  958. 'begin',
  959. ' b.Fly(3);']);
  960. ParseProgram;
  961. end;
  962. procedure TTestResolveGenerics.TestGen_Array;
  963. begin
  964. StartProgram(false);
  965. Add([
  966. 'type',
  967. ' generic TArray<T> = array of T;',
  968. ' TWordArray = specialize TArray<word>;',
  969. 'var',
  970. ' a: specialize TArray<word>;',
  971. ' b: TWordArray;',
  972. ' w: word;',
  973. 'begin',
  974. ' a[1]:=2;',
  975. ' b[2]:=a[3]+b[4];',
  976. ' a:=b;',
  977. ' b:=a;',
  978. ' SetLength(a,5);',
  979. ' SetLength(b,6);',
  980. '']);
  981. ParseProgram;
  982. end;
  983. procedure TTestResolveGenerics.TestGen_ProcType;
  984. begin
  985. StartProgram(false);
  986. Add([
  987. 'type',
  988. ' generic TFunc<T> = function(v: T): T;',
  989. ' TWordFunc = specialize TFunc<word>;',
  990. 'function GetIt(w: word): word;',
  991. 'begin',
  992. 'end;',
  993. 'var',
  994. ' a: specialize TFunc<word>;',
  995. ' b: TWordFunc;',
  996. ' w: word;',
  997. 'begin',
  998. ' a:=nil;',
  999. ' b:=nil;',
  1000. ' a:=b;',
  1001. ' b:=a;',
  1002. ' w:=a(w);',
  1003. ' w:=b(w);',
  1004. ' a:=@GetIt;',
  1005. ' b:=@GetIt;',
  1006. '']);
  1007. ParseProgram;
  1008. end;
  1009. procedure TTestResolveGenerics.TestGen_PointerDirectSpecializeFail;
  1010. begin
  1011. StartProgram(false);
  1012. Add([
  1013. 'type',
  1014. ' generic TRec<T> = record v: T; end;',
  1015. ' PRec = ^specialize TRec<word>;',
  1016. 'begin',
  1017. '']);
  1018. CheckParserException('Expected "Identifier" at token "specialize" in file afile.pp at line 4 column 11',nParserExpectTokenError);
  1019. end;
  1020. procedure TTestResolveGenerics.TestGen_GenericFunction;
  1021. begin
  1022. exit;
  1023. StartProgram(false);
  1024. Add([
  1025. 'generic function DoIt<T>(a: T): T;',
  1026. 'var i: T;',
  1027. 'begin',
  1028. ' a:=i;',
  1029. ' Result:=a;',
  1030. 'end;',
  1031. 'var w: word;',
  1032. 'begin',
  1033. //' w:=DoIt<word>(3);',
  1034. '']);
  1035. ParseProgram;
  1036. end;
  1037. procedure TTestResolveGenerics.TestGen_LocalVar;
  1038. begin
  1039. StartProgram(false);
  1040. Add([
  1041. '{$mode objfpc}',
  1042. 'type',
  1043. ' TObject = class end;',
  1044. ' generic TBird<{#Templ}T> = class',
  1045. ' function Fly(p:T): T;',
  1046. ' end;',
  1047. 'function TBird.Fly(p:T): T;',
  1048. 'var l: T;',
  1049. 'begin',
  1050. ' l:=p;',
  1051. ' p:=l;',
  1052. ' Result:=p;',
  1053. ' Result:=l;',
  1054. ' l:=Result;',
  1055. 'end;',
  1056. 'var',
  1057. ' b: specialize TBird<word>;',
  1058. ' w: word;',
  1059. 'begin',
  1060. ' w:=b.Fly(w);',
  1061. '']);
  1062. ParseProgram;
  1063. end;
  1064. procedure TTestResolveGenerics.TestGen_Statements;
  1065. begin
  1066. StartProgram(false);
  1067. Add([
  1068. '{$mode objfpc}',
  1069. 'type',
  1070. ' TObject = class end;',
  1071. ' generic TBird<{#Templ}T> = class',
  1072. ' function Fly(p:T): T;',
  1073. ' end;',
  1074. 'function TBird.Fly(p:T): T;',
  1075. 'var',
  1076. ' v1,v2,v3:T;',
  1077. 'begin',
  1078. ' v1:=1;',
  1079. ' v2:=v1+v1*v1+v1 div p;',
  1080. ' v3:=-v1;',
  1081. ' repeat',
  1082. ' v1:=v1+1;',
  1083. ' until v1>=5;',
  1084. ' while v1>=0 do',
  1085. ' v1:=v1-v2;',
  1086. ' for v1:=v2 to v3 do v2:=v1;',
  1087. ' if v1<v2 then v3:=v1 else v3:=v2;',
  1088. ' if v1<v2 then else ;',
  1089. ' case v1 of',
  1090. ' 1: v3:=3;',
  1091. ' end;',
  1092. 'end;',
  1093. 'var',
  1094. ' b: specialize TBird<word>;',
  1095. 'begin',
  1096. ' b.Fly(2);',
  1097. '']);
  1098. ParseProgram;
  1099. end;
  1100. procedure TTestResolveGenerics.TestGen_InlineSpecializeExpr;
  1101. begin
  1102. StartProgram(false);
  1103. Add([
  1104. '{$mode objfpc}',
  1105. 'type',
  1106. ' TObject = class end;',
  1107. ' generic TBird<T> = class',
  1108. ' constructor Create;',
  1109. ' end;',
  1110. ' generic TAnt<U> = class',
  1111. ' constructor Create;',
  1112. ' end;',
  1113. 'constructor TBird.Create;',
  1114. 'var',
  1115. ' a: TAnt<T>;',
  1116. ' b: TAnt<word>;',
  1117. 'begin',
  1118. ' a:=TAnt<T>.create;',
  1119. ' b:=TAnt<word>.create;',
  1120. 'end;',
  1121. 'constructor TAnt.Create;',
  1122. 'var',
  1123. ' i: TBird<U>;',
  1124. ' j: TBird<word>;',
  1125. ' k: TAnt<U>;',
  1126. 'begin',
  1127. ' i:=TBird<U>.create;',
  1128. ' j:=TBird<word>.create;',
  1129. ' k:=TAnt<U>.create;',
  1130. 'end;',
  1131. 'var a: TAnt<word>;',
  1132. 'begin',
  1133. ' a:=TAnt<word>.create;',
  1134. '']);
  1135. ParseProgram;
  1136. end;
  1137. procedure TTestResolveGenerics.TestGen_TryExcept;
  1138. begin
  1139. StartProgram(false);
  1140. Add([
  1141. '{$mode objfpc}',
  1142. 'type',
  1143. ' TObject = class end;',
  1144. ' generic TBird<{#Templ}T> = class',
  1145. ' function Fly(p:T): T;',
  1146. ' end;',
  1147. ' Exception = class',
  1148. ' end;',
  1149. ' generic EMsg<T> = class',
  1150. ' Msg: T;',
  1151. ' end;',
  1152. 'function TBird.Fly(p:T): T;',
  1153. 'var',
  1154. ' v1,v2,v3:T;',
  1155. 'begin',
  1156. ' try',
  1157. ' finally',
  1158. ' end;',
  1159. ' try',
  1160. ' v1:=v2;',
  1161. ' finally',
  1162. ' v2:=v1;',
  1163. ' end;',
  1164. ' try',
  1165. ' except',
  1166. ' on Exception do ;',
  1167. ' on E: Exception do ;',
  1168. ' on E: EMsg<boolean> do E.Msg:=true;',
  1169. ' on E: EMsg<T> do E.Msg:=1;',
  1170. ' end;',
  1171. 'end;',
  1172. 'var',
  1173. ' b: specialize TBird<word>;',
  1174. 'begin',
  1175. ' b.Fly(2);',
  1176. '']);
  1177. ParseProgram;
  1178. end;
  1179. initialization
  1180. RegisterTests([TTestResolveGenerics]);
  1181. end.