fcl-passrc: generics: allow both a<t> and a<s,t>

git-svn-id: trunk@42735 -
This commit is contained in:
Mattias Gaertner 2019-08-19 08:22:22 +00:00
parent 652e1985a9
commit c3b1450c4b
8 changed files with 558 additions and 219 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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};

View File

@ -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;',

View File

@ -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;

View File

@ -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));

View File

@ -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;