mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 17:29:10 +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/tgeneric70.pp svneol=native#text/pascal
|
||||||
tests/test/tgeneric71.pp svneol=native#text/pascal
|
tests/test/tgeneric71.pp svneol=native#text/pascal
|
||||||
tests/test/tgeneric72.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/tgeneric8.pp svneol=native#text/plain
|
||||||
tests/test/tgeneric9.pp svneol=native#text/plain
|
tests/test/tgeneric9.pp svneol=native#text/plain
|
||||||
tests/test/tgoto.pp svneol=native#text/plain
|
tests/test/tgoto.pp svneol=native#text/plain
|
||||||
|
@ -1152,6 +1152,12 @@ implementation
|
|||||||
if assigned(old_current_structdef) and
|
if assigned(old_current_structdef) and
|
||||||
(df_specialization in old_current_structdef.defoptions) then
|
(df_specialization in old_current_structdef.defoptions) then
|
||||||
include(current_structdef.defoptions,df_specialization);
|
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
|
{ 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) }
|
be added when the parent class set with tobjectdef.set_parent (PFV) }
|
||||||
|
@ -386,7 +386,14 @@ implementation
|
|||||||
(
|
(
|
||||||
parse_generic and
|
parse_generic and
|
||||||
(current_genericdef.typ in [recorddef,objectdef]) 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
|
then
|
||||||
begin
|
begin
|
||||||
@ -742,6 +749,12 @@ implementation
|
|||||||
if assigned(old_current_structdef) and
|
if assigned(old_current_structdef) and
|
||||||
(df_specialization in old_current_structdef.defoptions) then
|
(df_specialization in old_current_structdef.defoptions) then
|
||||||
include(current_structdef.defoptions,df_specialization);
|
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);
|
insert_generic_parameter_types(current_structdef,genericdef,genericlist);
|
||||||
{ when we are parsing a generic already then this is a generic as
|
{ when we are parsing a generic already then this is a generic as
|
||||||
@ -921,8 +934,17 @@ implementation
|
|||||||
parse_generic and
|
parse_generic and
|
||||||
(current_genericdef.typ in [recorddef,objectdef]) and
|
(current_genericdef.typ in [recorddef,objectdef]) and
|
||||||
(def.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
|
then
|
||||||
begin
|
begin
|
||||||
|
@ -225,6 +225,7 @@ interface
|
|||||||
procedure addsymref(sym:tsym);
|
procedure addsymref(sym:tsym);
|
||||||
function is_owned_by(childdef,ownerdef:tdef):boolean;
|
function is_owned_by(childdef,ownerdef:tdef):boolean;
|
||||||
function sym_is_owned_by(childsym:tsym;symtable:tsymtable):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(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
|
||||||
function is_visible_for_object(pd:tprocdef;contextobjdef:tabstractrecorddef):boolean;
|
function is_visible_for_object(pd:tprocdef;contextobjdef:tabstractrecorddef):boolean;
|
||||||
function is_visible_for_object(sym:tsym;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;
|
function sym_is_owned_by(childsym:tsym;symtable:tsymtable):boolean;
|
||||||
begin
|
begin
|
||||||
result:=childsym.owner=symtable;
|
result:=assigned(childsym) and (childsym.owner=symtable);
|
||||||
if not result and (childsym.owner.symtabletype in [objectsymtable,recordsymtable]) then
|
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);
|
result:=sym_is_owned_by(tabstractrecorddef(childsym.owner.defowner).typesym,symtable);
|
||||||
end;
|
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;
|
function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
|
||||||
var
|
var
|
||||||
symownerdef : tabstractrecorddef;
|
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