mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-09 19:08:15 +02:00
* 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:
parent
6874aa9676
commit
a28a9a9521
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
|
||||
|
@ -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) }
|
||||
|
@ -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
|
||||
|
@ -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
22
tests/test/tgeneric73.pp
Normal 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.
|
Loading…
Reference in New Issue
Block a user