mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 08:28:09 +02:00
compiler: require generic name with type parameters for the method class prefix (like TGenericClass<T>.MethodName instead of TGenericClass.MethodName) in delphi mode
git-svn-id: trunk@16707 -
This commit is contained in:
parent
fa41b6ffe3
commit
bd64575add
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -9420,6 +9420,8 @@ tests/test/tgeneric27.pp svneol=native#text/pascal
|
||||
tests/test/tgeneric28.pp svneol=native#text/pascal
|
||||
tests/test/tgeneric29.pp svneol=native#text/pascal
|
||||
tests/test/tgeneric3.pp svneol=native#text/plain
|
||||
tests/test/tgeneric30.pp svneol=native#text/pascal
|
||||
tests/test/tgeneric31.pp svneol=native#text/pascal
|
||||
tests/test/tgeneric4.pp svneol=native#text/plain
|
||||
tests/test/tgeneric5.pp svneol=native#text/plain
|
||||
tests/test/tgeneric6.pp svneol=native#text/plain
|
||||
|
@ -1713,6 +1713,10 @@ type_w_procvar_univ_conflicting_para=04095_W_Coerced univ parameter type in proc
|
||||
% when \var{test} returns.
|
||||
type_e_generics_cannot_reference_itself=04096_E_Type parameters of specializations of generics cannot reference the currently specialized type
|
||||
% Recursive specializations of generics like \var{Type MyType = specialize MyGeneric<MyType>;} are not possible.
|
||||
type_e_type_parameters_are_not_allowed_here=04097_E_Type parameters are not allowed on non-generic class/record/object procedure or function
|
||||
% Type parameters are only allowed for methods of generic classes, records or objects
|
||||
type_e_generic_declaration_does_not_match=04098_E_Generic declaration of "$1" differs from previous declaration
|
||||
% Generic declaration does not match the previous declaration
|
||||
%
|
||||
% \end{description}
|
||||
#
|
||||
|
@ -480,6 +480,8 @@ const
|
||||
type_e_objcclass_type_expected=04094;
|
||||
type_w_procvar_univ_conflicting_para=04095;
|
||||
type_e_generics_cannot_reference_itself=04096;
|
||||
type_e_type_parameters_are_not_allowed_here=04097;
|
||||
type_e_generic_declaration_does_not_match=04098;
|
||||
sym_e_id_not_found=05000;
|
||||
sym_f_internal_error_in_symtablestack=05001;
|
||||
sym_e_duplicate_id=05002;
|
||||
@ -880,9 +882,9 @@ const
|
||||
option_info=11024;
|
||||
option_help_pages=11025;
|
||||
|
||||
MsgTxtSize = 58497;
|
||||
MsgTxtSize = 58664;
|
||||
|
||||
MsgIdxMax : array[1..20] of longint=(
|
||||
24,88,305,97,84,54,111,22,202,63,
|
||||
24,88,305,99,84,54,111,22,202,63,
|
||||
49,20,1,1,1,1,1,1,1,1
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -791,9 +791,7 @@ implementation
|
||||
hs : string;
|
||||
orgsp,sp : TIDString;
|
||||
srsym : tsym;
|
||||
srsymtable : TSymtable;
|
||||
checkstack : psymtablestackitem;
|
||||
storepos,
|
||||
procstartfilepos : tfileposinfo;
|
||||
searchagain : boolean;
|
||||
st,
|
||||
@ -885,6 +883,89 @@ implementation
|
||||
end;
|
||||
end;
|
||||
|
||||
function search_object_name(sp:TIDString;gen_error:boolean):tsym;
|
||||
var
|
||||
storepos:tfileposinfo;
|
||||
srsymtable:TSymtable;
|
||||
begin
|
||||
storepos:=current_tokenpos;
|
||||
current_tokenpos:=procstartfilepos;
|
||||
searchsym(sp,result,srsymtable);
|
||||
if not assigned(result) then
|
||||
begin
|
||||
if gen_error then
|
||||
identifier_not_found(orgsp);
|
||||
result:=generrorsym;
|
||||
end;
|
||||
current_tokenpos:=storepos;
|
||||
end;
|
||||
|
||||
function consume_generic_type_parameter:boolean;
|
||||
var
|
||||
i:integer;
|
||||
ok:boolean;
|
||||
sym:tsym;
|
||||
begin
|
||||
result:=not assigned(astruct)and(m_delphi in current_settings.modeswitches);
|
||||
if result then
|
||||
begin
|
||||
{ a generic type parameter? }
|
||||
srsym:=search_object_name(sp,false);
|
||||
if (srsym.typ=typesym) and
|
||||
(ttypesym(srsym).typedef.typ in [objectdef,recorddef]) then
|
||||
begin
|
||||
astruct:=tabstractrecorddef(ttypesym(srsym).typedef);
|
||||
if (df_generic in astruct.defoptions) then
|
||||
begin
|
||||
consume(_LT);
|
||||
ok:=true;
|
||||
i:=0;
|
||||
repeat
|
||||
if ok and (token=_ID) then
|
||||
begin
|
||||
ok:=false;
|
||||
while i<astruct.symtable.SymList.Count-1 do
|
||||
begin
|
||||
sym:=tsym(astruct.symtable.SymList[i]);
|
||||
if sp_generic_para in sym.symoptions then
|
||||
begin
|
||||
ok:=sym.RealName=pattern;
|
||||
inc(i);
|
||||
break;
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
if not ok then
|
||||
Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
|
||||
end;
|
||||
consume(_ID);
|
||||
until not try_to_consume(_COMMA);
|
||||
if ok then
|
||||
while i<astruct.symtable.SymList.Count-1 do
|
||||
begin
|
||||
sym:=tsym(astruct.symtable.SymList[i]);
|
||||
if sp_generic_para in sym.symoptions then
|
||||
begin
|
||||
Message1(type_e_generic_declaration_does_not_match,astruct.RttiName);
|
||||
break;
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
consume(_GT);
|
||||
end
|
||||
else
|
||||
if try_to_consume(_LT) then
|
||||
begin
|
||||
Message(type_e_type_parameters_are_not_allowed_here);
|
||||
repeat
|
||||
consume(_ID);
|
||||
until not try_to_consume(_COMMA);
|
||||
consume(_GT);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
{ Save the position where this procedure really starts }
|
||||
procstartfilepos:=current_tokenpos;
|
||||
@ -903,16 +984,7 @@ implementation
|
||||
(tobjectdef(astruct).ImplementedInterfaces.count>0) and
|
||||
try_to_consume(_POINT) then
|
||||
begin
|
||||
storepos:=current_tokenpos;
|
||||
current_tokenpos:=procstartfilepos;
|
||||
{ get interface syms}
|
||||
searchsym(sp,srsym,srsymtable);
|
||||
if not assigned(srsym) then
|
||||
begin
|
||||
identifier_not_found(orgsp);
|
||||
srsym:=generrorsym;
|
||||
end;
|
||||
current_tokenpos:=storepos;
|
||||
srsym:=search_object_name(sp,true);
|
||||
{ qualifier is interface? }
|
||||
ImplIntf:=nil;
|
||||
if (srsym.typ=typesym) and
|
||||
@ -933,25 +1005,14 @@ implementation
|
||||
end;
|
||||
|
||||
{ method ? }
|
||||
if not assigned(astruct) and
|
||||
if (consume_generic_type_parameter or not assigned(astruct)) and
|
||||
(symtablestack.top.symtablelevel=main_program_level) and
|
||||
try_to_consume(_POINT) then
|
||||
begin
|
||||
repeat
|
||||
searchagain:=false;
|
||||
if not assigned(astruct) then
|
||||
begin
|
||||
{ search for object name }
|
||||
storepos:=current_tokenpos;
|
||||
current_tokenpos:=procstartfilepos;
|
||||
searchsym(sp,srsym,srsymtable);
|
||||
if not assigned(srsym) then
|
||||
begin
|
||||
identifier_not_found(orgsp);
|
||||
srsym:=generrorsym;
|
||||
end;
|
||||
current_tokenpos:=storepos;
|
||||
end;
|
||||
srsym:=search_object_name(sp,true);
|
||||
{ consume proc name }
|
||||
procstartfilepos:=current_tokenpos;
|
||||
consume_proc_name;
|
||||
@ -1017,14 +1078,13 @@ implementation
|
||||
if (potype=potype_operator)and(optoken=NOTOKEN) then
|
||||
parse_operator_name;
|
||||
|
||||
srsymtable:=symtablestack.top;
|
||||
srsym:=tsym(srsymtable.Find(sp));
|
||||
srsym:=tsym(symtablestack.top.Find(sp));
|
||||
|
||||
{ Also look in the globalsymtable if we didn't found
|
||||
the symbol in the localsymtable }
|
||||
if not assigned(srsym) and
|
||||
not(parse_only) and
|
||||
(srsymtable=current_module.localsymtable) and
|
||||
(symtablestack.top=current_module.localsymtable) and
|
||||
assigned(current_module.globalsymtable) then
|
||||
srsym:=tsym(current_module.globalsymtable.Find(sp));
|
||||
|
||||
|
@ -21,12 +21,12 @@ type
|
||||
|
||||
TGenericArray<T> = array of T;
|
||||
|
||||
function TGenericClass{<T>}.DoSomething(Arg: T): T;
|
||||
function TGenericClass<T>.DoSomething(Arg: T): T;
|
||||
begin
|
||||
Result := Arg;
|
||||
end;
|
||||
|
||||
function TGenericClass{<T>}.Test(Arg: Intf): Intf;
|
||||
function TGenericClass<T>.Test(Arg: Intf): Intf;
|
||||
begin
|
||||
Result := Arg;
|
||||
end;
|
||||
|
18
tests/test/tgeneric30.pp
Normal file
18
tests/test/tgeneric30.pp
Normal file
@ -0,0 +1,18 @@
|
||||
{ %fail }
|
||||
program tgeneric30;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
type
|
||||
TGenericClass<T> = class
|
||||
function DoSomething(Arg: T): T;
|
||||
end;
|
||||
|
||||
// it must be TGenericClass<T> here
|
||||
function TGenericClass.DoSomething(Arg: T): T;
|
||||
begin
|
||||
Result := Arg;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
17
tests/test/tgeneric31.pp
Normal file
17
tests/test/tgeneric31.pp
Normal file
@ -0,0 +1,17 @@
|
||||
program tgeneric31;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
type
|
||||
TGenericClass<T1,T2> = class
|
||||
function DoSomething(Arg: T1): T1;
|
||||
end;
|
||||
|
||||
// it must be TGenericClass<T1,T2>
|
||||
function TGenericClass<T1>.DoSomething(Arg: T1): T1;
|
||||
begin
|
||||
Result := Arg;
|
||||
end;
|
||||
|
||||
begin
|
||||
end.
|
Loading…
Reference in New Issue
Block a user