mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-30 06:39:58 +02:00
fcl-passrc: resolver specialize name with params
git-svn-id: trunk@46786 -
This commit is contained in:
parent
9337b2a3ac
commit
f3579bf526
@ -1791,7 +1791,7 @@ type
|
|||||||
function GetTVarRec(El: TPasArrayType): TPasRecordType; virtual;
|
function GetTVarRec(El: TPasArrayType): TPasRecordType; virtual;
|
||||||
function FindDefaultConstructor(aClass: TPasClassType): TPasConstructor; virtual;
|
function FindDefaultConstructor(aClass: TPasClassType): TPasConstructor; virtual;
|
||||||
function GetTypeInfoParamType(Param: TPasExpr;
|
function GetTypeInfoParamType(Param: TPasExpr;
|
||||||
out ParamResolved: TPasResolverResult; LoType: boolean): TPasType; virtual;
|
out ParamResolved: TPasResolverResult; LoType: boolean): TPasType; virtual; // returns type of param in typeinfo(param)
|
||||||
protected
|
protected
|
||||||
// constant evaluation
|
// constant evaluation
|
||||||
fExprEvaluator: TResExprEvaluator;
|
fExprEvaluator: TResExprEvaluator;
|
||||||
@ -1840,8 +1840,7 @@ type
|
|||||||
GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement);
|
GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement);
|
||||||
function CreateSpecializedItem(El: TPasElement; GenericEl: TPasElement;
|
function CreateSpecializedItem(El: TPasElement; GenericEl: TPasElement;
|
||||||
const ParamsResolved: TPasTypeArray): TPRSpecializedItem; virtual;
|
const ParamsResolved: TPasTypeArray): TPRSpecializedItem; virtual;
|
||||||
function CreateSpecializedTypeName(SpecializedItems: TObjectList;
|
function CreateSpecializedTypeName(Item: TPRSpecializedItem): string; virtual;
|
||||||
Item: TPRSpecializedItem): string; virtual;
|
|
||||||
procedure InitSpecializeScopes(El: TPasElement; out State: TScopeStashState); virtual;
|
procedure InitSpecializeScopes(El: TPasElement; out State: TScopeStashState); virtual;
|
||||||
procedure RestoreSpecializeScopes(const State: TScopeStashState); virtual;
|
procedure RestoreSpecializeScopes(const State: TScopeStashState); virtual;
|
||||||
procedure SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem); virtual;
|
procedure SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem); virtual;
|
||||||
@ -2473,8 +2472,11 @@ function ProcNeedsBody(Proc: TPasProcedure): boolean;
|
|||||||
function ProcHasGroupOverload(Proc: TPasProcedure): boolean;
|
function ProcHasGroupOverload(Proc: TPasProcedure): boolean;
|
||||||
procedure ClearHelperList(var List: TPRHelperEntryArray);
|
procedure ClearHelperList(var List: TPRHelperEntryArray);
|
||||||
function ChompDottedIdentifier(const Identifier: string): string;
|
function ChompDottedIdentifier(const Identifier: string): string;
|
||||||
function FirstDottedIdentifier(const Identifier: string): string;
|
function FirstDottedIdentifier(const Identifier: string): string; // without <>
|
||||||
|
function LastDottedIdentifier(const Identifier: string): string; // without <>
|
||||||
function IsDottedIdentifierPrefix(const Prefix, Identifier: string): boolean;
|
function IsDottedIdentifierPrefix(const Prefix, Identifier: string): boolean;
|
||||||
|
function GetFirstDotPos(const Identifier: string): integer;
|
||||||
|
function GetLastDotPos(const Identifier: string): integer;
|
||||||
{$IF FPC_FULLVERSION<30101}
|
{$IF FPC_FULLVERSION<30101}
|
||||||
function IsValidIdent(const Ident: string; AllowDots: Boolean = False; StrictDots: Boolean = False): Boolean;
|
function IsValidIdent(const Ident: string; AllowDots: Boolean = False; StrictDots: Boolean = False): Boolean;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -2943,14 +2945,18 @@ end;
|
|||||||
|
|
||||||
function ChompDottedIdentifier(const Identifier: string): string;
|
function ChompDottedIdentifier(const Identifier: string): string;
|
||||||
var
|
var
|
||||||
p: Integer;
|
p, Lvl: Integer;
|
||||||
begin
|
begin
|
||||||
Result:=Identifier;
|
Result:=Identifier;
|
||||||
p:=length(Identifier);
|
p:=length(Identifier);
|
||||||
|
Lvl:=0;
|
||||||
while (p>0) do
|
while (p>0) do
|
||||||
begin
|
begin
|
||||||
if Identifier[p]='.' then
|
case Identifier[p] of
|
||||||
break;
|
'.': if Lvl=0 then break;
|
||||||
|
'>': inc(Lvl);
|
||||||
|
'<': dec(Lvl);
|
||||||
|
end;
|
||||||
dec(p);
|
dec(p);
|
||||||
end;
|
end;
|
||||||
Result:=LeftStr(Identifier,p-1);
|
Result:=LeftStr(Identifier,p-1);
|
||||||
@ -2958,13 +2964,41 @@ end;
|
|||||||
|
|
||||||
function FirstDottedIdentifier(const Identifier: string): string;
|
function FirstDottedIdentifier(const Identifier: string): string;
|
||||||
var
|
var
|
||||||
p: SizeInt;
|
p, l: SizeInt;
|
||||||
begin
|
begin
|
||||||
p:=Pos('.',Identifier);
|
p:=1;
|
||||||
if p<1 then
|
l:=length(Identifier);
|
||||||
Result:=Identifier
|
repeat
|
||||||
else
|
if p>l then
|
||||||
Result:=LeftStr(Identifier,p-1);
|
exit(Identifier)
|
||||||
|
else if Identifier[p] in ['<','.'] then
|
||||||
|
exit(LeftStr(Identifier,p-1))
|
||||||
|
else
|
||||||
|
inc(p);
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LastDottedIdentifier(const Identifier: string): string;
|
||||||
|
var
|
||||||
|
p, Lvl, EndP: Integer;
|
||||||
|
begin
|
||||||
|
p:=length(Identifier);
|
||||||
|
EndP:=p;
|
||||||
|
Lvl:=0;
|
||||||
|
while (p>0) do
|
||||||
|
begin
|
||||||
|
case Identifier[p] of
|
||||||
|
'.': if Lvl=0 then break;
|
||||||
|
'>': inc(Lvl);
|
||||||
|
'<':
|
||||||
|
begin
|
||||||
|
dec(Lvl);
|
||||||
|
EndP:=p-1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
dec(p);
|
||||||
|
end;
|
||||||
|
Result:=copy(Identifier,p+1,EndP-p);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function IsDottedIdentifierPrefix(const Prefix, Identifier: string): boolean;
|
function IsDottedIdentifierPrefix(const Prefix, Identifier: string): boolean;
|
||||||
@ -2978,6 +3012,43 @@ begin
|
|||||||
Result:=(length(Identifier)=l) or (Identifier[l+1]='.');
|
Result:=(length(Identifier)=l) or (Identifier[l+1]='.');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetFirstDotPos(const Identifier: string): integer;
|
||||||
|
var
|
||||||
|
l: SizeInt;
|
||||||
|
Lvl: Integer;
|
||||||
|
begin
|
||||||
|
Result:=1;
|
||||||
|
l:=length(Identifier);
|
||||||
|
Lvl:=0;
|
||||||
|
repeat
|
||||||
|
if Result>l then
|
||||||
|
exit(-1);
|
||||||
|
case Identifier[Result] of
|
||||||
|
'.': if Lvl=0 then exit;
|
||||||
|
'<': inc(Lvl);
|
||||||
|
'>': dec(Lvl);
|
||||||
|
end;
|
||||||
|
inc(Result);
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetLastDotPos(const Identifier: string): integer;
|
||||||
|
var
|
||||||
|
Lvl: Integer;
|
||||||
|
begin
|
||||||
|
Result:=length(Identifier);
|
||||||
|
Lvl:=0;
|
||||||
|
while (Result>0) do
|
||||||
|
begin
|
||||||
|
case Identifier[Result] of
|
||||||
|
'.': if Lvl=0 then exit;
|
||||||
|
'>': inc(Lvl);
|
||||||
|
'<': dec(Lvl);
|
||||||
|
end;
|
||||||
|
dec(Result);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function DotExprToName(Expr: TPasExpr): string;
|
function DotExprToName(Expr: TPasExpr): string;
|
||||||
var
|
var
|
||||||
C: TClass;
|
C: TClass;
|
||||||
@ -6931,7 +7002,7 @@ begin
|
|||||||
RaiseMsg(20181231150404,nXCannotHaveParameters,sXCannotHaveParameters,[GetElementTypeName(Proc)],Proc);
|
RaiseMsg(20181231150404,nXCannotHaveParameters,sXCannotHaveParameters,[GetElementTypeName(Proc)],Proc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
HasDots:=Pos('.',ProcName)>1;
|
HasDots:=GetFirstDotPos(ProcName)>0;
|
||||||
|
|
||||||
if Proc.Parent is TPasClassType then
|
if Proc.Parent is TPasClassType then
|
||||||
begin
|
begin
|
||||||
@ -7309,7 +7380,6 @@ var
|
|||||||
DeclProc: TPasProcedure;
|
DeclProc: TPasProcedure;
|
||||||
ClassOrRecScope: TPasClassOrRecordScope;
|
ClassOrRecScope: TPasClassOrRecordScope;
|
||||||
SelfArg: TPasArgument;
|
SelfArg: TPasArgument;
|
||||||
p: Integer;
|
|
||||||
SelfType, LoSelfType: TPasType;
|
SelfType, LoSelfType: TPasType;
|
||||||
LastNamePart: TProcedureNamePart;
|
LastNamePart: TProcedureNamePart;
|
||||||
begin
|
begin
|
||||||
@ -7336,11 +7406,7 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// remove path from ProcName
|
// remove path from ProcName
|
||||||
repeat
|
ProcName:=LastDottedIdentifier(ProcName);
|
||||||
p:=Pos('.',ProcName);
|
|
||||||
if p<1 then break;
|
|
||||||
Delete(ProcName,1,p);
|
|
||||||
until false;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if ImplProcScope.DeclarationProc=nil then
|
if ImplProcScope.DeclarationProc=nil then
|
||||||
@ -12412,7 +12478,7 @@ begin
|
|||||||
|
|
||||||
// Note: El.ProcType is nil ! It is parsed later.
|
// Note: El.ProcType is nil ! It is parsed later.
|
||||||
|
|
||||||
HasDot:=Pos('.',ProcName)>1;
|
HasDot:=GetFirstDotPos(ProcName)>1;
|
||||||
if (TypeParams<>nil) then
|
if (TypeParams<>nil) then
|
||||||
if HasDot<>(TypeParams.Count>1) then
|
if HasDot<>(TypeParams.Count>1) then
|
||||||
RaiseNotYetImplemented(20190818093923,El);
|
RaiseNotYetImplemented(20190818093923,El);
|
||||||
@ -12485,14 +12551,14 @@ begin
|
|||||||
Level:=0;
|
Level:=0;
|
||||||
repeat
|
repeat
|
||||||
inc(Level);
|
inc(Level);
|
||||||
p:=Pos('.',ProcName);
|
p:=GetFirstDotPos(ProcName);
|
||||||
if p<1 then
|
if p<1 then
|
||||||
begin
|
begin
|
||||||
if ClassOrRecType=nil then
|
if ClassOrRecType=nil then
|
||||||
RaiseInternalError(20161013170829);
|
RaiseInternalError(20161013170829);
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
aClassName:=LeftStr(ProcName,p-1);
|
aClassName:=FirstDottedIdentifier(ProcName);
|
||||||
Delete(ProcName,1,p);
|
Delete(ProcName,1,p);
|
||||||
TypeParamCount:=0;
|
TypeParamCount:=0;
|
||||||
if TypeParams<>nil then
|
if TypeParams<>nil then
|
||||||
@ -16503,7 +16569,7 @@ var
|
|||||||
begin
|
begin
|
||||||
// insert in front of currently parsed elements
|
// insert in front of currently parsed elements
|
||||||
// beware: specializing an element can create other specialized elements
|
// beware: specializing an element can create other specialized elements
|
||||||
// add behind last specialized element of this GenericEl
|
// add behind last finished specialized element of this GenericEl
|
||||||
// for example: A = class(B<C<D>>)
|
// for example: A = class(B<C<D>>)
|
||||||
// =>
|
// =>
|
||||||
// D
|
// D
|
||||||
@ -16548,15 +16614,6 @@ var
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//if i<0 then
|
|
||||||
// begin
|
|
||||||
// {$IF defined(VerbosePasResolver) or defined(VerbosePas2JS)}
|
|
||||||
// writeln('InsertBehind Generic=',GetObjName(GenericEl),' Last=',GetObjName(Last));
|
|
||||||
// //for i:=0 to List.Count-1 do writeln(' ',GetObjName(TObject(List[i])));
|
|
||||||
// {$ENDIF}
|
|
||||||
// i:=List.Count-1;
|
|
||||||
// end;
|
|
||||||
List.Insert(i+1,NewEl);
|
List.Insert(i+1,NewEl);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -16571,8 +16628,6 @@ var
|
|||||||
ProcItem: TPRSpecializedProcItem;
|
ProcItem: TPRSpecializedProcItem;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
if Pos('$G',GenericEl.Name)>0 then
|
|
||||||
RaiseNotYetImplemented(20190813003729,El);
|
|
||||||
|
|
||||||
SrcModule:=GenericEl.GetModule;
|
SrcModule:=GenericEl.GetModule;
|
||||||
SrcModuleScope:=SrcModule.CustomData as TPasModuleScope;
|
SrcModuleScope:=SrcModule.CustomData as TPasModuleScope;
|
||||||
@ -16602,7 +16657,7 @@ begin
|
|||||||
Result.Params:=ParamsResolved;
|
Result.Params:=ParamsResolved;
|
||||||
Result.Index:=SpecializedItems.Count;
|
Result.Index:=SpecializedItems.Count;
|
||||||
SpecializedItems.Add(Result);
|
SpecializedItems.Add(Result);
|
||||||
NewName:=CreateSpecializedTypeName(SpecializedItems,Result);
|
NewName:=CreateSpecializedTypeName(Result);
|
||||||
NewClass:=TPTreeElement(GenericEl.ClassType);
|
NewClass:=TPTreeElement(GenericEl.ClassType);
|
||||||
NewParent:=GenericEl.Parent;
|
NewParent:=GenericEl.Parent;
|
||||||
NewEl:=TPasElement(NewClass.Create(NewName,NewParent));
|
NewEl:=TPasElement(NewClass.Create(NewName,NewParent));
|
||||||
@ -16631,10 +16686,66 @@ begin
|
|||||||
SpecializeGenericImpl(Result);
|
SpecializeGenericImpl(Result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasResolver.CreateSpecializedTypeName(SpecializedItems: TObjectList;
|
function TPasResolver.CreateSpecializedTypeName(Item: TPRSpecializedItem): string;
|
||||||
Item: TPRSpecializedItem): string;
|
|
||||||
|
function GetTypeName(aType: TPasType): string; forward;
|
||||||
|
|
||||||
|
function GetSpecParams(Item: TPRSpecializedItem): string;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result:='<';
|
||||||
|
for i:=0 to length(Item.Params)-1 do
|
||||||
|
begin
|
||||||
|
if i>0 then Result:=Result+',';
|
||||||
|
Result:=Result+GetTypeName(Item.Params[i]);
|
||||||
|
end;
|
||||||
|
Result:=Result+'>';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTypeName(aType: TPasType): string;
|
||||||
|
var
|
||||||
|
Arr: TPasArrayType;
|
||||||
|
ElType: TPasType;
|
||||||
|
ChildItem: TPRSpecializedItem;
|
||||||
|
begin
|
||||||
|
if aType.Name='' then
|
||||||
|
begin
|
||||||
|
if aType is TPasArrayType then
|
||||||
|
begin
|
||||||
|
// e.g. TBird<array of word>
|
||||||
|
Result:='array of ';
|
||||||
|
Arr:=TPasArrayType(aType);
|
||||||
|
if length(Arr.Ranges)>0 then
|
||||||
|
RaiseNotYetImplemented(20200905173026,Item.FirstSpecialize);
|
||||||
|
ElType:=ResolveAliasType(Arr.ElType,false);
|
||||||
|
if ElType is TPasArrayType then
|
||||||
|
RaiseNotYetImplemented(20200905173159,Arr,'multidimensional anonymous array as generic param');
|
||||||
|
Result:=Result+GetTypeName(ElType);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseNotYetImplemented(20200905173241,aType);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if aType.Parent is TPasType then
|
||||||
|
Result:=GetTypeName(TPasType(aType.Parent))
|
||||||
|
else if aType is TPasUnresolvedSymbolRef then
|
||||||
|
Result:='System'
|
||||||
|
else
|
||||||
|
Result:=aType.GetModule.Name;
|
||||||
|
Result:=Result+'.'+aType.Name;
|
||||||
|
if aType.CustomData is TPasGenericScope then
|
||||||
|
begin
|
||||||
|
ChildItem:=TPasGenericScope(aType.CustomData).SpecializedFromItem;
|
||||||
|
if ChildItem<>nil then
|
||||||
|
Result:=Result+GetSpecParams(ChildItem);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=Item.GenericEl.Name+'$G'+IntToStr(SpecializedItems.Count);
|
Result:=Item.GenericEl.Name+GetSpecParams(Item);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPasResolver.InitSpecializeScopes(El: TPasElement; out
|
procedure TPasResolver.InitSpecializeScopes(El: TPasElement; out
|
||||||
@ -17063,12 +17174,11 @@ begin
|
|||||||
if SpecClassOrRecScope=nil then
|
if SpecClassOrRecScope=nil then
|
||||||
RaiseNotYetImplemented(20190921221839,SpecDeclProc);
|
RaiseNotYetImplemented(20190921221839,SpecDeclProc);
|
||||||
NewImplProcName:=GenImplProc.Name;
|
NewImplProcName:=GenImplProc.Name;
|
||||||
p:=length(NewImplProcName);
|
LastDotP:=GetLastDotPos(NewImplProcName);
|
||||||
while (p>0) and (NewImplProcName[p]<>'.') do dec(p);
|
if LastDotP<1 then
|
||||||
if p=0 then
|
|
||||||
RaiseNotYetImplemented(20190921221730,GenImplProc);
|
RaiseNotYetImplemented(20190921221730,GenImplProc);
|
||||||
// has classname -> replace generic classname with specialized classname
|
// has classname -> replace generic classname with specialized classname
|
||||||
LastDotP:=p;
|
p:=LastDotP;
|
||||||
while (p>1) and (NewImplProcName[p-1]<>'.') do dec(p);
|
while (p>1) and (NewImplProcName[p-1]<>'.') do dec(p);
|
||||||
OldClassname:=copy(NewImplProcName,p,LastDotP-p);
|
OldClassname:=copy(NewImplProcName,p,LastDotP-p);
|
||||||
GenClassOrRec:=GenDeclProc.Parent as TPasMembersType;
|
GenClassOrRec:=GenDeclProc.Parent as TPasMembersType;
|
||||||
@ -17080,8 +17190,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// use classname of GenImplProc and name of SpecDeclProc
|
// use classname of GenImplProc and name of SpecDeclProc
|
||||||
OldClassname:=GenImplProc.Name;
|
OldClassname:=GenImplProc.Name;
|
||||||
p:=length(OldClassname);
|
p:=GetLastDotPos(OldClassname);
|
||||||
while (p>0) and (OldClassname[p]<>'.') do dec(p);
|
|
||||||
if p>0 then
|
if p>0 then
|
||||||
NewImplProcName:=LeftStr(OldClassname,p)+SpecDeclProc.Name
|
NewImplProcName:=LeftStr(OldClassname,p)+SpecDeclProc.Name
|
||||||
else
|
else
|
||||||
@ -25384,12 +25493,14 @@ function TPasResolver.GetTypeDescription(aType: TPasType; AddPath: boolean): str
|
|||||||
begin
|
begin
|
||||||
i:=GetTypeParameterCount(TPasGenericType(aType));
|
i:=GetTypeParameterCount(TPasGenericType(aType));
|
||||||
if i>0 then
|
if i>0 then
|
||||||
|
// generic, not specialized
|
||||||
Result:=Result+GetGenericParamCommas(GetTypeParameterCount(TPasGenericType(aType)))
|
Result:=Result+GetGenericParamCommas(GetTypeParameterCount(TPasGenericType(aType)))
|
||||||
else if aType.CustomData is TPasGenericScope then
|
else if aType.CustomData is TPasGenericScope then
|
||||||
begin
|
begin
|
||||||
GenScope:=TPasGenericScope(aType.CustomData);
|
GenScope:=TPasGenericScope(aType.CustomData);
|
||||||
if GenScope.SpecializedFromItem<>nil then
|
if (GenScope.SpecializedFromItem<>nil) and IsValidIdent(aType.Name) then
|
||||||
begin
|
begin
|
||||||
|
// specialized without params in name -> append params
|
||||||
Params:=GenScope.SpecializedFromItem.Params;
|
Params:=GenScope.SpecializedFromItem.Params;
|
||||||
Result:=Result+'<';
|
Result:=Result+'<';
|
||||||
for i:=0 to length(Params)-1 do
|
for i:=0 to length(Params)-1 do
|
||||||
@ -29527,6 +29638,7 @@ function TPasResolver.CheckClassIsClass(SrcType, DestType: TPasType): integer;
|
|||||||
// check if Src is equal or descends from Dest
|
// check if Src is equal or descends from Dest
|
||||||
// Generics: TBird<T> is both directions a TBird<word>
|
// Generics: TBird<T> is both directions a TBird<word>
|
||||||
// and TBird<TMap<T>> is both directions a TBird<TMap<word>>
|
// and TBird<TMap<T>> is both directions a TBird<TMap<word>>
|
||||||
|
// but a TBird<word> is not a TBird<char>
|
||||||
|
|
||||||
function CheckSpecialized(SrcScope, DestScope: TPasGenericScope): boolean;
|
function CheckSpecialized(SrcScope, DestScope: TPasGenericScope): boolean;
|
||||||
var
|
var
|
||||||
|
@ -5,7 +5,8 @@ unit tcresolvegenerics;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, testregistry, tcresolver, PasResolveEval, PParser;
|
Classes, SysUtils, testregistry, tcresolver, PasResolveEval, PParser,
|
||||||
|
PScanner;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -91,7 +92,8 @@ type
|
|||||||
procedure TestGen_Class_MemberTypeConstructor;
|
procedure TestGen_Class_MemberTypeConstructor;
|
||||||
procedure TestGen_Class_AliasMemberType;
|
procedure TestGen_Class_AliasMemberType;
|
||||||
procedure TestGen_Class_AccessGenericMemberTypeFail;
|
procedure TestGen_Class_AccessGenericMemberTypeFail;
|
||||||
procedure TestGen_Class_ReferenceTo; // ToDo
|
procedure TestGen_Class_ReferenceTo;
|
||||||
|
procedure TestGen_Class_TwoSpecsAreNotRelatedWarn;
|
||||||
procedure TestGen_Class_List;
|
procedure TestGen_Class_List;
|
||||||
// ToDo: different modeswitches at parse time and specialize time
|
// ToDo: different modeswitches at parse time and specialize time
|
||||||
|
|
||||||
@ -1568,6 +1570,26 @@ begin
|
|||||||
ParseProgram;
|
ParseProgram;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolveGenerics.TestGen_Class_TwoSpecsAreNotRelatedWarn;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$mode delphi}',
|
||||||
|
'type',
|
||||||
|
' TObject = class end;',
|
||||||
|
' TBird<T> = class F: T; end;',
|
||||||
|
' TBirdWord = TBird<Word>;',
|
||||||
|
' TBirdChar = TBird<Char>;',
|
||||||
|
'var',
|
||||||
|
' w: TBirdWord;',
|
||||||
|
' c: TBirdChar;',
|
||||||
|
'begin',
|
||||||
|
' w:=TBirdWord(c);',
|
||||||
|
'']);
|
||||||
|
ParseProgram;
|
||||||
|
CheckResolverHint(mtWarning,nClassTypesAreNotRelatedXY,'Class types "TBird<System.Char>" and "TBird<System.Word>" are not related');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestResolveGenerics.TestGen_Class_List;
|
procedure TTestResolveGenerics.TestGen_Class_List;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user