* pdecobj.pas, object_dec:

Always define nested types of a generic as generic as well.
* symtable.pas: 
	+ Add a function which decides whether two defs belong to the same generic.
	* Fix sym_is_owned_by as there can be corner cases where childsym becomes Nil.
* ptype.pas:
	* record_dec: Always define nested types of a generic as generic as well.
	* single_type & read_named_type.expr_type:
		Use the newly added function to improve the checks whether a generic 
		symbol should be rejected as "generics not allowed for types of 
		variables or fields".
+ Add a test for which the improved checks are necessary.

git-svn-id: trunk@20189 -
This commit is contained in:
svenbarth 2012-01-28 18:09:40 +00:00
parent 6874aa9676
commit a28a9a9521
5 changed files with 71 additions and 5 deletions

1
.gitattributes vendored
View File

@ -10342,6 +10342,7 @@ tests/test/tgeneric7.pp svneol=native#text/plain
tests/test/tgeneric70.pp svneol=native#text/pascal
tests/test/tgeneric71.pp svneol=native#text/pascal
tests/test/tgeneric72.pp svneol=native#text/pascal
tests/test/tgeneric73.pp svneol=native#text/pascal
tests/test/tgeneric8.pp svneol=native#text/plain
tests/test/tgeneric9.pp svneol=native#text/plain
tests/test/tgoto.pp svneol=native#text/plain

View File

@ -1152,6 +1152,12 @@ implementation
if assigned(old_current_structdef) and
(df_specialization in old_current_structdef.defoptions) then
include(current_structdef.defoptions,df_specialization);
if assigned(old_current_structdef) and
(df_generic in old_current_structdef.defoptions) then
begin
include(current_structdef.defoptions,df_generic);
current_genericdef:=current_structdef;
end;
{ set published flag in $M+ mode, it can also be inherited and will
be added when the parent class set with tobjectdef.set_parent (PFV) }

View File

@ -386,7 +386,14 @@ implementation
(
parse_generic and
(current_genericdef.typ in [recorddef,objectdef]) and
sym_is_owned_by(srsym,tabstractrecorddef(current_genericdef).symtable)
(
{ if both defs belong to the same generic (e.g. both are
subtypes) then we must allow the usage }
defs_belong_to_same_generic(def,current_genericdef) or
{ this is needed to correctly resolve "type Foo=SomeGeneric<T>"
declarations inside a generic }
sym_is_owned_by(srsym,tabstractrecorddef(current_genericdef).symtable)
)
)
then
begin
@ -742,6 +749,12 @@ implementation
if assigned(old_current_structdef) and
(df_specialization in old_current_structdef.defoptions) then
include(current_structdef.defoptions,df_specialization);
if assigned(old_current_structdef) and
(df_generic in old_current_structdef.defoptions) then
begin
include(current_structdef.defoptions,df_generic);
current_genericdef:=current_structdef;
end;
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
{ when we are parsing a generic already then this is a generic as
@ -921,8 +934,17 @@ implementation
parse_generic and
(current_genericdef.typ in [recorddef,objectdef]) and
(def.typ in [recorddef,objectdef]) and
(ttypenode(pt1).typesym<>nil) and
sym_is_owned_by(ttypenode(pt1).typesym,tabstractrecorddef(current_genericdef).symtable)
(
{ if both defs belong to the same generic (e.g. both are
subtypes) then we must allow the usage }
defs_belong_to_same_generic(def,current_genericdef) or
{ this is needed to correctly resolve "type Foo=SomeGeneric<T>"
declarations inside a generic }
(
(ttypenode(pt1).typesym<>nil) and
sym_is_owned_by(ttypenode(pt1).typesym,tabstractrecorddef(current_genericdef).symtable)
)
)
)
then
begin

View File

@ -225,6 +225,7 @@ interface
procedure addsymref(sym:tsym);
function is_owned_by(childdef,ownerdef:tdef):boolean;
function sym_is_owned_by(childsym:tsym;symtable:tsymtable):boolean;
function defs_belong_to_same_generic(def1,def2:tdef):boolean;
function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
function is_visible_for_object(pd:tprocdef;contextobjdef:tabstractrecorddef):boolean;
function is_visible_for_object(sym:tsym;contextobjdef:tabstractrecorddef):boolean;
@ -1880,11 +1881,25 @@ implementation
function sym_is_owned_by(childsym:tsym;symtable:tsymtable):boolean;
begin
result:=childsym.owner=symtable;
if not result and (childsym.owner.symtabletype in [objectsymtable,recordsymtable]) then
result:=assigned(childsym) and (childsym.owner=symtable);
if not result and assigned(childsym) and
(childsym.owner.symtabletype in [objectsymtable,recordsymtable]) then
result:=sym_is_owned_by(tabstractrecorddef(childsym.owner.defowner).typesym,symtable);
end;
function defs_belong_to_same_generic(def1, def2: tdef): boolean;
begin
result:=false;
if not assigned(def1) or not assigned(def2) then
exit;
{ for both defs walk to the topmost generic }
while assigned(def1.owner.defowner) and (df_generic in tstoreddef(def1.owner.defowner).defoptions) do
def1:=tdef(def1.owner.defowner);
while assigned(def2.owner.defowner) and (df_generic in tstoreddef(def2.owner.defowner).defoptions) do
def2:=tdef(def2.owner.defowner);
result:=def1=def2;
end;
function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
var
symownerdef : tabstractrecorddef;

22
tests/test/tgeneric73.pp Normal file
View File

@ -0,0 +1,22 @@
{ %NORUN }
{ This tests that nested types can reference each other inside a generic }
program tgeneric73;
{$mode objfpc}
type
generic TTest<T> = class
public type
TSubClass1 = class
end;
TSubClass2 = class
f: TSubClass1;
end;
end;
begin
end.