fcl-passrc: specialize generic array

git-svn-id: trunk@42669 -
This commit is contained in:
Mattias Gaertner 2019-08-12 23:20:35 +00:00
parent f23f3a4c5e
commit 3c9732cd3b
3 changed files with 221 additions and 54 deletions

View File

@ -688,6 +688,7 @@ type
FirstSpecialize: TPasElement;
Params: TPasTypeArray;
ImplProcs: TFPList;
HeaderScope: TObject;
destructor Destroy; override;
property SpecializedType: TPasGenericType read FSpecializedType write SetSpecializedType;
end;
@ -941,10 +942,16 @@ type
SpecializedTypes: TObjectList; // list of TPSSpecializedItem
GenericStep: TPSGenericStep;
// for specialized type:
SpecializedFrom: TPasGenericType;
SpecializedItem: TPSSpecializedItem;
destructor Destroy; override;
end;
{ TPasArrayScope }
TPasArrayScope = Class(TPasGenericScope)
public
end;
{ TPasClassOrRecordScope }
TPasClassOrRecordScope = Class(TPasGenericScope)
@ -959,7 +966,9 @@ type
TPasRecordScope = Class(TPasClassOrRecordScope)
end;
{ TPasClassHeaderScope - scope for resolving templates during parsing ancestor+interfaces }
{ TPasClassHeaderScope -
scope for resolving templates during parsing ancestor+interfaces.
Note that "Element" is the first TPasGenericTemplateType. }
TPasClassHeaderScope = class(TPasIdentifierScope)
public
@ -1523,7 +1532,8 @@ type
procedure AddSection(El: TPasSection); virtual;
procedure AddInitialFinalizationSection(El: TPasImplBlock); virtual;
procedure AddType(El: TPasType); virtual;
procedure AddRecordType(El: TPasRecordType); virtual;
procedure AddArrayType(El: TPasArrayType; TypeParams: TFPList); virtual;
procedure AddRecordType(El: TPasRecordType; TypeParams: TFPList); virtual;
procedure AddClassType(El: TPasClassType; TypeParams: TFPList); virtual;
procedure AddVariable(El: TPasVariable); virtual;
procedure AddResourceString(El: TPasResString); virtual;
@ -1773,7 +1783,7 @@ type
procedure SpecializeAliasType(GenEl, SpecEl: TPasAliasType);
procedure SpecializePointerType(GenEl, SpecEl: TPasPointerType);
procedure SpecializeRangeType(GenEl, SpecEl: TPasRangeType);
procedure SpecializeArrayType(GenEl, SpecEl: TPasArrayType);
procedure SpecializeArrayType(GenEl, SpecEl: TPasArrayType; SpecializedItem: TPSSpecializedItem);
procedure SpecializeEnumValue(GenEl, SpecEl: TPasEnumValue);
procedure SpecializeEnumType(GenEl, SpecEl: TPasEnumType);
procedure SpecializeSetType(GenEl, SpecEl: TPasSetType);
@ -2975,6 +2985,8 @@ begin
ImplProcs:=nil;
end;
SpecializedType:=nil;
HeaderScope.Free;
HeaderScope:=nil;
inherited Destroy;
end;
@ -6051,6 +6063,7 @@ var
RangeResolved: TPasResolverResult;
TypeEl: TPasType;
Parent: TPasArrayType;
Scope: TPasArrayScope;
begin
// check cycles
Parent:=El;
@ -6111,16 +6124,28 @@ begin
CheckUseAsType(El.ElType,20190123095401,El);
FinishSubElementType(El,El.ElType);
end;
if El.CustomData is TPasArrayScope then
begin
Scope:=TPasArrayScope(El.CustomData);
Scope.GenericStep:=psgsImplementationParsed;
end;
if TopScope.Element=El then
PopScope;
end;
procedure TPasResolver.FinishGenericTemplateTypes(aType: TPasGenericType);
var
C: TClass;
Scope: TPasIdentifierScope;
GenTemplates: TFPList;
TemplType: TPasGenericTemplateType;
i: Integer;
ClassHeaderScope: TPasClassHeaderScope;
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');
@ -6137,21 +6162,21 @@ begin
// add template names to scope
C:=aType.ClassType;
if C=TPasRecordType then
Scope:=NoNil(aType.CustomData) as TPasRecordScope
else if C=TPasClassType then
begin
// Note: TPasClassType.Forward is not yet set!
// create class header scope
TemplType:=TPasGenericTemplateType(GenTemplates[0]);
Scope:=TPasClassHeaderScope(PushScope(TemplType,TPasClassHeaderScope));
TPasClassHeaderScope(Scope).GenericType:=aType;
ClassHeaderScope:=TPasClassHeaderScope(PushScope(TemplType,TPasClassHeaderScope));
ClassHeaderScope.GenericType:=aType;
AddGenericTemplateIdentifiers(GenTemplates,ClassHeaderScope);
end
// ToDo: TPasArrayType
// ToDo: TPasProcedureType
else if C=TPasArrayType then
else if (C=TPasProcedureType)
or (C=TPasFunctionType) then
RaiseNotYetImplemented(20190812220555,aType,GetObjName(aType))
else
RaiseNotYetImplemented(20190726150359,aType,GetObjName(aType));
AddGenericTemplateIdentifiers(GenTemplates,Scope);
end;
procedure TPasResolver.FinishGenericTemplateType(El: TPasGenericTemplateType);
@ -7991,8 +8016,8 @@ begin
if TypeParamCnt>0 then
begin
// generic forward needs TPasClassScope to store the specialized
// which will later be transferred to the actual class
// A generic forward needs TPasClassScope to store the specialized types.
// Will later be transferred to the actual class.
CreateScope(aClass,ScopeClass_Class);
end;
exit;
@ -10897,7 +10922,7 @@ begin
exit;
end;
ClassOrRecScope:=aClassOrRec.CustomData as TPasClassOrRecordScope;
if ClassOrRecScope.SpecializedFrom<>nil then
if ClassOrRecScope.SpecializedItem<>nil then
exit;
// finish implementation of (generic) class/record
if ClassOrRecScope.GenericStep<>psgsInterfaceParsed then
@ -11007,9 +11032,31 @@ begin
AddIdentifier(TPasIdentifierScope(TopScope),El.Name,El,pikSimple);
end;
procedure TPasResolver.AddRecordType(El: TPasRecordType);
procedure TPasResolver.AddArrayType(El: TPasArrayType; TypeParams: TFPList);
var
Scope: TPasScope;
Scope: TPasArrayScope;
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.AddArrayType ',GetObjName(El),' Parent=',GetObjName(El.Parent));
{$ENDIF}
if El.Name<>'' then begin
if not (TopScope is TPasIdentifierScope) then
RaiseInvalidScopeForElement(20190812215622,El);
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;
end;
procedure TPasResolver.AddRecordType(El: TPasRecordType; TypeParams: TFPList);
var
Scope: TPasRecordScope;
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.AddRecordType ',GetObjName(El),' Parent=',GetObjName(El.Parent));
@ -11027,8 +11074,15 @@ begin
if El.Parent.ClassType<>TPasVariant then
begin
Scope:=PushScope(El,TPasRecordScope);
Scope:=TPasRecordScope(PushScope(El,TPasRecordScope));
Scope.VisibilityContext:=El;
if TypeParams<>nil then
begin
// generic array
if El.Name='' then
RaiseNotYetImplemented(20190812220821,El);
AddGenericTemplateIdentifiers(TypeParams,Scope);
end;
end;
end;
@ -14539,6 +14593,9 @@ var
begin
Result:=nil;
GenericType:=El.DestType as TPasGenericType;
if Pos('$G',GenericType.Name)>0 then
RaiseNotYetImplemented(20190813003729,El);
SrcModule:=GenericType.GetModule;
SrcModuleScope:=SrcModule.CustomData as TPasModuleScope;
SrcResolver:=SrcModuleScope.Owner as TPasResolver;
@ -14552,7 +14609,7 @@ begin
//writeln('TPasResolver.CreateSpecializedType ',ScopeCount,' FStashScopeCount=',FStashScopeCount);
OldStashCount:=InitSpecializeScopes(GenericType);
{$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.CreateSpecializedType InitSpecializeScopes: ');
WriteScopesShort('TPasResolver.CreateSpecializedType InitSpecializeScopes: El='+El.FullName+' GenType='+GenericType.FullName);
{$ENDIF}
Result:=TPSSpecializedItem.Create;
@ -14582,12 +14639,12 @@ begin
SpecializeGenTypeIntf(GenericType,Result);
{$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.CreateSpecializedType FinishTypeDef:');
WriteScopesShort('TPasResolver.CreateSpecializedType FinishTypeDef: '+El.FullName);
{$ENDIF}
RestoreStashedScopes(OldStashCount);
{$IFDEF VerbosePasResolver}
WriteScopesShort('TPasResolver.CreateSpecializedType RestoreStashedScopes:');
WriteScopesShort('TPasResolver.CreateSpecializedType RestoreStashedScopes: '+El.FullName);
{$ENDIF}
if GenScope.GenericStep>=psgsImplementationParsed then
@ -14601,6 +14658,9 @@ function TPasResolver.InitSpecializeScopes(El: TPasElement): integer;
Keep: Integer;
Scope: TPasScope;
begin
{$IFDEF VerboseInitSpecializeScopes}
writeln(' PushParentScopes START ',GetObjName(CurEl));
{$ENDIF}
if CurEl=nil then
RaiseInternalError(20190728125025);
if CurEl is TPasModule then
@ -14625,6 +14685,9 @@ function TPasResolver.InitSpecializeScopes(El: TPasElement): integer;
end;
inc(Keep);
Scope:=TPasScope(CurEl.CustomData);
{$IFDEF VerboseInitSpecializeScopes}
writeln(' PushParentScopes ',GetObjName(CurEl),' Scope=',GetObjName(Scope),' Keep=',Keep);
{$ENDIF}
if Scope.FreeOnPop then
RaiseInternalError(20190728131153,GetObjName(CurEl));
if (Keep<FScopeCount) and (FScopes[Keep]=Scope) then
@ -14632,16 +14695,41 @@ function TPasResolver.InitSpecializeScopes(El: TPasElement): integer;
else
begin
if Keep<FScopeCount then
begin
// cannot use current scope stack -> stash
{$IFDEF VerboseInitSpecializeScopes}
writeln(' PushParentScopes StashScopes Keep=',Keep);
{$ENDIF}
StashScopes(Keep);
if Keep<>FScopeCount then
RaiseNotYetImplemented(20190813005130,El);
end;
PushScope(Scope);
end;
exit(Keep);
end;
var
Keep: Integer;
begin
{$IFDEF VerboseInitSpecializeScopes}
writeln('TPasResolver.InitSpecializeScopes START ',GetObjName(El));
{$ENDIF}
Result:=FStashScopeCount;
PushParentScopes(El.Parent);
Keep:=PushParentScopes(El.Parent)+1;
if Keep<FScopeCount then
begin
// cannot use current scope stack -> stash
{$IFDEF VerboseInitSpecializeScopes}
writeln('TPasResolver.InitSpecializeScopes StashScopes Keep=',Keep);
{$ENDIF}
StashScopes(Keep);
if Keep<>FScopeCount then
RaiseNotYetImplemented(20190813005859,El);
end;
{$IFDEF VerboseInitSpecializeScopes}
WriteScopesShort('TPasResolver.InitSpecializeScopes END');
{$ENDIF}
end;
procedure TPasResolver.SpecializeGenTypeIntf(GenericType: TPasGenericType;
@ -14652,6 +14740,9 @@ var
NewClassType, GenClassType: TPasClassType;
GenScope: TPasGenericScope;
TemplType: TPasGenericTemplateType;
C: TClass;
NewArrayType, GenArrayType: TPasArrayType;
NewRecordType, GenRecordType: TPasRecordType;
HeaderScope: TPasClassHeaderScope;
begin
if SpecializedItem.Step<>psssNone then
@ -14664,22 +14755,30 @@ begin
// create GenScope of specialized type
GenScope:=nil;
if SpecType.ClassType=TPasRecordType then
C:=SpecType.ClassType;
if C=TPasRecordType then
begin
TPasRecordType(SpecType).PackMode:=TPasRecordType(GenericType).PackMode;
GenScope:=TPasGenericScope(PushScope(SpecType,TPasRecordScope));
GenScope.VisibilityContext:=SpecType;
NewRecordType:=TPasRecordType(SpecType);
GenRecordType:=TPasRecordType(GenericType);
NewRecordType.PackMode:=GenRecordType.PackMode;
GenScope:=TPasGenericScope(PushScope(NewRecordType,TPasRecordScope));
GenScope.SpecializedItem:=SpecializedItem;
GenScope.VisibilityContext:=NewRecordType;
AddSpecializedTemplateIdentifiers(GenericTemplateTypes,
SpecializedItem.Params,GenScope);
// specialize sub elements
SpecializeMembers(GenRecordType,NewRecordType);
SpecializedItem.Step:=psssInterfaceFinished;
FinishRecordType(NewRecordType);
end
else if SpecType.ClassType=TPasClassType then
else if C=TPasClassType then
begin
NewClassType:=TPasClassType(SpecType);
GenClassType:=TPasClassType(GenericType);
NewClassType.ObjKind:=GenClassType.ObjKind;
NewClassType.PackMode:=GenClassType.PackMode;
// todo AncestorType
if GenClassType.HelperForType<>nil then
RaiseNotYetImplemented(20190730182758,GenClassType,'');
// ToDo: IsForward
if GenClassType.IsForward then
RaiseNotYetImplemented(20190730182858,GenClassType);
NewClassType.IsExternal:=GenClassType.IsExternal;
@ -14687,33 +14786,52 @@ begin
if GenClassType.GUIDExpr<>nil then
SpecializeElExpr(GenClassType,NewClassType,GenClassType.GUIDExpr,NewClassType.GUIDExpr);
NewClassType.Modifiers.Assign(GenClassType.Modifiers);
// ToDo NewClassType.Interfaces
NewClassType.ExternalNameSpace:=GenClassType.ExternalNameSpace;
NewClassType.ExternalName:=GenClassType.ExternalName;
NewClassType.InterfaceType:=GenClassType.InterfaceType;
// ancestor+interfaces
// ancestor can be specialized types. For example: = class(TAncestor<T>)
// -> create a scope with the specialized parameters
HeaderScope:=TPasClassHeaderScope.Create;
SpecializedItem.HeaderScope:=HeaderScope;
TemplType:=TPasGenericTemplateType(GenericTemplateTypes[0]);
HeaderScope:=NoNil(TemplType.CustomData) as TPasClassHeaderScope;
HeaderScope.Element:=TemplType;
AddSpecializedTemplateIdentifiers(GenericTemplateTypes,
SpecializedItem.Params,HeaderScope);
PushScope(HeaderScope);
SpecializeElType(GenClassType,NewClassType,
GenClassType.AncestorType,NewClassType.AncestorType);
SpecializeElList(GenClassType,NewClassType,
GenClassType.Interfaces,NewClassType.Interfaces,true
{$IFDEF CheckPasTreeRefCount},'TPasClassType.Interfaces'{$ENDIF});
if TopScope<>HeaderScope then
RaiseNotYetImplemented(20190813003056,GenClassType);
PopScope;
SpecializedItem.HeaderScope:=nil;
HeaderScope.Free;
FinishAncestors(NewClassType);
// Note: class scope is created by FinishAncestors
GenScope:=NoNil(NewClassType.CustomData) as TPasClassScope;
GenScope.SpecializedItem:=SpecializedItem;
AddSpecializedTemplateIdentifiers(GenericTemplateTypes,
SpecializedItem.Params,GenScope);
// specialize sub elements
SpecializeMembers(GenClassType,NewClassType);
SpecializedItem.Step:=psssInterfaceFinished;
FinishClassType(NewClassType);
end
else if C=TPasArrayType then
begin
GenArrayType:=TPasArrayType(GenericType);
NewArrayType:=TPasArrayType(SpecType);
SpecializeArrayType(GenArrayType,NewArrayType,SpecializedItem);
SpecializedItem.Step:=psssImplementationFinished;
end
else
RaiseNotYetImplemented(20190728134933,GenericType);
GenScope.SpecializedFrom:=GenericType;
AddSpecializedTemplateIdentifiers(GenericTemplateTypes,
SpecializedItem.Params,GenScope);
// specialize recursively
if SpecType is TPasMembersType then
SpecializeMembers(TPasMembersType(GenericType),TPasMembersType(SpecType));
SpecializedItem.Step:=psssInterfaceFinished;
FinishTypeDef(SpecType);
end;
procedure TPasResolver.SpecializeGenTypeImpl(GenericType: TPasGenericType;
@ -14785,9 +14903,9 @@ begin
begin
// switch scope (e.g. unit implementation section)
ImplParent:=GenImplProc.Parent;
OldStashCount:=InitSpecializeScopes(ImplParent);
OldStashCount:=InitSpecializeScopes(GenImplProc);
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.SpecializeGenTypeImpl Specialize implprocs: ',GetObjName(SpecType),' ',ScopeCount,' FStashScopeCount=',FStashScopeCount,' TopScope=',GetObjName(TopScope));
writeln('TPasResolver.SpecializeGenTypeImpl Specialize implprocs: SpecType=',GetObjName(SpecType),' ImplParent=',GetObjName(ImplParent),' ScopeCount=',ScopeCount,' FStashScopeCount=',FStashScopeCount,' TopScope=',GetObjName(TopScope));
{$ENDIF}
end
else if ImplParent<>GenImplProc.Parent then
@ -14894,8 +15012,10 @@ begin
end
else if C=TPasArrayType then
begin
AddType(TPasArrayType(SpecEl));
SpecializeArrayType(TPasArrayType(GenEl),TPasArrayType(SpecEl));
if TPasArrayType(GenEl).GenericTemplateTypes<>nil then
RaiseNotYetImplemented(20190812220312,GenEl);
AddArrayType(TPasArrayType(SpecEl),nil);
SpecializeArrayType(TPasArrayType(GenEl),TPasArrayType(SpecEl),nil);
end
else if C=TPasEnumValue then
begin
@ -15076,7 +15196,8 @@ var
NewClass: TPTreeElement;
begin
if GenElType=nil then exit;
if GenElType.Parent<>GenEl then
if (GenElType.Parent<>GenEl)
or (GenElType.ClassType=TPasGenericTemplateType) then
begin
// reference
Ref:=FindElement(GenElType.Name);
@ -15167,6 +15288,8 @@ begin
SpecList.Add(Ref);
continue;
end;
if GenListItem.ClassType=TPasGenericTemplateType then
RaiseNotYetImplemented(20190812233309,GenEl);
NewClass:=TPTreeElement(GenListItem.ClassType);
SpecListItem:=TPasElement(NewClass.Create(GenListItem.Name,SpecEl));
SpecList.Add(SpecListItem);
@ -15665,10 +15788,29 @@ begin
FinishRangeType(SpecEl);
end;
procedure TPasResolver.SpecializeArrayType(GenEl, SpecEl: TPasArrayType);
procedure TPasResolver.SpecializeArrayType(GenEl, SpecEl: TPasArrayType;
SpecializedItem: TPSSpecializedItem);
var
GenScope: TPasGenericScope;
begin
SpecEl.IndexRange:=GenEl.IndexRange;
SpecEl.PackMode:=GenEl.PackMode;
if GenEl.GenericTemplateTypes<>nil then
begin
GenScope:=TPasGenericScope(PushScope(SpecEl,TPasArrayScope));
if SpecializedItem<>nil then
begin
// specialized generic array
GenScope.SpecializedItem:=SpecializedItem;
AddSpecializedTemplateIdentifiers(GenEl.GenericTemplateTypes,
SpecializedItem.Params,GenScope);
end
else
begin
// generic arraytype inside a generic type
RaiseNotYetImplemented(20190812225218,GenEl);
end;
end;
SpecializeExprArray(GenEl,SpecEl,GenEl.Ranges,SpecEl.Ranges);
SpecializeElType(GenEl,SpecEl,GenEl.ElType,SpecEl.ElType);
FinishArrayType(SpecEl);
@ -17925,8 +18067,9 @@ begin
or (AClass=TPasRangeType)
or (AClass=TPasSpecializeType) then
AddType(TPasType(El))
else if (AClass=TPasArrayType)
or (AClass=TPasProcedureType)
else if AClass=TPasArrayType then
AddArrayType(TPasArrayType(El),TypeParams)
else if (AClass=TPasProcedureType)
or (AClass=TPasFunctionType) then
AddType(TPasType(El)) // ToDo: TypeParams
else if AClass=TPasGenericTemplateType then
@ -17941,7 +18084,7 @@ begin
RaiseMsg(20170419203043,nIllegalQualifier,sIllegalQualifier,['['],El);
end
else if AClass=TPasRecordType then
AddRecordType(TPasRecordType(El)) // ToDo: TypeParams
AddRecordType(TPasRecordType(El),TypeParams)
else if AClass=TPasClassType then
AddClassType(TPasClassType(El),TypeParams)
else if AClass=TPasVariant then

View File

@ -65,7 +65,8 @@ type
// ToDo: generic interface
// ToDo: generic array
// generic array
procedure TestGen_Array;
// ToDo: generic procedure type
@ -480,6 +481,7 @@ begin
'var',
' e: specialize TEagle<word>;',
'begin',
' e.i:=e.j;',
'']);
ParseProgram;
end;
@ -591,6 +593,27 @@ begin
ParseProgram;
end;
procedure TTestResolveGenerics.TestGen_Array;
begin
StartProgram(false);
Add([
'type',
' generic TArray<T> = array of T;',
' TWordArray = specialize TArray<word>;',
'var',
' a: specialize TArray<word>;',
' b: TWordArray;',
' w: word;',
'begin',
' a[1]:=2;',
' b[2]:=a[3]+b[4];',
' a:=b;',
' SetLength(a,5);',
' SetLength(b,6);',
'']);
ParseProgram;
end;
procedure TTestResolveGenerics.TestGen_GenericFunction;
begin
StartProgram(false);

View File

@ -1339,7 +1339,7 @@ type
procedure ClearOverloadScopes;
protected
procedure AddType(El: TPasType); override;
procedure AddRecordType(El: TPasRecordType); override;
procedure AddRecordType(El: TPasRecordType; TypeParams: TFPList); override;
procedure AddClassType(El: TPasClassType; TypeParams: TFPList); override;
procedure AddEnumType(El: TPasEnumType); override;
procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
@ -3229,7 +3229,8 @@ begin
AddElevatedLocal(El);
end;
procedure TPas2JSResolver.AddRecordType(El: TPasRecordType);
procedure TPas2JSResolver.AddRecordType(El: TPasRecordType; TypeParams: TFPList
);
begin
inherited;
if (El.Name='') and (El.Parent.ClassType<>TPasVariant) then