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:
paul 2011-01-05 04:35:56 +00:00
parent fa41b6ffe3
commit bd64575add
8 changed files with 450 additions and 343 deletions

2
.gitattributes vendored
View File

@ -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

View File

@ -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}
#

View File

@ -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

View File

@ -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));

View File

@ -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
View 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
View 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.