mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 13:09:32 +02:00
* synchronized with trunk
git-svn-id: branches/z80@45131 -
This commit is contained in:
commit
6f6598712f
31
.gitattributes
vendored
31
.gitattributes
vendored
@ -14782,6 +14782,36 @@ 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/tgenconst1.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst10.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst11.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst12.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst13.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst14.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst15.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst16.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst17.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst18.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst19.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst2.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst20.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst21.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst22.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst23.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst24.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst25.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst26.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst27.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst28.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst29.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst3.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst30.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst4.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst5.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst6.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst7.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst8.pp svneol=native#text/pascal
|
||||
tests/test/tgenconst9.pp svneol=native#text/pascal
|
||||
tests/test/tgenconstraint1.pp svneol=native#text/pascal
|
||||
tests/test/tgenconstraint10.pp svneol=native#text/pascal
|
||||
tests/test/tgenconstraint11.pp svneol=native#text/pascal
|
||||
@ -16411,6 +16441,7 @@ tests/webtbf/tw36631b.pp svneol=native#text/pascal
|
||||
tests/webtbf/tw36652.pp svneol=native#text/pascal
|
||||
tests/webtbf/tw36720.pp svneol=native#text/pascal
|
||||
tests/webtbf/tw3680.pp svneol=native#text/plain
|
||||
tests/webtbf/tw36975.pp svneol=native#text/pascal
|
||||
tests/webtbf/tw3716.pp svneol=native#text/plain
|
||||
tests/webtbf/tw3738.pp svneol=native#text/plain
|
||||
tests/webtbf/tw3740.pp svneol=native#text/plain
|
||||
|
@ -345,9 +345,13 @@ implementation
|
||||
internalerror(2012091302);
|
||||
symfrom:=ttypesym(tstoreddef(def_from).genericparas[i]);
|
||||
symto:=ttypesym(tstoreddef(def_to).genericparas[i]);
|
||||
if not (symfrom.typ=typesym) or not (symto.typ=typesym) then
|
||||
if not (symfrom.typ in [typesym,constsym]) or not (symto.typ in [typesym,constsym]) then
|
||||
internalerror(2012121401);
|
||||
if not equal_defs(ttypesym(symfrom).typedef,ttypesym(symto).typedef) then
|
||||
if symto.typ<>symfrom.typ then
|
||||
diff:=true
|
||||
else if (symfrom.typ=constsym) and (symto.typ=constsym) and not equal_constsym(tconstsym(symfrom),tconstsym(symto),true) then
|
||||
diff:=true
|
||||
else if not equal_defs(ttypesym(symfrom).typedef,ttypesym(symto).typedef) then
|
||||
diff:=true;
|
||||
if diff then
|
||||
break;
|
||||
|
@ -2779,7 +2779,7 @@ implementation
|
||||
internalerror(2015060301);
|
||||
{ check whether the given parameters are compatible
|
||||
to the def's constraints }
|
||||
if not check_generic_constraints(pd,spezcontext.genericdeflist,spezcontext.poslist) then
|
||||
if not check_generic_constraints(pd,spezcontext.paramlist,spezcontext.poslist) then
|
||||
exit;
|
||||
def:=generate_specialization_phase2(spezcontext,pd,false,'');
|
||||
case def.typ of
|
||||
|
@ -1617,7 +1617,7 @@ parser_e_generic_constraints_not_allowed_here=03355_E_Generic constraint not all
|
||||
%
|
||||
# Type Checking
|
||||
#
|
||||
# 04127 is the last used one
|
||||
# 04128 is the last used one
|
||||
#
|
||||
% \section{Type checking errors}
|
||||
% This section lists all errors that can occur when type checking is
|
||||
@ -2061,6 +2061,9 @@ type_e_forward_interface_type_does_not_match=04127_E_The interface type of the f
|
||||
% When declaring an interface forward, the interface type must be the same as at the actual declaration of the interface.
|
||||
% This is in particular important with regard to the parent interface which implicitly sets the interface type for the
|
||||
% child interface.
|
||||
type_e_generic_const_type_not_allowed=04128_E_Type not allowed for generic constant parameter: $1
|
||||
% Only types that can also be used (indirectly) for untyped constants can be used as a
|
||||
% type for a generic constant parameter.
|
||||
% \end{description}
|
||||
#
|
||||
# Symtable
|
||||
|
@ -584,6 +584,7 @@ const
|
||||
type_w_empty_constant_range_set=04125;
|
||||
type_e_cblock_callconv=04126;
|
||||
type_e_forward_interface_type_does_not_match=04127;
|
||||
type_e_generic_const_type_not_allowed=04128;
|
||||
sym_e_id_not_found=05000;
|
||||
sym_f_internal_error_in_symtablestack=05001;
|
||||
sym_e_duplicate_id=05002;
|
||||
@ -1125,9 +1126,9 @@ const
|
||||
option_info=11024;
|
||||
option_help_pages=11025;
|
||||
|
||||
MsgTxtSize = 85143;
|
||||
MsgTxtSize = 85203;
|
||||
|
||||
MsgIdxMax : array[1..20] of longint=(
|
||||
28,106,356,128,99,63,143,36,223,68,
|
||||
28,106,356,129,99,63,143,36,223,68,
|
||||
62,20,30,1,1,1,1,1,1,1
|
||||
);
|
||||
|
1006
compiler/msgtxt.inc
1006
compiler/msgtxt.inc
File diff suppressed because it is too large
Load Diff
@ -3102,7 +3102,8 @@ implementation
|
||||
{ for constant values on absolute variables, swapping is required }
|
||||
if (target_info.endian = endian_big) and (nf_absolute in flags) then
|
||||
swap_const_value(tordconstnode(left).value,tordconstnode(left).resultdef.size);
|
||||
adaptrange(resultdef,tordconstnode(left).value,([nf_internal,nf_absolute]*flags)<>[],nf_explicit in flags,cs_check_range in localswitches);
|
||||
if not(nf_generic_para in flags) then
|
||||
adaptrange(resultdef,tordconstnode(left).value,([nf_internal,nf_absolute]*flags)<>[],nf_explicit in flags,cs_check_range in localswitches);
|
||||
{ swap value back, but according to new type }
|
||||
if (target_info.endian = endian_big) and (nf_absolute in flags) then
|
||||
swap_const_value(tordconstnode(left).value,resultdef.size);
|
||||
@ -3219,6 +3220,7 @@ implementation
|
||||
end;
|
||||
if (convtype=tc_int_2_int) and (left.nodetype=typeconvn) and (ttypeconvnode(left).convtype=tc_bool_2_int) then
|
||||
begin
|
||||
ttypeconvnode(left).totypedef:=resultdef;
|
||||
ttypeconvnode(left).resultdef:=resultdef;
|
||||
result:=left;
|
||||
left:=nil;
|
||||
|
@ -306,6 +306,7 @@ implementation
|
||||
p1 : tnode;
|
||||
len : longint;
|
||||
pc : pchar;
|
||||
value_set : pconstset;
|
||||
begin
|
||||
p1:=nil;
|
||||
case p.consttyp of
|
||||
@ -331,18 +332,50 @@ implementation
|
||||
constwstring :
|
||||
p1:=cstringconstnode.createunistr(pcompilerwidestring(p.value.valueptr));
|
||||
constreal :
|
||||
p1:=crealconstnode.create(pbestreal(p.value.valueptr)^,p.constdef);
|
||||
begin
|
||||
if (sp_generic_para in p.symoptions) and not (sp_generic_const in p.symoptions) then
|
||||
p1:=crealconstnode.create(default(bestreal),p.constdef)
|
||||
else
|
||||
p1:=crealconstnode.create(pbestreal(p.value.valueptr)^,p.constdef);
|
||||
end;
|
||||
constset :
|
||||
p1:=csetconstnode.create(pconstset(p.value.valueptr),p.constdef);
|
||||
begin
|
||||
if sp_generic_const in p.symoptions then
|
||||
begin
|
||||
new(value_set);
|
||||
value_set^:=pconstset(p.value.valueptr)^;
|
||||
p1:=csetconstnode.create(value_set,p.constdef);
|
||||
end
|
||||
else if sp_generic_para in p.symoptions then
|
||||
begin
|
||||
new(value_set);
|
||||
p1:=csetconstnode.create(value_set,p.constdef);
|
||||
end
|
||||
else
|
||||
p1:=csetconstnode.create(pconstset(p.value.valueptr),p.constdef);
|
||||
end;
|
||||
constpointer :
|
||||
p1:=cpointerconstnode.create(p.value.valueordptr,p.constdef);
|
||||
begin
|
||||
if sp_generic_para in p.symoptions then
|
||||
p1:=cpointerconstnode.create(default(tconstptruint),p.constdef)
|
||||
else
|
||||
p1:=cpointerconstnode.create(p.value.valueordptr,p.constdef);
|
||||
end;
|
||||
constnil :
|
||||
p1:=cnilnode.create;
|
||||
constguid :
|
||||
p1:=cguidconstnode.create(pguid(p.value.valueptr)^);
|
||||
begin
|
||||
if sp_generic_para in p.symoptions then
|
||||
p1:=cguidconstnode.create(default(tguid))
|
||||
else
|
||||
p1:=cguidconstnode.create(pguid(p.value.valueptr)^);
|
||||
end;
|
||||
else
|
||||
internalerror(200205103);
|
||||
end;
|
||||
{ transfer generic param flag from symbol to node }
|
||||
if sp_generic_para in p.symoptions then
|
||||
include(p1.flags,nf_generic_para);
|
||||
genconstsymtree:=p1;
|
||||
end;
|
||||
|
||||
|
@ -131,7 +131,10 @@ implementation
|
||||
end;
|
||||
if rv = 0 then
|
||||
begin
|
||||
Message(parser_e_division_by_zero);
|
||||
{ if the node is derived from a generic const parameter
|
||||
then don't issue an error }
|
||||
if not (nf_generic_para in flags) then
|
||||
Message(parser_e_division_by_zero);
|
||||
{ recover }
|
||||
tordconstnode(right).value := 1;
|
||||
end;
|
||||
|
@ -276,10 +276,13 @@ interface
|
||||
nf_block_with_exit,
|
||||
|
||||
{ tloadvmtaddrnode }
|
||||
nf_ignore_for_wpo { we know that this loadvmtaddrnode cannot be used to construct a class instance }
|
||||
nf_ignore_for_wpo, { we know that this loadvmtaddrnode cannot be used to construct a class instance }
|
||||
|
||||
{ WARNING: there are now 31 elements in this type, and a set of this
|
||||
type is written to the PPU. So before adding more than 32 elements,
|
||||
{ node is derived from generic parameter }
|
||||
nf_generic_para
|
||||
|
||||
{ WARNING: there are now 32 elements in this type, and a set of this
|
||||
type is written to the PPU. So before adding more elements,
|
||||
either move some flags to specific nodes, or stream a normalset
|
||||
to the ppu
|
||||
}
|
||||
@ -1380,6 +1383,9 @@ implementation
|
||||
constructor tunarynode.create(t:tnodetype;l : tnode);
|
||||
begin
|
||||
inherited create(t);
|
||||
{ transfer generic paramater flag }
|
||||
if assigned(l) and (nf_generic_para in l.flags) then
|
||||
include(flags,nf_generic_para);
|
||||
left:=l;
|
||||
end;
|
||||
|
||||
@ -1482,7 +1488,10 @@ implementation
|
||||
constructor tbinarynode.create(t:tnodetype;l,r : tnode);
|
||||
begin
|
||||
inherited create(t,l);
|
||||
right:=r
|
||||
{ transfer generic paramater flag }
|
||||
if assigned(r) and (nf_generic_para in r.flags) then
|
||||
include(flags,nf_generic_para);
|
||||
right:=r;
|
||||
end;
|
||||
|
||||
|
||||
@ -1635,6 +1644,9 @@ implementation
|
||||
constructor ttertiarynode.create(_t:tnodetype;l,r,t : tnode);
|
||||
begin
|
||||
inherited create(_t,l,r);
|
||||
{ transfer generic parameter flag }
|
||||
if assigned(t) and (nf_generic_para in t.flags) then
|
||||
include(flags,nf_generic_para);
|
||||
third:=t;
|
||||
end;
|
||||
|
||||
|
@ -424,8 +424,9 @@ implementation
|
||||
{ both types must be compatible }
|
||||
if compare_defs(left.resultdef,right.resultdef,left.nodetype)=te_incompatible then
|
||||
IncompatibleTypes(left.resultdef,right.resultdef);
|
||||
{ Check if only when its a constant set }
|
||||
if (left.nodetype=ordconstn) and (right.nodetype=ordconstn) then
|
||||
{ check if only when its a constant set and
|
||||
ignore range nodes which are generic parameter derived }
|
||||
if not (nf_generic_para in flags) and (left.nodetype=ordconstn) and (right.nodetype=ordconstn) then
|
||||
begin
|
||||
{ upper limit must be greater or equal than lower limit }
|
||||
if (tordconstnode(left).value>tordconstnode(right).value) and
|
||||
|
@ -62,6 +62,7 @@ implementation
|
||||
procedure typecheckpass_internal_loop(var p : tnode; out node_changed: boolean);
|
||||
var
|
||||
hp : tnode;
|
||||
oldflags : tnodeflags;
|
||||
begin
|
||||
codegenerror:=false;
|
||||
repeat
|
||||
@ -73,9 +74,13 @@ implementation
|
||||
if assigned(hp) then
|
||||
begin
|
||||
node_changed:=true;
|
||||
oldflags:=p.flags;
|
||||
p.free;
|
||||
{ switch to new node }
|
||||
p:=hp;
|
||||
{ transfer generic paramter flag }
|
||||
if nf_generic_para in oldflags then
|
||||
include(p.flags,nf_generic_para);
|
||||
end;
|
||||
until not assigned(hp) or
|
||||
assigned(hp.resultdef);
|
||||
|
@ -135,7 +135,10 @@ implementation
|
||||
setconstn :
|
||||
begin
|
||||
new(ps);
|
||||
ps^:=tsetconstnode(p).value_set^;
|
||||
if assigned(tsetconstnode(p).value_set) then
|
||||
ps^:=tsetconstnode(p).value_set^
|
||||
else
|
||||
ps^:=[];
|
||||
hp:=cconstsym.create_ptr(orgname,constset,ps,p.resultdef);
|
||||
end;
|
||||
pointerconstn :
|
||||
@ -185,8 +188,22 @@ implementation
|
||||
end;
|
||||
end;
|
||||
else
|
||||
Message(parser_e_illegal_expression);
|
||||
begin
|
||||
{ the node is from a generic parameter constant and is
|
||||
untyped so we need to pass a placeholder constant
|
||||
instead of givng an error }
|
||||
if nf_generic_para in p.flags then
|
||||
hp:=cconstsym.create_ord(orgname,constnil,0,p.resultdef)
|
||||
else
|
||||
Message(parser_e_illegal_expression);
|
||||
end;
|
||||
end;
|
||||
{ transfer generic param flag from node to symbol }
|
||||
if nf_generic_para in p.flags then
|
||||
begin
|
||||
include(hp.symoptions,sp_generic_const);
|
||||
include(hp.symoptions,sp_generic_para);
|
||||
end;
|
||||
current_tokenpos:=storetokenpos;
|
||||
p.free;
|
||||
readconstant:=hp;
|
||||
@ -716,8 +733,9 @@ implementation
|
||||
{ we are not freeing the type parameters, so register them }
|
||||
for i:=0 to generictypelist.count-1 do
|
||||
begin
|
||||
ttypesym(generictypelist[i]).register_sym;
|
||||
tstoreddef(ttypesym(generictypelist[i]).typedef).register_def;
|
||||
tstoredsym(generictypelist[i]).register_sym;
|
||||
if tstoredsym(generictypelist[i]).typ=typesym then
|
||||
tstoreddef(ttypesym(generictypelist[i]).typedef).register_def;
|
||||
end;
|
||||
|
||||
str(generictypelist.Count,s);
|
||||
|
@ -628,7 +628,7 @@ implementation
|
||||
for i:=0 to genericparams.count-1 do
|
||||
begin
|
||||
sym:=ttypesym(genericparams[i]);
|
||||
if tstoreddef(sym.typedef).is_registered then
|
||||
if (sym.typ<>constsym) and tstoreddef(sym.typedef).is_registered then
|
||||
begin
|
||||
sym.typedef.free;
|
||||
sym.typedef:=nil;
|
||||
@ -813,9 +813,11 @@ implementation
|
||||
function check_generic_parameters(def:tstoreddef):boolean;
|
||||
var
|
||||
i : longint;
|
||||
decltype,
|
||||
impltype : ttypesym;
|
||||
declsym,
|
||||
implsym : tsym;
|
||||
impltype : ttypesym absolute implsym;
|
||||
implname : tsymstr;
|
||||
fileinfo : tfileposinfo;
|
||||
begin
|
||||
result:=true;
|
||||
if not assigned(def.genericparas) then
|
||||
@ -826,18 +828,23 @@ implementation
|
||||
internalerror(2018090104);
|
||||
for i:=0 to def.genericparas.count-1 do
|
||||
begin
|
||||
decltype:=ttypesym(def.genericparas[i]);
|
||||
impltype:=ttypesym(genericparams[i]);
|
||||
declsym:=tsym(def.genericparas[i]);
|
||||
implsym:=tsym(genericparams[i]);
|
||||
implname:=upper(genericparams.nameofindex(i));
|
||||
if decltype.name<>implname then
|
||||
if declsym.name<>implname then
|
||||
begin
|
||||
messagepos1(impltype.fileinfo,sym_e_generic_type_param_mismatch,impltype.realname);
|
||||
messagepos1(decltype.fileinfo,sym_e_generic_type_param_decl,decltype.realname);
|
||||
messagepos1(implsym.fileinfo,sym_e_generic_type_param_mismatch,implsym.realname);
|
||||
messagepos1(declsym.fileinfo,sym_e_generic_type_param_decl,declsym.realname);
|
||||
result:=false;
|
||||
end;
|
||||
if df_genconstraint in impltype.typedef.defoptions then
|
||||
if ((implsym.typ=typesym) and (df_genconstraint in impltype.typedef.defoptions)) or
|
||||
(implsym.typ=constsym) then
|
||||
begin
|
||||
messagepos(tstoreddef(impltype.typedef).genconstraintdata.fileinfo,parser_e_generic_constraints_not_allowed_here);
|
||||
if implsym.typ=constsym then
|
||||
fileinfo:=impltype.fileinfo
|
||||
else
|
||||
fileinfo:=tstoreddef(impltype.typedef).genconstraintdata.fileinfo;
|
||||
messagepos(fileinfo,parser_e_generic_constraints_not_allowed_here);
|
||||
result:=false;
|
||||
end;
|
||||
end;
|
||||
@ -1127,8 +1134,9 @@ implementation
|
||||
{ register the parameters }
|
||||
for i:=0 to genericparams.count-1 do
|
||||
begin
|
||||
ttypesym(genericparams[i]).register_sym;
|
||||
tstoreddef(ttypesym(genericparams[i]).typedef).register_def;
|
||||
tsym(genericparams[i]).register_sym;
|
||||
if tsym(genericparams[i]).typ=typesym then
|
||||
tstoreddef(ttypesym(genericparams[i]).typedef).register_def;
|
||||
end;
|
||||
insert_generic_parameter_types(pd,nil,genericparams);
|
||||
{ the list is no longer required }
|
||||
|
@ -1707,6 +1707,10 @@ implementation
|
||||
hdef:=generrordef;
|
||||
end;
|
||||
|
||||
{ field type is a generic param so set a flag in the struct }
|
||||
if assigned(hdef.typesym) and (sp_generic_para in hdef.typesym.symoptions) then
|
||||
include(current_structdef.defoptions,df_has_generic_fields);
|
||||
|
||||
{ Process procvar directives }
|
||||
if maybe_parse_proc_directives(hdef) then
|
||||
semicoloneaten:=true;
|
||||
|
@ -447,6 +447,9 @@ implementation
|
||||
{ no packed bit support for these things }
|
||||
if l=in_bitsizeof_x then
|
||||
statement_syssym:=caddnode.create(muln,statement_syssym,cordconstnode.create(8,sizesinttype,true));
|
||||
{ type sym is a generic parameter }
|
||||
if assigned(p1.resultdef.typesym) and (sp_generic_para in p1.resultdef.typesym.symoptions) then
|
||||
include(statement_syssym.flags,nf_generic_para);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -467,6 +470,9 @@ implementation
|
||||
end
|
||||
else
|
||||
statement_syssym:=cordconstnode.create(p1.resultdef.packedbitsize,sizesinttype,true);
|
||||
{ type def is a struct with generic fields }
|
||||
if df_has_generic_fields in p1.resultdef.defoptions then
|
||||
include(statement_syssym.flags,nf_generic_para);
|
||||
{ p1 not needed !}
|
||||
p1.destroy;
|
||||
end;
|
||||
@ -4247,7 +4253,10 @@ implementation
|
||||
gendef:=generate_specialization_phase2(spezcontext,tstoreddef(gendef),false,'');
|
||||
spezcontext.free;
|
||||
spezcontext:=nil;
|
||||
gensym:=gendef.typesym;
|
||||
if gendef.typ=errordef then
|
||||
gensym:=generrorsym
|
||||
else
|
||||
gensym:=gendef.typesym;
|
||||
end;
|
||||
procdef:
|
||||
begin
|
||||
@ -4601,7 +4610,7 @@ implementation
|
||||
filepos : tfileposinfo;
|
||||
oldafterassignment,
|
||||
updatefpos : boolean;
|
||||
|
||||
oldflags : tnodeflags;
|
||||
begin
|
||||
oldafterassignment:=afterassignment;
|
||||
p1:=sub_expr(opcompare,[ef_accept_equal],nil);
|
||||
@ -4658,10 +4667,14 @@ implementation
|
||||
else
|
||||
updatefpos:=false;
|
||||
end;
|
||||
oldflags:=p1.flags;
|
||||
{ get the resultdef for this expression }
|
||||
if not assigned(p1.resultdef) and
|
||||
dotypecheck then
|
||||
do_typecheckpass(p1);
|
||||
{ transfer generic paramter flag }
|
||||
if nf_generic_para in oldflags then
|
||||
include(p1.flags,nf_generic_para);
|
||||
afterassignment:=oldafterassignment;
|
||||
if updatefpos then
|
||||
p1.fileinfo:=filepos;
|
||||
|
@ -42,7 +42,7 @@ type
|
||||
|
||||
tspecializationcontext=class
|
||||
public
|
||||
genericdeflist : tfpobjectlist;
|
||||
paramlist : tfpobjectlist;
|
||||
poslist : tfplist;
|
||||
prettyname : ansistring;
|
||||
specializename : ansistring;
|
||||
@ -58,7 +58,7 @@ implementation
|
||||
|
||||
constructor tspecializationcontext.create;
|
||||
begin
|
||||
genericdeflist:=tfpobjectlist.create(false);
|
||||
paramlist:=tfpobjectlist.create(false);
|
||||
poslist:=tfplist.create;
|
||||
end;
|
||||
|
||||
@ -66,7 +66,7 @@ destructor tspecializationcontext.destroy;
|
||||
var
|
||||
i : longint;
|
||||
begin
|
||||
genericdeflist.free;
|
||||
paramlist.free;
|
||||
for i:=0 to poslist.count-1 do
|
||||
dispose(pfileposinfo(poslist[i]));
|
||||
poslist.free;
|
||||
|
@ -42,9 +42,9 @@ uses
|
||||
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;symname:string):tdef;inline;
|
||||
function generate_specialization_phase1(out context:tspecializationcontext;genericdef:tdef;parsedtype:tdef;symname:string;parsedpos:tfileposinfo):tdef;
|
||||
function generate_specialization_phase2(context:tspecializationcontext;genericdef:tstoreddef;parse_class_parent:boolean;_prettyname:ansistring):tdef;
|
||||
function check_generic_constraints(genericdef:tstoreddef;paradeflist:tfpobjectlist;poslist:tfplist):boolean;
|
||||
function check_generic_constraints(genericdef:tstoreddef;paramlist:tfpobjectlist;poslist:tfplist):boolean;
|
||||
function parse_generic_parameters(allowconstraints:boolean):tfphashobjectlist;
|
||||
function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean;
|
||||
function parse_generic_specialization_types(paramlist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean;
|
||||
procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:tfphashobjectlist);
|
||||
procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfphashobjectlist);
|
||||
function generate_generic_name(const name:tidstring;specializename:ansistring;owner_hierarchy:string):tidstring;
|
||||
@ -65,16 +65,148 @@ uses
|
||||
{ common }
|
||||
cutils,fpccrc,
|
||||
{ global }
|
||||
globals,tokens,verbose,finput,
|
||||
globals,tokens,verbose,finput,constexp,
|
||||
{ symtable }
|
||||
symconst,symsym,symtable,defcmp,procinfo,
|
||||
symconst,symsym,symtable,defcmp,defutil,procinfo,
|
||||
{ modules }
|
||||
fmodule,
|
||||
node,nobj,
|
||||
node,nobj,ncon,
|
||||
{ parser }
|
||||
scanner,
|
||||
pbase,pexpr,pdecsub,ptype,psub,pparautl;
|
||||
|
||||
type
|
||||
tdeftypeset = set of tdeftyp;
|
||||
const
|
||||
tgeneric_param_const_types : tdeftypeset = [orddef,stringdef,floatdef,setdef,pointerdef,enumdef];
|
||||
tgeneric_param_nodes : tnodetypeset = [typen,ordconstn,stringconstn,realconstn,setconstn,niln];
|
||||
|
||||
function get_generic_param_def(sym:tsym):tdef;
|
||||
begin
|
||||
if sym.typ=constsym then
|
||||
result:=tconstsym(sym).constdef
|
||||
else
|
||||
result:=ttypesym(sym).typedef;
|
||||
end;
|
||||
|
||||
function compare_orddef_by_range(param1,param2:torddef;value:tconstvalue):boolean;
|
||||
begin
|
||||
if (value.valueord<param2.low) or (value.valueord>param2.high) then
|
||||
result:=false
|
||||
else
|
||||
result:=true;
|
||||
end;
|
||||
|
||||
function compare_generic_params(param1,param2:tdef;constparamsym:tconstsym):boolean;
|
||||
begin
|
||||
if (param1.typ=orddef) and (param2.typ=orddef) then
|
||||
begin
|
||||
if is_boolean(param2) then
|
||||
result:=is_boolean(param1)
|
||||
else if is_char(param2) then
|
||||
result:=is_char(param1)
|
||||
else if compare_orddef_by_range(torddef(param1),torddef(param2),constparamsym.value) then
|
||||
result:=true
|
||||
else
|
||||
result:=false;
|
||||
end
|
||||
{ arraydef is string constant so it's compatible with stringdef }
|
||||
else if (param1.typ=arraydef) and (param2.typ=stringdef) then
|
||||
result:=true
|
||||
{ integer ords are compatible with float }
|
||||
else if (param1.typ=orddef) and is_integer(param1) and (param2.typ=floatdef) then
|
||||
result:=true
|
||||
{ undefined def is compatible with all types }
|
||||
else if param2.typ=undefineddef then
|
||||
result:=true
|
||||
{ sets require stricter checks }
|
||||
else if is_set(param2) then
|
||||
result:=equal_defs(param1,param2)
|
||||
else
|
||||
result:=param1.typ=param2.typ;
|
||||
end;
|
||||
|
||||
function create_generic_constsym(fromdef:tdef;node:tnode;out prettyname:string):tconstsym;
|
||||
const
|
||||
undefinedname = 'undefined';
|
||||
var
|
||||
sym : tconstsym;
|
||||
setdef : tsetdef;
|
||||
enumsym : tsym;
|
||||
enumname : string;
|
||||
sp : pchar;
|
||||
ps : ^tconstset;
|
||||
pd : ^bestreal;
|
||||
i : integer;
|
||||
begin
|
||||
if node=nil then
|
||||
internalerror(2020011401);
|
||||
case node.nodetype of
|
||||
ordconstn:
|
||||
begin
|
||||
sym:=cconstsym.create_ord(undefinedname,constord,tordconstnode(node).value,fromdef);
|
||||
prettyname:=tostr(tordconstnode(node).value.svalue);
|
||||
end;
|
||||
stringconstn:
|
||||
begin
|
||||
getmem(sp,tstringconstnode(node).len+1);
|
||||
move(tstringconstnode(node).value_str^,sp^,tstringconstnode(node).len+1);
|
||||
sym:=cconstsym.create_string(undefinedname,conststring,sp,tstringconstnode(node).len,fromdef);
|
||||
prettyname:=''''+tstringconstnode(node).value_str+'''';
|
||||
end;
|
||||
realconstn:
|
||||
begin
|
||||
new(pd);
|
||||
pd^:=trealconstnode(node).value_real;
|
||||
sym:=cconstsym.create_ptr(undefinedname,constreal,pd,fromdef);
|
||||
prettyname:=realtostr(trealconstnode(node).value_real);
|
||||
end;
|
||||
setconstn:
|
||||
begin
|
||||
new(ps);
|
||||
ps^:=tsetconstnode(node).value_set^;
|
||||
sym:=cconstsym.create_ptr(undefinedname,constset,ps,fromdef);
|
||||
setdef:=tsetdef(tsetconstnode(node).resultdef);
|
||||
prettyname:='[';
|
||||
for i := setdef.setbase to setdef.setmax do
|
||||
if i in tsetconstnode(node).value_set^ then
|
||||
begin
|
||||
if setdef.elementdef.typ=enumdef then
|
||||
enumsym:=tenumdef(setdef.elementdef).int2enumsym(i)
|
||||
else
|
||||
enumsym:=nil;
|
||||
if assigned(enumsym) then
|
||||
enumname:=enumsym.realname
|
||||
else if setdef.elementdef.typ=orddef then
|
||||
begin
|
||||
if torddef(setdef.elementdef).ordtype=uchar then
|
||||
enumname:=chr(i)
|
||||
else
|
||||
enumname:=tostr(i);
|
||||
end
|
||||
else
|
||||
enumname:=tostr(i);
|
||||
if length(prettyname) > 1 then
|
||||
prettyname:=prettyname+','+enumname
|
||||
else
|
||||
prettyname:=prettyname+enumname;
|
||||
end;
|
||||
prettyname:=prettyname+']';
|
||||
end;
|
||||
niln:
|
||||
begin
|
||||
{ only "nil" is available for pointer constants }
|
||||
sym:=cconstsym.create_ord(undefinedname,constnil,0,fromdef);
|
||||
prettyname:='nil';
|
||||
end;
|
||||
else
|
||||
internalerror(2019021601);
|
||||
end;
|
||||
{ the sym needs an owner for later checks so use the typeparam owner }
|
||||
sym.owner:=fromdef.owner;
|
||||
include(sym.symoptions,sp_generic_const);
|
||||
result:=sym;
|
||||
end;
|
||||
|
||||
procedure maybe_add_waiting_unit(tt:tdef);
|
||||
var
|
||||
@ -104,203 +236,231 @@ uses
|
||||
end;
|
||||
end;
|
||||
|
||||
function check_generic_constraints(genericdef:tstoreddef;paradeflist:tfpobjectlist;poslist:tfplist):boolean;
|
||||
function check_generic_constraints(genericdef:tstoreddef;paramlist:tfpobjectlist;poslist:tfplist):boolean;
|
||||
var
|
||||
i,j,
|
||||
intfcount : longint;
|
||||
formaldef,
|
||||
paradef : tstoreddef;
|
||||
genparadef : tdef;
|
||||
objdef,
|
||||
paraobjdef,
|
||||
formalobjdef : tobjectdef;
|
||||
intffound : boolean;
|
||||
filepos : tfileposinfo;
|
||||
is_const : boolean;
|
||||
begin
|
||||
{ check whether the given specialization parameters fit to the eventual
|
||||
constraints of the generic }
|
||||
if not assigned(genericdef.genericparas) or (genericdef.genericparas.count=0) then
|
||||
internalerror(2012101001);
|
||||
if genericdef.genericparas.count<>paradeflist.count then
|
||||
if genericdef.genericparas.count<>paramlist.count then
|
||||
internalerror(2012101002);
|
||||
if paradeflist.count<>poslist.count then
|
||||
if paramlist.count<>poslist.count then
|
||||
internalerror(2012120801);
|
||||
result:=true;
|
||||
for i:=0 to genericdef.genericparas.count-1 do
|
||||
begin
|
||||
filepos:=pfileposinfo(poslist[i])^;
|
||||
formaldef:=tstoreddef(ttypesym(genericdef.genericparas[i]).typedef);
|
||||
if formaldef.typ=undefineddef then
|
||||
{ the parameter is of unspecified type, so no need to check }
|
||||
continue;
|
||||
if not (df_genconstraint in formaldef.defoptions) or
|
||||
not assigned(formaldef.genconstraintdata) then
|
||||
internalerror(2013021602);
|
||||
paradef:=tstoreddef(paradeflist[i]);
|
||||
{ undefineddef is compatible with anything }
|
||||
if formaldef.typ=undefineddef then
|
||||
continue;
|
||||
if paradef.typ<>formaldef.typ then
|
||||
paradef:=tstoreddef(get_generic_param_def(tsym(paramlist[i])));
|
||||
is_const:=tsym(paramlist[i]).typ=constsym;
|
||||
genparadef:=genericdef.get_generic_param_def(i);
|
||||
{ validate const params }
|
||||
if not genericdef.is_generic_param_const(i) and is_const then
|
||||
begin
|
||||
case formaldef.typ of
|
||||
recorddef:
|
||||
{ delphi has own fantasy about record constraint
|
||||
(almost non-nullable/non-nilable value type) }
|
||||
if m_delphi in current_settings.modeswitches then
|
||||
case paradef.typ of
|
||||
floatdef,enumdef,orddef:
|
||||
continue;
|
||||
objectdef:
|
||||
if tobjectdef(paradef).objecttype=odt_object then
|
||||
continue
|
||||
else
|
||||
MessagePos(filepos,type_e_record_type_expected);
|
||||
MessagePos(filepos,type_e_mismatch);
|
||||
exit(false);
|
||||
end
|
||||
else if genericdef.is_generic_param_const(i) then
|
||||
begin
|
||||
{ param type mismatch (type <> const) }
|
||||
if genericdef.is_generic_param_const(i)<>is_const then
|
||||
begin
|
||||
MessagePos(filepos,type_e_mismatch);
|
||||
exit(false);
|
||||
end;
|
||||
{ type constrained param doesn't match type }
|
||||
if not compare_generic_params(paradef,genericdef.get_generic_param_def(i),tconstsym(paramlist[i])) then
|
||||
begin
|
||||
MessagePos2(filepos,type_e_incompatible_types,FullTypeName(paradef,genparadef),FullTypeName(genparadef,paradef));
|
||||
exit(false);
|
||||
end;
|
||||
end;
|
||||
{ test constraints for non-const params }
|
||||
if not genericdef.is_generic_param_const(i) then
|
||||
begin
|
||||
formaldef:=tstoreddef(ttypesym(genericdef.genericparas[i]).typedef);
|
||||
if formaldef.typ=undefineddef then
|
||||
{ the parameter is of unspecified type, so no need to check }
|
||||
continue;
|
||||
if not (df_genconstraint in formaldef.defoptions) or
|
||||
not assigned(formaldef.genconstraintdata) then
|
||||
internalerror(2013021602);
|
||||
{ undefineddef is compatible with anything }
|
||||
if formaldef.typ=undefineddef then
|
||||
continue;
|
||||
if paradef.typ<>formaldef.typ then
|
||||
begin
|
||||
case formaldef.typ of
|
||||
recorddef:
|
||||
{ delphi has own fantasy about record constraint
|
||||
(almost non-nullable/non-nilable value type) }
|
||||
if m_delphi in current_settings.modeswitches then
|
||||
case paradef.typ of
|
||||
floatdef,enumdef,orddef:
|
||||
continue;
|
||||
objectdef:
|
||||
if tobjectdef(paradef).objecttype=odt_object then
|
||||
continue
|
||||
else
|
||||
MessagePos(filepos,type_e_record_type_expected);
|
||||
else
|
||||
MessagePos(filepos,type_e_record_type_expected);
|
||||
end
|
||||
else
|
||||
MessagePos(filepos,type_e_record_type_expected);
|
||||
end
|
||||
else
|
||||
MessagePos(filepos,type_e_record_type_expected);
|
||||
objectdef:
|
||||
case tobjectdef(formaldef).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 formaldef.typ=objectdef then
|
||||
begin
|
||||
paraobjdef:=tobjectdef(paradef);
|
||||
formalobjdef:=tobjectdef(formaldef);
|
||||
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
|
||||
objectdef:
|
||||
case tobjectdef(formaldef).objecttype of
|
||||
odt_class,
|
||||
odt_javaclass:
|
||||
MessagePos1(filepos,type_e_class_type_expected,paradef.typename);
|
||||
odt_interfacecom,
|
||||
odt_interfacecorba,
|
||||
odt_interfacejava,
|
||||
odt_dispinterface:
|
||||
begin
|
||||
if (oo_is_forward in paraobjdef.objectoptions) and
|
||||
(paraobjdef.objecttype=formalobjdef.objecttype) and
|
||||
(df_genconstraint in formalobjdef.defoptions) and
|
||||
(
|
||||
(formalobjdef.objecttype=odt_interfacecom) and
|
||||
(formalobjdef.childof=interface_iunknown)
|
||||
)
|
||||
or
|
||||
(
|
||||
(formalobjdef.objecttype=odt_interfacecorba) and
|
||||
(formalobjdef.childof=nil)
|
||||
) then
|
||||
continue;
|
||||
if not def_is_related(paraobjdef,formalobjdef.childof) then
|
||||
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 formaldef.typ=objectdef then
|
||||
begin
|
||||
paraobjdef:=tobjectdef(paradef);
|
||||
formalobjdef:=tobjectdef(formaldef);
|
||||
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:
|
||||
begin
|
||||
MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.childof.typename);
|
||||
if (oo_is_forward in paraobjdef.objectoptions) and
|
||||
(paraobjdef.objecttype=formalobjdef.objecttype) and
|
||||
(df_genconstraint in formalobjdef.defoptions) and
|
||||
(
|
||||
(formalobjdef.objecttype=odt_interfacecom) and
|
||||
(formalobjdef.childof=interface_iunknown)
|
||||
)
|
||||
or
|
||||
(
|
||||
(formalobjdef.objecttype=odt_interfacecorba) and
|
||||
(formalobjdef.childof=nil)
|
||||
) then
|
||||
continue;
|
||||
if not def_is_related(paraobjdef,formalobjdef.childof) then
|
||||
begin
|
||||
MessagePos2(filepos,type_e_incompatible_types,paraobjdef.typename,formalobjdef.childof.typename);
|
||||
result:=false;
|
||||
end;
|
||||
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.childof 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.childof.typename);
|
||||
end;
|
||||
else
|
||||
begin
|
||||
MessagePos1(filepos,type_e_class_or_interface_type_expected,paraobjdef.typename);
|
||||
result:=false;
|
||||
end;
|
||||
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.childof 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.childof.typename);
|
||||
end;
|
||||
else
|
||||
begin
|
||||
MessagePos1(filepos,type_e_class_or_interface_type_expected,paraobjdef.typename);
|
||||
result:=false;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ this is either a "class" or a concrete instance with
|
||||
or without implemented interfaces }
|
||||
if not (paraobjdef.objecttype in [odt_class,odt_javaclass]) then
|
||||
end
|
||||
else
|
||||
begin
|
||||
MessagePos1(filepos,type_e_class_type_expected,paraobjdef.typename);
|
||||
result:=false;
|
||||
continue;
|
||||
end;
|
||||
{ for forward declared classes we allow pure TObject/class declarations }
|
||||
if (oo_is_forward in paraobjdef.objectoptions) and
|
||||
(df_genconstraint in formaldef.defoptions) then
|
||||
begin
|
||||
if (formalobjdef.childof=class_tobject) and
|
||||
not formalobjdef.implements_any_interfaces then
|
||||
continue;
|
||||
end;
|
||||
if assigned(formalobjdef.childof) and
|
||||
not def_is_related(paradef,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
|
||||
{ this is either a "class" or a concrete instance with
|
||||
or without implemented interfaces }
|
||||
if not (paraobjdef.objecttype in [odt_class,odt_javaclass]) then
|
||||
begin
|
||||
intffound:=assigned(
|
||||
find_implemented_interface(objdef,
|
||||
timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef
|
||||
)
|
||||
);
|
||||
if intffound then
|
||||
break;
|
||||
objdef:=objdef.childof;
|
||||
MessagePos1(filepos,type_e_class_type_expected,paraobjdef.typename);
|
||||
result:=false;
|
||||
continue;
|
||||
end;
|
||||
if intffound then
|
||||
inc(intfcount)
|
||||
else
|
||||
MessagePos2(filepos,parser_e_class_doesnt_implement_interface,paraobjdef.typename,timplementedinterface(formalobjdef.implementedinterfaces[j]).intfdef.typename);
|
||||
{ for forward declared classes we allow pure TObject/class declarations }
|
||||
if (oo_is_forward in paraobjdef.objectoptions) and
|
||||
(df_genconstraint in formaldef.defoptions) then
|
||||
begin
|
||||
if (formalobjdef.childof=class_tobject) and
|
||||
not formalobjdef.implements_any_interfaces then
|
||||
continue;
|
||||
end;
|
||||
if assigned(formalobjdef.childof) and
|
||||
not def_is_related(paradef,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(
|
||||
find_implemented_interface(objdef,
|
||||
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;
|
||||
if intfcount<>formalobjdef.implementedinterfaces.count then
|
||||
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;
|
||||
function parse_generic_specialization_types_internal(paramlist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring;parsedtype:tdef;parsedpos:tfileposinfo):boolean;
|
||||
var
|
||||
old_block_type : tblock_type;
|
||||
first : boolean;
|
||||
@ -310,9 +470,11 @@ uses
|
||||
namepart : string;
|
||||
prettynamepart : ansistring;
|
||||
module : tmodule;
|
||||
constprettyname : string;
|
||||
validparam : boolean;
|
||||
begin
|
||||
result:=true;
|
||||
if genericdeflist=nil then
|
||||
if paramlist=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
|
||||
@ -324,7 +486,7 @@ uses
|
||||
first:=not assigned(parsedtype);
|
||||
if assigned(parsedtype) then
|
||||
begin
|
||||
genericdeflist.Add(parsedtype);
|
||||
paramlist.Add(parsedtype.typesym);
|
||||
module:=find_module_from_symtable(parsedtype.owner);
|
||||
if not assigned(module) then
|
||||
internalerror(2016112801);
|
||||
@ -350,8 +512,10 @@ uses
|
||||
consume(_COMMA);
|
||||
block_type:=bt_type;
|
||||
tmpparampos:=current_filepos;
|
||||
typeparam:=factor(false,[ef_type_only]);
|
||||
if typeparam.nodetype=typen then
|
||||
typeparam:=factor(false,[ef_accept_equal]);
|
||||
{ determine if the typeparam node is a valid type or const }
|
||||
validparam:=typeparam.nodetype in tgeneric_param_nodes;
|
||||
if validparam then
|
||||
begin
|
||||
if tstoreddef(typeparam.resultdef).is_generic and
|
||||
(
|
||||
@ -367,31 +531,46 @@ uses
|
||||
end;
|
||||
if typeparam.resultdef.typ<>errordef then
|
||||
begin
|
||||
if not assigned(typeparam.resultdef.typesym) then
|
||||
if (typeparam.nodetype=typen) and not assigned(typeparam.resultdef.typesym) then
|
||||
message(type_e_generics_cannot_reference_itself)
|
||||
else if (typeparam.resultdef.typ<>errordef) then
|
||||
begin
|
||||
genericdeflist.Add(typeparam.resultdef);
|
||||
{ all non-type nodes are considered const }
|
||||
if typeparam.nodetype<>typen then
|
||||
paramlist.Add(create_generic_constsym(typeparam.resultdef,typeparam,constprettyname))
|
||||
else
|
||||
begin
|
||||
constprettyname:='';
|
||||
paramlist.Add(typeparam.resultdef.typesym);
|
||||
end;
|
||||
module:=find_module_from_symtable(typeparam.resultdef.owner);
|
||||
if not assigned(module) then
|
||||
internalerror(2016112802);
|
||||
namepart:='_$'+hexstr(module.moduleid,8)+'$$'+typeparam.resultdef.unique_id_str;
|
||||
if constprettyname<>'' then
|
||||
namepart:=namepart+'$$'+constprettyname;
|
||||
{ we use the full name of the type to uniquely identify it }
|
||||
if (symtablestack.top.symtabletype=parasymtable) and
|
||||
(symtablestack.top.defowner.typ=procdef) and
|
||||
(typeparam.resultdef.owner=symtablestack.top) then
|
||||
if typeparam.nodetype=typen then
|
||||
begin
|
||||
{ special handling for specializations inside generic function declarations }
|
||||
prettynamepart:=tdef(symtablestack.top.defowner).fullownerhierarchyname(true)+tprocdef(symtablestack.top.defowner).procsym.prettyname;
|
||||
end
|
||||
else
|
||||
begin
|
||||
prettynamepart:=typeparam.resultdef.fullownerhierarchyname(true);
|
||||
if (symtablestack.top.symtabletype=parasymtable) and
|
||||
(symtablestack.top.defowner.typ=procdef) and
|
||||
(typeparam.resultdef.owner=symtablestack.top) then
|
||||
begin
|
||||
{ special handling for specializations inside generic function declarations }
|
||||
prettynamepart:=tdef(symtablestack.top.defowner).fullownerhierarchyname(true)+tprocdef(symtablestack.top.defowner).procsym.prettyname;
|
||||
end
|
||||
else
|
||||
begin
|
||||
prettynamepart:=typeparam.resultdef.fullownerhierarchyname(true);
|
||||
end;
|
||||
end;
|
||||
specializename:=specializename+namepart;
|
||||
if not first then
|
||||
prettyname:=prettyname+',';
|
||||
prettyname:=prettyname+prettynamepart+typeparam.resultdef.typesym.prettyname;
|
||||
if constprettyname<>'' then
|
||||
prettyname:=prettyname+constprettyname
|
||||
else
|
||||
prettyname:=prettyname+prettynamepart+typeparam.resultdef.typesym.prettyname;
|
||||
end;
|
||||
end
|
||||
else
|
||||
@ -411,12 +590,12 @@ uses
|
||||
end;
|
||||
|
||||
|
||||
function parse_generic_specialization_types(genericdeflist:tfpobjectlist;poslist:tfplist;out prettyname,specializename:ansistring):boolean;
|
||||
function parse_generic_specialization_types(paramlist: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);
|
||||
result:=parse_generic_specialization_types_internal(paramlist,poslist,prettyname,specializename,nil,dummypos);
|
||||
end;
|
||||
|
||||
|
||||
@ -502,7 +681,7 @@ uses
|
||||
context:=tspecializationcontext.create;
|
||||
|
||||
{ Parse type parameters }
|
||||
err:=not parse_generic_specialization_types_internal(context.genericdeflist,context.poslist,context.prettyname,context.specializename,parsedtype,parsedpos);
|
||||
err:=not parse_generic_specialization_types_internal(context.paramlist,context.poslist,context.prettyname,context.specializename,parsedtype,parsedpos);
|
||||
if err then
|
||||
begin
|
||||
if not try_to_consume(_GT) then
|
||||
@ -556,7 +735,7 @@ uses
|
||||
|
||||
{ search a generic with the given count of params }
|
||||
countstr:='';
|
||||
str(context.genericdeflist.Count,countstr);
|
||||
str(context.paramlist.Count,countstr);
|
||||
|
||||
genname:=genname+'$'+countstr;
|
||||
ugenname:=upper(genname);
|
||||
@ -681,6 +860,8 @@ uses
|
||||
tempst : tglobalsymtable;
|
||||
psym,
|
||||
srsym : tsym;
|
||||
paramdef1,
|
||||
paramdef2,
|
||||
def : tdef;
|
||||
old_block_type : tblock_type;
|
||||
state : tspecializationstate;
|
||||
@ -708,7 +889,7 @@ uses
|
||||
|
||||
pd:=nil;
|
||||
|
||||
if not check_generic_constraints(genericdef,context.genericdeflist,context.poslist) then
|
||||
if not check_generic_constraints(genericdef,context.paramlist,context.poslist) then
|
||||
begin
|
||||
{ the parameters didn't fit the constraints, so don't continue with the
|
||||
specialization }
|
||||
@ -724,20 +905,19 @@ uses
|
||||
else
|
||||
prettyname:=genericdef.typesym.prettyname;
|
||||
prettyname:=prettyname+'<'+context.prettyname+'>';
|
||||
|
||||
generictypelist:=tfphashobjectlist.create(false);
|
||||
|
||||
{ build the list containing the types for the generic params }
|
||||
if not assigned(genericdef.genericparas) then
|
||||
internalerror(2013092601);
|
||||
if context.genericdeflist.count<>genericdef.genericparas.count then
|
||||
if context.paramlist.count<>genericdef.genericparas.count then
|
||||
internalerror(2013092603);
|
||||
for i:=0 to genericdef.genericparas.Count-1 do
|
||||
begin
|
||||
srsym:=tsym(genericdef.genericparas[i]);
|
||||
if not (sp_generic_para in srsym.symoptions) then
|
||||
internalerror(2013092602);
|
||||
generictypelist.add(srsym.realname,tdef(context.genericdeflist[i]).typesym);
|
||||
generictypelist.add(srsym.realname,context.paramlist[i]);
|
||||
end;
|
||||
|
||||
{ Special case if we are referencing the current defined object }
|
||||
@ -792,11 +972,33 @@ uses
|
||||
allequal:=true;
|
||||
for i:=0 to generictypelist.count-1 do
|
||||
begin
|
||||
if not equal_defs(ttypesym(generictypelist[i]).typedef,ttypesym(tstoreddef(def).genericparas[i]).typedef) then
|
||||
if tsym(generictypelist[i]).typ<>tsym(tstoreddef(def).genericparas[i]).typ then
|
||||
begin
|
||||
allequal:=false;
|
||||
break;
|
||||
end;
|
||||
if tsym(generictypelist[i]).typ=constsym then
|
||||
paramdef1:=tconstsym(generictypelist[i]).constdef
|
||||
else
|
||||
paramdef1:=ttypesym(generictypelist[i]).typedef;
|
||||
if tsym(tstoreddef(def).genericparas[i]).typ=constsym then
|
||||
paramdef2:=tconstsym(tstoreddef(def).genericparas[i]).constdef
|
||||
else
|
||||
paramdef2:=ttypesym(tstoreddef(def).genericparas[i]).typedef;
|
||||
if not equal_defs(paramdef2,paramdef2) then
|
||||
begin
|
||||
allequal:=false;
|
||||
break;
|
||||
end;
|
||||
if (tsym(generictypelist[i]).typ=constsym) and
|
||||
(
|
||||
(tconstsym(generictypelist[i]).consttyp<>tconstsym(tstoreddef(def).genericparas[i]).consttyp) or
|
||||
not same_constvalue(tconstsym(generictypelist[i]).consttyp,tconstsym(generictypelist[i]).value,tconstsym(tstoreddef(def).genericparas[i]).value)
|
||||
) then
|
||||
begin
|
||||
allequal:=false;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if allequal then
|
||||
begin
|
||||
@ -1159,25 +1361,43 @@ uses
|
||||
|
||||
function parse_generic_parameters(allowconstraints:boolean):tfphashobjectlist;
|
||||
var
|
||||
generictype : ttypesym;
|
||||
i,firstidx : longint;
|
||||
generictype : tstoredsym;
|
||||
i,firstidx,const_list_index : longint;
|
||||
srsymtable : tsymtable;
|
||||
basedef,def : tdef;
|
||||
defname : tidstring;
|
||||
allowconst,
|
||||
allowconstructor,
|
||||
is_const,
|
||||
doconsume : boolean;
|
||||
constraintdata : tgenericconstraintdata;
|
||||
old_block_type : tblock_type;
|
||||
fileinfo : tfileposinfo;
|
||||
last_token : ttoken;
|
||||
last_type_pos : tfileposinfo;
|
||||
begin
|
||||
result:=tfphashobjectlist.create(false);
|
||||
firstidx:=0;
|
||||
const_list_index:=0;
|
||||
old_block_type:=block_type;
|
||||
block_type:=bt_type;
|
||||
allowconst:=true;
|
||||
is_const:=false;
|
||||
last_token:=NOTOKEN;
|
||||
last_type_pos:=current_filepos;
|
||||
repeat
|
||||
if allowconst and try_to_consume(_CONST) then
|
||||
begin
|
||||
allowconst:=false;
|
||||
is_const:=true;
|
||||
const_list_index:=result.count;
|
||||
end;
|
||||
if token=_ID then
|
||||
begin
|
||||
generictype:=ctypesym.create(orgpattern,cundefinedtype);
|
||||
if is_const then
|
||||
generictype:=cconstsym.create_undefined(orgpattern,cundefinedtype)
|
||||
else
|
||||
generictype:=ctypesym.create(orgpattern,cundefinedtype);
|
||||
{ type parameters need to be added as strict private }
|
||||
generictype.visibility:=vis_strictprivate;
|
||||
include(generictype.symoptions,sp_generic_para);
|
||||
@ -1185,7 +1405,43 @@ uses
|
||||
end;
|
||||
consume(_ID);
|
||||
fileinfo:=current_tokenpos;
|
||||
if try_to_consume(_COLON) then
|
||||
{ const restriction }
|
||||
if is_const and try_to_consume(_COLON) then
|
||||
begin
|
||||
def:=nil;
|
||||
{ parse the type and assign the const type to generictype }
|
||||
single_type(def,[]);
|
||||
for i:=const_list_index to result.count-1 do
|
||||
begin
|
||||
{ finalize constant information once type is known }
|
||||
if assigned(def) and (def.typ in tgeneric_param_const_types) then
|
||||
begin
|
||||
case def.typ of
|
||||
orddef,
|
||||
enumdef:
|
||||
tconstsym(result[i]).consttyp:=constord;
|
||||
stringdef:
|
||||
tconstsym(result[i]).consttyp:=conststring;
|
||||
floatdef:
|
||||
tconstsym(result[i]).consttyp:=constreal;
|
||||
setdef:
|
||||
tconstsym(result[i]).consttyp:=constset;
|
||||
{ pointer always refers to nil with constants }
|
||||
pointerdef:
|
||||
tconstsym(result[i]).consttyp:=constnil;
|
||||
else
|
||||
internalerror(2020011402);
|
||||
end;
|
||||
tconstsym(result[i]).constdef:=def;
|
||||
end
|
||||
else
|
||||
Message1(type_e_generic_const_type_not_allowed,def.fulltypename);
|
||||
end;
|
||||
{ after type restriction const list terminates }
|
||||
is_const:=false;
|
||||
end
|
||||
{ type restriction }
|
||||
else if try_to_consume(_COLON) then
|
||||
begin
|
||||
if not allowconstraints then
|
||||
Message(parser_e_generic_constraints_not_allowed_here);
|
||||
@ -1302,6 +1558,7 @@ uses
|
||||
basedef:=cobjectdef.create(tobjectdef(def).objecttype,defname,tobjectdef(def),false);
|
||||
constraintdata.interfaces.delete(0);
|
||||
end;
|
||||
|
||||
if basedef.typ<>errordef then
|
||||
with tstoreddef(basedef) do
|
||||
begin
|
||||
@ -1328,21 +1585,34 @@ uses
|
||||
begin
|
||||
{ two different typeless parameters are considered as incompatible }
|
||||
for i:=firstidx to result.count-1 do
|
||||
begin
|
||||
ttypesym(result[i]).typedef:=cundefineddef.create(false);
|
||||
ttypesym(result[i]).typedef.typesym:=ttypesym(result[i]);
|
||||
end;
|
||||
if tsym(result[i]).typ<>constsym then
|
||||
begin
|
||||
ttypesym(result[i]).typedef:=cundefineddef.create(false);
|
||||
ttypesym(result[i]).typedef.typesym:=ttypesym(result[i]);
|
||||
end;
|
||||
{ a semicolon terminates a type parameter group }
|
||||
firstidx:=result.count;
|
||||
end;
|
||||
end;
|
||||
if token=_SEMICOLON then
|
||||
begin
|
||||
is_const:=false;
|
||||
allowconst:=true;
|
||||
end;
|
||||
last_token:=token;
|
||||
last_type_pos:=current_filepos;
|
||||
until not (try_to_consume(_COMMA) or try_to_consume(_SEMICOLON));
|
||||
{ if the constant parameter is not terminated then the type restriction was
|
||||
not specified and we need to give an error }
|
||||
if is_const then
|
||||
consume(_COLON);
|
||||
{ two different typeless parameters are considered as incompatible }
|
||||
for i:=firstidx to result.count-1 do
|
||||
begin
|
||||
ttypesym(result[i]).typedef:=cundefineddef.create(false);
|
||||
ttypesym(result[i]).typedef.typesym:=ttypesym(result[i]);
|
||||
end;
|
||||
if tsym(result[i]).typ<>constsym then
|
||||
begin
|
||||
ttypesym(result[i]).typedef:=cundefineddef.create(false);
|
||||
ttypesym(result[i]).typedef.typesym:=ttypesym(result[i]);
|
||||
end;
|
||||
block_type:=old_block_type;
|
||||
end;
|
||||
|
||||
@ -1350,7 +1620,9 @@ uses
|
||||
procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:tfphashobjectlist);
|
||||
var
|
||||
i : longint;
|
||||
generictype,sym : ttypesym;
|
||||
generictype : tstoredsym;
|
||||
generictypedef : tdef;
|
||||
sym : tsym;
|
||||
st : tsymtable;
|
||||
begin
|
||||
def.genericdef:=genericdef;
|
||||
@ -1375,10 +1647,23 @@ uses
|
||||
def.genericparas:=tfphashobjectlist.create(false);
|
||||
for i:=0 to genericlist.count-1 do
|
||||
begin
|
||||
generictype:=ttypesym(genericlist[i]);
|
||||
generictype:=tstoredsym(genericlist[i]);
|
||||
if assigned(generictype.owner) then
|
||||
begin
|
||||
sym:=ctypesym.create(genericlist.nameofindex(i),generictype.typedef);
|
||||
if generictype.typ=typesym then
|
||||
sym:=ctypesym.create(genericlist.nameofindex(i),ttypesym(generictype).typedef)
|
||||
else if generictype.typ=constsym then
|
||||
{ generictype is a constsym that was created in create_generic_constsym
|
||||
during phase 1 so we pass this directly without copying }
|
||||
begin
|
||||
sym:=generictype;
|
||||
{ the sym name is still undefined so we set it to match
|
||||
the generic param name so it's accessible }
|
||||
sym.realname:=genericlist.nameofindex(i);
|
||||
include(sym.symoptions,sp_generic_const);
|
||||
end
|
||||
else
|
||||
internalerror(2019021602);
|
||||
{ type parameters need to be added as strict private }
|
||||
sym.visibility:=vis_strictprivate;
|
||||
st.insert(sym);
|
||||
@ -1386,13 +1671,17 @@ uses
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (generictype.typedef.typ=undefineddef) and (generictype.typedef<>cundefinedtype) then
|
||||
if generictype.typ=typesym then
|
||||
begin
|
||||
{ the generic parameters were parsed before the genericdef existed thus the
|
||||
undefineddefs were added as part of the parent symtable }
|
||||
if assigned(generictype.typedef.owner) then
|
||||
generictype.typedef.owner.DefList.Extract(generictype.typedef);
|
||||
generictype.typedef.changeowner(st);
|
||||
generictypedef:=ttypesym(generictype).typedef;
|
||||
if (generictypedef.typ=undefineddef) and (generictypedef<>cundefinedtype) then
|
||||
begin
|
||||
{ the generic parameters were parsed before the genericdef existed thus the
|
||||
undefineddefs were added as part of the parent symtable }
|
||||
if assigned(generictypedef.owner) then
|
||||
generictypedef.owner.DefList.Extract(generictypedef);
|
||||
generictypedef.changeowner(st);
|
||||
end;
|
||||
end;
|
||||
st.insert(generictype);
|
||||
include(generictype.symoptions,sp_generic_para);
|
||||
|
@ -631,27 +631,48 @@ implementation
|
||||
function check_generic_parameters(fwpd,currpd:tprocdef):boolean;
|
||||
var
|
||||
i : longint;
|
||||
fwtype,
|
||||
currtype : ttypesym;
|
||||
fwsym,
|
||||
currsym : tsym;
|
||||
currtype : ttypesym absolute currsym;
|
||||
fileinfo : tfileposinfo;
|
||||
begin
|
||||
result:=true;
|
||||
if fwpd.genericparas.count<>currpd.genericparas.count then
|
||||
internalerror(2018090101);
|
||||
for i:=0 to fwpd.genericparas.count-1 do
|
||||
begin
|
||||
fwtype:=ttypesym(fwpd.genericparas[i]);
|
||||
currtype:=ttypesym(currpd.genericparas[i]);
|
||||
if fwtype.name<>currtype.name then
|
||||
fwsym:=tsym(fwpd.genericparas[i]);
|
||||
currsym:=tsym(currpd.genericparas[i]);
|
||||
if fwsym.name<>currsym.name then
|
||||
begin
|
||||
messagepos1(currtype.fileinfo,sym_e_generic_type_param_mismatch,currtype.realname);
|
||||
messagepos1(fwtype.fileinfo,sym_e_generic_type_param_decl,fwtype.realname);
|
||||
messagepos1(currsym.fileinfo,sym_e_generic_type_param_mismatch,currsym.realname);
|
||||
messagepos1(fwsym.fileinfo,sym_e_generic_type_param_decl,fwsym.realname);
|
||||
result:=false;
|
||||
end;
|
||||
if (fwpd.interfacedef or assigned(fwpd.struct)) and (df_genconstraint in currtype.typedef.defoptions) then
|
||||
if (fwpd.interfacedef or assigned(fwpd.struct)) and
|
||||
(
|
||||
((currsym.typ=typesym) and (df_genconstraint in currtype.typedef.defoptions)) or
|
||||
(currsym.typ=constsym)
|
||||
) then
|
||||
begin
|
||||
messagepos(tstoreddef(currtype.typedef).genconstraintdata.fileinfo,parser_e_generic_constraints_not_allowed_here);
|
||||
if currsym.typ=constsym then
|
||||
fileinfo:=currsym.fileinfo
|
||||
else
|
||||
fileinfo:=tstoreddef(currtype.typedef).genconstraintdata.fileinfo;
|
||||
messagepos(fileinfo,parser_e_generic_constraints_not_allowed_here);
|
||||
result:=false;
|
||||
end;
|
||||
if not fwpd.interfacedef and not assigned(fwpd.struct) and
|
||||
(fwsym.typ=constsym) then
|
||||
begin
|
||||
{ without modeswitch RepeatForward we need to check here
|
||||
if the type of the constants match }
|
||||
if (currsym.typ<>constsym) or not equal_defs(tconstsym(fwsym).constdef,tconstsym(currsym).constdef) then
|
||||
begin
|
||||
messagepos1(currpd.fileinfo,parser_e_header_dont_match_forward,currpd.fullprocname(false));
|
||||
result:=false;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -659,8 +680,10 @@ implementation
|
||||
function equal_generic_procdefs(fwpd,currpd:tprocdef):boolean;
|
||||
var
|
||||
i : longint;
|
||||
fwtype,
|
||||
currtype : ttypesym;
|
||||
fwsym,
|
||||
currsym : tsym;
|
||||
fwtype : ttypesym absolute fwsym;
|
||||
currtype : ttypesym absolute currsym;
|
||||
foundretdef : boolean;
|
||||
begin
|
||||
result:=false;
|
||||
@ -677,14 +700,36 @@ implementation
|
||||
foundretdef:=false;
|
||||
for i:=0 to fwpd.genericparas.count-1 do
|
||||
begin
|
||||
fwtype:=ttypesym(fwpd.genericparas[i]);
|
||||
currtype:=ttypesym(currpd.genericparas[i]);
|
||||
fwsym:=tsym(fwpd.genericparas[i]);
|
||||
currsym:=tsym(currpd.genericparas[i]);
|
||||
{ if the type in the currpd isn't a pure undefineddef (thus there
|
||||
are constraints and the fwpd was declared in the interface, then
|
||||
we can stop right there }
|
||||
if fwpd.interfacedef and ((currtype.typedef.typ<>undefineddef) or (df_genconstraint in currtype.typedef.defoptions)) then
|
||||
if fwpd.interfacedef and
|
||||
(
|
||||
(currsym.typ=constsym) or
|
||||
((currsym.typ=typesym) and
|
||||
(
|
||||
(currtype.typedef.typ<>undefineddef) or
|
||||
(df_genconstraint in currtype.typedef.defoptions)
|
||||
)
|
||||
)
|
||||
)then
|
||||
exit;
|
||||
if not foundretdef then
|
||||
if not fwpd.interfacedef then
|
||||
begin
|
||||
if (fwsym.typ=constsym) and (currsym.typ=constsym) then
|
||||
begin
|
||||
{ check whether the constant type for forward functions match }
|
||||
if not equal_defs(tconstsym(fwsym).constdef,tconstsym(currsym).constdef) then
|
||||
exit;
|
||||
end
|
||||
else if (fwsym.typ=constsym) then
|
||||
{ if the forward sym is a constant, the implementation needs to be one
|
||||
as well }
|
||||
exit;
|
||||
end;
|
||||
if not foundretdef and (fwsym.typ=typesym) then
|
||||
begin
|
||||
{ if the returndef is the same as this parameter's def then this
|
||||
needs to be the case for both procdefs }
|
||||
|
@ -50,7 +50,7 @@ const
|
||||
CurrentPPUVersion = 207;
|
||||
{ for any other changes to the ppu format, increase this version number
|
||||
(it's a cardinal) }
|
||||
CurrentPPULongVersion = 8;
|
||||
CurrentPPULongVersion = 9;
|
||||
|
||||
{ unit flags }
|
||||
uf_big_endian = $000004;
|
||||
|
@ -361,7 +361,9 @@ implementation
|
||||
procedure check_range(hp:tnode; fordef: tdef);
|
||||
begin
|
||||
if (hp.nodetype=ordconstn) and
|
||||
(fordef.typ<>errordef) then
|
||||
(fordef.typ<>errordef) and
|
||||
{ the node was derived from a generic parameter so ignore range check }
|
||||
not(nf_generic_para in hp.flags) then
|
||||
adaptrange(fordef,tordconstnode(hp).value,false,false,true);
|
||||
end;
|
||||
|
||||
|
@ -1316,6 +1316,7 @@ implementation
|
||||
|
||||
procedure array_dec(is_packed:boolean;genericdef:tstoreddef;genericlist:tfphashobjectlist);
|
||||
var
|
||||
isgeneric : boolean;
|
||||
lowval,
|
||||
highval : TConstExprInt;
|
||||
indexdef : tdef;
|
||||
@ -1362,6 +1363,7 @@ implementation
|
||||
lowval:=0;
|
||||
highval:=1;
|
||||
indexdef:=def;
|
||||
isgeneric:=true;
|
||||
end;
|
||||
else
|
||||
Message(sym_e_error_in_type_def);
|
||||
@ -1409,6 +1411,7 @@ implementation
|
||||
begin
|
||||
{ defaults }
|
||||
indexdef:=generrordef;
|
||||
isgeneric:=false;
|
||||
{ use defaults which don't overflow the compiler }
|
||||
lowval:=0;
|
||||
highval:=0;
|
||||
@ -1424,12 +1427,15 @@ implementation
|
||||
else
|
||||
begin
|
||||
pt:=expr(true);
|
||||
isgeneric:=false;
|
||||
if pt.nodetype=typen then
|
||||
setdefdecl(pt.resultdef)
|
||||
else
|
||||
begin
|
||||
if pt.nodetype=rangen then
|
||||
begin
|
||||
if nf_generic_para in pt.flags then
|
||||
isgeneric:=true;
|
||||
{ pure ordconstn expressions can be checked for
|
||||
generics as well, but don't give an error in case
|
||||
of parsing a generic if that isn't yet the case }
|
||||
@ -1446,7 +1452,9 @@ implementation
|
||||
highval:=tordconstnode(trangenode(pt).right).value;
|
||||
if highval<lowval then
|
||||
begin
|
||||
Message(parser_e_array_lower_less_than_upper_bound);
|
||||
{ ignore error if node is generic param }
|
||||
if not (nf_generic_para in pt.flags) then
|
||||
Message(parser_e_array_lower_less_than_upper_bound);
|
||||
highval:=lowval;
|
||||
end
|
||||
else if (lowval<int64(low(asizeint))) or
|
||||
@ -1494,6 +1502,8 @@ implementation
|
||||
end;
|
||||
if is_packed then
|
||||
include(arrdef.arrayoptions,ado_IsBitPacked);
|
||||
if isgeneric then
|
||||
include(arrdef.arrayoptions,ado_IsGeneric);
|
||||
|
||||
if token=_COMMA then
|
||||
consume(_COMMA)
|
||||
|
@ -212,8 +212,9 @@ type
|
||||
generic is encountered to ease inline
|
||||
specializations, etc; those symbols can be
|
||||
"overridden" with a completely different symbol }
|
||||
sp_explicitrename { this is used to keep track of type renames created
|
||||
sp_explicitrename, { this is used to keep track of type renames created
|
||||
by the user }
|
||||
sp_generic_const
|
||||
);
|
||||
tsymoptions=set of tsymoption;
|
||||
|
||||
@ -241,7 +242,10 @@ type
|
||||
{ internal def that's not for any export }
|
||||
df_internal,
|
||||
{ the local def is referenced from a public function }
|
||||
df_has_global_ref
|
||||
df_has_global_ref,
|
||||
{ the def was derived with generic type or const fields so the size
|
||||
of the def can not be determined }
|
||||
df_has_generic_fields
|
||||
);
|
||||
tdefoptions=set of tdefoption;
|
||||
|
||||
@ -567,7 +571,8 @@ type
|
||||
ado_IsArrayOfConst, // array of const
|
||||
ado_IsConstString, // string constant
|
||||
ado_IsBitPacked, // bitpacked array
|
||||
ado_IsVector // Vector
|
||||
ado_IsVector, // Vector
|
||||
ado_IsGeneric // the index of the array is generic (meaning that the size is not yet known)
|
||||
);
|
||||
tarraydefoptions=set of tarraydefoption;
|
||||
|
||||
|
@ -175,6 +175,9 @@ interface
|
||||
function is_generic:boolean;
|
||||
{ same as above for specializations }
|
||||
function is_specialization:boolean;
|
||||
{ generic utilities }
|
||||
function is_generic_param_const(index:integer):boolean;inline;
|
||||
function get_generic_param_def(index:integer):tdef;inline;
|
||||
{ registers this def in the unit's deflist; no-op if already registered }
|
||||
procedure register_def; override;
|
||||
{ add the def to the top of the symtable stack if it's not yet owned
|
||||
@ -2407,14 +2410,32 @@ implementation
|
||||
for i:=0 to genericparas.count-1 do
|
||||
begin
|
||||
sym:=tsym(genericparas[i]);
|
||||
if sym.typ<>symconst.typesym then
|
||||
{ sym must be either a type or const }
|
||||
if not (sym.typ in [symconst.typesym,symconst.constsym]) then
|
||||
internalerror(2014050903);
|
||||
if sym.owner.defowner<>self then
|
||||
exit(false);
|
||||
if (sym.typ=symconst.constsym) and (sp_generic_const in sym.symoptions) then
|
||||
exit(false);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function tstoreddef.is_generic_param_const(index:integer):boolean;
|
||||
begin
|
||||
result:=tsym(genericparas[index]).typ=constsym;
|
||||
end;
|
||||
|
||||
|
||||
function tstoreddef.get_generic_param_def(index:integer):tdef;
|
||||
begin
|
||||
if tsym(genericparas[index]).typ=constsym then
|
||||
result:=tconstsym(genericparas[index]).constdef
|
||||
else
|
||||
result:=ttypesym(genericparas[index]).typedef;
|
||||
end;
|
||||
|
||||
|
||||
function tstoreddef.is_specialization: boolean;
|
||||
var
|
||||
i : longint;
|
||||
@ -2430,10 +2451,13 @@ implementation
|
||||
for i:=0 to genericparas.count-1 do
|
||||
begin
|
||||
sym:=tsym(genericparas[i]);
|
||||
if sym.typ<>symconst.typesym then
|
||||
{ sym must be either a type or const }
|
||||
if not (sym.typ in [symconst.typesym,symconst.constsym]) then
|
||||
internalerror(2014050904);
|
||||
if sym.owner.defowner<>self then
|
||||
exit(true);
|
||||
if (sym.typ=symconst.constsym) and (sp_generic_const in sym.symoptions) then
|
||||
exit(true);
|
||||
end;
|
||||
result:=false;
|
||||
end;
|
||||
@ -4179,7 +4203,7 @@ implementation
|
||||
ppufile.getderef(rangedefderef);
|
||||
lowrange:=ppufile.getasizeint;
|
||||
highrange:=ppufile.getasizeint;
|
||||
ppufile.getset(tppuset1(arrayoptions));
|
||||
ppufile.getset(tppuset2(arrayoptions));
|
||||
ppuload_platform(ppufile);
|
||||
symtable:=tarraysymtable.create(self);
|
||||
tarraysymtable(symtable).ppuload(ppufile)
|
||||
@ -4219,7 +4243,7 @@ implementation
|
||||
ppufile.putderef(rangedefderef);
|
||||
ppufile.putasizeint(lowrange);
|
||||
ppufile.putasizeint(highrange);
|
||||
ppufile.putset(tppuset1(arrayoptions));
|
||||
ppufile.putset(tppuset2(arrayoptions));
|
||||
writeentry(ppufile,ibarraydef);
|
||||
tarraysymtable(symtable).ppuwrite(ppufile);
|
||||
end;
|
||||
@ -4339,6 +4363,7 @@ implementation
|
||||
(ado_IsDynamicArray in arrayoptions) or
|
||||
(ado_IsConvertedPointer in arrayoptions) or
|
||||
(ado_IsConstructor in arrayoptions) or
|
||||
(ado_IsGeneric in arrayoptions) or
|
||||
(highrange<lowrange)
|
||||
) and
|
||||
(size=-1) then
|
||||
@ -4543,7 +4568,8 @@ implementation
|
||||
fullparas,
|
||||
paramname : ansistring;
|
||||
module : tmodule;
|
||||
sym : ttypesym;
|
||||
sym : tsym;
|
||||
def : tdef;
|
||||
i : longint;
|
||||
begin
|
||||
{ we want at least enough space for an ellipsis }
|
||||
@ -4552,15 +4578,21 @@ implementation
|
||||
fullparas:='';
|
||||
for i:=0 to genericparas.count-1 do
|
||||
begin
|
||||
sym:=ttypesym(genericparas[i]);
|
||||
sym:=tsym(genericparas[i]);
|
||||
module:=find_module_from_symtable(sym.owner);
|
||||
if not assigned(module) then
|
||||
internalerror(2014121202);
|
||||
paramname:=module.realmodulename^;
|
||||
if sym.typedef.typ in [objectdef,recorddef] then
|
||||
paramname:=paramname+'.'+tabstractrecorddef(sym.typedef).rttiname
|
||||
if not (sym.typ in [constsym,symconst.typesym]) then
|
||||
internalerror(2020042501);
|
||||
if sym.typ=constsym then
|
||||
def:=tconstsym(sym).constdef
|
||||
else
|
||||
paramname:=paramname+'.'+sym.typedef.typename;
|
||||
def:=ttypesym(sym).typedef;
|
||||
paramname:=module.realmodulename^;
|
||||
if def.typ in [objectdef,recorddef] then
|
||||
paramname:=paramname+'.'+tabstractrecorddef(def).rttiname
|
||||
else
|
||||
paramname:=paramname+'.'+def.typename;
|
||||
if length(fullparas)+commacount[i>0]+length(paramname)>maxlength then
|
||||
begin
|
||||
if i>0 then
|
||||
@ -5958,7 +5990,7 @@ implementation
|
||||
if AValue then
|
||||
include(implprocoptions,pio_empty)
|
||||
else
|
||||
include(implprocoptions,pio_empty);
|
||||
exclude(implprocoptions,pio_empty);
|
||||
end;
|
||||
|
||||
|
||||
|
@ -401,6 +401,7 @@ interface
|
||||
constructor create_ptr(const n : string;t : tconsttyp;v : pointer;def:tdef);virtual;
|
||||
constructor create_string(const n : string;t : tconsttyp;str:pchar;l:longint;def:tdef);virtual;
|
||||
constructor create_wstring(const n : string;t : tconsttyp;pw:pcompilerwidestring);virtual;
|
||||
constructor create_undefined(const n : string;def:tdef);virtual;
|
||||
constructor ppuload(ppufile:tcompilerppufile);
|
||||
destructor destroy;override;
|
||||
procedure buildderef;override;
|
||||
@ -491,6 +492,8 @@ interface
|
||||
procedure check_hints(const srsym: tsym; const symoptions: tsymoptions; const deprecatedmsg : pshortstring);inline;
|
||||
procedure check_hints(const srsym: tsym; const symoptions: tsymoptions; const deprecatedmsg : pshortstring;filepos:tfileposinfo);
|
||||
|
||||
function same_constvalue(consttyp:tconsttyp;const value1,value2:tconstvalue):boolean;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -528,6 +531,30 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function same_constvalue(consttyp:tconsttyp;const value1,value2:tconstvalue):boolean;
|
||||
begin
|
||||
case consttyp of
|
||||
constnone,
|
||||
constnil:
|
||||
result:=true;
|
||||
constord:
|
||||
result:=value1.valueord=value2.valueord;
|
||||
constpointer:
|
||||
result:=value1.valueordptr=value2.valueordptr;
|
||||
conststring,
|
||||
constreal,
|
||||
constset,
|
||||
constresourcestring,
|
||||
constwstring,
|
||||
constguid: begin
|
||||
if value1.len<>value2.len then
|
||||
exit(false);
|
||||
result:=CompareByte(value1.valueptr^,value2.valueptr^,value1.len)=0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure check_hints(const srsym: tsym; const symoptions: tsymoptions; const deprecatedmsg : pshortstring);
|
||||
begin
|
||||
check_hints(srsym,symoptions,deprecatedmsg,current_filepos);
|
||||
@ -1618,7 +1645,6 @@ implementation
|
||||
tparasymtable(parast).ppuwrite(ppufile);
|
||||
end;
|
||||
|
||||
|
||||
{****************************************************************************
|
||||
TABSTRACTVARSYM
|
||||
****************************************************************************}
|
||||
@ -2426,6 +2452,15 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
constructor tconstsym.create_undefined(const n : string;def: tdef);
|
||||
begin
|
||||
inherited create(constsym,n);
|
||||
fillchar(value,sizeof(value),#0);
|
||||
consttyp:=constnone;
|
||||
constdef:=def;
|
||||
end;
|
||||
|
||||
|
||||
constructor tconstsym.ppuload(ppufile:tcompilerppufile);
|
||||
var
|
||||
pd : pbestreal;
|
||||
@ -2509,8 +2544,7 @@ implementation
|
||||
destructor tconstsym.destroy;
|
||||
begin
|
||||
case consttyp of
|
||||
constnone:
|
||||
internalerror(2019050703);
|
||||
constnone,
|
||||
constord,
|
||||
constpointer,
|
||||
constnil:
|
||||
|
@ -1147,7 +1147,14 @@ begin
|
||||
{$endif riscv64}
|
||||
|
||||
{$ifdef xtensa}
|
||||
{$ifdef linux}
|
||||
{$define default_target_set}
|
||||
default_target(system_xtensa_linux);
|
||||
{$endif}
|
||||
|
||||
{$ifndef default_target_set}
|
||||
default_target(system_xtensa_embedded);
|
||||
{$endif ndef default_target_set}
|
||||
{$endif xtensa}
|
||||
|
||||
end;
|
||||
|
@ -1687,7 +1687,8 @@ const
|
||||
(mask:sp_generic_para; str:'Generic Parameter'),
|
||||
(mask:sp_has_deprecated_msg; str:'Has Deprecated Message'),
|
||||
(mask:sp_generic_dummy; str:'Generic Dummy'),
|
||||
(mask:sp_explicitrename; str:'Explicit Rename')
|
||||
(mask:sp_explicitrename; str:'Explicit Rename'),
|
||||
(mask:sp_generic_const; str:'Generic Constant Parameter')
|
||||
);
|
||||
var
|
||||
symoptions : tsymoptions;
|
||||
@ -2743,7 +2744,8 @@ const
|
||||
(mask:df_not_registered_no_free; str:'Unregistered/No free (invalid)'),
|
||||
(mask:df_llvm_no_struct_packing; str:'LLVM unpacked struct'),
|
||||
(mask:df_internal; str:'Internal'),
|
||||
(mask:df_has_global_ref; str:'Has Global Ref')
|
||||
(mask:df_has_global_ref; str:'Has Global Ref'),
|
||||
(mask:df_has_generic_fields; str:'Has generic fields')
|
||||
);
|
||||
defstate : array[1..ord(high(tdefstate))] of tdefstateinfo=(
|
||||
(mask:ds_vmt_written; str:'VMT Written'),
|
||||
@ -3267,14 +3269,15 @@ const
|
||||
{ ado_IsArrayOfConst } 'ArrayOfConst',
|
||||
{ ado_IsConstString } 'ConstString',
|
||||
{ ado_IsBitPacked } 'BitPacked',
|
||||
{ ado_IsVector } 'Vector'
|
||||
{ ado_IsVector } 'Vector',
|
||||
{ ado_IsGeneric } 'Generic'
|
||||
);
|
||||
var
|
||||
symoptions: tarraydefoptions;
|
||||
i: tarraydefoption;
|
||||
first: boolean;
|
||||
begin
|
||||
ppufile.getset(tppuset1(symoptions));
|
||||
ppufile.getset(tppuset2(symoptions));
|
||||
if symoptions<>[] then
|
||||
begin
|
||||
if ado_IsDynamicArray in symoptions then Include(ArrayDef.Options, aoDynamic);
|
||||
|
@ -80,6 +80,9 @@ interface
|
||||
{$ifdef cpuriscv32}
|
||||
source_cpu_string = 'riscv32';
|
||||
{$endif cpuriscv32}
|
||||
{$ifdef cpuxtensa}
|
||||
source_cpu_string = 'xtensa';
|
||||
{$endif cpuxtensa}
|
||||
|
||||
function version_string:string;
|
||||
function full_version_string:string;
|
||||
|
@ -173,7 +173,7 @@ unit agcpugas;
|
||||
idtxt : 'AS';
|
||||
asmbin : 'as';
|
||||
asmcmd : '-o $OBJ $EXTRAOPT $ASM --longcalls';
|
||||
supported_targets : [system_xtensa_embedded];
|
||||
supported_targets : [system_xtensa_embedded,system_xtensa_linux,system_xtensa_freertos];
|
||||
flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
|
||||
labelprefix : '.L';
|
||||
labelmaxlen : -1;
|
||||
|
@ -431,7 +431,8 @@ const
|
||||
btArrayRangeTypes = btAllChars+btAllBooleans+btAllInteger;
|
||||
btAllRanges = btArrayRangeTypes+[btRange];
|
||||
btAllWithSubType = [btSet, btArrayLit, btArrayOrSet, btRange];
|
||||
btAllStandardTypes = [
|
||||
btAllIntrinsicTypes = btAllInteger+btAllStringAndChars+btAllFloats+btAllBooleans;
|
||||
btAllFPCTypes = [
|
||||
btChar,
|
||||
{$ifdef FPC_HAS_CPSTRING}
|
||||
btAnsiChar,
|
||||
@ -2080,7 +2081,7 @@ type
|
||||
// built in types and functions
|
||||
procedure ClearBuiltInIdentifiers; virtual;
|
||||
procedure AddObjFPCBuiltInIdentifiers(
|
||||
const TheBaseTypes: TResolveBaseTypes = btAllStandardTypes;
|
||||
const TheBaseTypes: TResolveBaseTypes = btAllFPCTypes;
|
||||
const TheBaseProcs: TResolverBuiltInProcs = bfAllStandardProcs); virtual;
|
||||
function AddBaseType(const aName: string; Typ: TResolverBaseType): TResElDataBaseType;
|
||||
function AddCustomBaseType(const aName: string; aClass: TResElDataBaseTypeClass): TPasUnresolvedSymbolRef;
|
||||
@ -10435,7 +10436,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
// default: search for type helpers
|
||||
if (LeftResolved.BaseType in btAllStandardTypes)
|
||||
if (LeftResolved.BaseType in btAllIntrinsicTypes)
|
||||
or (LeftResolved.BaseType=btContext)
|
||||
or (LeftResolved.BaseType=btCustom) then
|
||||
begin
|
||||
@ -22038,7 +22039,7 @@ begin
|
||||
if LoType=nil then
|
||||
RaiseMsg(20170216152004,nExprTypeMustBeClassOrRecordTypeGot,sExprTypeMustBeClassOrRecordTypeGot,
|
||||
[BaseTypeNames[ExprResolved.BaseType]],ErrorEl);
|
||||
if (ExprResolved.BaseType in btAllStandardTypes) then
|
||||
if (ExprResolved.BaseType in btAllIntrinsicTypes) then
|
||||
// ok
|
||||
else if (ExprResolved.BaseType=btContext) then
|
||||
// ok
|
||||
|
@ -272,8 +272,8 @@ const
|
||||
FFI_TRAMPOLINE_SIZE = 20;
|
||||
{$elseif defined(CPUMIPS64)}
|
||||
FFI_TRAMPOLINE_SIZE = 56;
|
||||
#endif
|
||||
|
||||
{$elseif defined(CPUXTENSA)}
|
||||
FFI_TRAMPOLINE_SIZE = 24;
|
||||
{$endif}
|
||||
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
**********************************************************************}
|
||||
unit clipboard;
|
||||
|
||||
{$PACKRECORDS 2}
|
||||
interface
|
||||
|
||||
uses
|
||||
|
@ -15106,42 +15106,39 @@ begin
|
||||
ClassPath:=CreateReferencePath(ProcScope.ClassRecScope.Element,AContext,rpkPathAndName);
|
||||
Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
|
||||
end;
|
||||
if (ImplProc.Body.Functions.Count>0)
|
||||
or aResolver.HasAnonymousFunctions(ImplProc.Body.Body) then
|
||||
begin
|
||||
// has nested procs -> add "var self = this;"
|
||||
FuncContext.AddLocalVar(GetBIName(pbivnSelf),ThisPas);
|
||||
SelfSt:=CreateVarStatement(GetBIName(pbivnSelf),
|
||||
CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
|
||||
AddBodyStatement(SelfSt,PosEl);
|
||||
if ImplProcScope.SelfArg<>nil then
|
||||
begin
|
||||
// redirect Pascal-Self to JS-Self
|
||||
FuncContext.AddLocalVar(GetBIName(pbivnSelf),ImplProcScope.SelfArg);
|
||||
end;
|
||||
end
|
||||
else if ImplProcScope.SelfArg<>nil then
|
||||
begin
|
||||
// no nested procs -> redirect Pascal-Self to JS-this
|
||||
FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// no "this"
|
||||
// "this" has no direct Pascal element
|
||||
if ProcScope.ClassRecScope<>nil then
|
||||
begin
|
||||
// static method -> hide local
|
||||
// static method
|
||||
ClassOrRec:=ProcScope.ClassRecScope.Element;
|
||||
LocalVar:=FuncContext.FindLocalIdentifier(ClassOrRec);
|
||||
if (LocalVar<>nil) and (LocalVar.Name='this') then
|
||||
// "this" is not the class -> hide it (absolute path will be used)
|
||||
FuncContext.AddLocalVar(LocalVarHide,ClassOrRec);
|
||||
end;
|
||||
end;
|
||||
if (ImplProc.Body.Functions.Count>0)
|
||||
or aResolver.HasAnonymousFunctions(ImplProc.Body.Body) then
|
||||
begin
|
||||
// has nested procs -> add "var $Self = this;"
|
||||
if ThisPas<>nil then
|
||||
FuncContext.AddLocalVar(GetBIName(pbivnSelf),ThisPas);
|
||||
SelfSt:=CreateVarStatement(GetBIName(pbivnSelf),
|
||||
CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
|
||||
AddBodyStatement(SelfSt,PosEl);
|
||||
if ImplProcScope.SelfArg<>nil then
|
||||
begin
|
||||
// no nested procs -> redirect Pascal-Self to JS-this
|
||||
FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
|
||||
// redirect Pascal-Self to JS-Self
|
||||
FuncContext.AddLocalVar(GetBIName(pbivnSelf),ImplProcScope.SelfArg);
|
||||
end;
|
||||
end
|
||||
else if ImplProcScope.SelfArg<>nil then
|
||||
begin
|
||||
// no nested procs -> redirect Pascal-Self to JS-this
|
||||
FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
|
||||
end;
|
||||
end;
|
||||
{$IFDEF VerbosePas2JS}
|
||||
|
@ -702,12 +702,14 @@ type
|
||||
Procedure TestTypeHelper_Constructor;
|
||||
Procedure TestTypeHelper_Word;
|
||||
Procedure TestTypeHelper_Double;
|
||||
Procedure TestTypeHelper_NativeInt;
|
||||
Procedure TestTypeHelper_StringChar;
|
||||
Procedure TestTypeHelper_JSValue;
|
||||
Procedure TestTypeHelper_Array;
|
||||
Procedure TestTypeHelper_EnumType;
|
||||
Procedure TestTypeHelper_SetType;
|
||||
Procedure TestTypeHelper_InterfaceType;
|
||||
Procedure TestTypeHelper_NestedSelf;
|
||||
|
||||
// proc types
|
||||
Procedure TestProcType;
|
||||
@ -24090,6 +24092,99 @@ begin
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestTypeHelper_NativeInt;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch typehelpers}',
|
||||
'type',
|
||||
' MaxInt = type nativeint;',
|
||||
' THelperI = type helper for MaxInt',
|
||||
' function ToStr: String;',
|
||||
' end;',
|
||||
' MaxUInt = type nativeuint;',
|
||||
' THelperU = type helper for MaxUInt',
|
||||
' function ToStr: String;',
|
||||
' end;',
|
||||
'function THelperI.ToStr: String;',
|
||||
'begin',
|
||||
' Result:=str(Self);',
|
||||
'end;',
|
||||
'function THelperU.ToStr: String;',
|
||||
'begin',
|
||||
' Result:=str(Self);',
|
||||
'end;',
|
||||
'procedure DoIt(s: string);',
|
||||
'begin',
|
||||
'end;',
|
||||
'var i: MaxInt;',
|
||||
'begin',
|
||||
' DoIt(i.toStr);',
|
||||
' DoIt(i.toStr());',
|
||||
' (i*i).toStr;',
|
||||
' DoIt((i*i).toStr);',
|
||||
'']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestTypeHelper_NativeInt',
|
||||
LinesToStr([ // statements
|
||||
'rtl.createHelper($mod, "THelperI", null, function () {',
|
||||
' this.ToStr = function () {',
|
||||
' var Result = "";',
|
||||
' Result = "" + this.get();',
|
||||
' return Result;',
|
||||
' };',
|
||||
'});',
|
||||
'rtl.createHelper($mod, "THelperU", null, function () {',
|
||||
' this.ToStr = function () {',
|
||||
' var Result = "";',
|
||||
' Result = "" + this.get();',
|
||||
' return Result;',
|
||||
' };',
|
||||
'});',
|
||||
'this.DoIt = function (s) {',
|
||||
'};',
|
||||
'this.i = 0;',
|
||||
'']),
|
||||
LinesToStr([ // $mod.$main
|
||||
'$mod.DoIt($mod.THelperI.ToStr.call({',
|
||||
' p: $mod,',
|
||||
' get: function () {',
|
||||
' return this.p.i;',
|
||||
' },',
|
||||
' set: function (v) {',
|
||||
' this.p.i = v;',
|
||||
' }',
|
||||
'}));',
|
||||
'$mod.DoIt($mod.THelperI.ToStr.call({',
|
||||
' p: $mod,',
|
||||
' get: function () {',
|
||||
' return this.p.i;',
|
||||
' },',
|
||||
' set: function (v) {',
|
||||
' this.p.i = v;',
|
||||
' }',
|
||||
'}));',
|
||||
'$mod.THelperI.ToStr.call({',
|
||||
' a: $mod.i * $mod.i,',
|
||||
' get: function () {',
|
||||
' return this.a;',
|
||||
' },',
|
||||
' set: function (v) {',
|
||||
' rtl.raiseE("EPropReadOnly");',
|
||||
' }',
|
||||
'});',
|
||||
'$mod.DoIt($mod.THelperI.ToStr.call({',
|
||||
' a: $mod.i * $mod.i,',
|
||||
' get: function () {',
|
||||
' return this.a;',
|
||||
' },',
|
||||
' set: function (v) {',
|
||||
' rtl.raiseE("EPropReadOnly");',
|
||||
' }',
|
||||
'}));',
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestTypeHelper_StringChar;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -24597,6 +24692,44 @@ begin
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestTypeHelper_NestedSelf;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch typehelpers}',
|
||||
'type',
|
||||
' THelper = type helper for string',
|
||||
' procedure Run(Value: string);',
|
||||
' end;',
|
||||
'procedure THelper.Run(Value: string);',
|
||||
' function Sub(i: nativeint): boolean;',
|
||||
' begin',
|
||||
' Result:=Self[i+1]=Value[i];',
|
||||
' end;',
|
||||
'begin',
|
||||
' if Self[3]=Value[4] then ;',
|
||||
'end;',
|
||||
'begin',
|
||||
'']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestTypeHelper_NestedSelf',
|
||||
LinesToStr([ // statements
|
||||
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||
' this.Run = function (Value) {',
|
||||
' var $Self = this;',
|
||||
' function Sub(i) {',
|
||||
' var Result = false;',
|
||||
' Result = $Self.get().charAt((i + 1) - 1) === Value.charAt(i - 1);',
|
||||
' return Result;',
|
||||
' };',
|
||||
' if ($Self.get().charAt(2) === Value.charAt(3)) ;',
|
||||
' };',
|
||||
'});',
|
||||
'']),
|
||||
LinesToStr([ // $mod.$main
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestProcType;
|
||||
begin
|
||||
StartProgram(false);
|
||||
|
@ -584,11 +584,11 @@ begin
|
||||
SmallForce or ForceCursorUpdate then
|
||||
begin
|
||||
{$ifdef WITHBUFFERING}
|
||||
DrawChar(BufRp, OldCursorY, OldCursorX, crHidden);
|
||||
if CursorState then DrawChar(BufRp, CursorY, CursorX, CursorType);
|
||||
DrawChar(BufRp, OldCursorX, OldCursorY, crHidden);
|
||||
if CursorState then DrawChar(BufRp, CursorX, CursorY, CursorType);
|
||||
{$else}
|
||||
DrawChar(VideoWindow^.RPort, OldCursorY, OldCursorX, crHidden);
|
||||
if CursorState then DrawChar(VideoWindow^.RPort, CursorY, CursorX, CursorType);
|
||||
DrawChar(VideoWindow^.RPort, OldCursorX, OldCursorY, crHidden);
|
||||
if CursorState then DrawChar(VideoWindow^.RPort, CursorX, CursorY, CursorType);
|
||||
{$endif}
|
||||
OldCursorX := CursorX;
|
||||
OldCursorY := CursorY;
|
||||
@ -602,8 +602,8 @@ end;
|
||||
|
||||
procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
|
||||
begin
|
||||
CursorX := NewCursorY;
|
||||
CursorY := NewCursorX;
|
||||
CursorX := NewCursorX;
|
||||
CursorY := NewCursorY;
|
||||
SysUpdateScreen(False);
|
||||
end;
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
}
|
||||
|
||||
{$if not defined(cpux86_64) and not defined(cpuaarch64) and not defined(cpuriscv32) and not defined(cpuriscv64) and not defined(NO_SYSCALL_SOCKETCALL)}
|
||||
{$if not defined(cpux86_64) and not defined(cpuaarch64) and not defined(cpuriscv32) and not defined(cpuriscv64) and not defined(cpuxtensa) and not defined(NO_SYSCALL_SOCKETCALL)}
|
||||
{$define NEED_SOCKETCALL}
|
||||
{$endif}
|
||||
|
||||
|
@ -546,7 +546,7 @@ type
|
||||
msg_lrpid : ipc_pid_t;
|
||||
pad1 : qword;
|
||||
pad2 : qword;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
end;
|
||||
{$else}
|
||||
{$if defined(Darwin)}
|
||||
@ -888,7 +888,7 @@ uses Syscall;
|
||||
|
||||
{$ifndef FPC_USE_LIBC}
|
||||
{$if defined(Linux)}
|
||||
{$if defined(cpux86_64) or defined(cpuaarch64) or defined(cpuriscv32) or defined(cpuriscv64) or defined(NO_SYSCALL_IPC)}
|
||||
{$if defined(cpux86_64) or defined(cpuaarch64) or defined(cpuriscv32) or defined(cpuriscv64) or defined(cpuxtensa) or defined(NO_SYSCALL_IPC)}
|
||||
{$i ipcsys.inc}
|
||||
{$else}
|
||||
{$i ipccall.inc}
|
||||
|
@ -14,13 +14,12 @@
|
||||
|
||||
**********************************************************************}
|
||||
|
||||
function fpc_setjmp(var S : jmp_buf) : longint;assembler;[Public, alias : 'FPC_SETJMP'];nostackframe; compilerproc;
|
||||
function fpc_setjmp(var S : jmp_buf) : longint;assembler;[Public, alias : 'FPC_SETJMP']; compilerproc;
|
||||
asm
|
||||
movi a2,0
|
||||
end;
|
||||
|
||||
|
||||
procedure fpc_longjmp(var S : jmp_buf;value : longint);assembler;[Public, alias : 'FPC_LONGJMP']; compilerproc;
|
||||
asm
|
||||
end;
|
||||
|
||||
|
||||
|
39
tests/test/tgenconst1.pp
Normal file
39
tests/test/tgenconst1.pp
Normal file
@ -0,0 +1,39 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{
|
||||
test all possible constants
|
||||
}
|
||||
program tgenconst1;
|
||||
|
||||
type
|
||||
TEnums = (Blaise, Pascal);
|
||||
kNames = set of TEnums;
|
||||
kChars = set of char;
|
||||
|
||||
type
|
||||
generic TBoolean<const U: boolean> = record end;
|
||||
generic TString<const U: string> = record end;
|
||||
generic TFloat<const U: single> = record end;
|
||||
generic TInteger<const U: integer> = record end;
|
||||
generic TChar<const U: char> = record end;
|
||||
generic TByte<const U: byte> = record end;
|
||||
generic TQWord<const U: QWord> = record end;
|
||||
generic TEnum<const U: TEnums> = record end;
|
||||
generic TNames<const U: kNames> = record end;
|
||||
generic TChars<const U: kChars> = record end;
|
||||
generic TPointer<const U: pointer> = record end;
|
||||
|
||||
var
|
||||
a: specialize TBoolean<true>;
|
||||
b: specialize TString<'string'>;
|
||||
c: specialize TFloat<1>;
|
||||
d: specialize TInteger<10>;
|
||||
e: specialize TByte<255>;
|
||||
f: specialize TChar<'a'>;
|
||||
g: specialize TEnum<Pascal>;
|
||||
h: specialize TNames<[Blaise,Pascal]>;
|
||||
i: specialize TChars<['a','b']>;
|
||||
j: specialize TQWord<10>;
|
||||
k: specialize TPointer<nil>;
|
||||
begin
|
||||
end.
|
14
tests/test/tgenconst10.pp
Normal file
14
tests/test/tgenconst10.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test type mismatch when specializing generic type with constant value
|
||||
}
|
||||
program tgenconst10;
|
||||
|
||||
type
|
||||
generic TByte<T> = record end;
|
||||
|
||||
var
|
||||
a: specialize TByte<10>;
|
||||
begin
|
||||
end.
|
13
tests/test/tgenconst11.pp
Normal file
13
tests/test/tgenconst11.pp
Normal file
@ -0,0 +1,13 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test def compare fail with specialized types
|
||||
}
|
||||
program tgenconst11;
|
||||
type
|
||||
generic TConst<const U: integer> = class end;
|
||||
var
|
||||
a:specialize TConst<10>;
|
||||
begin
|
||||
a:=specialize TConst<'string'>.Create;
|
||||
end
|
15
tests/test/tgenconst12.pp
Normal file
15
tests/test/tgenconst12.pp
Normal file
@ -0,0 +1,15 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{
|
||||
test def compare with specialized types
|
||||
}
|
||||
program tgenconst12;
|
||||
|
||||
type
|
||||
generic TTest<const U: integer> = class
|
||||
end;
|
||||
|
||||
type
|
||||
ATest = specialize TTest<100>;
|
||||
begin
|
||||
end.
|
51
tests/test/tgenconst13.pp
Normal file
51
tests/test/tgenconst13.pp
Normal file
@ -0,0 +1,51 @@
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
test advanced record constants assigned from generic constant values
|
||||
}
|
||||
program tgenconst13;
|
||||
|
||||
type
|
||||
kNames = set of (Blaise,Pascal);
|
||||
kChars = set of char;
|
||||
type
|
||||
generic TBoolean<const U: boolean> = record const value = U; end;
|
||||
generic TString<const U: string> = record const value = U; end;
|
||||
generic TFloat<const U: single> = record const value = U; end;
|
||||
generic TInteger<const U: integer> = record const value = U; end;
|
||||
generic TByte<const U: byte> = record const value = U; end;
|
||||
generic TChar<const U: char> = record const value = U; end;
|
||||
generic TQWord<const U: QWord> = record const value = U; end;
|
||||
generic TNames<const U: kNames> = record const value = U; end;
|
||||
generic TChars<const U: kChars> = record const value = U; end;
|
||||
|
||||
procedure Test(failed: boolean); inline;
|
||||
begin
|
||||
if failed then
|
||||
begin
|
||||
writeln('failed!');
|
||||
halt(-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
g0: specialize TBoolean<true>;
|
||||
g1: specialize TString<'string'>;
|
||||
g2: specialize TFloat<10.5>;
|
||||
g3: specialize TInteger<10>;
|
||||
g4: specialize TByte<255>;
|
||||
g5: specialize TChar<'a'>;
|
||||
g6: specialize TQWord<1000000000>;
|
||||
g7: specialize TNames<[Blaise,Pascal]>;
|
||||
g8: specialize TChars<['a','b']>;
|
||||
begin
|
||||
Test(g0.value <> true);
|
||||
Test(g1.value <> 'string');
|
||||
Test(g2.value <> 10.5);
|
||||
Test(g3.value <> 10);
|
||||
Test(g4.value <> 255);
|
||||
Test(g5.value <> 'a');
|
||||
Test(g6.value <> 1000000000);
|
||||
Test(g7.value <> [Blaise,Pascal]);
|
||||
Test(g8.value <> ['a','b']);
|
||||
end.
|
42
tests/test/tgenconst14.pp
Normal file
42
tests/test/tgenconst14.pp
Normal file
@ -0,0 +1,42 @@
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
test binary operators with generic constant params
|
||||
}
|
||||
program tgenconst14;
|
||||
|
||||
type
|
||||
generic TBinaryOp<const I: Integer> = record
|
||||
const
|
||||
d0 = I + I;
|
||||
d1 = I - I;
|
||||
d2 = I * I;
|
||||
d3 = I / I;
|
||||
d4 = I div I;
|
||||
d5 = I mod I;
|
||||
d6 = I and I;
|
||||
d7 = I or I;
|
||||
d8 = I shl 2;
|
||||
d9 = I shr 2;
|
||||
end;
|
||||
|
||||
procedure Check(aExpected, aActual: Integer; aErrorCode: LongInt);
|
||||
begin
|
||||
if aExpected <> aActual then
|
||||
Halt(aErrorCode);
|
||||
end;
|
||||
|
||||
var
|
||||
op: specialize TBinaryOp<100>;
|
||||
begin
|
||||
Check(op.d0, 100 + 100, 1);
|
||||
Check(op.d1, 100 - 100, 2);
|
||||
Check(op.d2, 100 * 100, 3);
|
||||
Check(Trunc(op.d3), Trunc(100 / 100), 4);
|
||||
Check(op.d4, 100 div 100, 5);
|
||||
Check(op.d5, 100 mod 100, 6);
|
||||
Check(op.d6, 100 and 100, 7);
|
||||
Check(op.d7, 100 or 100, 8);
|
||||
Check(op.d8, 100 shl 2, 9);
|
||||
Check(op.d9, 100 shr 2, 10);
|
||||
end.
|
15
tests/test/tgenconst15.pp
Normal file
15
tests/test/tgenconst15.pp
Normal file
@ -0,0 +1,15 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
test binary operator error with wrong constant type
|
||||
}
|
||||
program tgenconst15;
|
||||
|
||||
type
|
||||
generic TInt<const I: string> = record
|
||||
const c = I div I;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
79
tests/test/tgenconst16.pp
Normal file
79
tests/test/tgenconst16.pp
Normal file
@ -0,0 +1,79 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
various operator tests
|
||||
}
|
||||
program tgenconst16;
|
||||
|
||||
type
|
||||
Day = (mon,tue,wed,thu,fri,sat,sun);
|
||||
Days = set of Day;
|
||||
generic TSet<const I: Days> = record
|
||||
const
|
||||
d0 = I + I; // Union
|
||||
d1 = I - I; // Difference
|
||||
d2 = I * I; // Intersection
|
||||
d3 = I >< I; // Symmetric difference
|
||||
d4 = I <= I; // Contains
|
||||
d5 = mon in I;
|
||||
end;
|
||||
generic TArray<const I: integer> = record
|
||||
type
|
||||
t0 = array[0..I - 1] of integer;
|
||||
t1 = array[0..high(I)] of integer;
|
||||
t2 = array[0..low(I)] of integer;
|
||||
t3 = array[0..sizeof(I)] of integer;
|
||||
public
|
||||
d0: array[0..I - 1] of integer;
|
||||
d1: array[0..high(I)] of integer;
|
||||
d2: array[0..low(I)] of integer;
|
||||
d3: array[0..sizeof(I)] of integer;
|
||||
end;
|
||||
generic TUnaryOp<const I: integer> = record
|
||||
const
|
||||
d0 = -I;
|
||||
d1 = +I;
|
||||
d2 = not I;
|
||||
end;
|
||||
generic TBinaryOp<const I: integer> = record
|
||||
const
|
||||
// Arithmetic operators
|
||||
// https://freepascal.org/docs-html/ref/refsu45.html
|
||||
d0 = I + I;
|
||||
d1 = I - I;
|
||||
d2 = I * I;
|
||||
d3 = I / I;
|
||||
d4 = I div I;
|
||||
d5 = I mod I;
|
||||
// Boolean operators
|
||||
// https://freepascal.org/docs-html/ref/refsu47.html
|
||||
d6 = I and I;
|
||||
d7 = I or I;
|
||||
d8 = I xor I;
|
||||
// Logical operators
|
||||
// https://freepascal.org/docs-html/ref/refsu46.html
|
||||
d9 = I shl I;
|
||||
d10 = I shr I;
|
||||
d11 = I << I;
|
||||
d12 = I >> I;
|
||||
// Relational operators
|
||||
// https://freepascal.org/docs-html/ref/refsu50.html#x153-17500012.8.6
|
||||
d13 = I <> I;
|
||||
d14 = I < I;
|
||||
d15 = I > I;
|
||||
d16 = I <= I;
|
||||
d17 = I >= I;
|
||||
d18 = I = I;
|
||||
end;
|
||||
generic TOther<const I: integer> = record
|
||||
procedure DoThis(param: integer = I);
|
||||
end;
|
||||
|
||||
procedure TOther.DoThis(param: integer = I);
|
||||
begin
|
||||
writeln(param, ' default:', I);
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
27
tests/test/tgenconst17.pp
Normal file
27
tests/test/tgenconst17.pp
Normal file
@ -0,0 +1,27 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
testing range checking for arrays and for-loops
|
||||
}
|
||||
|
||||
program tgenconst17;
|
||||
|
||||
type
|
||||
generic TStaticList<T; const Length: SizeUInt> = record
|
||||
Values: array[0..Length - 1] of T;
|
||||
procedure Display;
|
||||
end;
|
||||
|
||||
procedure TStaticList.Display;
|
||||
var
|
||||
I, n: SizeUInt;
|
||||
begin
|
||||
for I := 0 to Length - 1 do
|
||||
WriteLn(Values[I]);
|
||||
end;
|
||||
|
||||
var
|
||||
list: specialize TStaticList<Integer, 20>;
|
||||
begin
|
||||
end.
|
12
tests/test/tgenconst18.pp
Normal file
12
tests/test/tgenconst18.pp
Normal file
@ -0,0 +1,12 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test undefined constants which must be typed
|
||||
}
|
||||
program tgenconst18;
|
||||
|
||||
type
|
||||
generic TUndefined<const U> = record end;
|
||||
|
||||
begin
|
||||
end.
|
24
tests/test/tgenconst19.pp
Normal file
24
tests/test/tgenconst19.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %NORUN }
|
||||
unit tgenconst19;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
generic procedure Test<const A, B: LongInt>;
|
||||
generic procedure Test2<const A, B: LongInt>;
|
||||
|
||||
implementation
|
||||
|
||||
{ currently it does not matter whether , or ; is used in the definition (Delphi
|
||||
compatible) }
|
||||
|
||||
generic procedure Test<A, B>;
|
||||
begin
|
||||
end;
|
||||
|
||||
generic procedure Test2<A; B>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
14
tests/test/tgenconst2.pp
Normal file
14
tests/test/tgenconst2.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{
|
||||
test lists of types/contants
|
||||
}
|
||||
program tgenconst2;
|
||||
|
||||
type
|
||||
generic TMoreThanOne<T1,T2;const U1,U2:integer> = record end;
|
||||
|
||||
var
|
||||
a: specialize TMoreThanOne<integer,string,10,10>;
|
||||
begin
|
||||
end.
|
24
tests/test/tgenconst20.pp
Normal file
24
tests/test/tgenconst20.pp
Normal file
@ -0,0 +1,24 @@
|
||||
{ %NORUN }
|
||||
unit tgenconst20;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
procedure Test<const A, B: LongInt>;
|
||||
procedure Test2<const A, B: LongInt>;
|
||||
|
||||
implementation
|
||||
|
||||
{ currently it does not matter whether , or ; is used in the definition (Delphi
|
||||
compatible) }
|
||||
|
||||
procedure Test<A, B>;
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure Test2<A; B>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
16
tests/test/tgenconst21.pp
Normal file
16
tests/test/tgenconst21.pp
Normal file
@ -0,0 +1,16 @@
|
||||
unit tgenconst21;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
generic procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
generic procedure Test<A; const N: LongInt>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
||||
|
16
tests/test/tgenconst22.pp
Normal file
16
tests/test/tgenconst22.pp
Normal file
@ -0,0 +1,16 @@
|
||||
unit tgenconst22;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
procedure Test<A; const N: LongInt>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
||||
|
19
tests/test/tgenconst23.pp
Normal file
19
tests/test/tgenconst23.pp
Normal file
@ -0,0 +1,19 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst23;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
generic procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
generic procedure Test<A; const N: String>;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
19
tests/test/tgenconst24.pp
Normal file
19
tests/test/tgenconst24.pp
Normal file
@ -0,0 +1,19 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst24;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
procedure Test<A; const N: String>;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
18
tests/test/tgenconst25.pp
Normal file
18
tests/test/tgenconst25.pp
Normal file
@ -0,0 +1,18 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst25;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
generic procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
generic procedure Test<A; N>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
||||
|
18
tests/test/tgenconst26.pp
Normal file
18
tests/test/tgenconst26.pp
Normal file
@ -0,0 +1,18 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst26;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
implementation
|
||||
|
||||
procedure Test<A; const N: LongInt>; forward;
|
||||
|
||||
procedure Test<A; N>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
||||
|
17
tests/test/tgenconst27.pp
Normal file
17
tests/test/tgenconst27.pp
Normal file
@ -0,0 +1,17 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst27;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
generic procedure Test<const A: LongInt>;
|
||||
|
||||
implementation
|
||||
|
||||
generic procedure Test<const A: LongInt>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
17
tests/test/tgenconst28.pp
Normal file
17
tests/test/tgenconst28.pp
Normal file
@ -0,0 +1,17 @@
|
||||
{ %FAIL }
|
||||
|
||||
unit tgenconst28;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
procedure Test<const A: LongInt>;
|
||||
|
||||
implementation
|
||||
|
||||
procedure Test<const A: LongInt>;
|
||||
begin
|
||||
end;
|
||||
|
||||
end.
|
14
tests/test/tgenconst29.pp
Normal file
14
tests/test/tgenconst29.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{ %NORUN }
|
||||
program tgenconst29;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
type
|
||||
TRange = 3..4;
|
||||
|
||||
generic TTest<const U: TRange> = record end;
|
||||
|
||||
var
|
||||
t: specialize TTest<3>;
|
||||
begin
|
||||
end.
|
20
tests/test/tgenconst3.pp
Normal file
20
tests/test/tgenconst3.pp
Normal file
@ -0,0 +1,20 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{$modeswitch advancedrecords}
|
||||
{
|
||||
test integer constants in static array ranges
|
||||
}
|
||||
program tgenconst3;
|
||||
|
||||
type
|
||||
generic TList<T;const U:integer> = record
|
||||
const
|
||||
max = U;
|
||||
public
|
||||
m_list: array[0..max-1] of T;
|
||||
end;
|
||||
|
||||
var
|
||||
list: specialize TList<integer,128>;
|
||||
begin
|
||||
end.
|
14
tests/test/tgenconst30.pp
Normal file
14
tests/test/tgenconst30.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{ %FAIL }
|
||||
program tgenconst30;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
type
|
||||
TRange = 3..4;
|
||||
|
||||
generic TTest<const U: TRange> = record end;
|
||||
|
||||
var
|
||||
t: specialize TTest<2>;
|
||||
begin
|
||||
end.
|
15
tests/test/tgenconst4.pp
Normal file
15
tests/test/tgenconst4.pp
Normal file
@ -0,0 +1,15 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{
|
||||
test constants in generic procedures
|
||||
}
|
||||
program tgenconst4;
|
||||
|
||||
generic procedure DoThis<T;const U:string>(msg: string = U);
|
||||
begin
|
||||
writeln(msg, ' sizeof:',sizeof(t), ' default: ', U);
|
||||
end;
|
||||
|
||||
begin
|
||||
specialize DoThis<integer,'genparam'>('hello world');
|
||||
end.
|
28
tests/test/tgenconst5.pp
Normal file
28
tests/test/tgenconst5.pp
Normal file
@ -0,0 +1,28 @@
|
||||
{ %NORUN }
|
||||
{$mode objfpc}
|
||||
{
|
||||
test nested generic records with constants
|
||||
}
|
||||
program tgenconst5;
|
||||
|
||||
type
|
||||
generic THelperA<const U:integer> = record
|
||||
list: array[0..U-1] of byte;
|
||||
end;
|
||||
|
||||
type
|
||||
generic THelperB<T> = record
|
||||
value: T;
|
||||
end;
|
||||
|
||||
type
|
||||
generic TList<T; const U:integer> = record
|
||||
helperA: specialize THelperA<U>;
|
||||
helperB: specialize THelperB<T>;
|
||||
end;
|
||||
|
||||
var
|
||||
list: specialize TList<integer,32>;
|
||||
begin
|
||||
writeln('sizeof:',sizeof(list));
|
||||
end.
|
25
tests/test/tgenconst6.pp
Normal file
25
tests/test/tgenconst6.pp
Normal file
@ -0,0 +1,25 @@
|
||||
{ %NORUN }
|
||||
{$mode delphi}
|
||||
{
|
||||
test delphi mode
|
||||
}
|
||||
program tgenconst6;
|
||||
|
||||
type
|
||||
TList<T; const U: integer> = class
|
||||
list: array[0..U-1] of T;
|
||||
function capacity: integer;
|
||||
end;
|
||||
|
||||
function TList<T; U>.capacity: integer;
|
||||
begin
|
||||
result := U;
|
||||
end;
|
||||
|
||||
var
|
||||
nums:TList<integer,16>;
|
||||
strs:TList<string,16>;
|
||||
begin
|
||||
nums := TList<integer,16>.Create;
|
||||
strs := TList<string,16>.Create;
|
||||
end.
|
14
tests/test/tgenconst7.pp
Normal file
14
tests/test/tgenconst7.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test type mismatch when specializing constant values
|
||||
}
|
||||
program tgenconst7;
|
||||
|
||||
type
|
||||
generic TInteger<const U: integer> = record end;
|
||||
|
||||
var
|
||||
a: specialize TInteger<'string'>;
|
||||
begin
|
||||
end.
|
14
tests/test/tgenconst8.pp
Normal file
14
tests/test/tgenconst8.pp
Normal file
@ -0,0 +1,14 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test out of range error with constants
|
||||
}
|
||||
program tgenconst8;
|
||||
|
||||
type
|
||||
generic TByte<const U: Byte> = record end;
|
||||
|
||||
var
|
||||
a: specialize TByte<300>;
|
||||
begin
|
||||
end.
|
12
tests/test/tgenconst9.pp
Normal file
12
tests/test/tgenconst9.pp
Normal file
@ -0,0 +1,12 @@
|
||||
{%FAIL}
|
||||
{$mode objfpc}
|
||||
{
|
||||
test type mismatch when specializing constants with types
|
||||
}
|
||||
program tgenconst9;
|
||||
type
|
||||
generic TByte<const U: Byte> = record end;
|
||||
var
|
||||
a: specialize TByte<string>;
|
||||
begin
|
||||
end.
|
10
tests/webtbf/tw36975.pp
Normal file
10
tests/webtbf/tw36975.pp
Normal file
@ -0,0 +1,10 @@
|
||||
{ %FAIL }
|
||||
program tw36975;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
type
|
||||
generic TTest <T,const N:Tintegerarray> = class
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
Loading…
Reference in New Issue
Block a user