mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 18:09:30 +02:00
fcl-passrc: generics: allow both a<t> and a<s,t>
git-svn-id: trunk@42735 -
This commit is contained in:
parent
652e1985a9
commit
c3b1450c4b
@ -160,7 +160,7 @@ const
|
||||
nIllegalQualifierAfter = 3084;
|
||||
nIllegalQualifierInFrontOf = 3085;
|
||||
nIllegalQualifierWithin = 3086;
|
||||
nMethodClassXInOtherUnitY = 3087;
|
||||
nClassXNotFoundInThisModule = 3087;
|
||||
nClassMethodsMustBeStaticInX = 3088;
|
||||
nCannotMixMethodResolutionAndDelegationAtX = 3089;
|
||||
nImplementsDoesNotSupportArrayProperty = 3101;
|
||||
@ -199,6 +199,7 @@ const
|
||||
nTypeParamXIsMissingConstraintY = 3133;
|
||||
nTypeParamXIsNotCompatibleWithY = 3134;
|
||||
nTypeParamXMustSupportIntfY = 3135;
|
||||
nTypeParamsNotAllowedOnX = 3136;
|
||||
|
||||
// using same IDs as FPC
|
||||
nVirtualMethodXHasLowerVisibility = 3250; // was 3050
|
||||
@ -306,7 +307,7 @@ resourcestring
|
||||
sIllegalQualifierAfter = 'illegal qualifier "%s" after "%s"';
|
||||
sIllegalQualifierInFrontOf = 'illegal qualifier "%s" in front of "%s"';
|
||||
sIllegalQualifierWithin = 'illegal qualifier "%s" within "%s"';
|
||||
sMethodClassXInOtherUnitY = 'method class "%s" in other unit "%s"';
|
||||
sClassXNotFoundInThisModule = 'class "%s" not found in this module';
|
||||
sNoMatchingImplForIntfMethodXFound = 'No matching implementation for interface method "%s" found';
|
||||
sClassMethodsMustBeStaticInX = 'Class methods must be static in %s';
|
||||
sCannotMixMethodResolutionAndDelegationAtX = 'Cannot mix method resolution and delegation at %s';
|
||||
@ -345,6 +346,7 @@ resourcestring
|
||||
sTypeParamXIsMissingConstraintY = 'Type parameter "%s" is missing constraint "%s"';
|
||||
sTypeParamXIsNotCompatibleWithY = 'Type parameter "%s" is not compatible with type "%s"';
|
||||
sTypeParamXMustSupportIntfY = 'Type parameter "%s" must support interface "%s"';
|
||||
sTypeParamsNotAllowedOnX = 'Type parameters not allowed on %s';
|
||||
|
||||
type
|
||||
{ TResolveData - base class for data stored in TPasElement.CustomData }
|
||||
@ -785,6 +787,7 @@ function CodePointToUnicodeString(u: longword): UnicodeString;
|
||||
|
||||
function GetObjName(o: TObject): string;
|
||||
function GetObjPath(o: TObject): string;
|
||||
function GetTypeParamCommas(Cnt: integer): string;
|
||||
function dbgs(const Flags: TResEvalFlags): string; overload;
|
||||
function dbgs(v: TResEvalValue): string; overload;
|
||||
|
||||
@ -1002,11 +1005,23 @@ begin
|
||||
end;
|
||||
|
||||
function GetObjName(o: TObject): string;
|
||||
var
|
||||
GenType: TPasGenericType;
|
||||
begin
|
||||
if o=nil then
|
||||
Result:='nil'
|
||||
else if o is TPasElement then
|
||||
Result:=TPasElement(o).Name+':'+o.ClassName
|
||||
begin
|
||||
Result:=TPasElement(o).Name;
|
||||
if o is TPasGenericType then
|
||||
begin
|
||||
GenType:=TPasGenericType(o);
|
||||
if (GenType.GenericTemplateTypes<>nil)
|
||||
and (GenType.GenericTemplateTypes.Count>0) then
|
||||
Result:=Result+GetTypeParamCommas(GenType.GenericTemplateTypes.Count);
|
||||
end;
|
||||
Result:=Result+':'+o.ClassName;
|
||||
end
|
||||
else
|
||||
Result:=o.ClassName;
|
||||
end;
|
||||
@ -1014,6 +1029,7 @@ end;
|
||||
function GetObjPath(o: TObject): string;
|
||||
var
|
||||
El: TPasElement;
|
||||
GenType: TPasGenericType;
|
||||
begin
|
||||
if o is TPasElement then
|
||||
begin
|
||||
@ -1023,6 +1039,13 @@ begin
|
||||
begin
|
||||
if El<>o then
|
||||
Result:='.'+Result;
|
||||
if El is TPasGenericType then
|
||||
begin
|
||||
GenType:=TPasGenericType(El);
|
||||
if (GenType.GenericTemplateTypes<>nil)
|
||||
and (GenType.GenericTemplateTypes.Count>0) then
|
||||
Result:=GetTypeParamCommas(GenType.GenericTemplateTypes.Count)+Result;
|
||||
end;
|
||||
if El.Name<>'' then
|
||||
begin
|
||||
if IsValidIdent(El.Name) then
|
||||
@ -1039,6 +1062,14 @@ begin
|
||||
Result:=GetObjName(o);
|
||||
end;
|
||||
|
||||
function GetTypeParamCommas(Cnt: integer): string;
|
||||
begin
|
||||
if Cnt<=0 then
|
||||
Result:=''
|
||||
else
|
||||
Result:='<'+StringOfChar(',',Cnt-1)+'>';
|
||||
end;
|
||||
|
||||
function dbgs(const Flags: TResEvalFlags): string;
|
||||
var
|
||||
s: string;
|
||||
|
@ -1547,7 +1547,7 @@ type
|
||||
procedure AddEnumValue(El: TPasEnumValue); virtual;
|
||||
procedure AddProperty(El: TPasProperty); virtual;
|
||||
procedure AddProcedureType(El: TPasProcedureType; TypeParams: TFPList); virtual;
|
||||
procedure AddProcedure(El: TPasProcedure); virtual;
|
||||
procedure AddProcedure(El: TPasProcedure; TypeParams: TFPList); virtual;
|
||||
procedure AddProcedureBody(El: TProcedureBody); virtual;
|
||||
procedure AddArgument(El: TPasArgument); virtual;
|
||||
procedure AddFunctionResult(El: TPasResultElement); virtual;
|
||||
@ -1609,11 +1609,10 @@ type
|
||||
procedure FinishClassOfType(El: TPasClassOfType); virtual;
|
||||
procedure FinishPointerType(El: TPasPointerType); virtual;
|
||||
procedure FinishArrayType(El: TPasArrayType); virtual;
|
||||
procedure FinishGenericTemplateTypes(aType: TPasGenericType); virtual;
|
||||
procedure FinishAliasType(El: TPasAliasType); virtual;
|
||||
procedure FinishGenericTemplateType(El: TPasGenericTemplateType); virtual;
|
||||
procedure FinishSpecializeType(El: TPasSpecializeType); virtual;
|
||||
procedure FinishResourcestring(El: TPasResString); virtual;
|
||||
procedure FinishProcNameParts(aProc: TPasProcedure); virtual;
|
||||
procedure FinishProcedure(aProc: TPasProcedure); virtual;
|
||||
procedure FinishProcedureType(El: TPasProcedureType); virtual;
|
||||
procedure FinishMethodDeclHeader(Proc: TPasProcedure); virtual;
|
||||
@ -1643,6 +1642,7 @@ type
|
||||
procedure CheckProcSignatureMatch(DeclProc, ImplProc: TPasProcedure; CheckNames: boolean);
|
||||
procedure CheckPendingForwardProcs(El: TPasElement);
|
||||
procedure CheckPointerCycle(El: TPasPointerType);
|
||||
procedure CheckGenericTemplateTypes(El: TPasGenericType); virtual;
|
||||
procedure ComputeUnaryNot(El: TUnaryExpr; var ResolvedEl: TPasResolverResult;
|
||||
Flags: TPasResolverComputeFlags); virtual;
|
||||
procedure ComputeBinaryExpr(Bin: TBinaryExpr;
|
||||
@ -1762,6 +1762,7 @@ type
|
||||
procedure SpecializeProcedureBody(GenEl, SpecEl: TProcedureBody);
|
||||
procedure SpecializeDeclarations(GenEl, SpecEl: TPasDeclarations);
|
||||
procedure SpecializeSpecializeType(GenEl, SpecEl: TPasSpecializeType);
|
||||
procedure SpecializeGenericTemplateType(GenEl, SpecEl: TPasGenericTemplateType);
|
||||
procedure SpecializeArgument(GenEl, SpecEl: TPasArgument);
|
||||
procedure SpecializeImplBlock(GenEl, SpecEl: TPasImplBlock);
|
||||
procedure SpecializeImplAsmStatement(GenEl, SpecEl: TPasImplAsmStatement);
|
||||
@ -5206,13 +5207,31 @@ end;
|
||||
function TPasResolver.AddIdentifier(Scope: TPasIdentifierScope;
|
||||
const aName: String; El: TPasElement; const Kind: TPasIdentifierKind
|
||||
): TPasIdentifier;
|
||||
|
||||
function SkipGenericTypes(Identifier: TPasIdentifier;
|
||||
TypeParamCnt: integer): TPasIdentifier;
|
||||
var
|
||||
CurEl: TPasElement;
|
||||
begin
|
||||
while Identifier<>nil do
|
||||
begin
|
||||
CurEl:=Identifier.Element;
|
||||
if not (CurEl is TPasGenericType) then break;
|
||||
if GetTypeParameterCount(TPasGenericType(CurEl))=TypeParamCnt then break;
|
||||
Identifier:=Identifier.NextSameIdentifier;
|
||||
end;
|
||||
Result:=Identifier;
|
||||
end;
|
||||
|
||||
var
|
||||
Group: TPasGroupScope;
|
||||
Identifier, OlderIdentifier: TPasIdentifier;
|
||||
OlderEl: TPasElement;
|
||||
C: TClass;
|
||||
i: Integer;
|
||||
i, TypeParamCnt: Integer;
|
||||
OtherScope: TPasIdentifierScope;
|
||||
ParentScope: TPasScope;
|
||||
IsGeneric: Boolean;
|
||||
begin
|
||||
if aName='' then exit(nil);
|
||||
if Scope is TPasGroupScope then
|
||||
@ -5222,6 +5241,16 @@ begin
|
||||
end
|
||||
else
|
||||
Group:=nil;
|
||||
if El is TPasGenericType then
|
||||
begin
|
||||
IsGeneric:=true;
|
||||
TypeParamCnt:=GetTypeParameterCount(TPasGenericType(El));
|
||||
end
|
||||
else
|
||||
begin
|
||||
IsGeneric:=false;
|
||||
TypeParamCnt:=0;
|
||||
end;
|
||||
|
||||
if (El.Visibility=visPublished) then
|
||||
begin
|
||||
@ -5241,6 +5270,8 @@ begin
|
||||
begin
|
||||
OtherScope:=Group.Scopes[i];
|
||||
OlderIdentifier:=OtherScope.FindLocalIdentifier(aName);
|
||||
if IsGeneric then
|
||||
OlderIdentifier:=SkipGenericTypes(OlderIdentifier,TypeParamCnt);
|
||||
while OlderIdentifier<>nil do
|
||||
begin
|
||||
OlderEl:=OlderIdentifier.Element;
|
||||
@ -5263,29 +5294,51 @@ begin
|
||||
|
||||
// check duplicate in current scope
|
||||
OlderIdentifier:=Identifier.NextSameIdentifier;
|
||||
if IsGeneric then
|
||||
OlderIdentifier:=SkipGenericTypes(OlderIdentifier,TypeParamCnt);
|
||||
if OlderIdentifier<>nil then
|
||||
begin
|
||||
if (OlderIdentifier.Element.ClassType=TPasEnumValue)
|
||||
and (OlderIdentifier.Element.Parent.Parent<>Scope.Element) then
|
||||
OlderEl:=OlderIdentifier.Element;
|
||||
if (OlderEl.ClassType=TPasEnumValue)
|
||||
and (OlderEl.Parent.Parent<>Scope.Element) then
|
||||
begin
|
||||
// this enum was propagated from a sub type -> remove enum from this scope
|
||||
if OlderIdentifier.NextSameIdentifier<>nil then
|
||||
RaiseNotYetImplemented(20190807114726,El,GetElementSourcePosStr(OlderIdentifier.Element));
|
||||
Scope.RemoveLocalIdentifier(OlderIdentifier.Element);
|
||||
RaiseNotYetImplemented(20190807114726,El,GetElementSourcePosStr(OlderEl));
|
||||
Scope.RemoveLocalIdentifier(OlderEl);
|
||||
OlderIdentifier:=nil;
|
||||
end;
|
||||
if (El.Visibility=visPublished) and (El is TPasProcedure)
|
||||
and (OlderIdentifier.Element is TPasProcedure) then
|
||||
OlderEl:=nil;
|
||||
end
|
||||
else if (El.Visibility=visPublished) and (El is TPasProcedure)
|
||||
and (OlderEl is TPasProcedure) then
|
||||
// published method bites method in same scope
|
||||
RaiseMsg(20190626175432,nDuplicatePublishedMethodXAtY,
|
||||
sDuplicatePublishedMethodXAtY,
|
||||
[aName,GetElementSourcePosStr(OlderIdentifier.Element)],El);
|
||||
if (Identifier.Kind=pikSimple)
|
||||
[aName,GetElementSourcePosStr(OlderEl)],El)
|
||||
else if (Identifier.Kind=pikSimple)
|
||||
or (OlderIdentifier.Kind=pikSimple) then
|
||||
// duplicate identifier
|
||||
RaiseMsg(20170216151530,nDuplicateIdentifier,sDuplicateIdentifier,
|
||||
[aName,GetElementSourcePosStr(OlderIdentifier.Element)],El);
|
||||
[aName,GetElementSourcePosStr(OlderEl)],El);
|
||||
end;
|
||||
|
||||
if (Scope=TopScope) and (Scope is TPasSectionScope) then
|
||||
begin
|
||||
ParentScope:=Scopes[ScopeCount-2];
|
||||
if ParentScope is TPasSectionScope then
|
||||
begin
|
||||
OlderIdentifier:=TPasSectionScope(ParentScope).FindLocalIdentifier(aName);
|
||||
if IsGeneric then
|
||||
OlderIdentifier:=SkipGenericTypes(OlderIdentifier,TypeParamCnt);
|
||||
if OlderIdentifier<>nil then
|
||||
begin
|
||||
OlderEl:=OlderIdentifier.Element;
|
||||
if (Identifier.Kind=pikSimple)
|
||||
or (OlderIdentifier.Kind=pikSimple) then
|
||||
RaiseMsg(20190818141630,nDuplicateIdentifier,sDuplicateIdentifier,
|
||||
[aName,GetElementSourcePosStr(OlderEl)],El);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result:=Identifier;
|
||||
@ -5648,7 +5701,6 @@ end;
|
||||
procedure TPasResolver.FinishTypeDef(El: TPasType);
|
||||
var
|
||||
C: TClass;
|
||||
aType: TPasType;
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
//writeln('TPasResolver.FinishTypeDef El=',GetObjName(El));
|
||||
@ -5671,12 +5723,7 @@ begin
|
||||
else if C=TPasArrayType then
|
||||
FinishArrayType(TPasArrayType(El))
|
||||
else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
|
||||
begin
|
||||
aType:=ResolveAliasType(El);
|
||||
if (aType is TPasMembersType) and (aType.CustomData=nil) then
|
||||
exit;
|
||||
EmitTypeHints(El,TPasAliasType(El).DestType);
|
||||
end
|
||||
FinishAliasType(TPasAliasType(El))
|
||||
else if (C=TPasPointerType) then
|
||||
EmitTypeHints(El,TPasPointerType(El).DestType)
|
||||
else if C=TPasGenericTemplateType then
|
||||
@ -6149,47 +6196,18 @@ begin
|
||||
PopScope;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.FinishGenericTemplateTypes(aType: TPasGenericType);
|
||||
procedure TPasResolver.FinishAliasType(El: TPasAliasType);
|
||||
var
|
||||
C: TClass;
|
||||
GenTemplates: TFPList;
|
||||
TemplType: TPasGenericTemplateType;
|
||||
i: Integer;
|
||||
ClassHeaderScope: TPasClassHeaderScope;
|
||||
aType: TPasType;
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.FinishGenericTemplateTypes ',GetObjName(aType));
|
||||
{$ENDIF}
|
||||
GenTemplates:=aType.GenericTemplateTypes;
|
||||
if (GenTemplates=nil) or (GenTemplates.Count=0) then
|
||||
RaiseNotYetImplemented(20190726184902,aType,'emty generic template list');
|
||||
|
||||
// template names must differ from generic type name
|
||||
for i:=0 to GenTemplates.Count-1 do
|
||||
begin
|
||||
TemplType:=TPasGenericTemplateType(GenTemplates[i]);
|
||||
if SameText(TemplType.Name,aType.Name) then
|
||||
RaiseMsg(20190801101444,nDuplicateIdentifier,sDuplicateIdentifier,[
|
||||
TemplType.Name,GetElementSourcePosStr(aType)],TemplType);
|
||||
end;
|
||||
|
||||
// add template names to scope
|
||||
C:=aType.ClassType;
|
||||
if C=TPasRecordType then
|
||||
else if C=TPasClassType then
|
||||
begin
|
||||
// Note: TPasClassType.Forward is not yet set!
|
||||
// create class header scope
|
||||
TemplType:=TPasGenericTemplateType(GenTemplates[0]);
|
||||
ClassHeaderScope:=TPasClassHeaderScope(PushScope(TemplType,TPasClassHeaderScope));
|
||||
ClassHeaderScope.GenericType:=aType;
|
||||
AddGenericTemplateIdentifiers(GenTemplates,ClassHeaderScope);
|
||||
end
|
||||
else if C=TPasArrayType then
|
||||
else if (C=TPasProcedureType)
|
||||
or (C=TPasFunctionType) then
|
||||
else
|
||||
RaiseNotYetImplemented(20190726150359,aType,GetObjName(aType));
|
||||
aType:=ResolveAliasType(El);
|
||||
if (aType is TPasMembersType) and (aType.CustomData=nil) then
|
||||
exit;
|
||||
if (aType is TPasGenericType)
|
||||
and (GetTypeParameterCount(TPasGenericType(aType))>0) then
|
||||
RaiseMsg(20190818135830,nXExpectedButYFound,sXExpectedButYFound,
|
||||
['type',GetTypeDescription(aType)],El);
|
||||
EmitTypeHints(El,TPasAliasType(El).DestType);
|
||||
end;
|
||||
|
||||
procedure TPasResolver.FinishGenericTemplateType(El: TPasGenericTemplateType);
|
||||
@ -6365,19 +6383,6 @@ begin
|
||||
RaiseXExpectedButYFound(20171004135753,'string',GetTypeDescription(ResolvedEl),El.Expr);
|
||||
end;
|
||||
|
||||
procedure TPasResolver.FinishProcNameParts(aProc: TPasProcedure);
|
||||
var
|
||||
i, j: Integer;
|
||||
begin
|
||||
for i:=0 to length(aProc.NameParts)-1 do
|
||||
with aProc.NameParts[i] do
|
||||
begin
|
||||
if Templates<>nil then
|
||||
for j:=0 to Templates.Count-1 do
|
||||
AddType(TPasGenericTemplateType(Templates[j]));
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.FinishProcedure(aProc: TPasProcedure);
|
||||
var
|
||||
i: Integer;
|
||||
@ -11029,6 +11034,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.CheckGenericTemplateTypes(El: TPasGenericType);
|
||||
var
|
||||
GenTemplates: TFPList;
|
||||
i: Integer;
|
||||
TemplType: TPasGenericTemplateType;
|
||||
begin
|
||||
GenTemplates:=El.GenericTemplateTypes;
|
||||
if (GenTemplates=nil) or (GenTemplates.Count=0) then
|
||||
RaiseNotYetImplemented(20190726184902,El,'emty generic template list');
|
||||
|
||||
// template names must differ from generic type name
|
||||
for i:=0 to GenTemplates.Count-1 do
|
||||
begin
|
||||
TemplType:=TPasGenericTemplateType(GenTemplates[i]);
|
||||
if SameText(TemplType.Name,El.Name) then
|
||||
RaiseMsg(20190801101444,nDuplicateIdentifier,sDuplicateIdentifier,[
|
||||
TemplType.Name,GetElementSourcePosStr(El)],TemplType);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPasResolver.ComputeUnaryNot(El: TUnaryExpr;
|
||||
var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
|
||||
begin
|
||||
@ -11101,16 +11126,23 @@ begin
|
||||
if El.Name<>'' then begin
|
||||
if not (TopScope is TPasIdentifierScope) then
|
||||
RaiseInvalidScopeForElement(20190812215622,El);
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
El.SetGenericTemplates(TypeParams);
|
||||
TypeParams:=El.GenericTemplateTypes;
|
||||
CheckGenericTemplateTypes(El);
|
||||
end;
|
||||
|
||||
AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
|
||||
end;
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
// generic array
|
||||
if El.Name='' then
|
||||
RaiseNotYetImplemented(20190812215851,El);
|
||||
Scope:=TPasArrayScope(PushScope(El,TPasArrayScope));
|
||||
AddGenericTemplateIdentifiers(TypeParams,Scope);
|
||||
end;
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
Scope:=TPasArrayScope(PushScope(El,TPasArrayScope));
|
||||
AddGenericTemplateIdentifiers(TypeParams,Scope);
|
||||
end;
|
||||
end else if TypeParams<>nil then
|
||||
RaiseNotYetImplemented(20190812215851,El);
|
||||
end;
|
||||
|
||||
procedure TPasResolver.AddRecordType(El: TPasRecordType; TypeParams: TFPList);
|
||||
@ -11122,6 +11154,14 @@ begin
|
||||
{$ENDIF}
|
||||
if not (TopScope is TPasIdentifierScope) then
|
||||
RaiseInvalidScopeForElement(20160922163508,El);
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
El.SetGenericTemplates(TypeParams);
|
||||
TypeParams:=El.GenericTemplateTypes;
|
||||
CheckGenericTemplateTypes(El);
|
||||
end;
|
||||
|
||||
if El.Name<>'' then begin
|
||||
AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
|
||||
{$IFDEF VerbosePasResolver}
|
||||
@ -11154,11 +11194,12 @@ var
|
||||
GenTemplCnt, i, j: Integer;
|
||||
DuplEl: TPasElement;
|
||||
ClassScope: TPasClassScope;
|
||||
ForwGenTempl, ActGenTempl: TPasGenericTemplateType;
|
||||
ForwGenTempl, ActGenTempl, TemplType: TPasGenericTemplateType;
|
||||
ForwConstraints, ActConstraints: TPasExprArray;
|
||||
ForwExpr, ActExpr: TPasExpr;
|
||||
ForwToken, ActToken: TToken;
|
||||
ForwConstraintResolved, ActConstraintResolved: TPasResolverResult;
|
||||
ClassHeaderScope: TPasClassHeaderScope;
|
||||
begin
|
||||
// Beware: El.ObjKind is not yet set!
|
||||
{$IFDEF VerbosePasResolver}
|
||||
@ -11166,6 +11207,15 @@ begin
|
||||
{$ENDIF}
|
||||
if not (TopScope is TPasIdentifierScope) then
|
||||
RaiseInvalidScopeForElement(20160922163510,El);
|
||||
if TypeParams=nil then
|
||||
GenTemplCnt:=0
|
||||
else
|
||||
begin
|
||||
GenTemplCnt:=TypeParams.Count;
|
||||
El.SetGenericTemplates(TypeParams);
|
||||
TypeParams:=El.GenericTemplateTypes;
|
||||
CheckGenericTemplateTypes(El);
|
||||
end;
|
||||
|
||||
CurScope:=TPasIdentifierScope(TopScope);
|
||||
if CurScope is TPasGroupScope then
|
||||
@ -11173,10 +11223,6 @@ begin
|
||||
else
|
||||
LocalScope:=CurScope;
|
||||
Duplicate:=LocalScope.FindLocalIdentifier(El.Name);
|
||||
if TypeParams=nil then
|
||||
GenTemplCnt:=0
|
||||
else
|
||||
GenTemplCnt:=TypeParams.Count;
|
||||
while Duplicate<>nil do
|
||||
begin
|
||||
DuplEl:=Duplicate.Element;
|
||||
@ -11254,6 +11300,15 @@ begin
|
||||
else
|
||||
AddIdentifier(CurScope,El.Name,El,pikSimple);
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
// Parsing the ancestor+interface list requires the type params.
|
||||
TemplType:=TPasGenericTemplateType(TypeParams[0]);
|
||||
ClassHeaderScope:=TPasClassHeaderScope(PushScope(TemplType,TPasClassHeaderScope));
|
||||
ClassHeaderScope.GenericType:=El;
|
||||
AddGenericTemplateIdentifiers(TypeParams,ClassHeaderScope);
|
||||
end;
|
||||
|
||||
{$IFDEF VerbosePasResolver}
|
||||
if FPendingForwardProcs.IndexOf(El)>=0 then
|
||||
RaiseNotYetImplemented(20190804114746,El);
|
||||
@ -11390,19 +11445,26 @@ begin
|
||||
{$ENDIF}
|
||||
if not (TopScope is TPasIdentifierScope) then
|
||||
RaiseInvalidScopeForElement(20190813193703,El);
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
El.SetGenericTemplates(TypeParams);
|
||||
TypeParams:=El.GenericTemplateTypes;
|
||||
CheckGenericTemplateTypes(El);
|
||||
end;
|
||||
|
||||
AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
|
||||
end;
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
// generic procedure type
|
||||
if El.Name='' then
|
||||
RaiseNotYetImplemented(20190813193745,El);
|
||||
Scope:=TPasProcTypeScope(PushScope(El,TPasProcTypeScope));
|
||||
AddGenericTemplateIdentifiers(TypeParams,Scope);
|
||||
end;
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
Scope:=TPasProcTypeScope(PushScope(El,TPasProcTypeScope));
|
||||
AddGenericTemplateIdentifiers(TypeParams,Scope);
|
||||
end;
|
||||
end else if TypeParams<>nil then
|
||||
RaiseNotYetImplemented(20190813193745,El);
|
||||
end;
|
||||
|
||||
procedure TPasResolver.AddProcedure(El: TPasProcedure);
|
||||
procedure TPasResolver.AddProcedure(El: TPasProcedure; TypeParams: TFPList);
|
||||
|
||||
procedure AddClassConDestructor(ClassOrRecordScope: TPasClassOrRecordScope;
|
||||
var Field: TPasProcedure);
|
||||
@ -11415,23 +11477,95 @@ procedure TPasResolver.AddProcedure(El: TPasProcedure);
|
||||
Field:=El;
|
||||
end;
|
||||
|
||||
function FindBestMembersType(const ClassOrRecName: string;
|
||||
TypeParamCnt: integer; Scope: TPasIdentifierScope;
|
||||
var Best: TPasMembersType; ErrorPos: TPasElement): integer;
|
||||
// returns number of candidates
|
||||
var
|
||||
Identifier: TPasIdentifier;
|
||||
CurEl: TPasElement;
|
||||
begin
|
||||
Result:=0;
|
||||
Identifier:=Scope.FindLocalIdentifier(ClassOrRecName);
|
||||
while Identifier<>nil do
|
||||
begin
|
||||
CurEl:=Identifier.Element;
|
||||
if not (CurEl is TPasMembersType) then
|
||||
RaiseXExpectedButYFound(20170216152557,
|
||||
'class',CurEl.Name+':'+GetElementTypeName(CurEl),ErrorPos);
|
||||
inc(Result);
|
||||
if Best=nil then
|
||||
Best:=TPasMembersType(CurEl);
|
||||
if GetTypeParameterCount(TPasGenericType(CurEl))=TypeParamCnt then
|
||||
begin
|
||||
// fits
|
||||
Best:=TPasMembersType(CurEl);
|
||||
exit;
|
||||
end;
|
||||
Identifier:=Identifier.NextSameIdentifier;
|
||||
end;
|
||||
end;
|
||||
|
||||
function FindMembersType(Scope: TPasIdentifierScope;
|
||||
const ClassOrRecName: string; TypeParamCnt: integer; IsDelphi: boolean;
|
||||
ErrorPos: TPasElement): TPasMembersType;
|
||||
var
|
||||
Found: integer;
|
||||
begin
|
||||
Result:=nil;
|
||||
if Scope<>nil then
|
||||
Found:=FindBestMembersType(ClassOrRecName,TypeParamCnt,Scope,Result,ErrorPos)
|
||||
else if TopScope is TPasIdentifierScope then
|
||||
begin
|
||||
Found:=FindBestMembersType(ClassOrRecName,TypeParamCnt,
|
||||
TPasIdentifierScope(TopScope),Result,ErrorPos);
|
||||
if (Result=nil) or (TypeParamCnt<>GetTypeParameterCount(Result)) then
|
||||
begin
|
||||
if (TopScope is TPasSectionScope)
|
||||
and (ScopeCount>1) and (Scopes[ScopeCount-2] is TPasSectionScope) then
|
||||
// search in unit interface too
|
||||
Found:=Found+FindBestMembersType(ClassOrRecName,TypeParamCnt,
|
||||
TPasIdentifierScope(Scopes[ScopeCount-2]),Result,ErrorPos);
|
||||
end;
|
||||
end;
|
||||
if Result=nil then
|
||||
RaiseMsg(20190818112356,nClassXNotFoundInThisModule,sClassXNotFoundInThisModule,
|
||||
[ClassOrRecName],ErrorPos);
|
||||
if TypeParamCnt=GetTypeParameterCount(Result) then
|
||||
exit; // fits perfectly
|
||||
if (not IsDelphi) and (TypeParamCnt=0) and (Found=1) then
|
||||
exit; // in objfpc type params can be omitted if there is only one type
|
||||
// found one or more, but type param count do not fit
|
||||
RaiseMsg(20190818112856,nXExpectedButYFound,sXExpectedButYFound,
|
||||
[Result.Name+GetTypeParamCommas(GetTypeParameterCount(Result)),
|
||||
ClassOrRecName+GetTypeParamCommas(TypeParamCnt)],ErrorPos);
|
||||
end;
|
||||
|
||||
var
|
||||
ProcName, aClassName: String;
|
||||
p: SizeInt;
|
||||
ClassOrRecType: TPasMembersType;
|
||||
ProcScope: TPasProcedureScope;
|
||||
HasDot, IsClassConDestructor: Boolean;
|
||||
CurEl: TPasElement;
|
||||
Identifier: TPasIdentifier;
|
||||
HasDot, IsClassConDestructor, IsDelphi: Boolean;
|
||||
ClassOrRecScope: TPasClassOrRecordScope;
|
||||
C: TClass;
|
||||
CurScope: TPasScope;
|
||||
LocalScope: TPasScope;
|
||||
Level, TypeParamCount, i: Integer;
|
||||
TypeParam: TProcedureNamePart;
|
||||
TemplType: TPasGenericTemplateType;
|
||||
begin
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.AddProcedure ',GetObjName(El));
|
||||
{$ENDIF}
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
// move type param elements to El
|
||||
El.SetNameParts(TypeParams);
|
||||
TypeParams:=El.NameParts;
|
||||
end;
|
||||
|
||||
CurScope:=TopScope;
|
||||
if CurScope.ClassType=TPasGroupScope then
|
||||
LocalScope:=TPasGroupScope(CurScope).Scopes[0]
|
||||
@ -11448,6 +11582,8 @@ begin
|
||||
else
|
||||
begin
|
||||
// anonymous proc
|
||||
if TypeParams<>nil then
|
||||
RaiseNotYetImplemented(20190818101856,El);
|
||||
C:=LocalScope.ClassType;
|
||||
if (C=ScopeClass_InitialFinalization)
|
||||
or C.InheritsFrom(TPasProcedureScope)
|
||||
@ -11463,6 +11599,10 @@ begin
|
||||
// Note: El.ProcType is nil ! It is parsed later.
|
||||
|
||||
HasDot:=Pos('.',ProcName)>1;
|
||||
if (TypeParams<>nil) then
|
||||
if HasDot<>(TypeParams.Count>1) then
|
||||
RaiseNotYetImplemented(20190818093923,El);
|
||||
|
||||
if El.CustomData is TPasProcedureScope then
|
||||
begin
|
||||
// adding a specialized implementation proc
|
||||
@ -11480,6 +11620,7 @@ begin
|
||||
end
|
||||
else
|
||||
begin
|
||||
IsDelphi:=msDelphi in CurrentParser.CurrentModeswitches;
|
||||
IsClassConDestructor:=(El.ClassType=TPasClassConstructor)
|
||||
or (El.ClassType=TPasClassDestructor);
|
||||
if (not HasDot) and IsClassConDestructor then
|
||||
@ -11493,6 +11634,9 @@ begin
|
||||
AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassConstructor))
|
||||
else
|
||||
AddClassConDestructor(ClassOrRecScope,TPasProcedure(ClassOrRecScope.ClassDestructor));
|
||||
if TypeParams<>nil then
|
||||
RaiseMsg(20190818094753,nTypeParamsNotAllowedOnX,sTypeParamsNotAllowedOnX,
|
||||
[El.ElementTypeName],El);
|
||||
end;
|
||||
|
||||
if (not HasDot) and (ProcName<>'')
|
||||
@ -11503,7 +11647,7 @@ begin
|
||||
AddIdentifier(TPasIdentifierScope(CurScope),ProcName,El,pikProc);
|
||||
end;
|
||||
|
||||
ProcScope:=TPasProcedureScope(PushScope(El,FScopeClass_Proc));
|
||||
ProcScope:=TPasProcedureScope(CreateScope(El,FScopeClass_Proc));
|
||||
ProcScope.ModeSwitches:=CurrentParser.CurrentModeswitches;
|
||||
if HasDot then
|
||||
begin
|
||||
@ -11512,7 +11656,9 @@ begin
|
||||
writeln('TPasResolver.AddProcedure searching class of "',ProcName,'" ...');
|
||||
{$ENDIF}
|
||||
ClassOrRecType:=nil;
|
||||
Level:=0;
|
||||
repeat
|
||||
inc(Level);
|
||||
p:=Pos('.',ProcName);
|
||||
if p<1 then
|
||||
begin
|
||||
@ -11522,8 +11668,29 @@ begin
|
||||
end;
|
||||
aClassName:=LeftStr(ProcName,p-1);
|
||||
Delete(ProcName,1,p);
|
||||
TypeParamCount:=0;
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
// e.g. aclassname<T>.
|
||||
if Level>TypeParams.Count then
|
||||
RaiseNotYetImplemented(20190818122217,El);
|
||||
TypeParam:=TProcedureNamePart(TypeParams[Level-1]);
|
||||
if TypeParam.Name<>aClassName then
|
||||
RaiseNotYetImplemented(20190818102541,El,IntToStr(Level)+': '+TypeParam.Name+'<>'+aClassName);
|
||||
if TypeParam.Templates<>nil then
|
||||
begin
|
||||
TypeParamCount:=TypeParam.Templates.Count;
|
||||
for i:=0 to TypeParamCount-1 do
|
||||
begin
|
||||
TemplType:=TPasGenericTemplateType(TypeParam.Templates[i]);
|
||||
if length(TemplType.Constraints)>0 then
|
||||
RaiseMsg(20190818102850,nXCannotHaveParameters,sXCannotHaveParameters,
|
||||
[TemplType.Name],TemplType.Constraints[0]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" ...');
|
||||
writeln('TPasResolver.AddProcedure searching class "',aClassName,GetTypeParamCommas(TypeParamCount),'" ProcName="',ProcName,'" ...');
|
||||
{$ENDIF}
|
||||
if not IsValidIdent(aClassName) then
|
||||
RaiseNotYetImplemented(20161013170844,El);
|
||||
@ -11531,41 +11698,25 @@ begin
|
||||
if ClassOrRecType<>nil then
|
||||
begin
|
||||
ClassOrRecScope:=TPasClassOrRecordScope(ClassOrRecType.CustomData);
|
||||
Identifier:=ClassOrRecScope.FindLocalIdentifier(aClassName);
|
||||
if Identifier=nil then
|
||||
RaiseIdentifierNotFound(20180430130635,aClassName,El)
|
||||
else
|
||||
CurEl:=Identifier.Element;
|
||||
ClassOrRecType:=FindMembersType(ClassOrRecScope,aClassName,
|
||||
TypeParamCount,IsDelphi,El);
|
||||
end
|
||||
else
|
||||
CurEl:=FindElementWithoutParams(aClassName,El,false);
|
||||
ClassOrRecType:=FindMembersType(nil,aClassName,
|
||||
TypeParamCount,IsDelphi,El);
|
||||
|
||||
if not (CurEl is TPasMembersType) then
|
||||
begin
|
||||
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
|
||||
{$IFDEF VerbosePasResolver}
|
||||
writeln('TPasResolver.AddProcedure searching class "',aClassName,'" ProcName="',ProcName,'" found: '+GetObjName(CurEl));
|
||||
{$ENDIF}
|
||||
RaiseXExpectedButYFound(20170216152557,
|
||||
'class',aClassname+':'+GetElementTypeName(CurEl),El);
|
||||
end;
|
||||
ClassOrRecType:=TPasMembersType(CurEl);
|
||||
if ClassOrRecType is TPasClassType then
|
||||
begin
|
||||
if not (TPasClassType(ClassOrRecType).ObjKind in
|
||||
([okClass]+okAllHelpers)) then
|
||||
begin
|
||||
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
|
||||
RaiseXExpectedButYFound(20180321161722,
|
||||
'class',aClassname+':'+GetElementTypeName(CurEl),El);
|
||||
RaiseXExpectedButYFound(20180321161722,'class',
|
||||
aClassname+GetTypeParamCommas(GetTypeParameterCount(ClassOrRecType))+':'+GetElementTypeName(ClassOrRecType),El);
|
||||
end
|
||||
end;
|
||||
if ClassOrRecType.GetModule<>El.GetModule then
|
||||
begin
|
||||
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
|
||||
RaiseMsg(20180211230432,nMethodClassXInOtherUnitY,sMethodClassXInOtherUnitY,
|
||||
[aClassName,ClassOrRecType.GetModule.Name],El);
|
||||
end;
|
||||
RaiseNotYetImplemented(20190818120051,El);
|
||||
until false;
|
||||
|
||||
if not IsValidIdent(ProcName) then
|
||||
@ -11573,8 +11724,30 @@ begin
|
||||
|
||||
ProcScope.VisibilityContext:=ClassOrRecType;
|
||||
ProcScope.ClassRecScope:=NoNil(ClassOrRecType.CustomData) as TPasClassOrRecordScope;
|
||||
end; // HasDot=true
|
||||
end;
|
||||
|
||||
if TypeParams<>nil then
|
||||
begin
|
||||
if Level<>TypeParams.Count then
|
||||
RaiseNotYetImplemented(20190818122315,El);
|
||||
TypeParam:=TProcedureNamePart(TypeParams[Level-1]);
|
||||
if TypeParam.Name<>ProcName then
|
||||
RaiseNotYetImplemented(20190818122551,El,IntToStr(Level)+': '+TypeParam.Name+'<>'+ProcName);
|
||||
if TypeParam.Templates<>nil then
|
||||
begin
|
||||
// ToDo: generic method
|
||||
RaiseNotYetImplemented(20190818122619,El);
|
||||
end;
|
||||
end;
|
||||
|
||||
end
|
||||
else
|
||||
begin
|
||||
// HasDot=false
|
||||
if TypeParams<>nil then
|
||||
RaiseNotYetImplemented(20190818095452,El);
|
||||
end;
|
||||
PushScope(ProcScope);
|
||||
end;// source proc, not specialized
|
||||
|
||||
if HasDot then
|
||||
begin
|
||||
@ -14577,7 +14750,7 @@ begin
|
||||
if Item=nil then
|
||||
begin
|
||||
// new specialization
|
||||
SrcModule:=El.GetModule;
|
||||
SrcModule:=GenericType.GetModule;
|
||||
SrcModuleScope:=SrcModule.CustomData as TPasModuleScope;
|
||||
SrcResolver:=SrcModuleScope.Owner as TPasResolver;
|
||||
Item:=SrcResolver.CreateSpecializedType(El,ParamsResolved);
|
||||
@ -15242,6 +15415,8 @@ begin
|
||||
AddType(TPasSpecializeType(SpecEl));
|
||||
SpecializeSpecializeType(TPasSpecializeType(GenEl),TPasSpecializeType(SpecEl));
|
||||
end
|
||||
else if C=TPasGenericTemplateType then
|
||||
SpecializeGenericTemplateType(TPasGenericTemplateType(GenEl),TPasGenericTemplateType(SpecEl))
|
||||
// empty statement
|
||||
else if C=TPasImplCommand then
|
||||
// TPasImplBlock
|
||||
@ -15320,12 +15495,12 @@ begin
|
||||
end
|
||||
else if C=TPasOperator then
|
||||
begin
|
||||
AddProcedure(TPasOperator(SpecEl));
|
||||
AddProcedure(TPasOperator(SpecEl),nil);
|
||||
SpecializeOperator(TPasOperator(GenEl),TPasOperator(SpecEl));
|
||||
end
|
||||
else if C.InheritsFrom(TPasProcedure) then
|
||||
begin
|
||||
AddProcedure(TPasProcedure(SpecEl));
|
||||
AddProcedure(TPasProcedure(SpecEl),nil);
|
||||
SpecializeProcedure(TPasProcedure(GenEl),TPasProcedure(SpecEl));
|
||||
end
|
||||
else if C.InheritsFrom(TPasProcedureType) then
|
||||
@ -15507,6 +15682,9 @@ var
|
||||
NewClass: TPTreeElement;
|
||||
SpecProcScope: TPasProcedureScope;
|
||||
GenBody: TProcedureBody;
|
||||
i, j: Integer;
|
||||
GenPart, SpecPart: TProcedureNamePart;
|
||||
GenTempl, SpecTempl: TPasGenericTemplateType;
|
||||
begin
|
||||
SpecProcScope:=SpecEl.CustomData as TPasProcedureScope;
|
||||
Include(SpecProcScope.Flags,ppsfIsSpecialized);
|
||||
@ -15525,6 +15703,33 @@ begin
|
||||
SpecEl.MessageType:=GenEl.MessageType;
|
||||
SpecEl.AliasName:=GenEl.AliasName;
|
||||
SpecEl.Modifiers:=GenEl.Modifiers;
|
||||
if GenEl.NameParts<>nil then
|
||||
begin
|
||||
if SpecEl.NameParts<>nil then
|
||||
RaiseNotYetImplemented(20190818125620,SpecEl);
|
||||
SpecEl.NameParts:=TFPList.Create;
|
||||
for i:=0 to GenEl.NameParts.Count-1 do
|
||||
begin
|
||||
GenPart:=TProcedureNamePart(GenEl.NameParts[i]);
|
||||
SpecPart:=TProcedureNamePart.Create;
|
||||
SpecEl.NameParts.Add(SpecPart);
|
||||
SpecPart.Name:=GenPart.Name;
|
||||
if GenPart.Templates<>nil then
|
||||
begin
|
||||
SpecPart.Templates:=TFPList.Create;
|
||||
for j:=0 to GenPart.Templates.Count-1 do
|
||||
begin
|
||||
GenTempl:=TPasGenericTemplateType(GenPart.Templates[j]);
|
||||
if GenTempl.Parent<>GenEl then
|
||||
RaiseNotYetImplemented(20190818130001,GenEl,IntToStr(i)+','+IntToStr(j)+':'+GenTempl.Name+' GenParent='+GetObjName(GenTempl.Parent)+' GenEl='+GetObjName(GenEl));
|
||||
NewClass:=TPTreeElement(GenTempl.ClassType);
|
||||
SpecTempl:=TPasGenericTemplateType(NewClass.Create(GenTempl.Name,SpecEl));
|
||||
SpecPart.Templates.Add(SpecTempl);
|
||||
SpecializeElement(GenTempl,SpecTempl);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if GenEl.ProcType<>nil then
|
||||
begin
|
||||
GenProcType:=GenEl.ProcType;
|
||||
@ -15544,8 +15749,6 @@ begin
|
||||
SpecializeElement(GenBody,SpecEl.Body);
|
||||
end;
|
||||
|
||||
if length(GenEl.NameParts)>0 then RaiseNotYetImplemented(20190803215418,GenEl);
|
||||
|
||||
FinishProcedure(SpecEl);
|
||||
end;
|
||||
|
||||
@ -15695,6 +15898,12 @@ begin
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TPasResolver.SpecializeGenericTemplateType(GenEl,
|
||||
SpecEl: TPasGenericTemplateType);
|
||||
begin
|
||||
SpecializeExprArray(GenEl,SpecEl,GenEl.Constraints,SpecEl.Constraints);
|
||||
end;
|
||||
|
||||
procedure TPasResolver.SpecializeArgument(GenEl, SpecEl: TPasArgument);
|
||||
begin
|
||||
SpecEl.Access:=GenEl.Access;
|
||||
@ -18420,7 +18629,7 @@ begin
|
||||
AddClassType(TPasClassType(El),TypeParams)
|
||||
else if AClass=TPasVariant then
|
||||
else if AClass.InheritsFrom(TPasProcedure) then
|
||||
AddProcedure(TPasProcedure(El))
|
||||
AddProcedure(TPasProcedure(El),TypeParams)
|
||||
else if AClass=TPasResultElement then
|
||||
AddFunctionResult(TPasResultElement(El))
|
||||
else if AClass=TProcedureBody then
|
||||
@ -19169,11 +19378,6 @@ begin
|
||||
stTypeSection: FinishTypeSection(El);
|
||||
stTypeDef: FinishTypeDef(El as TPasType);
|
||||
stResourceString: FinishResourcestring(El as TPasResString);
|
||||
stGenericTypeTemplates:
|
||||
if El is TPasGenericType then
|
||||
FinishGenericTemplateTypes(TPasGenericType(El))
|
||||
else
|
||||
FinishProcNameParts(El as TPasProcedure);
|
||||
stProcedure: FinishProcedure(El as TPasProcedure);
|
||||
stProcedureHeader: FinishProcedureType(El as TPasProcedureType);
|
||||
stExceptOnExpr: FinishExceptOnExpr;
|
||||
@ -22689,7 +22893,9 @@ function TPasResolver.GetTypeDescription(aType: TPasType; AddPath: boolean): str
|
||||
end
|
||||
else
|
||||
Result:=GetElementTypeName(aType);
|
||||
end;
|
||||
end
|
||||
else if aType is TPasGenericType then
|
||||
Result:=Result+GetTypeParamCommas(GetTypeParameterCount(TPasGenericType(aType)));
|
||||
if AddPath then
|
||||
begin
|
||||
s:=aType.ParentPath;
|
||||
@ -25379,7 +25585,7 @@ begin
|
||||
AncestorScope:=(aClass.CustomData as TPasClassScope).AncestorScope;
|
||||
if AncestorScope=nil then exit;
|
||||
aClass:=NoNil(AncestorScope.Element) as TPasClassType;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPasResolver.IsProcedureType(const ResolvedEl: TPasResolverResult;
|
||||
|
@ -1049,11 +1049,11 @@ type
|
||||
|
||||
{ TProcedureNamePart }
|
||||
|
||||
TProcedureNamePart = record
|
||||
TProcedureNamePart = class
|
||||
Name: string;
|
||||
Templates: TFPList; // optional list of TPasGenericTemplateType, can nil!
|
||||
Templates: TFPList; // optional list of TPasGenericTemplateType, can be nil!
|
||||
end;
|
||||
TProcedureNameParts = array of TProcedureNamePart;
|
||||
TProcedureNameParts = TFPList;
|
||||
|
||||
TProcedureBody = class;
|
||||
|
||||
@ -1097,7 +1097,7 @@ type
|
||||
Function IsStatic : Boolean;
|
||||
Function IsForward: Boolean;
|
||||
Function GetProcTypeEnum: TProcType; virtual;
|
||||
procedure SetNameParts(var Parts: TProcedureNameParts);
|
||||
procedure SetNameParts(Parts: TProcedureNameParts);
|
||||
Property Modifiers : TProcedureModifiers Read FModifiers Write FModifiers;
|
||||
Property CallingConvention : TCallingConvention Read GetCallingConvention Write SetCallingConvention;
|
||||
Property MessageName : String Read FMessageName Write FMessageName;
|
||||
@ -1809,21 +1809,27 @@ procedure ReleaseProcNameParts(var NameParts: TProcedureNameParts);
|
||||
var
|
||||
El: TPasElement;
|
||||
i, j: Integer;
|
||||
Part: TProcedureNamePart;
|
||||
begin
|
||||
for i := 0 to length(NameParts)-1 do
|
||||
if NameParts=nil then exit;
|
||||
for i := NameParts.Count-1 downto 0 do
|
||||
begin
|
||||
with NameParts[i] do
|
||||
if Templates<>nil then
|
||||
Part:=TProcedureNamePart(NameParts[i]);
|
||||
if Part.Templates<>nil then
|
||||
begin
|
||||
for j:=0 to Part.Templates.Count-1 do
|
||||
begin
|
||||
for j:=0 to Templates.Count-1 do
|
||||
begin
|
||||
El:=TPasGenericTemplateType(Templates[j]);
|
||||
El.Parent:=nil;
|
||||
El.Release{$IFDEF CheckPasTreeRefCount}('TPasProcedure.NameParts'){$ENDIF};
|
||||
end;
|
||||
Templates.Free;
|
||||
El:=TPasGenericTemplateType(Part.Templates[j]);
|
||||
El.Parent:=nil;
|
||||
El.Release{$IFDEF CheckPasTreeRefCount}('TPasProcedure.NameParts'){$ENDIF};
|
||||
end;
|
||||
Part.Templates.Free;
|
||||
Part.Templates:=nil;
|
||||
end;
|
||||
NameParts.Delete(i);
|
||||
Part.Free;
|
||||
end;
|
||||
NameParts.Free;
|
||||
NameParts:=nil;
|
||||
end;
|
||||
|
||||
@ -4664,11 +4670,12 @@ var
|
||||
i, j: Integer;
|
||||
begin
|
||||
inherited ForEachCall(aMethodCall, Arg);
|
||||
for i:=0 to length(NameParts)-1 do
|
||||
with NameParts[i] do
|
||||
if Templates<>nil then
|
||||
for j:=0 to Templates.Count-1 do
|
||||
ForEachChildCall(aMethodCall,Arg,TPasElement(Templates[i]),false);
|
||||
if NameParts<>nil then
|
||||
for i:=0 to NameParts.Count-1 do
|
||||
with TProcedureNamePart(NameParts[i]) do
|
||||
if Templates<>nil then
|
||||
for j:=0 to Templates.Count-1 do
|
||||
ForEachChildCall(aMethodCall,Arg,TPasElement(Templates[i]),false);
|
||||
ForEachChildCall(aMethodCall,Arg,ProcType,false);
|
||||
ForEachChildCall(aMethodCall,Arg,PublicName,false);
|
||||
ForEachChildCall(aMethodCall,Arg,LibraryExpr,false);
|
||||
@ -4743,17 +4750,18 @@ begin
|
||||
Result:=ptProcedure;
|
||||
end;
|
||||
|
||||
procedure TPasProcedure.SetNameParts(var Parts: TProcedureNameParts);
|
||||
procedure TPasProcedure.SetNameParts(Parts: TProcedureNameParts);
|
||||
var
|
||||
i, j: Integer;
|
||||
El: TPasElement;
|
||||
begin
|
||||
if length(NameParts)>0 then
|
||||
if NameParts<>nil then
|
||||
ReleaseProcNameParts(NameParts);
|
||||
NameParts:=Parts;
|
||||
Parts:=nil;
|
||||
for i:=0 to length(NameParts)-1 do
|
||||
with NameParts[i] do
|
||||
NameParts:=TFPList.Create;
|
||||
NameParts.Assign(Parts);
|
||||
Parts.Clear;
|
||||
for i:=0 to NameParts.Count-1 do
|
||||
with TProcedureNamePart(NameParts[i]) do
|
||||
if Templates<>nil then
|
||||
for j:=0 to Templates.Count-1 do
|
||||
begin
|
||||
@ -4773,14 +4781,14 @@ begin
|
||||
If Full then
|
||||
begin
|
||||
T:=TypeName;
|
||||
if length(NameParts)>0 then
|
||||
if NameParts<>nil then
|
||||
begin
|
||||
T:=T+' ';
|
||||
for i:=0 to length(NameParts)-1 do
|
||||
for i:=0 to NameParts.Count-1 do
|
||||
begin
|
||||
if i>0 then
|
||||
T:=T+'.';
|
||||
with NameParts[i] do
|
||||
with TProcedureNamePart(NameParts[i]) do
|
||||
begin
|
||||
T:=T+Name;
|
||||
if Templates<>nil then
|
||||
|
@ -169,7 +169,6 @@ type
|
||||
stTypeSection,
|
||||
stTypeDef, // e.g. a TPasType
|
||||
stResourceString, // e.g. TPasResString
|
||||
stGenericTypeTemplates, // called after TPasGenericType.SetGenericTemplates or TPasProcedure.setNameParts
|
||||
stProcedure, // also method, procedure, constructor, destructor, ...
|
||||
stProcedureHeader,
|
||||
stWithExpr, // calls BeginScope after parsing every WITH-expression
|
||||
@ -4306,8 +4305,12 @@ function TPasParser.ParseGenericTypeDecl(Parent: TPasElement;
|
||||
{$IFDEF CheckPasTreeRefCount}NewEl.ChangeRefId('CreateElement','TPasMembersType.Members');{$ENDIF}
|
||||
end;
|
||||
end;
|
||||
NewEl.SetGenericTemplates(GenericTemplateTypes);
|
||||
Engine.FinishScope(stGenericTypeTemplates,NewEl);
|
||||
if GenericTemplateTypes.Count>0 then
|
||||
begin
|
||||
// Note: TPasResolver sets GenericTemplateTypes already in CreateElement
|
||||
// This is for other tools like fpdoc.
|
||||
NewEl.SetGenericTemplates(GenericTemplateTypes);
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
@ -4392,13 +4395,14 @@ begin
|
||||
begin
|
||||
if CurToken=tkFunction then
|
||||
begin
|
||||
ProcTypeEl := CreateFunctionType(TypeName, 'Result', Parent, False, NamePos, TypeParams);
|
||||
ProcTypeEl := CreateFunctionType(TypeName, 'Result', Parent, False,
|
||||
NamePos, TypeParams);
|
||||
ProcType:=ptFunction;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ProcTypeEl := TPasProcedureType(CreateElement(TPasProcedureType,
|
||||
TypeName, Parent, visDefault, NamePos, TypeParams));
|
||||
TypeName, Parent, visDefault, NamePos, TypeParams));
|
||||
ProcType:=ptProcedure;
|
||||
end;
|
||||
if AddToParent and (Parent is TPasDeclarations) then
|
||||
@ -6366,6 +6370,7 @@ var
|
||||
L : TFPList;
|
||||
I , Cnt, p: Integer;
|
||||
CurName: String;
|
||||
Part: TProcedureNamePart;
|
||||
begin
|
||||
Result:=ExpectIdentifier;
|
||||
Cnt:=1;
|
||||
@ -6373,51 +6378,54 @@ var
|
||||
NextToken;
|
||||
if CurToken=tkDot then
|
||||
begin
|
||||
if Parent is TImplementationSection then
|
||||
if Parent is TImplementationSection then
|
||||
begin
|
||||
inc(Cnt);
|
||||
CurName:=ExpectIdentifier;
|
||||
Result:=Result+'.'+CurName;
|
||||
if NameParts<>nil then
|
||||
begin
|
||||
inc(Cnt);
|
||||
CurName:=ExpectIdentifier;
|
||||
Result:=Result+'.'+CurName;
|
||||
if length(NameParts)>0 then
|
||||
begin
|
||||
SetLength(NameParts,Cnt);
|
||||
NameParts[Cnt-1].Name:=CurName;
|
||||
end;
|
||||
end
|
||||
else
|
||||
ParseExcSyntaxError;
|
||||
Part:=TProcedureNamePart.Create;
|
||||
NameParts.Add(Part);
|
||||
Part.Name:=CurName;
|
||||
end;
|
||||
end
|
||||
else
|
||||
ParseExcSyntaxError;
|
||||
end
|
||||
else if CurToken=tkLessThan then
|
||||
begin
|
||||
if (not MustBeGeneric) and not (msDelphi in CurrentModeswitches) then
|
||||
ParseExc(nParserGenericFunctionNeedsGenericKeyword,SParserGenericFunctionNeedsGenericKeyword);
|
||||
// generic templates
|
||||
if length(NameParts)=0 then
|
||||
if NameParts=nil then
|
||||
begin
|
||||
// initialize NameParts
|
||||
SetLength(NameParts,Cnt);
|
||||
NameParts:=TProcedureNameParts.Create;
|
||||
i:=0;
|
||||
CurName:=Result;
|
||||
repeat
|
||||
Part:=TProcedureNamePart.Create;
|
||||
NameParts.Add(Part);
|
||||
p:=Pos('.',CurName);
|
||||
if p>0 then
|
||||
begin
|
||||
NameParts[i].Name:=LeftStr(CurName,p-1);
|
||||
Part.Name:=LeftStr(CurName,p-1);
|
||||
System.Delete(CurName,1,p);
|
||||
end
|
||||
else
|
||||
begin
|
||||
NameParts[i].Name:=CurName;
|
||||
Part.Name:=CurName;
|
||||
break;
|
||||
end;
|
||||
inc(i);
|
||||
until false;
|
||||
end
|
||||
else if NameParts[Cnt-1].Templates<>nil then
|
||||
else if TProcedureNamePart(NameParts[Cnt-1]).Templates<>nil then
|
||||
ParseExcSyntaxError;
|
||||
UnGetToken;
|
||||
L:=TFPList.Create;
|
||||
NameParts[Cnt-1].Templates:=L;
|
||||
TProcedureNamePart(NameParts[Cnt-1]).Templates:=L;
|
||||
ReadGenericArguments(L,Parent);
|
||||
end
|
||||
else
|
||||
@ -6431,6 +6439,7 @@ var
|
||||
PC : TPTreeElement;
|
||||
Ot : TOperatorType;
|
||||
IsTokenBased , ok: Boolean;
|
||||
j, i: Integer;
|
||||
begin
|
||||
NameParts:=nil;
|
||||
Result:=nil;
|
||||
@ -6463,13 +6472,24 @@ begin
|
||||
PC:=GetProcedureClass(ProcType);
|
||||
if Name<>'' then
|
||||
Parent:=CheckIfOverLoaded(Parent,Name);
|
||||
Result:=TPasProcedure(CreateElement(PC,Name,Parent,AVisibility));
|
||||
//TPasProcedure(CreateElement(PC,Name,Parent,AVisibility));
|
||||
Result := TPasProcedure(Engine.CreateElement(PC, Name, Parent, AVisibility,
|
||||
CurSourcePos, NameParts));
|
||||
if NameParts<>nil then
|
||||
begin
|
||||
Result.SetNameParts(NameParts);
|
||||
Engine.FinishScope(stGenericTypeTemplates,Result);
|
||||
if Result.NameParts=nil then
|
||||
// CreateElement has not used the NameParts -> do it now
|
||||
Result.SetNameParts(NameParts);
|
||||
// sanity check
|
||||
for i:=0 to Result.NameParts.Count-1 do
|
||||
with TProcedureNamePart(Result.NameParts[i]) do
|
||||
if Templates<>nil then
|
||||
for j:=0 to Templates.Count-1 do
|
||||
if TPasElement(Templates[j]).Parent<>Result then
|
||||
ParseExc(nParserError,SParserError+'[20190818131750] '+TPasElement(Templates[j]).Parent.Name+':'+TPasElement(Templates[j]).Parent.ClassName);
|
||||
if NameParts.Count>0 then
|
||||
ParseExc(nParserError,SParserError+'[20190818131909] "'+Name+'"');
|
||||
end;
|
||||
|
||||
case ProcType of
|
||||
ptFunction, ptClassFunction, ptOperator, ptClassOperator, ptAnonymousFunction:
|
||||
begin
|
||||
@ -6506,7 +6526,7 @@ begin
|
||||
end;
|
||||
ok:=true;
|
||||
finally
|
||||
if NameParts<>nil then;
|
||||
if NameParts<>nil then
|
||||
ReleaseProcNameParts(NameParts);
|
||||
if (not ok) and (Result<>nil) then
|
||||
Result.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
|
||||
|
@ -19,6 +19,7 @@ type
|
||||
procedure TestGen_GenTypeWithWrongParamCountFail;
|
||||
procedure TestGen_GenericNotFoundFail;
|
||||
procedure TestGen_SameNameSameParamCountFail;
|
||||
procedure TestGen_TypeAliasWithoutSpecializeFail;
|
||||
|
||||
// constraints
|
||||
procedure TestGen_ConstraintStringFail;
|
||||
@ -53,13 +54,18 @@ type
|
||||
procedure TestGen_ClassForwardConstraintKeywordMismatch;
|
||||
procedure TestGen_ClassForwardConstraintTypeMismatch;
|
||||
procedure TestGen_ClassForward_Circle;
|
||||
procedure TestGen_Class_RedeclareInUnitImplFail;
|
||||
// ToDo: add another in unit implementation
|
||||
procedure TestGen_Class_Method;
|
||||
// ToDo: procedure TestGen_Class_MethodOverride;
|
||||
procedure TestGen_Class_MethodDelphi;
|
||||
// ToDo: procedure TestGen_Class_MethodDelphiTypeParamMissing;
|
||||
// ToDo: procedure TestGen_Class_MethodImplConstraintFail;
|
||||
procedure TestGen_Class_SpecializeSelfInside;
|
||||
// ToDo: generic class overload <T> <S,T>
|
||||
procedure TestGen_Class_GenAncestor;
|
||||
procedure TestGen_Class_AncestorSelfFail;
|
||||
// ToDo: class-of
|
||||
// ToDo: class of TBird<word> fail
|
||||
// ToDo: UnitA.impl uses UnitB.intf uses UnitA.intf, UnitB has specialize of UnitA
|
||||
procedure TestGen_Class_NestedType;
|
||||
procedure TestGen_Class_NestedRecord;
|
||||
@ -81,12 +87,14 @@ type
|
||||
procedure TestGen_ProcType;
|
||||
|
||||
// ToDo: pointer of generic
|
||||
// ToDo: PBird = ^TBird<word> fail
|
||||
|
||||
// ToDo: helpers for generics
|
||||
|
||||
// generic functions
|
||||
// ToDo: generic class method overload <T> <S,T>
|
||||
procedure TestGen_GenericFunction; // ToDo
|
||||
// ToDo: generic class method overload <T> <S,T>
|
||||
// ToDo: procedure TestGen_GenMethod_ClassConstructorFail;
|
||||
|
||||
// generic statements
|
||||
procedure TestGen_LocalVar;
|
||||
@ -166,6 +174,20 @@ begin
|
||||
nDuplicateIdentifier);
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_TypeAliasWithoutSpecializeFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$mode delphi}',
|
||||
'type',
|
||||
' TBird<T> = record w: T; end;',
|
||||
' TBirdAlias = TBird;',
|
||||
'begin',
|
||||
'']);
|
||||
CheckResolverException('type expected, but TBird<> found',
|
||||
nXExpectedButYFound);
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_ConstraintStringFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -381,7 +403,7 @@ begin
|
||||
' end;',
|
||||
'begin',
|
||||
'']);
|
||||
CheckResolverException('type "TBird" is not yet completely defined',
|
||||
CheckResolverException('type "TBird<>" is not yet completely defined',
|
||||
nTypeXIsNotYetCompletelyDefined);
|
||||
end;
|
||||
|
||||
@ -595,6 +617,21 @@ begin
|
||||
ParseProgram;
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_Class_RedeclareInUnitImplFail;
|
||||
begin
|
||||
StartUnit(false);
|
||||
Add([
|
||||
'interface',
|
||||
'type',
|
||||
' TObject = class end;',
|
||||
' generic TBird<T> = class v: T; end;',
|
||||
'implementation',
|
||||
'type generic TBird<T> = record v: T; end;',
|
||||
'']);
|
||||
CheckResolverException('Duplicate identifier "TBird" at afile.pp(5,16)',
|
||||
nDuplicateIdentifier);
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_Class_Method;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -620,6 +657,31 @@ begin
|
||||
ParseProgram;
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_Class_MethodDelphi;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$mode delphi}',
|
||||
'type',
|
||||
' TObject = class end;',
|
||||
' {#Typ}T = word;',
|
||||
' TBird<{#Templ}T> = class',
|
||||
' function Fly(p:T): T; virtual; abstract;',
|
||||
' function Run(p:T): T;',
|
||||
' end;',
|
||||
'function TBird<T>.Run(p:T): T;',
|
||||
'begin',
|
||||
'end;',
|
||||
'var',
|
||||
' b: TBird<word>;',
|
||||
' {=Typ}w: T;',
|
||||
'begin',
|
||||
' w:=b.Fly(w);',
|
||||
' w:=b.Run(w);',
|
||||
'']);
|
||||
ParseProgram;
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_Class_SpecializeSelfInside;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -676,7 +738,7 @@ begin
|
||||
' b: specialize TBird<word>;',
|
||||
'begin',
|
||||
'']);
|
||||
CheckResolverException('type "TBird" is not yet completely defined',nTypeXIsNotYetCompletelyDefined);
|
||||
CheckResolverException('type "TBird<>" is not yet completely defined',nTypeXIsNotYetCompletelyDefined);
|
||||
end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_Class_NestedType;
|
||||
@ -960,6 +1022,7 @@ end;
|
||||
|
||||
procedure TTestResolveGenerics.TestGen_GenericFunction;
|
||||
begin
|
||||
exit;
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'generic function DoIt<T>(a: T): T;',
|
||||
|
@ -9149,7 +9149,7 @@ begin
|
||||
Add('begin');
|
||||
Add('end;');
|
||||
Add('begin');
|
||||
CheckResolverException('identifier not found "TClassA"',nIdentifierNotFound);
|
||||
CheckResolverException('class "TClassA" not found in this module',nClassXNotFoundInThisModule);
|
||||
end;
|
||||
|
||||
procedure TTestResolver.TestClass_MethodInOtherUnitFail;
|
||||
@ -9170,7 +9170,8 @@ begin
|
||||
'begin',
|
||||
'end;',
|
||||
'begin']);
|
||||
CheckResolverException('method class "TObject" in other unit "unit1"',nMethodClassXInOtherUnitY);
|
||||
CheckResolverException('class "TObject" not found in this module',
|
||||
nClassXNotFoundInThisModule);
|
||||
end;
|
||||
|
||||
procedure TTestResolver.TestClass_MethodWithParams;
|
||||
|
@ -3762,14 +3762,14 @@ var
|
||||
NameParts: TProcedureNameParts;
|
||||
begin
|
||||
NameParts:=El.NameParts;
|
||||
if length(NameParts)=0 then exit;
|
||||
if (NameParts=nil) or (NameParts.Count=0) then exit;
|
||||
Arr:=TJSONArray.Create;
|
||||
Obj.Add('NameParts',Arr);
|
||||
for i:=0 to length(NameParts)-1 do
|
||||
for i:=0 to NameParts.Count-1 do
|
||||
begin
|
||||
NamePartObj:=TJSONObject.Create;
|
||||
Arr.Add(NamePartObj);
|
||||
with NameParts[i] do
|
||||
with TProcedureNamePart(NameParts[i]) do
|
||||
begin
|
||||
NamePartObj.Add('Name',Name);
|
||||
if Templates<>nil then
|
||||
@ -7484,15 +7484,21 @@ var
|
||||
NamePartObj, TemplObj: TJSONObject;
|
||||
GenTypeName: string;
|
||||
GenType: TPasGenericTemplateType;
|
||||
NamePart: TProcedureNamePart;
|
||||
begin
|
||||
ReleaseProcNameParts(El.NameParts);
|
||||
if ReadArray(Obj,'NameParts',Arr,El) then
|
||||
begin
|
||||
SetLength(El.NameParts,Arr.Count);
|
||||
if El.NameParts=nil then
|
||||
El.NameParts:=TProcedureNameParts.Create
|
||||
else
|
||||
El.NameParts.Clear;
|
||||
for i:=0 to Arr.Count-1 do
|
||||
begin
|
||||
NamePartObj:=CheckJSONObject(Arr[i],20190718113441);
|
||||
with El.NameParts[i] do
|
||||
NamePart:=TProcedureNamePart.Create;
|
||||
El.NameParts.Add(NamePart);
|
||||
with NamePart do
|
||||
begin
|
||||
if not ReadString(NamePartObj,'Name',Name,El) then
|
||||
RaiseMsg(20190718113739,El,IntToStr(i));
|
||||
|
@ -1549,16 +1549,20 @@ var
|
||||
begin
|
||||
OrigNameParts:=Orig.NameParts;
|
||||
RestNameParts:=Rest.NameParts;
|
||||
AssertEquals(Path+'.NameParts length',length(OrigNameParts),length(RestNameParts));
|
||||
for i:=0 to length(OrigNameParts)-1 do
|
||||
AssertEquals(Path+'.NameParts<>nil',OrigNameParts<>nil,RestNameParts<>nil);
|
||||
if OrigNameParts<>nil then
|
||||
begin
|
||||
SubPath:=Path+'.NameParts['+IntToStr(i)+']';
|
||||
AssertEquals(SubPath+'.Name',OrigNameParts[i].Name,RestNameParts[i].Name);
|
||||
OrigTemplates:=OrigNameParts[i].Templates;
|
||||
RestTemplates:=RestNameParts[i].Templates;
|
||||
CheckRestoredObject(SubPath+'.Templates',OrigTemplates,RestTemplates);
|
||||
if OrigTemplates=nil then continue;
|
||||
CheckRestoredElementList(SubPath+'.Templates',OrigTemplates,RestTemplates);
|
||||
AssertEquals(Path+'.NameParts.Count',OrigNameParts.Count,RestNameParts.Count);
|
||||
for i:=0 to OrigNameParts.Count-1 do
|
||||
begin
|
||||
SubPath:=Path+'.NameParts['+IntToStr(i)+']';
|
||||
AssertEquals(SubPath+'.Name',TProcedureNamePart(OrigNameParts[i]).Name,TProcedureNamePart(RestNameParts[i]).Name);
|
||||
OrigTemplates:=TProcedureNamePart(OrigNameParts[i]).Templates;
|
||||
RestTemplates:=TProcedureNamePart(RestNameParts[i]).Templates;
|
||||
CheckRestoredObject(SubPath+'.Templates',OrigTemplates,RestTemplates);
|
||||
if OrigTemplates=nil then continue;
|
||||
CheckRestoredElementList(SubPath+'.Templates',OrigTemplates,RestTemplates);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user