diff --git a/.gitattributes b/.gitattributes index 55923ebf77..67eebf1dbc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10808,6 +10808,42 @@ tests/test/tfpu5.pp svneol=native#text/plain tests/test/tfpuover.pp svneol=native#text/plain tests/test/tfwork1.pp svneol=native#text/plain tests/test/tfwork2.pp svneol=native#text/plain +tests/test/tgenconstraint1.pp svneol=native#text/pascal +tests/test/tgenconstraint10.pp svneol=native#text/pascal +tests/test/tgenconstraint11.pp svneol=native#text/pascal +tests/test/tgenconstraint12.pp svneol=native#text/pascal +tests/test/tgenconstraint13.pp svneol=native#text/pascal +tests/test/tgenconstraint14.pp svneol=native#text/pascal +tests/test/tgenconstraint15.pp svneol=native#text/pascal +tests/test/tgenconstraint16.pp svneol=native#text/pascal +tests/test/tgenconstraint17.pp svneol=native#text/pascal +tests/test/tgenconstraint18.pp svneol=native#text/pascal +tests/test/tgenconstraint19.pp svneol=native#text/pascal +tests/test/tgenconstraint2.pp svneol=native#text/pascal +tests/test/tgenconstraint20.pp svneol=native#text/pascal +tests/test/tgenconstraint21.pp svneol=native#text/pascal +tests/test/tgenconstraint22.pp svneol=native#text/pascal +tests/test/tgenconstraint23.pp svneol=native#text/pascal +tests/test/tgenconstraint24.pp svneol=native#text/pascal +tests/test/tgenconstraint25.pp svneol=native#text/pascal +tests/test/tgenconstraint26.pp svneol=native#text/pascal +tests/test/tgenconstraint27.pp svneol=native#text/pascal +tests/test/tgenconstraint28.pp svneol=native#text/pascal +tests/test/tgenconstraint29.pp svneol=native#text/pascal +tests/test/tgenconstraint3.pp svneol=native#text/pascal +tests/test/tgenconstraint30.pp svneol=native#text/pascal +tests/test/tgenconstraint31.pp svneol=native#text/pascal +tests/test/tgenconstraint32.pp svneol=native#text/pascal +tests/test/tgenconstraint33.pp svneol=native#text/pascal +tests/test/tgenconstraint34.pp svneol=native#text/pascal +tests/test/tgenconstraint35.pp svneol=native#text/pascal +tests/test/tgenconstraint36.pp svneol=native#text/pascal +tests/test/tgenconstraint4.pp svneol=native#text/pascal +tests/test/tgenconstraint5.pp svneol=native#text/pascal +tests/test/tgenconstraint6.pp svneol=native#text/pascal +tests/test/tgenconstraint7.pp svneol=native#text/pascal +tests/test/tgenconstraint8.pp svneol=native#text/pascal +tests/test/tgenconstraint9.pp svneol=native#text/pascal tests/test/tgeneric1.pp svneol=native#text/plain tests/test/tgeneric10.pp svneol=native#text/plain tests/test/tgeneric11.pp svneol=native#text/plain @@ -10944,6 +10980,7 @@ tests/test/thlp42.pp svneol=native#text/pascal tests/test/thlp43.pp svneol=native#text/pascal tests/test/thlp44.pp svneol=native#text/pascal tests/test/thlp45.pp svneol=native#text/pascal +tests/test/thlp46.pp svneol=native#text/pascal tests/test/thlp5.pp svneol=native#text/pascal tests/test/thlp6.pp svneol=native#text/pascal tests/test/thlp7.pp svneol=native#text/pascal @@ -11478,6 +11515,7 @@ tests/test/udots.prog.pp svneol=native#text/pascal tests/test/udots.test.pp svneol=native#text/pascal tests/test/uenum2a.pp svneol=native#text/plain tests/test/uenum2b.pp svneol=native#text/plain +tests/test/ugenconstraints.pas svneol=native#text/pascal tests/test/ugeneric.test75.pp svneol=native#text/pascal tests/test/ugeneric10.pp svneol=native#text/plain tests/test/ugeneric14.pp svneol=native#text/plain diff --git a/compiler/pdecl.pas b/compiler/pdecl.pas index cbab610dab..06a310233a 100644 --- a/compiler/pdecl.pas +++ b/compiler/pdecl.pas @@ -422,7 +422,7 @@ implementation Message(parser_f_no_generic_inside_generic); consume(_LSHARPBRACKET); - generictypelist:=parse_generic_parameters; + generictypelist:=parse_generic_parameters(true); consume(_RSHARPBRACKET); str(generictypelist.Count,s); diff --git a/compiler/pdecsub.pas b/compiler/pdecsub.pas index cc535eb552..ca360f109f 100644 --- a/compiler/pdecsub.pas +++ b/compiler/pdecsub.pas @@ -721,7 +721,7 @@ implementation consume(_LSHARPBRACKET); genparalist:=tfpobjectlist.create(false); - if not parse_generic_specialization_types(genparalist,prettyname,specializename,nil) then + if not parse_generic_specialization_types(genparalist,nil,prettyname,specializename) then srsym:=generrorsym else begin diff --git a/compiler/pexpr.pas b/compiler/pexpr.pas index 5c51458d1c..c39e88b233 100644 --- a/compiler/pexpr.pas +++ b/compiler/pexpr.pas @@ -3181,7 +3181,7 @@ implementation check_hints(parseddef.typesym,parseddef.typesym.symoptions,parseddef.typesym.deprecatedmsg); { generate the specialization } - generate_specialization(gendef,false,'',parseddef,gensym.RealName); + generate_specialization(gendef,false,'',parseddef,gensym.RealName,p2.fileinfo); { we don't need the old left and right nodes anymore } p1.Free; @@ -3272,7 +3272,7 @@ implementation Internalerror(2011071401); { generate the specialization } - generate_specialization(gendef,false,'',nil,''); + generate_specialization(gendef,false,''); { we don't need the old p2 anymore } p2.Free; diff --git a/compiler/pgenutil.pas b/compiler/pgenutil.pas index 1b41f3fb0e..4ec2dc752d 100644 --- a/compiler/pgenutil.pas +++ b/compiler/pgenutil.pas @@ -34,9 +34,10 @@ uses { symtable } symtype,symdef,symbase; - procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string); - function parse_generic_parameters:TFPObjectList; - function parse_generic_specialization_types(genericdeflist:tfpobjectlist;out prettyname,specializename:ansistring;parsedtype:tdef):boolean; + procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo); + procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string); + function parse_generic_parameters(allowconstraints:boolean):TFPObjectList; + function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean; procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList); procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist); function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring; @@ -97,7 +98,265 @@ uses end; end; - procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string); + function check_generic_constraints(genericdef:tstoreddef;paradeflist:tfpobjectlist;poslist:tfplist):boolean; + var + i,j, + intfcount : longint; + paradef : tstoreddef; + objdef, + paraobjdef, + formalobjdef : tobjectdef; + generictype : ttypesym; + intffound : boolean; + filepos : tfileposinfo; + begin + { check whether the given specialization parameters fit to the eventual + constraints of the generic } + if genericdef.genericparas.count=0 then + internalerror(2012101001); + if genericdef.genericparas.count<>paradeflist.count then + internalerror(2012101002); + if paradeflist.count<>poslist.count then + internalerror(2012120801); + result:=true; + for i:=0 to genericdef.genericparas.count-1 do + begin + generictype:=ttypesym(genericdef.genericparas[i]); + filepos:=pfileposinfo(poslist[i])^; + if not assigned(generictype.genconstraintdata) then + { the parameter is of unspecified type, so no need to check } + continue; + paradef:=tstoreddef(paradeflist[i]); + { undefineddef is compatible with anything } + if generictype.typedef.typ=undefineddef then + continue; + if paradef.typ<>generictype.typedef.typ then + begin + case generictype.typedef.typ of + recorddef: + MessagePos(filepos,type_e_record_type_expected); + objectdef: + case tobjectdef(generictype.typedef).objecttype of + odt_class, + odt_javaclass: + MessagePos1(filepos,type_e_class_type_expected,paradef.typename); + odt_interfacecom, + odt_interfacecorba, + odt_dispinterface, + odt_interfacejava: + MessagePos1(filepos,type_e_interface_type_expected,paradef.typename); + else + internalerror(2012101003); + end; + errordef: + { ignore } + ; + else + internalerror(2012101004); + end; + result:=false; + end + else + begin + { the paradef types are the same, so do special checks for the + cases in which they are needed } + if generictype.typedef.typ=objectdef then + begin + paraobjdef:=tobjectdef(paradef); + formalobjdef:=tobjectdef(generictype.typedef); + if not (formalobjdef.objecttype in [odt_class,odt_javaclass,odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_dispinterface]) then + internalerror(2012101102); + if formalobjdef.objecttype in [odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_dispinterface] then + begin + { this is either a concerete interface or class type (the + latter without specific implemented interfaces) } + case paraobjdef.objecttype of + odt_interfacecom, + odt_interfacecorba, + odt_interfacejava, + odt_dispinterface: + if not paraobjdef.is_related(formalobjdef) then + begin + MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.typename); + result:=false; + end; + odt_class, + odt_javaclass: + begin + objdef:=paraobjdef; + intffound:=false; + while assigned(objdef) do + begin + for j:=0 to objdef.implementedinterfaces.count-1 do + if timplementedinterface(objdef.implementedinterfaces[j]).intfdef=formalobjdef then + begin + intffound:=true; + break; + end; + if intffound then + break; + objdef:=objdef.childof; + end; + result:=intffound; + if not result then + MessagePos2(filepos,parser_e_class_doesnt_implement_interface,paraobjdef.typename,formalobjdef.typename); + end; + else + begin + MessagePos1(filepos,type_e_class_or_interface_type_expected,paraobjdef.typename); + result:=false; + end; + end; + end + else + if df_genconstraint in formalobjdef.defoptions then + begin + { this is either a "class" or a concrete instance + which shall implement interfaces } + if not (paraobjdef.objecttype in [odt_class,odt_javaclass]) then + begin + MessagePos1(filepos,type_e_class_type_expected,paraobjdef.typename); + result:=false; + continue; + end; + if assigned(formalobjdef.childof) and + not paradef.is_related(formalobjdef.childof) then + begin + MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.childof.typename); + result:=false; + end; + intfcount:=0; + for j:=0 to formalobjdef.implementedinterfaces.count-1 do + begin + objdef:=paraobjdef; + while assigned(objdef) do + begin + intffound:=assigned( + objdef.find_implemented_interface( + timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef + ) + ); + if intffound then + break; + objdef:=objdef.childof; + end; + if intffound then + inc(intfcount) + else + MessagePos2(filepos,parser_e_class_doesnt_implement_interface,paraobjdef.typename,timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef.typename); + end; + if intfcount<>formalobjdef.implementedinterfaces.count then + result:=false; + end + else + if not paraobjdef.is_related(formalobjdef) then + begin + MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.typename); + result:=false; + end; + end; + end; + end; + end; + + + function parse_generic_specialization_types_internal(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring;parsedtype:tdef;parsedpos:tfileposinfo):boolean; + var + old_block_type : tblock_type; + first : boolean; + typeparam : tnode; + parampos : pfileposinfo; + tmpparampos : tfileposinfo; + begin + result:=true; + if genericdeflist=nil then + internalerror(2012061401); + { set the block type to type, so that the parsed type are returned as + ttypenode (e.g. classes are in non type-compatible blocks returned as + tloadvmtaddrnode) } + old_block_type:=block_type; + { if parsedtype is set, then the first type identifer was already parsed + (happens in inline specializations) and thus we only need to parse + the remaining types and do as if the first one was already given } + first:=not assigned(parsedtype); + if assigned(parsedtype) then + begin + genericdeflist.Add(parsedtype); + specializename:='$'+parsedtype.typename; + prettyname:=parsedtype.typesym.prettyname; + if assigned(poslist) then + begin + New(parampos); + parampos^:=parsedpos; + poslist.add(parampos); + end; + end + else + begin + specializename:=''; + prettyname:=''; + end; + while not (token in [_GT,_RSHARPBRACKET]) do + begin + { "first" is set to false at the end of the loop! } + if not first then + consume(_COMMA); + block_type:=bt_type; + tmpparampos:=current_filepos; + typeparam:=factor(false,true); + if typeparam.nodetype=typen then + begin + if df_generic in typeparam.resultdef.defoptions then + Message(parser_e_no_generics_as_params); + if assigned(poslist) then + begin + New(parampos); + parampos^:=tmpparampos; + poslist.add(parampos); + end; + genericdeflist.Add(typeparam.resultdef); + if not assigned(typeparam.resultdef.typesym) then + message(type_e_generics_cannot_reference_itself) + else + begin + specializename:=specializename+'$'+typeparam.resultdef.typename; + if first then + prettyname:=prettyname+typeparam.resultdef.typesym.prettyname + else + prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname; + end; + end + else + begin + Message(type_e_type_id_expected); + result:=false; + end; + typeparam.free; + first:=false; + end; + block_type:=old_block_type; + end; + + + function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean; + var + dummypos : tfileposinfo; + begin + FillChar(dummypos, SizeOf(tfileposinfo), 0); + result:=parse_generic_specialization_types_internal(genericdeflist,poslist,prettyname,specializename,nil,dummypos); + end; + + + procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string); + var + dummypos : tfileposinfo; + begin + FillChar(dummypos, SizeOf(tfileposinfo), 0); + generate_specialization(tt,parse_class_parent,_prettyname,nil,'',dummypos); + end; + + + procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string;parsedpos:tfileposinfo); var st : TSymtable; srsym : tsym; @@ -108,7 +367,6 @@ uses errval, i, gencount : longint; - crc : cardinal; genericdef,def : tstoreddef; generictype : ttypesym; genericdeflist : TFPObjectList; @@ -127,6 +385,7 @@ uses state : tspecializationstate; hmodule : tmodule; oldcurrent_filepos : tfileposinfo; + poslist : tfplist; begin { retrieve generic def that we are going to replace } genericdef:=tstoreddef(tt); @@ -218,14 +477,19 @@ uses if not assigned(parsedtype) and not try_to_consume(_LT) then consume(_LSHARPBRACKET); - generictypelist:=TFPObjectList.create(false); genericdeflist:=TFPObjectList.Create(false); + poslist:=tfplist.create; { Parse type parameters } - err:=not parse_generic_specialization_types(genericdeflist,prettyname,specializename,parsedtype); + err:=not parse_generic_specialization_types_internal(genericdeflist,poslist,prettyname,specializename,parsedtype,parsedpos); if err then begin - try_to_consume(_RSHARPBRACKET); + if not try_to_consume(_GT) then + try_to_consume(_RSHARPBRACKET); + genericdeflist.free; + for i:=0 to poslist.count-1 do + dispose(pfileposinfo(poslist[i])); + poslist.free; tt:=generrordef; exit; end; @@ -295,8 +559,12 @@ uses if not found or (srsym.typ<>typesym) then begin identifier_not_found(genname); + if not try_to_consume(_GT) then + try_to_consume(_RSHARPBRACKET); + for i:=0 to poslist.count-1 do + dispose(pfileposinfo(poslist[i])); + poslist.free; genericdeflist.Free; - generictypelist.Free; tt:=generrordef; exit; end; @@ -304,6 +572,20 @@ uses { we've found the correct def } genericdef:=tstoreddef(ttypesym(srsym).typedef); + if not check_generic_constraints(genericdef,genericdeflist,poslist) then + begin + { the parameters didn't fit the constraints, so don't continue with the + specialization } + genericdeflist.free; + for i:=0 to poslist.count-1 do + dispose(pfileposinfo(poslist[i])); + poslist.free; + tt:=generrordef; + if not try_to_consume(_GT) then + try_to_consume(_RSHARPBRACKET); + exit; + end; + { build the new type's name } finalspecializename:=generate_generic_name(genname,specializename); ufinalspecializename:=upper(finalspecializename); @@ -324,6 +606,8 @@ uses internalerror(200511182); end; + generictypelist:=tfpobjectlist.create(false); + { build the list containing the types for the generic params } gencount:=0; for i:=0 to st.SymList.Count-1 do @@ -558,11 +842,19 @@ uses end; - function parse_generic_parameters:TFPObjectList; + function parse_generic_parameters(allowconstraints:boolean):TFPObjectList; var generictype : ttypesym; + i,firstidx : longint; + srsymtable : tsymtable; + def : tdef; + defname : tidstring; + allowconstructor, + doconsume : boolean; + constraintdata : tgenericconstraintdata; begin result:=TFPObjectList.Create(false); + firstidx:=0; repeat if token=_ID then begin @@ -571,70 +863,131 @@ uses result.add(generictype); end; consume(_ID); - until not try_to_consume(_COMMA) ; + if try_to_consume(_COLON) then + begin + if not allowconstraints then + { TODO } + Message(parser_e_illegal_expression{ parser_e_generic_constraints_not_allowed_here}); + { construct a name which can be used for a type specification } + constraintdata:=tgenericconstraintdata.create; + defname:=''; + str(current_module.deflist.count,defname); + defname:='$gendef'+defname; + + allowconstructor:=m_delphi in current_settings.modeswitches; + + constraintdata.basedef:=generrordef; + repeat + doconsume:=true; + + case token of + _CONSTRUCTOR: + begin + if not allowconstructor or (gcf_constructor in constraintdata.flags) then + Message(parser_e_illegal_expression); + include(constraintdata.flags,gcf_constructor); + allowconstructor:=false; + end; + _CLASS: + begin + if gcf_class in constraintdata.flags then + Message(parser_e_illegal_expression); + if constraintdata.basedef=generrordef then + include(constraintdata.flags,gcf_class) + else + Message(parser_e_illegal_expression); + end; + _RECORD: + begin + if ([gcf_constructor,gcf_class]*constraintdata.flags<>[]) + or (constraintdata.interfaces.count>0) then + Message(parser_e_illegal_expression) + else + begin + srsymtable:=trecordsymtable.create(defname,0); + constraintdata.basedef:=trecorddef.create(defname,srsymtable); + include(constraintdata.flags,gcf_record); + allowconstructor:=false; + end; + end; + else + begin + { after single_type "token" is the trailing ",", ";" or + ">"! } + doconsume:=false; + { def is already set to a class or record } + if gcf_record in constraintdata.flags then + Message(parser_e_illegal_expression); + single_type(def, [stoAllowSpecialization]); + { only types that are inheritable are allowed } + if (def.typ<>objectdef) or + not (tobjectdef(def).objecttype in [odt_class,odt_interfacecom,odt_interfacecorba,odt_interfacejava,odt_javaclass]) then + Message(type_e_class_or_interface_type_expected); + case tobjectdef(def).objecttype of + odt_class, + odt_javaclass: + begin + if gcf_class in constraintdata.flags then + { "class" + concrete class is not allowed } + Message(parser_e_illegal_expression) + else + { do we already have a concrete class? } + if constraintdata.basedef<>generrordef then + Message(parser_e_illegal_expression) + else + constraintdata.basedef:=def; + end; + odt_interfacecom, + odt_interfacecorba, + odt_interfacejava, + odt_dispinterface: + constraintdata.interfaces.add(def); + end; + end; + end; + if doconsume then + consume(token); + until not try_to_consume(_COMMA); + + if ([gcf_class,gcf_constructor]*constraintdata.flags<>[]) or + ((constraintdata.interfaces.count>1) and (constraintdata.basedef=generrordef)) or + ((constraintdata.interfaces.count>0) and (constraintdata.basedef<>generrordef)) then + begin + if constraintdata.basedef.typ=errordef then + { don't pass an errordef as a parent to a tobjectdef } + constraintdata.basedef:=nil + else + if constraintdata.basedef.typ<>objectdef then + internalerror(2012101101); + constraintdata.basedef:=tobjectdef.create({$ifdef jvm}odt_javaclass{$else}odt_class{$endif},defname,tobjectdef(constraintdata.basedef)); + include(constraintdata.basedef.defoptions,df_genconstraint); + for i:=0 to constraintdata.interfaces.count-1 do + tobjectdef(constraintdata.basedef).implementedinterfaces.add( + timplementedinterface.create(tobjectdef(constraintdata.interfaces[i]))); + end + else + if constraintdata.interfaces.count=1 then + begin + constraintdata.basedef:=tdef(constraintdata.interfaces[0]); + constraintdata.interfaces.delete(0); + end; + + for i:=firstidx to result.count-1 do + with ttypesym(result[i]) do + begin + genconstraintdata:=tgenericconstraintdata.create; + genconstraintdata.basedef:=constraintdata.basedef; + genconstraintdata.flags:=constraintdata.flags; + genconstraintdata.interfaces.assign(constraintdata.interfaces); + typedef:=constraintdata.basedef; + end; + firstidx:=result.count; + + constraintdata.free; + end; + until not (try_to_consume(_COMMA) or try_to_consume(_SEMICOLON)); end; - function parse_generic_specialization_types(genericdeflist:tfpobjectlist;out prettyname,specializename:ansistring;parsedtype:tdef):boolean; - var - old_block_type : tblock_type; - first : boolean; - typeparam : tnode; - begin - result:=true; - if genericdeflist=nil then - internalerror(2012061401); - { set the block type to type, so that the parsed type are returned as - ttypenode (e.g. classes are in non type-compatible blocks returned as - tloadvmtaddrnode) } - old_block_type:=block_type; - { if parsedtype is set, then the first type identifer was already parsed - (happens in inline specializations) and thus we only need to parse - the remaining types and do as if the first one was already given } - first:=not assigned(parsedtype); - if assigned(parsedtype) then - begin - genericdeflist.Add(parsedtype); - specializename:='$'+parsedtype.typename; - prettyname:=parsedtype.typesym.prettyname; - end - else - begin - specializename:=''; - prettyname:=''; - end; - while not (token in [_GT,_RSHARPBRACKET]) do - begin - { "first" is set to false at the end of the loop! } - if not first then - consume(_COMMA); - block_type:=bt_type; - typeparam:=factor(false,true); - if typeparam.nodetype=typen then - begin - if df_generic in typeparam.resultdef.defoptions then - Message(parser_e_no_generics_as_params); - genericdeflist.Add(typeparam.resultdef); - if not assigned(typeparam.resultdef.typesym) then - message(type_e_generics_cannot_reference_itself) - else - begin - specializename:=specializename+'$'+typeparam.resultdef.typename; - if first then - prettyname:=prettyname+typeparam.resultdef.typesym.prettyname - else - prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname; - end; - end - else - begin - Message(type_e_type_id_expected); - result:=false; - end; - typeparam.free; - first:=false; - end; - block_type:=old_block_type; - end; procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList); var @@ -646,6 +999,12 @@ uses if not assigned(genericlist) then exit; + if assigned(genericdef) then + include(def.defoptions,df_specialization) + else + if genericlist.count>0 then + include(def.defoptions,df_generic); + case def.typ of recorddef,objectdef: st:=tabstractrecorddef(def).symtable; arraydef: st:=tarraydef(def).symtable; @@ -657,10 +1016,6 @@ uses for i:=0 to genericlist.count-1 do begin generictype:=ttypesym(genericlist[i]); - if generictype.typedef.typ=undefineddef then - include(def.defoptions,df_generic) - else - include(def.defoptions,df_specialization); st.insert(generictype); include(generictype.symoptions,sp_generic_para); def.genericparas.add(generictype.name,generictype); diff --git a/compiler/ptype.pas b/compiler/ptype.pas index 1fd72d4909..1778a2f5cd 100644 --- a/compiler/ptype.pas +++ b/compiler/ptype.pas @@ -453,7 +453,7 @@ implementation begin if def.typ=forwarddef then def:=ttypesym(srsym).typedef; - generate_specialization(def,stoParseClassParent in options,'',nil,''); + generate_specialization(def,stoParseClassParent in options,''); end else begin @@ -968,7 +968,7 @@ implementation end; if dospecialize then begin - generate_specialization(def,false,name,nil,''); + generate_specialization(def,false,name); { handle nested types } if assigned(def) then post_comp_expr_gendef(def); @@ -1689,7 +1689,7 @@ implementation objectdef : begin { Skip generics and forward defs } - if (df_generic in def.defoptions) or + if ([df_generic,df_genconstraint]*def.defoptions<>[]) or (oo_is_forward in tobjectdef(def).objectoptions) then continue; write_persistent_type_info(tobjectdef(def).symtable,is_global); diff --git a/compiler/symconst.pas b/compiler/symconst.pas index f2983df96e..69c3b2fdb8 100644 --- a/compiler/symconst.pas +++ b/compiler/symconst.pas @@ -187,7 +187,9 @@ type { type is a specialization of a generic type } df_specialization, { def has been copied from another def so symtable is not owned } - df_copied_def + df_copied_def, + { def was created as a generic constraint and thus is only "shallow" } + df_genconstraint ); tdefoptions=set of tdefoption; diff --git a/compiler/symsym.pas b/compiler/symsym.pas index 4046c343f0..21475f5cf9 100644 --- a/compiler/symsym.pas +++ b/compiler/symsym.pas @@ -121,12 +121,35 @@ interface property ProcdefList:TFPObjectList read FProcdefList; end; + tgenericconstraintflag=( + gcf_constructor, + gcf_class, + gcf_record + ); + tgenericconstraintflags=set of tgenericconstraintflag; + + tgenericconstraintdata=class + basedef : tdef; + basedefderef : tderef; + interfaces : tfpobjectlist; + interfacesderef : tfplist; + flags : tgenericconstraintflags; + constructor create; + destructor destroy;override; + procedure ppuload(ppufile:tcompilerppufile); + procedure ppuwrite(ppufile:tcompilerppufile); + procedure buildderef; + procedure deref; + end; + ttypesym = class(Tstoredsym) public + genconstraintdata : tgenericconstraintdata; typedef : tdef; typedefderef : tderef; fprettyname : ansistring; constructor create(const n : string;def:tdef); + destructor destroy;override; constructor ppuload(ppufile:tcompilerppufile); procedure ppuwrite(ppufile:tcompilerppufile);override; procedure buildderef;override; @@ -2352,6 +2375,77 @@ implementation TTYPESYM ****************************************************************************} + + constructor tgenericconstraintdata.create; + begin + interfaces:=tfpobjectlist.create(false); + interfacesderef:=tfplist.create; + end; + + + destructor tgenericconstraintdata.destroy; + var + i : longint; + begin + for i:=0 to interfacesderef.count-1 do + dispose(pderef(interfacesderef[i])); + interfacesderef.free; + interfaces.free; + inherited destroy; + end; + + procedure tgenericconstraintdata.ppuload(ppufile: tcompilerppufile); + var + cnt,i : longint; + intfderef : pderef; + begin + ppufile.getsmallset(flags); + ppufile.getderef(basedefderef); + cnt:=ppufile.getlongint; + for i:=0 to cnt-1 do + begin + new(intfderef); + ppufile.getderef(intfderef^); + interfacesderef.add(intfderef); + end; + end; + + + procedure tgenericconstraintdata.ppuwrite(ppufile: tcompilerppufile); + var + i : longint; + begin + ppufile.putsmallset(flags); + ppufile.putderef(basedefderef); + ppufile.putlongint(interfacesderef.count); + for i:=0 to interfacesderef.count-1 do + ppufile.putderef(pderef(interfacesderef[i])^); + end; + + procedure tgenericconstraintdata.buildderef; + var + intfderef : pderef; + i : longint; + begin + basedefderef.build(basedef); + for i:=0 to interfaces.count-1 do + begin + new(intfderef); + intfderef^.build(tobjectdef(interfaces[i])); + interfacesderef.add(intfderef); + end; + end; + + procedure tgenericconstraintdata.deref; + var + i : longint; + begin + basedef:=tdef(basedefderef.resolve); + for i:=0 to interfacesderef.count-1 do + interfaces.add(pderef(interfacesderef[i])^.resolve); + end; + + constructor ttypesym.create(const n : string;def:tdef); begin @@ -2364,24 +2458,39 @@ implementation typedef.typesym:=self; end; + destructor ttypesym.destroy; + begin + genconstraintdata.free; + inherited destroy; + end; + constructor ttypesym.ppuload(ppufile:tcompilerppufile); begin inherited ppuload(typesym,ppufile); ppufile.getderef(typedefderef); fprettyname:=ppufile.getansistring; + if ppufile.getbyte<>0 then + begin + genconstraintdata:=tgenericconstraintdata.create; + genconstraintdata.ppuload(ppufile); + end; end; procedure ttypesym.buildderef; begin typedefderef.build(typedef); + if assigned(genconstraintdata) then + genconstraintdata.buildderef; end; procedure ttypesym.deref; begin typedef:=tdef(typedefderef.resolve); + if assigned(genconstraintdata) then + genconstraintdata.deref; end; @@ -2390,6 +2499,13 @@ implementation inherited ppuwrite(ppufile); ppufile.putderef(typedefderef); ppufile.putansistring(fprettyname); + if assigned(genconstraintdata) then + begin + ppufile.putbyte(1); + genconstraintdata.ppuwrite(ppufile); + end + else + ppufile.putbyte(0); ppufile.writeentry(ibtypesym); end; diff --git a/compiler/symtype.pas b/compiler/symtype.pas index ae2d381ffa..1ff195f77e 100644 --- a/compiler/symtype.pas +++ b/compiler/symtype.pas @@ -137,6 +137,7 @@ interface procedure build(s:TObject); function resolve:TObject; end; + pderef = ^tderef; {************************************************ tpropaccesslist diff --git a/compiler/utils/ppudump.pp b/compiler/utils/ppudump.pp index cad83e06c4..2d583774dc 100644 --- a/compiler/utils/ppudump.pp +++ b/compiler/utils/ppudump.pp @@ -1170,7 +1170,8 @@ const (mask:df_unique; str:'Unique Type'), (mask:df_generic; str:'Generic'), (mask:df_specialization; str:'Specialization'), - (mask:df_copied_def; str:'Copied Typedef') + (mask:df_copied_def; str:'Copied Typedef'), + (mask:df_genconstraint; str:'Generic Constraint') ); defstate : array[1..ord(high(tdefstate))] of tdefstateinfo=( (mask:ds_vmt_written; str:'VMT Written'), diff --git a/tests/test/tgenconstraint1.pp b/tests/test/tgenconstraint1.pp new file mode 100644 index 0000000000..76d737816e --- /dev/null +++ b/tests/test/tgenconstraint1.pp @@ -0,0 +1,78 @@ +{ %NORUN } + +{ Extensively test the Delphi compatible constraint syntax } + +program tgenconstraint1; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +{ types used for tests } +uses + ugenconstraints; + +type + TTest1TObject = TTest1<TObject>; + // the documentation did say something different here... + //TTest1IInterface = TTest1<IInterface>; + TTest1TTestClass = TTest1<TTestClass>; + + TTest2TTestRec = TTest2<TTestRec>; + + TTest3TTestClass = TTest3<TTestClass>; + TTest3TTestClass2 = TTest3<TTestClass2>; + + { ToDo } + TTest4TTestClass = TTest4<TTestClass>; + TTest4TTestClass2 = TTest4<TTestClass2>; + + TTest5IInterface = TTest5<IInterface>; + TTest5ITest1 = TTest5<ITest1>; + TTest5ITest2 = TTest5<ITest2>; + TTest5TInterfacedObject = TTest5<TInterfacedObject>; + + TTest6TTestClass3 = TTest6<TTestClass3>; + TTest6TTestClass4 = TTest6<TTestClass4>; + + TTest7TTestClass4 = TTest7<TTestClass4>; + + TTest8TTestClass3 = TTest8<TTestClass3>; + TTest8TTestClass4 = TTest8<TTestClass4>; + //TTest8TTestClass5 = TTest8<TTestClass5>; + + // TTest9 is the same as TTest8 + + TTest10TTestClass3 = TTest10<TTestClass3>; + TTest10TTestClass6 = TTest10<TTestClass6>; + + // TTest11 is the same as TTest10 + + TTest12TTestClass = TTest12<TTestClass7>; + + TTest13TTestClass = TTest13<TTestClass>; + TTest13TTestClass6 = TTest13<TTestClass2>; + + // TTest14 is the same as TTest10 + + TTest15TTestClass8 = TTest15<TTestClass8>; + + TTest16TTestClass3 = TTest16<TTestClass3>; + + TTest17ITest1ITest1 = TTest17<ITest1, ITest1>; + TTest17ITestClass3ITest2 = TTest17<TTestClass3, ITest2>; + + TTest18ITest1ITest2 = TTest18<ITest1, ITest2>; + TTest18TTestClass3TTestClass5 = TTest18<TTestClass3, TTestClass5>; + TTest18TTestClass4TTestClass4TTestClass4 = TTest18<TTestClass4, TTestClass4>; + + TTest19TTestRecTObject = TTest19<TTestRec, TObject>; + + TTest20TTestClassTTestClass = TTest20<TTestClass, TTestClass>; + + TTest21TObject = TTest21<TObject>; + TTest21TestClass = TTest21<TTestClass>; + +begin + +end. diff --git a/tests/test/tgenconstraint10.pp b/tests/test/tgenconstraint10.pp new file mode 100644 index 0000000000..89e5b90aef --- /dev/null +++ b/tests/test/tgenconstraint10.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint10; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest3TTestObject1 = TTest3<TTestObject1>; + +begin + +end. diff --git a/tests/test/tgenconstraint11.pp b/tests/test/tgenconstraint11.pp new file mode 100644 index 0000000000..7e6687fc76 --- /dev/null +++ b/tests/test/tgenconstraint11.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint11; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest4TTestRec = TTest4<TTestRec>; + +begin + +end. diff --git a/tests/test/tgenconstraint12.pp b/tests/test/tgenconstraint12.pp new file mode 100644 index 0000000000..47b898f94e --- /dev/null +++ b/tests/test/tgenconstraint12.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint12; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest4ITest1 = TTest4<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint13.pp b/tests/test/tgenconstraint13.pp new file mode 100644 index 0000000000..7a23e64540 --- /dev/null +++ b/tests/test/tgenconstraint13.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint13; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest4TTestObject1 = TTest4<TTestObject1>; + +begin + +end. diff --git a/tests/test/tgenconstraint14.pp b/tests/test/tgenconstraint14.pp new file mode 100644 index 0000000000..cdfebc6f6b --- /dev/null +++ b/tests/test/tgenconstraint14.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint14; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest5TObject = TTest5<TObject>; + +begin + +end. diff --git a/tests/test/tgenconstraint15.pp b/tests/test/tgenconstraint15.pp new file mode 100644 index 0000000000..c62459792c --- /dev/null +++ b/tests/test/tgenconstraint15.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint15; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest5TTestRec = TTest5<TTestRec>; + +begin + +end. diff --git a/tests/test/tgenconstraint16.pp b/tests/test/tgenconstraint16.pp new file mode 100644 index 0000000000..bcb0cb7b2c --- /dev/null +++ b/tests/test/tgenconstraint16.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint16; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest5TTestObject1 = TTest5<TTestObject1>; + +begin + +end. diff --git a/tests/test/tgenconstraint17.pp b/tests/test/tgenconstraint17.pp new file mode 100644 index 0000000000..89295a4abd --- /dev/null +++ b/tests/test/tgenconstraint17.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint17; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest7IInterface = TTest7<IInterface>; + +begin + +end. diff --git a/tests/test/tgenconstraint18.pp b/tests/test/tgenconstraint18.pp new file mode 100644 index 0000000000..9cf4c3040b --- /dev/null +++ b/tests/test/tgenconstraint18.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint18; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest7TTestClass5 = TTest7<TTestClass5>; + +begin + +end. diff --git a/tests/test/tgenconstraint19.pp b/tests/test/tgenconstraint19.pp new file mode 100644 index 0000000000..dc353bd928 --- /dev/null +++ b/tests/test/tgenconstraint19.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint19; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest7ITest1 = TTest7<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint2.pp b/tests/test/tgenconstraint2.pp new file mode 100644 index 0000000000..d49e1e9e76 --- /dev/null +++ b/tests/test/tgenconstraint2.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint2; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest1TTestRec = TTest1<TTestRec>; + +begin + +end. diff --git a/tests/test/tgenconstraint20.pp b/tests/test/tgenconstraint20.pp new file mode 100644 index 0000000000..cbc05b7e32 --- /dev/null +++ b/tests/test/tgenconstraint20.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint20; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest7TTestClass3 = TTest7<TTestClass3>; + +begin + +end. diff --git a/tests/test/tgenconstraint21.pp b/tests/test/tgenconstraint21.pp new file mode 100644 index 0000000000..2411860b0f --- /dev/null +++ b/tests/test/tgenconstraint21.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint21; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest8ITest1 = TTest8<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint22.pp b/tests/test/tgenconstraint22.pp new file mode 100644 index 0000000000..b702301206 --- /dev/null +++ b/tests/test/tgenconstraint22.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint22; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest12TTestClass = TTest12<TTestClass>; + +begin + +end. diff --git a/tests/test/tgenconstraint23.pp b/tests/test/tgenconstraint23.pp new file mode 100644 index 0000000000..06df2e8ad1 --- /dev/null +++ b/tests/test/tgenconstraint23.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint23; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest12TTestClass9 = TTest12<TTestClass9>; + +begin + +end. diff --git a/tests/test/tgenconstraint24.pp b/tests/test/tgenconstraint24.pp new file mode 100644 index 0000000000..089fb7e3a1 --- /dev/null +++ b/tests/test/tgenconstraint24.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint24; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest12TTestClass3 = TTest12<TTestClass3>; + +begin + +end. diff --git a/tests/test/tgenconstraint25.pp b/tests/test/tgenconstraint25.pp new file mode 100644 index 0000000000..233a56b94f --- /dev/null +++ b/tests/test/tgenconstraint25.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint25; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest5TTestClass7 = TTest5<TTestClass7>; + +begin + +end. diff --git a/tests/test/tgenconstraint26.pp b/tests/test/tgenconstraint26.pp new file mode 100644 index 0000000000..9cb7b558ab --- /dev/null +++ b/tests/test/tgenconstraint26.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint26; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest12TTestClass5 = TTest12<TTestClass5>; + +begin + +end. diff --git a/tests/test/tgenconstraint27.pp b/tests/test/tgenconstraint27.pp new file mode 100644 index 0000000000..a51f7138d1 --- /dev/null +++ b/tests/test/tgenconstraint27.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint27; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest15TTestClass4 = TTest15<TTestClass4>; + +begin + +end. diff --git a/tests/test/tgenconstraint28.pp b/tests/test/tgenconstraint28.pp new file mode 100644 index 0000000000..f5ef833f04 --- /dev/null +++ b/tests/test/tgenconstraint28.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint28; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest15TTestClass7 = TTest15<TTestClass7>; + +begin + +end. diff --git a/tests/test/tgenconstraint29.pp b/tests/test/tgenconstraint29.pp new file mode 100644 index 0000000000..1ed433da2b --- /dev/null +++ b/tests/test/tgenconstraint29.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint29; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest16ITest1 = TTest16<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint3.pp b/tests/test/tgenconstraint3.pp new file mode 100644 index 0000000000..693af426f2 --- /dev/null +++ b/tests/test/tgenconstraint3.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint3; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest1ITest1 = TTest1<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint30.pp b/tests/test/tgenconstraint30.pp new file mode 100644 index 0000000000..1a535621b5 --- /dev/null +++ b/tests/test/tgenconstraint30.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint30; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest16TTestRec = TTest16<TTestRec>; + +begin + +end. diff --git a/tests/test/tgenconstraint31.pp b/tests/test/tgenconstraint31.pp new file mode 100644 index 0000000000..8c173cd9bf --- /dev/null +++ b/tests/test/tgenconstraint31.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint31; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest17TTestClassTTestClass = TTest17<TTestClass, TTestClass>; + +begin + +end. diff --git a/tests/test/tgenconstraint32.pp b/tests/test/tgenconstraint32.pp new file mode 100644 index 0000000000..b2e5e39921 --- /dev/null +++ b/tests/test/tgenconstraint32.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint32; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest17ITestTTestClass = TTest17<ITest1, TTestClass>; + +begin + +end. diff --git a/tests/test/tgenconstraint33.pp b/tests/test/tgenconstraint33.pp new file mode 100644 index 0000000000..3fbb79bd53 --- /dev/null +++ b/tests/test/tgenconstraint33.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint33; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest17TTestClass5ITest2 = TTest17<TTestClass5, IInterface>; + +begin + +end. diff --git a/tests/test/tgenconstraint34.pp b/tests/test/tgenconstraint34.pp new file mode 100644 index 0000000000..08712fc8f3 --- /dev/null +++ b/tests/test/tgenconstraint34.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint34; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest21TTestRec = TTest21<TTestRec>; + +begin + +end. diff --git a/tests/test/tgenconstraint35.pp b/tests/test/tgenconstraint35.pp new file mode 100644 index 0000000000..3fd347ab10 --- /dev/null +++ b/tests/test/tgenconstraint35.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint35; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest21ITest1 = TTest21<ITest1>; + +begin + +end. diff --git a/tests/test/tgenconstraint36.pp b/tests/test/tgenconstraint36.pp new file mode 100644 index 0000000000..dd46727a3e --- /dev/null +++ b/tests/test/tgenconstraint36.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint36; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest21TTestObject1 = TTest21<TTestObject1>; + +begin + +end. diff --git a/tests/test/tgenconstraint4.pp b/tests/test/tgenconstraint4.pp new file mode 100644 index 0000000000..4db1b8f7c3 --- /dev/null +++ b/tests/test/tgenconstraint4.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint4; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest1LongInt = TTest1<LongInt>; + +begin + +end. diff --git a/tests/test/tgenconstraint5.pp b/tests/test/tgenconstraint5.pp new file mode 100644 index 0000000000..6b3fa6d7a6 --- /dev/null +++ b/tests/test/tgenconstraint5.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint5; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest1TClass = TTest1<TClass>; + +begin + +end. diff --git a/tests/test/tgenconstraint6.pp b/tests/test/tgenconstraint6.pp new file mode 100644 index 0000000000..941aff1ac8 --- /dev/null +++ b/tests/test/tgenconstraint6.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint6; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest1TTestObject1 = TTest1<TTestObject1>; + +begin + +end. diff --git a/tests/test/tgenconstraint7.pp b/tests/test/tgenconstraint7.pp new file mode 100644 index 0000000000..34afa6c3b7 --- /dev/null +++ b/tests/test/tgenconstraint7.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint7; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest2TObject = TTest2<TObject>; + +begin + +end. diff --git a/tests/test/tgenconstraint8.pp b/tests/test/tgenconstraint8.pp new file mode 100644 index 0000000000..4a3c675cb9 --- /dev/null +++ b/tests/test/tgenconstraint8.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint8; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest3TObject = TTest3<TObject>; + +begin + +end. diff --git a/tests/test/tgenconstraint9.pp b/tests/test/tgenconstraint9.pp new file mode 100644 index 0000000000..ddaa34fcb0 --- /dev/null +++ b/tests/test/tgenconstraint9.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tgenconstraint9; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +uses + ugenconstraints; + +type + TTest3ITest1 = TTest3<ITest1>; + +begin + +end. diff --git a/tests/test/thlp30.pp b/tests/test/thlp30.pp index 1a49394b29..db99759500 100644 --- a/tests/test/thlp30.pp +++ b/tests/test/thlp30.pp @@ -1,6 +1,4 @@ -{ %FAIL } - -{ helpers can not extend type parameters even if they can only be classes } +{ helpers can extend type parameters if they can only be classes } program thlp30; {$ifdef fpc} @@ -14,6 +12,9 @@ type end; end; +type + TFooTObject = TFoo<TObject>; + begin end. diff --git a/tests/test/thlp46.pp b/tests/test/thlp46.pp new file mode 100644 index 0000000000..e691a0b44f --- /dev/null +++ b/tests/test/thlp46.pp @@ -0,0 +1,24 @@ +{ helpers can extend type parameters if they can only be records } +program thlp46; + +{$ifdef fpc} + {$mode delphi} +{$endif} + +type + TFoo<T: record> = class + type + THelper = record helper for T + end; + end; + + TBar = record + f: LongInt; + end; + +type + TFooTBar = TFoo<TBar>; + +begin + +end. diff --git a/tests/test/ugenconstraints.pas b/tests/test/ugenconstraints.pas new file mode 100644 index 0000000000..1f5e1116a2 --- /dev/null +++ b/tests/test/ugenconstraints.pas @@ -0,0 +1,186 @@ +unit ugenconstraints; + +{$ifdef fpc} + {$mode delphi} +{$else} + // Delphi only knows "MSWINDOWS" + {$define windows} +{$endif} + +interface + +type + TTestClass = class + + end; + + TTestClass2 = class(TTestClass) + + end; + + TTestRec = record + + end; + + ITest1 = interface + + end; + + ITest2 = interface(ITest1) + + end; + + TTestClass3 = class(TInterfacedObject, ITest1) + + end; + + TTestClass4 = class(TInterfacedObject, ITest1, ITest2) + + end; + + TTestClass5 = class(TInterfacedObject, ITest2) + + end; + + TTestClass6 = class(TTestClass3, ITest2) + + end; + + TTestClass7 = class(TTestClass, ITest1) + function QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + end; + + TTestClass8 = class(TTestClass7, ITest2) + + end; + + TTestClass9 = class(TTestClass, ITest2) + function QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + end; + + TTestObject1 = object + + end; + +type + TTest1<T: class> = class + + end; + + TTest2<T: record> = class + + end; + + TTest3<T: TTestClass> = class + + end; + + TTest4<T: class, constructor> = class + + end; + + TTest5<T: IInterface> = class + + end; + + TTest6<T: ITest1> = class + + end; + + TTest7<T: ITest1, ITest2> = class + + end; + + TTest8<T: class, ITest1> = class + + end; + + TTest9<T: ITest1, class> = class + + end; + + TTest10<T: class, constructor, ITest1> = class + + end; + + TTest11<T: constructor, ITest1, class> = class + + end; + + TTest12<T: TTestClass, ITest1> = class + + end; + + TTest13<T: TTestClass, constructor> = class + + end; + + TTest14<T: TTestClass, ITest1, constructor> = class + + end; + + TTest15<T: ITest1, constructor, ITest2, TTestClass> = class + + end; + + TTest16<T: ITest1, constructor> = class + + end; + + TTest17<T1, T2: ITest1> = class + + end; + + TTest18<T1: ITest1; T2: ITest2> = class + + end; + + TTest19<T1: record; T2: class> = class + + end; + + TTest20<T1: TTestClass; T2: constructor> = class + + end; + + TTest21<T: constructor> = class + + end; + +implementation + +function TTestClass7.QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; +begin + +end; + +function TTestClass7._AddRef : longint; +begin + +end; + +function TTestClass7._Release : longint; +begin + +end; + +function TTestClass9.QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; +begin + +end; + +function TTestClass9._AddRef : longint; +begin + +end; + +function TTestClass9._Release : longint; +begin + +end; + +end.