From fa41b6ffe382bfb75d6b28c48227230e3c20b01b Mon Sep 17 00:00:00 2001 From: paul <paul@idefix.freepascal.org> Date: Tue, 4 Jan 2011 18:20:40 +0000 Subject: [PATCH] compiler: allow generic classes to derive from generic classes and generic interfaces - change id_type to single_type in readImplementedInterfacesAndProtocols to allow use of interface specializations inside class parent block - change single_type boolean arguments to set, add stoParseClassParent option to that set - move parse_generic variable assignment from parse_object_members to outer routine to setup it before parsing class parents - return paticular generic in generate_specialization instead of undefineddef to pass class/interface checks inside parent class block - add test for delphi mode - modify tw11431 to be syntatically correct git-svn-id: trunk@16706 - --- .gitattributes | 1 + compiler/pdecobj.pas | 23 ++++++++++---------- compiler/pdecsub.pas | 8 +++---- compiler/pdecvar.pas | 8 +++---- compiler/ptype.pas | 45 ++++++++++++++++++++++++---------------- tests/test/tgeneric29.pp | 39 ++++++++++++++++++++++++++++++++++ tests/webtbs/tw11431.pp | 2 +- 7 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 tests/test/tgeneric29.pp diff --git a/.gitattributes b/.gitattributes index 081fdf1794..79ac491bd6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9418,6 +9418,7 @@ tests/test/tgeneric25.pp svneol=native#text/pascal tests/test/tgeneric26.pp svneol=native#text/pascal tests/test/tgeneric27.pp svneol=native#text/pascal tests/test/tgeneric28.pp svneol=native#text/pascal +tests/test/tgeneric29.pp svneol=native#text/pascal tests/test/tgeneric3.pp svneol=native#text/plain tests/test/tgeneric4.pp svneol=native#text/plain tests/test/tgeneric5.pp svneol=native#text/plain diff --git a/compiler/pdecobj.pas b/compiler/pdecobj.pas index 07cc077815..d900674618 100644 --- a/compiler/pdecobj.pas +++ b/compiler/pdecobj.pas @@ -306,7 +306,8 @@ implementation begin while try_to_consume(_COMMA) do begin - id_type(hdef,false); + { use single_type instead of id_type for specialize support } + single_type(hdef,[stoAllowTypeDef,stoParseClassParent]); if (hdef.typ<>objectdef) then begin if intf then @@ -442,7 +443,7 @@ implementation begin consume(_LKLAMMER); { use single_type instead of id_type for specialize support } - single_type(hdef,false,false); + single_type(hdef,[stoAllowTypeDef, stoParseClassParent]); if (not assigned(hdef)) or (hdef.typ<>objectdef) then begin @@ -662,8 +663,7 @@ implementation var pd : tprocdef; has_destructor, - oldparse_only, - old_parse_generic: boolean; + oldparse_only: boolean; object_member_blocktype : tblock_type; fields_allowed, is_classdef, classfields: boolean; vdoptions: tvar_dec_options; @@ -673,9 +673,6 @@ implementation (token=_SEMICOLON) then exit; - old_parse_generic:=parse_generic; - - parse_generic:=(df_generic in current_structdef.defoptions); { in "publishable" classes the default access type is published } if (oo_can_have_published in current_structdef.objectoptions) then current_structdef.symtable.currentvisibility:=vis_published @@ -1016,9 +1013,6 @@ implementation consume(_ID); { Give a ident expected message, like tp7 } end; until false; - - { restore } - parse_generic:=old_parse_generic; end; @@ -1027,10 +1021,12 @@ implementation old_current_structdef: tabstractrecorddef; old_current_genericdef, old_current_specializedef: tstoreddef; + old_parse_generic: boolean; begin old_current_structdef:=current_structdef; old_current_genericdef:=current_genericdef; old_current_specializedef:=current_specializedef; + old_parse_generic:=parse_generic; current_structdef:=nil; current_genericdef:=nil; @@ -1129,14 +1125,16 @@ implementation if not(objecttype in [odt_objcclass,odt_objcprotocol,odt_objccategory]) then parse_object_options; + symtablestack.push(current_structdef.symtable); + insert_generic_parameter_types(current_structdef,genericdef,genericlist); + parse_generic:=(df_generic in current_structdef.defoptions); + { parse list of parent classes } parse_parent_classes; { parse optional GUID for interfaces } parse_guid; - symtablestack.push(current_structdef.symtable); - insert_generic_parameter_types(current_structdef,genericdef,genericlist); { parse and insert object members } parse_object_members; symtablestack.pop(current_structdef.symtable); @@ -1171,6 +1169,7 @@ implementation current_structdef:=old_current_structdef; current_genericdef:=old_current_genericdef; current_specializedef:=old_current_specializedef; + parse_generic:=old_parse_generic; end; end. diff --git a/compiler/pdecsub.pas b/compiler/pdecsub.pas index 71507e8784..dd5cbfb035 100644 --- a/compiler/pdecsub.pas +++ b/compiler/pdecsub.pas @@ -593,7 +593,7 @@ implementation begin block_type:=bt_var_type; consume(_COLON); - single_type(pv.returndef,false,false); + single_type(pv.returndef,[]); block_type:=bt_var; end; hdef:=pv; @@ -641,7 +641,7 @@ implementation else begin { define field type } - single_type(arrayelementdef,false,false); + single_type(arrayelementdef,[]); tarraydef(hdef).elementdef:=arrayelementdef; end; end @@ -655,7 +655,7 @@ implementation else begin block_type:=bt_var_type; - single_type(hdef,false,false); + single_type(hdef,[]); block_type:=bt_var; end; @@ -1211,7 +1211,7 @@ implementation if assigned(current_structdef) and (df_specialization in current_structdef.defoptions) then current_specializedef:=current_structdef; end; - single_type(pd.returndef,false,false); + single_type(pd.returndef,[]); if is_dispinterface(pd.struct) and not is_automatable(pd.returndef) then Message1(type_e_not_automatable,pd.returndef.typename); diff --git a/compiler/pdecvar.pas b/compiler/pdecvar.pas index 6dff496bd8..ed60bf3d8f 100644 --- a/compiler/pdecvar.pas +++ b/compiler/pdecvar.pas @@ -384,11 +384,11 @@ implementation { define range and type of range } hdef:=tarraydef.create(0,-1,s32inttype); { define field type } - single_type(arraytype,false,false); + single_type(arraytype,[]); tarraydef(hdef).elementdef:=arraytype; end else - single_type(hdef,false,false); + single_type(hdef,[]); end else hdef:=cformaltype; @@ -417,7 +417,7 @@ implementation if (token=_COLON) or (paranr>0) or (astruct=nil) then begin consume(_COLON); - single_type(p.propdef,false,false); + single_type(p.propdef,[]); if is_dispinterface(astruct) and not is_automatable(p.propdef) then Message1(type_e_not_automatable,p.propdef.typename); @@ -728,7 +728,7 @@ implementation { Parse possible "implements" keyword } if not is_record(astruct) and try_to_consume(_IMPLEMENTS) then begin - single_type(def,false,false); + single_type(def,[]); if not(is_interface(def)) then message(parser_e_class_implements_must_be_interface); diff --git a/compiler/ptype.pas b/compiler/ptype.pas index e2fff9ad9c..b253f00cba 100644 --- a/compiler/ptype.pas +++ b/compiler/ptype.pas @@ -29,13 +29,17 @@ interface globtype,cclasses, symtype,symdef,symbase; + type + TSingleTypeOption=(stoIsForwardDef,stoAllowTypeDef,stoParseClassParent); + TSingleTypeOptions=set of TSingleTypeOption; + procedure resolve_forward_types; { reads a type identifier } procedure id_type(var def : tdef;isforwarddef:boolean); { reads a string, file type or a type identifier } - procedure single_type(var def:tdef;isforwarddef,allowtypedef:boolean); + procedure single_type(var def:tdef;options:TSingleTypeOptions); { reads any type declaration, where the resulting type will get name as type identifier } procedure read_named_type(var def:tdef;const name : TIDString;genericdef:tstoreddef;genericlist:TFPObjectList;parseprocvardir:boolean); @@ -136,7 +140,7 @@ implementation end; - procedure generate_specialization(var tt:tdef); + procedure generate_specialization(var tt:tdef;parse_class_parent:boolean); var st : TSymtable; srsym : tsym; @@ -177,6 +181,8 @@ implementation of generic and specialization might not be equally sized which is later assumed } tt:=tundefineddef.create; + if parse_class_parent then + tt:=genericdef; onlyparsepara:=true; end; @@ -438,7 +444,7 @@ implementation end; - procedure single_type(var def:tdef;isforwarddef,allowtypedef:boolean); + procedure single_type(var def:tdef;options:TSingleTypeOptions); var t2 : tdef; dospecialize, @@ -449,17 +455,17 @@ implementation again:=false; case token of _STRING: - string_dec(def,allowtypedef); + string_dec(def,stoAllowTypeDef in options); _FILE: begin consume(_FILE); if (token=_OF) then begin - if not(allowtypedef) then + if not(stoAllowTypeDef in options) then Message(parser_e_no_local_para_def); consume(_OF); - single_type(t2,false,false); + single_type(t2,[]); if is_managed_type(t2) then Message(parser_e_no_refcounted_typed_file); def:=tfiledef.createtyped(t2); @@ -472,7 +478,7 @@ implementation begin if try_to_consume(_SPECIALIZE) then begin - if not(allowtypedef) then + if not(stoAllowTypeDef in options) then begin Message(parser_e_no_local_para_def); @@ -489,7 +495,7 @@ implementation end else begin - id_type(def,isforwarddef); + id_type(def,stoIsForwardDef in options); { handle types inside classes, e.g. TNode.TLongint } while (token=_POINT) do begin @@ -502,7 +508,7 @@ implementation begin symtablestack.push(tabstractrecorddef(def).symtable); consume(_POINT); - id_type(t2,isforwarddef); + id_type(t2,stoIsForwardDef in options); symtablestack.pop(tabstractrecorddef(def).symtable); def:=t2; end @@ -519,8 +525,10 @@ implementation end; end; until not again; + if (stoAllowTypeDef in options)and(m_delphi in current_settings.modeswitches) then + dospecialize:=token=_LSHARPBRACKET; if dospecialize then - generate_specialization(def) + generate_specialization(def,stoParseClassParent in options) else begin if assigned(current_specializedef) and (def=current_specializedef.genericdef) then @@ -990,7 +998,7 @@ implementation if (m_delphi in current_settings.modeswitches) then dospecialize:=token=_LSHARPBRACKET; if dospecialize then - generate_specialization(def) + generate_specialization(def,false) else begin if assigned(current_specializedef) and (def=current_specializedef.genericdef) then @@ -1236,7 +1244,8 @@ implementation current_genericdef:=old_current_genericdef; current_specializedef:=old_current_specializedef; end; - + const + SingleTypeOptionsInTypeBlock:array[Boolean] of TSingleTypeOptions = ([],[stoIsForwardDef]); var p : tnode; hdef : tdef; @@ -1254,7 +1263,7 @@ implementation case token of _STRING,_FILE: begin - single_type(def,false,true); + single_type(def,[stoAllowTypeDef]); end; _LKLAMMER: begin @@ -1362,7 +1371,7 @@ implementation _CARET: begin consume(_CARET); - single_type(tt2,(block_type=bt_type),false); + single_type(tt2,SingleTypeOptionsInTypeBlock[block_type=bt_type]); def:=tpointerdef.create(tt2); if tt2.typ=forwarddef then current_module.checkforwarddefs.add(def); @@ -1383,7 +1392,7 @@ implementation else if token=_SET then set_dec else if token=_FILE then - single_type(def,false,true) + single_type(def,[stoAllowTypeDef]) else begin oldpackrecords:=current_settings.packrecords; @@ -1429,7 +1438,7 @@ implementation ) then begin consume(_OF); - single_type(hdef,(block_type=bt_type),false); + single_type(hdef,SingleTypeOptionsInTypeBlock[block_type=bt_type]); if is_class(hdef) or is_objcclass(hdef) then def:=tclassrefdef.create(hdef) @@ -1502,7 +1511,7 @@ implementation if is_func then begin consume(_COLON); - single_type(pd.returndef,false,false); + single_type(pd.returndef,[]); end; if try_to_consume(_OF) then begin @@ -1536,7 +1545,7 @@ implementation if (token=_KLAMMERAFFE) and (m_iso in current_settings.modeswitches) then begin consume(_KLAMMERAFFE); - single_type(tt2,(block_type=bt_type),false); + single_type(tt2,SingleTypeOptionsInTypeBlock[block_type=bt_type]); def:=tpointerdef.create(tt2); if tt2.typ=forwarddef then current_module.checkforwarddefs.add(def); diff --git a/tests/test/tgeneric29.pp b/tests/test/tgeneric29.pp new file mode 100644 index 0000000000..141210d755 --- /dev/null +++ b/tests/test/tgeneric29.pp @@ -0,0 +1,39 @@ +program tgeneric29; + +{$mode delphi} + +type + IGenericInterface<T> = interface + function DoSomething(Arg: T): T; + end; + + TGenericClass<T> = class(TInterfacedObject, IGenericInterface<T>) + F: T; + type + Intf = IGenericInterface<Integer>; + function DoSomething(Arg: T): T; + function Test(Arg: Intf): Intf; + end; + + TGenericRecord<T> = record + F: T; + end; + + TGenericArray<T> = array of T; + +function TGenericClass{<T>}.DoSomething(Arg: T): T; +begin + Result := Arg; +end; + +function TGenericClass{<T>}.Test(Arg: Intf): Intf; +begin + Result := Arg; +end; + +var + ClassSpecialize: TGenericClass<Integer>; + RecordSpecialize: TGenericRecord<Integer>; + ArraySpecialize: TGenericArray<Integer>; +begin +end. diff --git a/tests/webtbs/tw11431.pp b/tests/webtbs/tw11431.pp index e2dd238c2f..21965f8e5c 100644 --- a/tests/webtbs/tw11431.pp +++ b/tests/webtbs/tw11431.pp @@ -10,7 +10,7 @@ type generic IGenericCollection<_T> = interface end; - generic CGenericCollection<_T> = class( IGenericCollection) + generic CGenericCollection<_T> = class(TInterfacedObject, specialize IGenericCollection<_T>) end; implementation