fcl-passrc: TPasClassType and TPasRecordType now have common ancestor, resolver: started advancedrecord methods

git-svn-id: trunk@40591 -
This commit is contained in:
Mattias Gaertner 2018-12-18 22:19:43 +00:00
parent 883f832263
commit 0043b747c7
8 changed files with 392 additions and 216 deletions

View File

@ -134,7 +134,7 @@ const
nFoundCallCandidateX = 3057; nFoundCallCandidateX = 3057;
nTextAfterFinalIgnored = 3058; nTextAfterFinalIgnored = 3058;
nNoMemberIsProvidedToAccessProperty = 3059; nNoMemberIsProvidedToAccessProperty = 3059;
// free 3060 nTheUseOfXisNotAllowedInARecord = 3060;
// free 3061 // free 3061
// free 3062 // free 3062
// free 3063 // free 3063
@ -251,6 +251,7 @@ resourcestring
sFoundCallCandidateX = 'Found call candidate %s'; sFoundCallCandidateX = 'Found call candidate %s';
sTextAfterFinalIgnored = 'Text after final ''end.''. ignored by compiler'; sTextAfterFinalIgnored = 'Text after final ''end.''. ignored by compiler';
sNoMemberIsProvidedToAccessProperty = 'No member is provided to access property'; sNoMemberIsProvidedToAccessProperty = 'No member is provided to access property';
sTheUseOfXisNotAllowedInARecord = 'The use of "%s" is not allowed in a record';
sSymbolXIsNotPortable = 'Symbol "%s" is not portable'; sSymbolXIsNotPortable = 'Symbol "%s" is not portable';
sSymbolXIsExperimental = 'Symbol "%s" is experimental'; sSymbolXIsExperimental = 'Symbol "%s" is experimental';
sSymbolXIsNotImplemented = 'Symbol "%s" is not implemented'; sSymbolXIsNotImplemented = 'Symbol "%s" is not implemented';

View File

@ -216,14 +216,24 @@ Works:
- pass as arg doit(procedure begin end) - pass as arg doit(procedure begin end)
- modifiers assembler varargs cdecl - modifiers assembler varargs cdecl
- typecast - typecast
- with
- self
- built-in procedure Val(const s: string; var e: enumtype; out Code: integertype); - built-in procedure Val(const s: string; var e: enumtype; out Code: integertype);
ToDo: ToDo:
- anonymous methods: - operator overload
- with - operator enumerator
- self - binaryexpr
- advanced records:
- $modeswitch AdvancedRecords
- sub type
- const
- var
- function/procedure/class function/class procedure
- property, class property
- RTTI
- operator overloading
- Include/Exclude for set of int/char/bool - Include/Exclude for set of int/char/bool
- set of CharRange
- error if property method resolution is not used - error if property method resolution is not used
- $H-hintpos$H+ - $H-hintpos$H+
- $pop, $push - $pop, $push
@ -235,13 +245,12 @@ ToDo:
- proc: check if forward and impl default values match - proc: check if forward and impl default values match
- call array of proc without () - call array of proc without ()
- attributes - attributes
- object
- type helpers - type helpers
- record/class helpers - record/class helpers
- array of const
- generics, nested param lists - generics, nested param lists
- object
- futures - futures
- operator overload
- operator enumerator
- TPasFileType - TPasFileType
- labels - labels
- $zerobasedstrings on|off - $zerobasedstrings on|off
@ -838,9 +847,16 @@ type
destructor Destroy; override; destructor Destroy; override;
end; end;
{ TPasClassOrRecordScope }
TPasClassOrRecordScope = Class(TPasIdentifierScope)
public
DefaultProperty: TPasProperty;
end;
{ TPasRecordScope } { TPasRecordScope }
TPasRecordScope = Class(TPasIdentifierScope) TPasRecordScope = Class(TPasClassOrRecordScope)
end; end;
TPasClassScopeFlag = ( TPasClassScopeFlag = (
@ -863,12 +879,11 @@ type
{ TPasClassScope } { TPasClassScope }
TPasClassScope = Class(TPasIdentifierScope) TPasClassScope = Class(TPasClassOrRecordScope)
public public
AncestorScope: TPasClassScope; AncestorScope: TPasClassScope;
CanonicalClassOf: TPasClassOfType; CanonicalClassOf: TPasClassOfType;
DirectAncestor: TPasType; // TPasClassType or TPasAliasType, see GetPasClassAncestor DirectAncestor: TPasType; // TPasClassType or TPasAliasType, see GetPasClassAncestor
DefaultProperty: TPasProperty;
Flags: TPasClassScopeFlags; Flags: TPasClassScopeFlags;
AbstractProcs: TArrayOfPasProcedure; AbstractProcs: TArrayOfPasProcedure;
Interfaces: TFPList; // list corresponds to TPasClassType(Element).Interfaces, Interfaces: TFPList; // list corresponds to TPasClassType(Element).Interfaces,
@ -894,7 +909,7 @@ type
DeclarationProc: TPasProcedure; // the corresponding forward declaration DeclarationProc: TPasProcedure; // the corresponding forward declaration
ImplProc: TPasProcedure; // the corresponding proc with Body ImplProc: TPasProcedure; // the corresponding proc with Body
OverriddenProc: TPasProcedure; // if IsOverride then this is the ancestor proc (virtual or override) OverriddenProc: TPasProcedure; // if IsOverride then this is the ancestor proc (virtual or override)
ClassScope: TPasClassScope; ClassScope: TPasClassOrRecordScope;
SelfArg: TPasArgument; SelfArg: TPasArgument;
Flags: TPasProcedureScopeFlags; Flags: TPasProcedureScopeFlags;
BoolSwitches: TBoolSwitches; // if Body<>nil then body start, otherwise when FinishProc BoolSwitches: TBoolSwitches; // if Body<>nil then body start, otherwise when FinishProc
@ -1424,7 +1439,7 @@ type
procedure FinishWithDo(El: TPasImplWithDo); virtual; procedure FinishWithDo(El: TPasImplWithDo); virtual;
procedure FinishDeclaration(El: TPasElement); virtual; procedure FinishDeclaration(El: TPasElement); virtual;
procedure FinishVariable(El: TPasVariable); virtual; procedure FinishVariable(El: TPasVariable); virtual;
procedure FinishPropertyOfClass(PropEl: TPasProperty); virtual; procedure FinishProperty(PropEl: TPasProperty); virtual;
procedure FinishArgument(El: TPasArgument); virtual; procedure FinishArgument(El: TPasArgument); virtual;
procedure FinishAncestors(aClass: TPasClassType); virtual; procedure FinishAncestors(aClass: TPasClassType); virtual;
procedure FinishMethodResolution(El: TPasMethodResolution); virtual; procedure FinishMethodResolution(El: TPasMethodResolution); virtual;
@ -4298,7 +4313,7 @@ begin
else else
begin begin
// give a hint // give a hint
if Data^.Proc.Parent is TPasClassType then if Data^.Proc.Parent is TPasMembersType then
LogMsg(20171118205344,mtHint,nFunctionHidesIdentifier_NonProc,sFunctionHidesIdentifier, LogMsg(20171118205344,mtHint,nFunctionHidesIdentifier_NonProc,sFunctionHidesIdentifier,
[GetElementSourcePosStr(El)],Data^.Proc.ProcType); [GetElementSourcePosStr(El)],Data^.Proc.ProcType);
end; end;
@ -4397,7 +4412,7 @@ begin
begin begin
// Delphi/FPC do not give a message when hiding a non virtual method // Delphi/FPC do not give a message when hiding a non virtual method
// -> emit Hint with other message id // -> emit Hint with other message id
if (Data^.Proc.Parent is TPasClassType) then if (Data^.Proc.Parent is TPasMembersType) then
begin begin
ProcScope:=Proc.CustomData as TPasProcedureScope; ProcScope:=Proc.CustomData as TPasProcedureScope;
if (ProcScope.ImplProc<>nil) // not abstract, external if (ProcScope.ImplProc<>nil) // not abstract, external
@ -4920,7 +4935,7 @@ begin
else if (C=TPasAliasType) or (C=TPasTypeAliasType) then else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
begin begin
aType:=ResolveAliasType(El); aType:=ResolveAliasType(El);
if (aType is TPasClassType) and (aType.CustomData=nil) then if (aType is TPasMembersType) and (aType.CustomData=nil) then
exit; exit;
EmitTypeHints(El,TPasAliasType(El).DestType); EmitTypeHints(El,TPasAliasType(El).DestType);
end end
@ -5423,6 +5438,22 @@ begin
if (Proc.ClassType<>TPasClassProcedure) and (Proc.ClassType<>TPasClassFunction) then if (Proc.ClassType<>TPasClassProcedure) and (Proc.ClassType<>TPasClassFunction) then
RaiseMsg(20170216151631,nInvalidXModifierY,sInvalidXModifierY,[GetElementTypeName(Proc),'static'],Proc); RaiseMsg(20170216151631,nInvalidXModifierY,sInvalidXModifierY,[GetElementTypeName(Proc),'static'],Proc);
end end
else if Proc.Parent is TPasRecordType then
begin
if Proc.IsReintroduced then
RaiseMsg(20181218195735,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'reintroduce'],Proc);
if Proc.IsVirtual then
RaiseMsg(20181218195431,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'virtual'],Proc);
if Proc.IsOverride then
RaiseMsg(20181218195437,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'override'],Proc);
if Proc.IsAbstract then
RaiseMsg(20181218195552,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'abstract'],Proc);
if Proc.IsForward then
RaiseMsg(20181218195514,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'forward'],Proc);
if Proc.IsStatic then
if (Proc.ClassType<>TPasClassProcedure) and (Proc.ClassType<>TPasClassFunction) then
RaiseMsg(20181218195519,nInvalidXModifierY,sInvalidXModifierY,['record '+GetElementTypeName(Proc),'static'],Proc);
end
else else
begin begin
// intf proc, forward proc, proc body, method body, anonymous proc // intf proc, forward proc, proc body, method body, anonymous proc
@ -5466,7 +5497,7 @@ begin
if Proc.LibrarySymbolName<>nil then if Proc.LibrarySymbolName<>nil then
ResolveExpr(Proc.LibrarySymbolName,rraRead); ResolveExpr(Proc.LibrarySymbolName,rraRead);
if Proc.Parent is TPasClassType then if Proc.Parent is TPasMembersType then
begin begin
FinishMethodDeclHeader(Proc); FinishMethodDeclHeader(Proc);
exit; exit;
@ -5581,7 +5612,7 @@ procedure TPasResolver.FinishMethodDeclHeader(Proc: TPasProcedure);
var var
Abort: boolean; Abort: boolean;
ClassScope: TPasClassScope; ClassOrRecScope: TPasClassOrRecordScope;
FindData: TFindOverloadProcData; FindData: TFindOverloadProcData;
OverloadProc: TPasProcedure; OverloadProc: TPasProcedure;
ProcScope: TPasProcedureScope; ProcScope: TPasProcedureScope;
@ -5591,14 +5622,14 @@ begin
ProcScope:=TopScope as TPasProcedureScope; ProcScope:=TopScope as TPasProcedureScope;
// ToDo: store the scanner flags *before* it has parsed the token after the proc // ToDo: store the scanner flags *before* it has parsed the token after the proc
StoreScannerFlagsInProc(ProcScope); StoreScannerFlagsInProc(ProcScope);
ClassScope:=Scopes[ScopeCount-2] as TPasClassScope; ClassOrRecScope:=Scopes[ScopeCount-2] as TPasClassOrRecordScope;
ProcScope.ClassScope:=ClassScope; ProcScope.ClassScope:=ClassOrRecScope;
FindData:=Default(TFindOverloadProcData); FindData:=Default(TFindOverloadProcData);
FindData.Proc:=Proc; FindData.Proc:=Proc;
FindData.Args:=Proc.ProcType.Args; FindData.Args:=Proc.ProcType.Args;
FindData.Kind:=fopkMethod; FindData.Kind:=fopkMethod;
Abort:=false; Abort:=false;
ClassScope.IterateElements(Proc.Name,ClassScope,@OnFindOverloadProc,@FindData,Abort); ClassOrRecScope.IterateElements(Proc.Name,ClassOrRecScope,@OnFindOverloadProc,@FindData,Abort);
if FindData.Found=nil then if FindData.Found=nil then
begin begin
@ -5643,24 +5674,25 @@ begin
if proFixCaseOfOverrides in Options then if proFixCaseOfOverrides in Options then
Proc.Name:=OverloadProc.Name; Proc.Name:=OverloadProc.Name;
// remove abstract // remove abstract
if OverloadProc.IsAbstract then if OverloadProc.IsAbstract and (ClassOrRecScope is TPasClassScope) then
for i:=length(ClassScope.AbstractProcs)-1 downto 0 do for i:=length(TPasClassScope(ClassOrRecScope).AbstractProcs)-1 downto 0 do
if ClassScope.AbstractProcs[i]=OverloadProc then if TPasClassScope(ClassOrRecScope).AbstractProcs[i]=OverloadProc then
Delete(ClassScope.AbstractProcs,i,1); Delete(TPasClassScope(ClassOrRecScope).AbstractProcs,i,1);
end; end;
end; end;
// add abstract // add abstract
if Proc.IsAbstract then if Proc.IsAbstract and (ClassOrRecScope is TPasClassScope) then
Insert(Proc,ClassScope.AbstractProcs,length(ClassScope.AbstractProcs)); Insert(Proc,TPasClassScope(ClassOrRecScope).AbstractProcs,
length(TPasClassScope(ClassOrRecScope).AbstractProcs));
end; end;
procedure TPasResolver.FinishMethodImplHeader(ImplProc: TPasProcedure); procedure TPasResolver.FinishMethodImplHeader(ImplProc: TPasProcedure);
var var
ProcName: String; ProcName: String;
CurClassType: TPasClassType; ClassRecType: TPasMembersType;
ImplProcScope, DeclProcScope: TPasProcedureScope; ImplProcScope, DeclProcScope: TPasProcedureScope;
DeclProc: TPasProcedure; DeclProc: TPasProcedure;
CurClassScope: TPasClassScope; CurClassRecScope: TPasClassOrRecordScope;
SelfArg: TPasArgument; SelfArg: TPasArgument;
p: Integer; p: Integer;
begin begin
@ -5685,14 +5717,14 @@ begin
if not IsValidIdent(ProcName) then if not IsValidIdent(ProcName) then
RaiseNotYetImplemented(20160922163421,ImplProc.ProcType); RaiseNotYetImplemented(20160922163421,ImplProc.ProcType);
// search proc in class // search proc in class/record
ImplProcScope:=ImplProc.CustomData as TPasProcedureScope; ImplProcScope:=ImplProc.CustomData as TPasProcedureScope;
CurClassScope:=ImplProcScope.ClassScope; CurClassRecScope:=ImplProcScope.ClassScope;
if CurClassScope=nil then if CurClassRecScope=nil then
RaiseInternalError(20161013172346); RaiseInternalError(20161013172346);
CurClassType:=NoNil(CurClassScope.Element) as TPasClassType; ClassRecType:=NoNil(CurClassRecScope.Element) as TPasMembersType;
DeclProc:=FindProcOverload(ProcName,ImplProc,CurClassScope); DeclProc:=FindProcOverload(ProcName,ImplProc,CurClassRecScope);
if DeclProc=nil then if DeclProc=nil then
RaiseIdentifierNotFound(20170216151720,ImplProc.Name,ImplProc.ProcType); RaiseIdentifierNotFound(20170216151720,ImplProc.Name,ImplProc.ProcType);
DeclProcScope:=DeclProc.CustomData as TPasProcedureScope; DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
@ -5721,14 +5753,14 @@ begin
or (DeclProc.ClassType=TPasClassProcedure) or (DeclProc.ClassType=TPasClassProcedure)
or (DeclProc.ClassType=TPasClassFunction) then or (DeclProc.ClassType=TPasClassFunction) then
begin begin
if not DeclProc.IsStatic then if (not DeclProc.IsStatic) and (CurClassRecScope is TPasClassScope) then
begin begin
// 'Self' in a class proc is the hidden classtype argument // 'Self' in a class proc is the hidden classtype argument
SelfArg:=TPasArgument.Create('Self',DeclProc); SelfArg:=TPasArgument.Create('Self',DeclProc);
ImplProcScope.SelfArg:=SelfArg; ImplProcScope.SelfArg:=SelfArg;
{$IFDEF CheckPasTreeRefCount}SelfArg.RefIds.Add('TPasProcedureScope.SelfArg');{$ENDIF} {$IFDEF CheckPasTreeRefCount}SelfArg.RefIds.Add('TPasProcedureScope.SelfArg');{$ENDIF}
SelfArg.Access:=argConst; SelfArg.Access:=argConst;
SelfArg.ArgType:=CurClassScope.CanonicalClassOf; SelfArg.ArgType:=TPasClassScope(CurClassRecScope).CanonicalClassOf;
SelfArg.ArgType.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArgument.ArgType'){$ENDIF}; SelfArg.ArgType.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArgument.ArgType'){$ENDIF};
AddIdentifier(ImplProcScope,'Self',SelfArg,pikSimple); AddIdentifier(ImplProcScope,'Self',SelfArg,pikSimple);
end; end;
@ -5740,8 +5772,8 @@ begin
ImplProcScope.SelfArg:=SelfArg; ImplProcScope.SelfArg:=SelfArg;
{$IFDEF CheckPasTreeRefCount}SelfArg.RefIds.Add('TPasProcedureScope.SelfArg');{$ENDIF} {$IFDEF CheckPasTreeRefCount}SelfArg.RefIds.Add('TPasProcedureScope.SelfArg');{$ENDIF}
SelfArg.Access:=argConst; SelfArg.Access:=argConst;
SelfArg.ArgType:=CurClassType; SelfArg.ArgType:=ClassRecType;
CurClassType.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArgument.ArgType'){$ENDIF}; ClassRecType.AddRef{$IFDEF CheckPasTreeRefCount}('TPasArgument.ArgType'){$ENDIF};
AddIdentifier(ImplProcScope,'Self',SelfArg,pikSimple); AddIdentifier(ImplProcScope,'Self',SelfArg,pikSimple);
end; end;
end; end;
@ -5783,7 +5815,7 @@ begin
if (C=TPasVariable) or (C=TPasConst) then if (C=TPasVariable) or (C=TPasConst) then
FinishVariable(TPasVariable(El)) FinishVariable(TPasVariable(El))
else if C=TPasProperty then else if C=TPasProperty then
FinishPropertyOfClass(TPasProperty(El)) FinishProperty(TPasProperty(El))
else if C=TPasArgument then else if C=TPasArgument then
FinishArgument(TPasArgument(El)) FinishArgument(TPasArgument(El))
else if C=TPasMethodResolution then else if C=TPasMethodResolution then
@ -5812,6 +5844,9 @@ begin
ResolveExpr(El.Expr,rraRead); ResolveExpr(El.Expr,rraRead);
if El.VarType<>nil then if El.VarType<>nil then
begin begin
if (El.Parent is TPasRecordType) and (El.VarType=El.Parent) then
RaiseMsg(20181218173631,nTypeXIsNotYetCompletelyDefined,
sTypeXIsNotYetCompletelyDefined,[El.VarType.Name],El);
if El.Expr<>nil then if El.Expr<>nil then
CheckAssignCompatibility(El,El.Expr,true); CheckAssignCompatibility(El,El.Expr,true);
end end
@ -5855,7 +5890,7 @@ begin
EmitTypeHints(El,El.VarType); EmitTypeHints(El,El.VarType);
end; end;
procedure TPasResolver.FinishPropertyOfClass(PropEl: TPasProperty); procedure TPasResolver.FinishProperty(PropEl: TPasProperty);
var var
PropType: TPasType; PropType: TPasType;
ClassScope: TPasClassScope; ClassScope: TPasClassScope;
@ -6750,7 +6785,7 @@ begin
CreateReference(IntfProc,Expr,rraRead); CreateReference(IntfProc,Expr,rraRead);
if IntfProc.ClassType<>El.ProcClass then if IntfProc.ClassType<>El.ProcClass then
RaiseXExpectedButYFound(20180323144107,GetElementTypeName(El.ProcClass),GetElementTypeName(IntfProc),El.InterfaceProc); RaiseXExpectedButYFound(20180323144107,GetElementTypeName(El.ProcClass),GetElementTypeName(IntfProc),El.InterfaceProc);
// Note: do not create map here. CheckImplements in FinishPropertyOfClass must be called before. // Note: do not create map here. CheckImplements in FinishProperty must be called before.
// El.ImplementationProc is resolved in FinishClassType // El.ImplementationProc is resolved in FinishClassType
end; end;
@ -7863,7 +7898,7 @@ begin
// identifier is a proc and args brackets are missing // identifier is a proc and args brackets are missing
if El.Parent.ClassType=TPasProperty then if El.Parent.ClassType=TPasProperty then
// a property accessor does not need args -> ok // a property accessor does not need args -> ok
// Note: the detailed tests are in FinishPropertyOfClass // Note: the detailed tests are in FinishProperty
else else
begin begin
// examples: funca or @proca or a.funca or @a.funca ... // examples: funca or @proca or a.funca or @a.funca ...
@ -7936,7 +7971,8 @@ procedure TPasResolver.ResolveInherited(El: TInheritedExpr;
Access: TResolvedRefAccess); Access: TResolvedRefAccess);
var var
ProcScope, DeclProcScope, SelfScope: TPasProcedureScope; ProcScope, DeclProcScope, SelfScope: TPasProcedureScope;
AncestorScope, ClassScope: TPasClassScope; AncestorScope: TPasClassScope;
ClassRecScope: TPasClassOrRecordScope;
DeclProc, AncestorProc: TPasProcedure; DeclProc, AncestorProc: TPasProcedure;
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
@ -7955,13 +7991,24 @@ begin
SelfScope:=ProcScope.GetSelfScope; SelfScope:=ProcScope.GetSelfScope;
if SelfScope=nil then if SelfScope=nil then
RaiseMsg(20170216152141,nInheritedOnlyWorksInMethods,sInheritedOnlyWorksInMethods,[],El); RaiseMsg(20170216152141,nInheritedOnlyWorksInMethods,sInheritedOnlyWorksInMethods,[],El);
ClassScope:=SelfScope.ClassScope; ClassRecScope:=SelfScope.ClassScope;
AncestorScope:=ClassScope.AncestorScope; AncestorScope:=nil;
if AncestorScope=nil then if ClassRecScope is TPasClassScope then
begin begin
// 'inherited;' without ancestor class is silently ignored // inherited in class method
exit; AncestorScope:=TPasClassScope(ClassRecScope).AncestorScope;
if AncestorScope=nil then
begin
// 'inherited;' without ancestor class is silently ignored
exit;
end;
end
else
begin
// inherited in record method
RaiseMsg(20181218194022,nTheUseOfXisNotAllowedInARecord,sTheUseOfXisNotAllowedInARecord,
['inherited'],El);
end; end;
// search ancestor in element, i.e. 'inherited' expression // search ancestor in element, i.e. 'inherited' expression
@ -7986,7 +8033,8 @@ procedure TPasResolver.ResolveInheritedCall(El: TBinaryExpr;
// El.right is the identifier and parameters // El.right is the identifier and parameters
var var
ProcScope, SelfScope: TPasProcedureScope; ProcScope, SelfScope: TPasProcedureScope;
AncestorScope, ClassScope: TPasClassScope; AncestorScope: TPasClassScope;
ClassRecScope: TPasClassOrRecordScope;
AncestorClass: TPasClassType; AncestorClass: TPasClassType;
InhScope: TPasDotClassScope; InhScope: TPasDotClassScope;
begin begin
@ -7998,11 +8046,22 @@ begin
SelfScope:=ProcScope.GetSelfScope; SelfScope:=ProcScope.GetSelfScope;
if SelfScope=nil then if SelfScope=nil then
RaiseMsg(20170216152148,nInheritedOnlyWorksInMethods,sInheritedOnlyWorksInMethods,[],El); RaiseMsg(20170216152148,nInheritedOnlyWorksInMethods,sInheritedOnlyWorksInMethods,[],El);
ClassScope:=SelfScope.ClassScope; ClassRecScope:=SelfScope.ClassScope;
AncestorScope:=ClassScope.AncestorScope; AncestorScope:=nil;
if AncestorScope=nil then if ClassRecScope is TPasClassScope then
RaiseMsg(20170216152151,nInheritedNeedsAncestor,sInheritedNeedsAncestor,[],El.left); begin
// inherited in class method
AncestorScope:=TPasClassScope(ClassRecScope).AncestorScope;
if AncestorScope=nil then
RaiseMsg(20170216152151,nInheritedNeedsAncestor,sInheritedNeedsAncestor,[],El.left);
end
else
begin
// inherited in record method
RaiseMsg(20181218194436,nTheUseOfXisNotAllowedInARecord,sTheUseOfXisNotAllowedInARecord,
['inherited'],El);
end;
// search call in ancestor // search call in ancestor
AncestorClass:=TPasClassType(AncestorScope.Element); AncestorClass:=TPasClassType(AncestorScope.Element);
@ -9325,12 +9384,12 @@ procedure TPasResolver.AddProcedure(El: TPasProcedure);
var var
ProcName, aClassName: String; ProcName, aClassName: String;
p: SizeInt; p: SizeInt;
CurClassType: TPasClassType; ClassOrRecType: TPasMembersType;
ProcScope: TPasProcedureScope; ProcScope: TPasProcedureScope;
HasDot: Boolean; HasDot: Boolean;
CurEl: TPasElement; CurEl: TPasElement;
Identifier: TPasIdentifier; Identifier: TPasIdentifier;
CurClassScope: TPasClassScope; ClassOrRecScope: TPasClassOrRecordScope;
C: TClass; C: TClass;
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
@ -9370,12 +9429,12 @@ begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TPasResolver.AddProcedure searching class of "',ProcName,'" ...'); writeln('TPasResolver.AddProcedure searching class of "',ProcName,'" ...');
{$ENDIF} {$ENDIF}
CurClassType:=nil; ClassOrRecType:=nil;
repeat repeat
p:=Pos('.',ProcName); p:=Pos('.',ProcName);
if p<1 then if p<1 then
begin begin
if CurClassType=nil then if ClassOrRecType=nil then
RaiseInternalError(20161013170829); RaiseInternalError(20161013170829);
break; break;
end; end;
@ -9387,10 +9446,10 @@ begin
if not IsValidIdent(aClassName) then if not IsValidIdent(aClassName) then
RaiseNotYetImplemented(20161013170844,El); RaiseNotYetImplemented(20161013170844,El);
if CurClassType<>nil then if ClassOrRecType<>nil then
begin begin
CurClassScope:=TPasClassScope(CurClassType.CustomData); ClassOrRecScope:=TPasClassOrRecordScope(ClassOrRecType.CustomData);
Identifier:=CurClassScope.FindLocalIdentifier(aClassName); Identifier:=ClassOrRecScope.FindLocalIdentifier(aClassName);
if Identifier=nil then if Identifier=nil then
RaiseIdentifierNotFound(20180430130635,aClassName,El); RaiseIdentifierNotFound(20180430130635,aClassName,El);
CurEl:=Identifier.Element; CurEl:=Identifier.Element;
@ -9398,7 +9457,7 @@ begin
else else
CurEl:=FindElementWithoutParams(aClassName,El,false); CurEl:=FindElementWithoutParams(aClassName,El,false);
if not (CurEl is TPasClassType) then if not (CurEl is TPasMembersType) then
begin begin
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1); aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
@ -9407,26 +9466,29 @@ begin
RaiseXExpectedButYFound(20170216152557, RaiseXExpectedButYFound(20170216152557,
'class',aClassname+':'+GetElementTypeName(CurEl),El); 'class',aClassname+':'+GetElementTypeName(CurEl),El);
end; end;
CurClassType:=TPasClassType(CurEl); ClassOrRecType:=TPasMembersType(CurEl);
if CurClassType.ObjKind<>okClass then if ClassOrRecType is TPasClassType then
begin begin
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1); if TPasClassType(ClassOrRecType).ObjKind<>okClass then
RaiseXExpectedButYFound(20180321161722, begin
'class',aClassname+':'+GetElementTypeName(CurEl),El); aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
RaiseXExpectedButYFound(20180321161722,
'class',aClassname+':'+GetElementTypeName(CurEl),El);
end
end; end;
if CurClassType.GetModule<>El.GetModule then if ClassOrRecType.GetModule<>El.GetModule then
begin begin
aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1); aClassName:=LeftStr(El.Name,length(El.Name)-length(ProcName)-1);
RaiseMsg(20180211230432,nMethodClassXInOtherUnitY,sMethodClassXInOtherUnitY, RaiseMsg(20180211230432,nMethodClassXInOtherUnitY,sMethodClassXInOtherUnitY,
[aClassName,CurClassType.GetModule.Name],El); [aClassName,ClassOrRecType.GetModule.Name],El);
end; end;
until false; until false;
if not IsValidIdent(ProcName) then if not IsValidIdent(ProcName) then
RaiseNotYetImplemented(20161013170956,El); RaiseNotYetImplemented(20161013170956,El);
ProcScope.VisibilityContext:=CurClassType; ProcScope.VisibilityContext:=ClassOrRecType;
ProcScope.ClassScope:=NoNil(CurClassType.CustomData) as TPasClassScope; ProcScope.ClassScope:=NoNil(ClassOrRecType.CustomData) as TPasClassOrRecordScope;
end;// HasDot=true end;// HasDot=true
end; end;
@ -14576,8 +14638,9 @@ var
OnlyTypeMembers, IsClassOf: Boolean; OnlyTypeMembers, IsClassOf: Boolean;
TypeEl: TPasType; TypeEl: TPasType;
C: TClass; C: TClass;
ClassScope: TPasClassScope; ClassRecScope: TPasClassOrRecordScope;
i: Integer; i: Integer;
AbstractProcs: TArrayOfPasProcedure;
begin begin
StartScope:=FindData.StartScope; StartScope:=FindData.StartScope;
OnlyTypeMembers:=false; OnlyTypeMembers:=false;
@ -14694,25 +14757,29 @@ begin
RaiseInternalError(20170131141936); RaiseInternalError(20170131141936);
Ref.Context:=TResolvedRefCtxConstructor.Create; Ref.Context:=TResolvedRefCtxConstructor.Create;
if StartScope is TPasDotClassScope then if StartScope is TPasDotClassScope then
ClassScope:=TPasDotClassScope(StartScope).ClassScope ClassRecScope:=TPasDotClassScope(StartScope).ClassScope
else if (StartScope is TPasWithExprScope) else if (StartScope is TPasWithExprScope)
and (TPasWithExprScope(StartScope).Scope is TPasClassScope) then and (TPasWithExprScope(StartScope).Scope is TPasClassOrRecordScope) then
ClassScope:=TPasClassScope(TPasWithExprScope(StartScope).Scope) ClassRecScope:=TPasClassOrRecordScope(TPasWithExprScope(StartScope).Scope)
else if (StartScope is TPasProcedureScope) then else if (StartScope is TPasProcedureScope) then
ClassScope:=TPasProcedureScope(StartScope).ClassScope ClassRecScope:=TPasProcedureScope(StartScope).ClassScope
else else
RaiseInternalError(20170131150855,GetObjName(StartScope)); RaiseInternalError(20170131150855,GetObjName(StartScope));
TypeEl:=ClassScope.Element as TPasType; TypeEl:=ClassRecScope.Element as TPasType;
TResolvedRefCtxConstructor(Ref.Context).Typ:=TypeEl; TResolvedRefCtxConstructor(Ref.Context).Typ:=TypeEl;
if (length(ClassScope.AbstractProcs)>0) then if ClassRecScope is TPasClassScope then
begin begin
if IsClassOf then AbstractProcs:=TPasClassScope(ClassRecScope).AbstractProcs;
// aClass.Create: do not warn if (length(AbstractProcs)>0) then
else begin
for i:=0 to length(ClassScope.AbstractProcs)-1 do if IsClassOf then
LogMsg(20171227110746,mtWarning,nConstructingClassXWithAbstractMethodY, // aClass.Create: do not warn
sConstructingClassXWithAbstractMethodY, else
[TypeEl.Name,ClassScope.AbstractProcs[i].Name],FindData.ErrorPosEl); for i:=0 to length(AbstractProcs)-1 do
LogMsg(20171227110746,mtWarning,nConstructingClassXWithAbstractMethodY,
sConstructingClassXWithAbstractMethodY,
[TypeEl.Name,AbstractProcs[i].Name],FindData.ErrorPosEl);
end;
end; end;
end; end;
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
@ -20528,7 +20595,7 @@ var
begin begin
Result:=false; Result:=false;
if El=nil then exit; if El=nil then exit;
if El.Parent is TPasClassType then exit(true); if El.Parent is TPasMembersType then exit(true);
if not (El.CustomData is TPasProcedureScope) then exit; if not (El.CustomData is TPasProcedureScope) then exit;
ProcScope:=TPasProcedureScope(El.CustomData); ProcScope:=TPasProcedureScope(El.CustomData);
Result:=IsMethod(ProcScope.DeclarationProc); Result:=IsMethod(ProcScope.DeclarationProc);

View File

@ -692,14 +692,31 @@ type
Members: TPasRecordType; Members: TPasRecordType;
end; end;
{ TPasRecordType } { TPasMembersType - base type for TPasRecordType and TPasClassType }
TPasRecordType = class(TPasType) TPasMembersType = class(TPasType)
private private
procedure ClearChildReferences(El: TPasElement; arg: pointer); procedure ClearChildReferences(El: TPasElement; arg: pointer);
procedure GetMembers(S: TStrings);
protected protected
procedure SetParent(const AValue: TPasElement); override; procedure SetParent(const AValue: TPasElement); override;
public
PackMode: TPackMode;
Members: TFPList;
GenericTemplateTypes: TFPList; // list of TPasGenericTemplateType
Constructor Create(const AName: string; AParent: TPasElement); override;
Destructor Destroy; override;
Function IsPacked: Boolean;
Function IsBitPacked : Boolean;
Procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override;
Procedure SetGenericTemplates(AList: TFPList); virtual;
end;
{ TPasRecordType }
TPasRecordType = class(TPasMembersType)
private
procedure GetMembers(S: TStrings);
public public
constructor Create(const AName: string; AParent: TPasElement); override; constructor Create(const AName: string; AParent: TPasElement); override;
destructor Destroy; override; destructor Destroy; override;
@ -708,15 +725,9 @@ type
procedure ForEachCall(const aMethodCall: TOnForEachPasElement; procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override; const Arg: Pointer); override;
public public
PackMode: TPackMode;
Members: TFPList; // list of TPasVariable elements
VariantEl: TPasElement; // nil or TPasVariable or TPasType VariantEl: TPasElement; // nil or TPasVariable or TPasType
Variants: TFPList; // list of TPasVariant elements, may be nil! Variants: TFPList; // list of TPasVariant elements, may be nil!
GenericTemplateTypes: TFPList; // list of TPasGenericTemplateType
Function IsPacked: Boolean;
Function IsBitPacked : Boolean;
Function IsAdvancedRecord : Boolean; Function IsAdvancedRecord : Boolean;
Procedure SetGenericTemplates(AList : TFPList);
end; end;
TPasGenericTemplateType = Class(TPasType); TPasGenericTemplateType = Class(TPasType);
@ -734,9 +745,7 @@ type
{ TPasClassType } { TPasClassType }
TPasClassType = class(TPasType) TPasClassType = class(TPasMembersType)
private
procedure ClearChildReferences(El: TPasElement; arg: pointer);
protected protected
procedure SetParent(const AValue: TPasElement); override; procedure SetParent(const AValue: TPasElement); override;
public public
@ -746,7 +755,6 @@ type
procedure ForEachCall(const aMethodCall: TOnForEachPasElement; procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer); override; const Arg: Pointer); override;
public public
PackMode: TPackMode;
ObjKind: TPasObjKind; ObjKind: TPasObjKind;
AncestorType: TPasType; // TPasClassType or TPasUnresolvedTypeRef or TPasAliasType or TPasTypeAliasType AncestorType: TPasType; // TPasClassType or TPasUnresolvedTypeRef or TPasAliasType or TPasTypeAliasType
// Note: AncestorType can be nil even though it has a default ancestor // Note: AncestorType can be nil even though it has a default ancestor
@ -755,25 +763,20 @@ type
IsExternal : Boolean; IsExternal : Boolean;
IsShortDefinition: Boolean;//class(anchestor); without end IsShortDefinition: Boolean;//class(anchestor); without end
GUIDExpr : TPasExpr; GUIDExpr : TPasExpr;
Members: TFPList; // list of TPasElement
Modifiers: TStringList; Modifiers: TStringList;
Interfaces : TFPList; // list of TPasType Interfaces : TFPList; // list of TPasType
GenericTemplateTypes: TFPList; // list of TPasGenericTemplateType
ExternalNameSpace : String; ExternalNameSpace : String;
ExternalName : String; ExternalName : String;
InterfaceType: TPasClassInterfaceType; InterfaceType: TPasClassInterfaceType;
Procedure SetGenericTemplates(AList : TFPList); Procedure SetGenericTemplates(AList : TFPList); override;
Function FindMember(MemberClass : TPTreeElement; Const MemberName : String) : TPasElement; Function FindMember(MemberClass : TPTreeElement; Const MemberName : String) : TPasElement;
Function FindMemberInAncestors(MemberClass : TPTreeElement; Const MemberName : String) : TPasElement; Function FindMemberInAncestors(MemberClass : TPTreeElement; Const MemberName : String) : TPasElement;
Function IsPacked : Boolean;
Function InterfaceGUID : string; Function InterfaceGUID : string;
Function IsSealed : Boolean; Function IsSealed : Boolean;
Function IsAbstract : Boolean; Function IsAbstract : Boolean;
Function HasModifier(const aModifier: String): Boolean; Function HasModifier(const aModifier: String): Boolean;
end; end;
TArgumentAccess = (argDefault, argConst, argVar, argOut, argConstRef); TArgumentAccess = (argDefault, argConst, argVar, argOut, argConstRef);
{ TPasArgument } { TPasArgument }
@ -2948,22 +2951,12 @@ end;
constructor TPasRecordType.Create(const AName: string; AParent: TPasElement); constructor TPasRecordType.Create(const AName: string; AParent: TPasElement);
begin begin
inherited Create(AName, AParent); inherited Create(AName, AParent);
Members := TFPList.Create;
GenericTemplateTypes:=TFPList.Create;
end; end;
destructor TPasRecordType.Destroy; destructor TPasRecordType.Destroy;
var var
i: Integer; i: Integer;
begin begin
for i := 0 to GenericTemplateTypes.Count - 1 do
TPasElement(GenericTemplateTypes[i]).Release{$IFDEF CheckPasTreeRefCount}('TPasRecordType.GenericTemplateTypes'){$ENDIF};
FreeAndNil(GenericTemplateTypes);
for i := 0 to Members.Count - 1 do
TPasVariable(Members[i]).Release{$IFDEF CheckPasTreeRefCount}('TPasRecordType.Members'){$ENDIF};
FreeAndNil(Members);
ReleaseAndNil(TPasElement(VariantEl){$IFDEF CheckPasTreeRefCount},'TPasRecordType.VariantEl'{$ENDIF}); ReleaseAndNil(TPasElement(VariantEl){$IFDEF CheckPasTreeRefCount},'TPasRecordType.VariantEl'{$ENDIF});
if Assigned(Variants) then if Assigned(Variants) then
@ -2978,19 +2971,12 @@ end;
{ TPasClassType } { TPasClassType }
procedure TPasClassType.ClearChildReferences(El: TPasElement; arg: pointer);
begin
El.ClearTypeReferences(Self);
if arg=nil then ;
end;
procedure TPasClassType.SetParent(const AValue: TPasElement); procedure TPasClassType.SetParent(const AValue: TPasElement);
begin begin
if (AValue=nil) and (Parent<>nil) then if (AValue=nil) and (Parent<>nil) then
begin begin
// parent is cleared // parent is cleared
// -> clear all child references to this class (releasing loops) // -> clear all references to this class (releasing loops)
ForEachCall(@ClearChildReferences,nil);
if AncestorType=Self then if AncestorType=Self then
ReleaseAndNil(TPasElement(AncestorType){$IFDEF CheckPasTreeRefCount},'TPasClassType.AncestorType'{$ENDIF}); ReleaseAndNil(TPasElement(AncestorType){$IFDEF CheckPasTreeRefCount},'TPasClassType.AncestorType'{$ENDIF});
if HelperForType=Self then if HelperForType=Self then
@ -3002,27 +2988,15 @@ end;
constructor TPasClassType.Create(const AName: string; AParent: TPasElement); constructor TPasClassType.Create(const AName: string; AParent: TPasElement);
begin begin
inherited Create(AName, AParent); inherited Create(AName, AParent);
PackMode:=pmNone; // 12/04/04 - Dave - Added
IsShortDefinition := False; IsShortDefinition := False;
Members := TFPList.Create;
Modifiers := TStringList.Create; Modifiers := TStringList.Create;
Interfaces:= TFPList.Create; Interfaces:= TFPList.Create;
GenericTemplateTypes:=TFPList.Create;
end; end;
destructor TPasClassType.Destroy; destructor TPasClassType.Destroy;
var var
i: Integer; i: Integer;
El: TPasElement;
begin begin
for i := 0 to Members.Count - 1 do
begin
El:=TPasElement(Members[i]);
El.Parent:=nil;
El.Release{$IFDEF CheckPasTreeRefCount}('TPasClassType.Members'){$ENDIF};
end;
FreeAndNil(Members);
for i := 0 to Interfaces.Count - 1 do for i := 0 to Interfaces.Count - 1 do
TPasElement(Interfaces[i]).Release{$IFDEF CheckPasTreeRefCount}('TPasClassType.Interfaces'){$ENDIF}; TPasElement(Interfaces[i]).Release{$IFDEF CheckPasTreeRefCount}('TPasClassType.Interfaces'){$ENDIF};
FreeAndNil(Interfaces); FreeAndNil(Interfaces);
@ -3030,9 +3004,6 @@ begin
ReleaseAndNil(TPasElement(HelperForType){$IFDEF CheckPasTreeRefCount},'TPasClassType.HelperForType'{$ENDIF}); ReleaseAndNil(TPasElement(HelperForType){$IFDEF CheckPasTreeRefCount},'TPasClassType.HelperForType'{$ENDIF});
ReleaseAndNil(TPasElement(GUIDExpr){$IFDEF CheckPasTreeRefCount},'TPasClassType.GUIDExpr'{$ENDIF}); ReleaseAndNil(TPasElement(GUIDExpr){$IFDEF CheckPasTreeRefCount},'TPasClassType.GUIDExpr'{$ENDIF});
FreeAndNil(Modifiers); FreeAndNil(Modifiers);
for i := 0 to GenericTemplateTypes.Count - 1 do
TPasElement(GenericTemplateTypes[i]).Release{$IFDEF CheckPasTreeRefCount}('TPasClassType.GenericTemplateTypes'){$ENDIF};
FreeAndNil(GenericTemplateTypes);
inherited Destroy; inherited Destroy;
end; end;
@ -3062,26 +3033,12 @@ begin
ForEachChildCall(aMethodCall,Arg,TPasElement(Interfaces[i]),true); ForEachChildCall(aMethodCall,Arg,TPasElement(Interfaces[i]),true);
ForEachChildCall(aMethodCall,Arg,HelperForType,true); ForEachChildCall(aMethodCall,Arg,HelperForType,true);
ForEachChildCall(aMethodCall,Arg,GUIDExpr,false); ForEachChildCall(aMethodCall,Arg,GUIDExpr,false);
for i:=0 to Members.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(Members[i]),false);
for i:=0 to GenericTemplateTypes.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(GenericTemplateTypes[i]),false);
end; end;
procedure TPasClassType.SetGenericTemplates(AList: TFPList); procedure TPasClassType.SetGenericTemplates(AList: TFPList);
Var
I : Integer;
begin begin
ObjKind:=okGeneric; ObjKind:=okGeneric;
For I:=0 to AList.Count-1 do inherited SetGenericTemplates(AList);
begin
TPasElement(AList[i]).Parent:=Self;
GenericTemplateTypes.Add(AList[i]);
end;
AList.Clear;
ObjKind:=okGeneric;
end; end;
function TPasClassType.FindMember(MemberClass: TPTreeElement; const MemberName: String): TPasElement; function TPasClassType.FindMember(MemberClass: TPTreeElement; const MemberName: String): TPasElement;
@ -3155,12 +3112,6 @@ begin
Result:=false; Result:=false;
end; end;
function TPasClassType.IsPacked: Boolean;
begin
Result:=PackMode<>pmNone;
end;
{ TPasArgument } { TPasArgument }
destructor TPasArgument.Destroy; destructor TPasArgument.Destroy;
@ -3987,12 +3938,95 @@ begin
ForEachChildCall(aMethodCall,Arg,EnumType,true); ForEachChildCall(aMethodCall,Arg,EnumType,true);
end; end;
procedure TPasRecordType.ClearChildReferences(El: TPasElement; arg: pointer); { TPasMembersType }
procedure TPasMembersType.ClearChildReferences(El: TPasElement; arg: pointer);
begin begin
El.ClearTypeReferences(Self); El.ClearTypeReferences(Self);
if arg=nil then ; if arg=nil then ;
end; end;
procedure TPasMembersType.SetParent(const AValue: TPasElement);
begin
if (AValue=nil) and (Parent<>nil) then
begin
// parent is cleared
// -> clear all child references to this class/record (releasing loops)
ForEachCall(@ClearChildReferences,nil);
end;
inherited SetParent(AValue);
end;
constructor TPasMembersType.Create(const AName: string; AParent: TPasElement);
begin
inherited Create(AName, AParent);
PackMode:=pmNone;
Members := TFPList.Create;
GenericTemplateTypes:=TFPList.Create;
end;
destructor TPasMembersType.Destroy;
var
i: Integer;
El: TPasElement;
begin
for i := 0 to Members.Count - 1 do
begin
El:=TPasElement(Members[i]);
El.Parent:=nil;
El.Release{$IFDEF CheckPasTreeRefCount}('TPasMembersType.Members'){$ENDIF};
end;
FreeAndNil(Members);
for i := 0 to GenericTemplateTypes.Count - 1 do
begin
El:=TPasElement(GenericTemplateTypes[i]);
El.Parent:=nil;
El.Release{$IFDEF CheckPasTreeRefCount}('TPasMembersType.GenericTemplateTypes'){$ENDIF};
end;
FreeAndNil(GenericTemplateTypes);
inherited Destroy;
end;
function TPasMembersType.IsPacked: Boolean;
begin
Result:=(PackMode <> pmNone);
end;
function TPasMembersType.IsBitPacked: Boolean;
begin
Result:=(PackMode=pmBitPacked)
end;
procedure TPasMembersType.ForEachCall(const aMethodCall: TOnForEachPasElement;
const Arg: Pointer);
var
i: Integer;
begin
inherited ForEachCall(aMethodCall, Arg);
for i:=0 to GenericTemplateTypes.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(GenericTemplateTypes[i]),true);
for i:=0 to Members.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(Members[i]),false);
end;
procedure TPasMembersType.SetGenericTemplates(AList: TFPList);
var
I: Integer;
El: TPasElement;
begin
For I:=0 to AList.Count-1 do
begin
El:=TPasElement(AList[i]);
El.Parent:=Self;
GenericTemplateTypes.Add(El);
end;
AList.Clear;
end;
{ TPasRecordType }
procedure TPasRecordType.GetMembers(S: TStrings); procedure TPasRecordType.GetMembers(S: TStrings);
Var Var
@ -4049,17 +4083,6 @@ begin
end; end;
end; end;
procedure TPasRecordType.SetParent(const AValue: TPasElement);
begin
if (AValue=nil) and (Parent<>nil) then
begin
// parent is cleared
// -> clear all child references to this class (releasing loops)
ForEachCall(@ClearChildReferences,nil);
end;
inherited SetParent(AValue);
end;
function TPasRecordType.GetDeclaration (full : boolean) : string; function TPasRecordType.GetDeclaration (full : boolean) : string;
Var Var
@ -4093,54 +4116,30 @@ var
i: Integer; i: Integer;
begin begin
inherited ForEachCall(aMethodCall, Arg); inherited ForEachCall(aMethodCall, Arg);
for i:=0 to GenericTemplateTypes.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(GenericTemplateTypes[i]),true);
for i:=0 to Members.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(Members[i]),false);
ForEachChildCall(aMethodCall,Arg,VariantEl,true); ForEachChildCall(aMethodCall,Arg,VariantEl,true);
if Variants<>nil then if Variants<>nil then
for i:=0 to Variants.Count-1 do for i:=0 to Variants.Count-1 do
ForEachChildCall(aMethodCall,Arg,TPasElement(Variants[i]),false); ForEachChildCall(aMethodCall,Arg,TPasElement(Variants[i]),false);
end; end;
function TPasRecordType.IsPacked: Boolean;
begin
Result:=(PackMode <> pmNone);
end;
function TPasRecordType.IsBitPacked: Boolean;
begin
Result:=(PackMode=pmBitPacked)
end;
function TPasRecordType.IsAdvancedRecord: Boolean; function TPasRecordType.IsAdvancedRecord: Boolean;
Var Var
I : Integer; I : Integer;
Member: TPasElement;
begin begin
Result:=False; Result:=False;
I:=0; I:=0;
While (Not Result) and (I<Members.Count) do While (Not Result) and (I<Members.Count) do
begin begin
Result:=TPasElement(Members[i]).InheritsFrom(TPasProcedureBase) or Member:=TPasElement(Members[i]);
TPasElement(Members[i]).InheritsFrom(TPasProperty); if (Member.Visibility<>visPublic) then exit(true);
if (Member.ClassType<>TPasVariable) then exit(true);
Inc(I); Inc(I);
end; end;
end; end;
procedure TPasRecordType.SetGenericTemplates(AList: TFPList);
var
I: Integer;
begin
For I:=0 to AList.Count-1 do
begin
TPasElement(AList[i]).Parent:=Self;
GenericTemplateTypes.Add(AList[i]);
end;
AList.Clear;
end;
procedure TPasProcedureType.GetArguments(List : TStrings); procedure TPasProcedureType.GetArguments(List : TStrings);
Var Var

View File

@ -1479,6 +1479,25 @@ begin
begin begin
BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData); BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
case BuiltInProc.BuiltIn of case BuiltInProc.BuiltIn of
bfExit:
begin
if El.Parent is TParamsExpr then
begin
Params:=(El.Parent as TParamsExpr).Params;
if length(Params)=1 then
begin
SubEl:=El.Parent;
while (SubEl<>nil) and not (SubEl is TPasProcedure) do
SubEl:=SubEl.Parent;
if (SubEl is TPasProcedure)
and (TPasProcedure(SubEl).ProcType is TPasFunctionType) then
begin
SubEl:=TPasFunctionType(TPasProcedure(SubEl).ProcType).ResultEl;
UseElement(SubEl,rraAssign,false);
end;
end;
end;
end;
bfTypeInfo: bfTypeInfo:
begin begin
Params:=(El.Parent as TParamsExpr).Params; Params:=(El.Parent as TParamsExpr).Params;
@ -1490,9 +1509,10 @@ begin
{$ENDIF} {$ENDIF}
if ParamResolved.IdentEl=nil then if ParamResolved.IdentEl=nil then
RaiseNotSupported(20180628155107,Params[0]); RaiseNotSupported(20180628155107,Params[0]);
if ParamResolved.IdentEl is TPasFunction then if (ParamResolved.IdentEl is TPasProcedure)
and (TPasProcedure(ParamResolved.IdentEl).ProcType is TPasFunctionType) then
begin begin
SubEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType; SubEl:=TPasFunctionType(TPasProcedure(ParamResolved.IdentEl).ProcType).ResultEl.ResultType;
MarkImplScopeRef(El,SubEl,psraTypeInfo); MarkImplScopeRef(El,SubEl,psraTypeInfo);
UseTypeInfo(SubEl); UseTypeInfo(SubEl);
end end

View File

@ -81,7 +81,7 @@ const
nErrRecordConstantsNotAllowed = 2035; nErrRecordConstantsNotAllowed = 2035;
nErrRecordMethodsNotAllowed = 2036; nErrRecordMethodsNotAllowed = 2036;
nErrRecordPropertiesNotAllowed = 2037; nErrRecordPropertiesNotAllowed = 2037;
nErrRecordVisibilityNotAllowed = 2038; // free , was nErrRecordVisibilityNotAllowed = 2038;
nParserTypeNotAllowedHere = 2039; nParserTypeNotAllowedHere = 2039;
nParserNotAnOperand = 2040; nParserNotAnOperand = 2040;
nParserArrayPropertiesCannotHaveDefaultValue = 2041; nParserArrayPropertiesCannotHaveDefaultValue = 2041;
@ -142,7 +142,7 @@ resourcestring
SErrRecordVariablesNotAllowed = 'Record variables not allowed at this location.'; SErrRecordVariablesNotAllowed = 'Record variables not allowed at this location.';
SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location.'; SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location.';
SErrRecordPropertiesNotAllowed = 'Record properties not allowed at this location.'; SErrRecordPropertiesNotAllowed = 'Record properties not allowed at this location.';
SErrRecordVisibilityNotAllowed = 'Record visibilities not allowed at this location.'; // free, was SErrRecordVisibilityNotAllowed = 'Record visibilities not allowed at this location.';
SParserTypeNotAllowedHere = 'Type "%s" not allowed here'; SParserTypeNotAllowedHere = 'Type "%s" not allowed here';
SParserNotAnOperand = 'Not an operand: (%d : %s)'; SParserNotAnOperand = 'Not an operand: (%d : %s)';
SParserArrayPropertiesCannotHaveDefaultValue = 'Array properties cannot have default value'; SParserArrayPropertiesCannotHaveDefaultValue = 'Array properties cannot have default value';
@ -4504,7 +4504,7 @@ begin
ParseVarList(Parent,List,AVisibility,False); ParseVarList(Parent,List,AVisibility,False);
tt:=[tkEnd,tkSemicolon]; tt:=[tkEnd,tkSemicolon];
if ClosingBrace then if ClosingBrace then
include(tt,tkBraceClose); Include(tt,tkBraceClose);
if not (CurToken in tt) then if not (CurToken in tt) then
ParseExc(nParserExpectedSemiColonEnd,SParserExpectedSemiColonEnd); ParseExc(nParserExpectedSemiColonEnd,SParserExpectedSemiColonEnd);
end; end;
@ -6362,15 +6362,13 @@ begin
tkGeneric, // Counts as field name tkGeneric, // Counts as field name
tkIdentifier : tkIdentifier :
begin begin
if CheckVisibility(CurtokenString,v) then If AllowMethods and CheckVisibility(CurTokenString,v) then
begin begin
If not (msAdvancedRecords in Scanner.CurrentModeSwitches) then if not (v in [visPrivate,visPublic,visStrictPrivate]) then
ParseExc(nErrRecordVisibilityNotAllowed,SErrRecordVisibilityNotAllowed); ParseExc(nParserInvalidRecordVisibility,SParserInvalidRecordVisibility);
if not (v in [visPrivate,visPublic,visStrictPrivate]) then NextToken;
ParseExc(nParserInvalidRecordVisibility,SParserInvalidRecordVisibility); Continue;
NextToken; end;
Continue;
end;
OldCount:=ARec.Members.Count; OldCount:=ARec.Members.Count;
ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose); ParseInlineVarDecl(ARec, ARec.Members, v, AEndToken=tkBraceClose);
for i:=OldCount to ARec.Members.Count-1 do for i:=OldCount to ARec.Members.Count-1 do
@ -6423,12 +6421,15 @@ begin
try try
Result.PackMode:=PackMode; Result.PackMode:=PackMode;
NextToken; NextToken;
ParseRecordFieldList(Result,tkEnd,true); ParseRecordFieldList(Result,tkEnd,msAdvancedRecords in Scanner.CurrentModeSwitches);
Engine.FinishScope(stTypeDef,Result); Engine.FinishScope(stTypeDef,Result);
ok:=true; ok:=true;
finally finally
if not ok then if not ok then
begin
Result.Parent:=nil; // clear references from members to Result
Result.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF}; Result.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
end;
end; end;
end; end;
@ -6826,7 +6827,8 @@ begin
end; end;
exit; exit;
end; end;
if ((AobjKind in [okClass,OKInterface]) and (msExternalClass in CurrentModeswitches) and CurTokenIsIdentifier('external')) then if ((AObjKind in [okClass,OKInterface]) and (msExternalClass in CurrentModeswitches)
and CurTokenIsIdentifier('external')) then
begin begin
NextToken; NextToken;
if CurToken<>tkString then if CurToken<>tkString then

View File

@ -483,7 +483,27 @@ type
Procedure TestRecord_Const_UntypedFail; Procedure TestRecord_Const_UntypedFail;
Procedure TestRecord_Const_NestedRecord; Procedure TestRecord_Const_NestedRecord;
Procedure TestRecord_Const_Variant; Procedure TestRecord_Const_Variant;
Procedure TestRecord_VarExternal; // ToDo Procedure TestRecord_VarExternal;
Procedure TestRecord_VarSelfFail;
// advanced record
Procedure TestAdvRecord;
Procedure TestAdvRecord_Private; // ToDo
// Todo: Procedure TestAdvRecord_ForwardFail
// ToDo: public, private, strict private
// ToDo: TestAdvRecordPublsihedFail
// ToDo: TestAdvRecord_VirtualFail
// ToDo: TestAdvRecord_OverrideFail
// ToDo: constructor, destructor
// ToDo: class function/procedure
// ToDo: nested record type
// ToDo: const
// todo: var
// todo: class var
// todo: property
// todo: class property
// todo: TestRecordAsFuncResult
// todo: for in record
// class // class
Procedure TestClass; Procedure TestClass;
@ -1579,7 +1599,7 @@ begin
if (Msg<>E.Message) and (Msg<>E.MsgPattern) and (Msg<>Full) then if (Msg<>E.Message) and (Msg<>E.MsgPattern) and (Msg<>Full) then
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
writeln('TCustomTestResolver.CheckResolverException E.MsgPattern={',E.MsgPattern,'}'); writeln('TCustomTestResolver.CheckResolverException E.MsgPattern={',E.MsgPattern,'} E.Message={',E.Message,'} Full={',Full,'}');
{$ENDIF} {$ENDIF}
AssertEquals('Expected message ('+IntToStr(MsgNumber)+')', AssertEquals('Expected message ('+IntToStr(MsgNumber)+')',
'{'+Msg+'}','{'+E.Message+'} OR {'+E.MsgPattern+'} OR {'+Full+'}'); '{'+Msg+'}','{'+E.Message+'} OR {'+E.MsgPattern+'} OR {'+Full+'}');
@ -7787,6 +7807,55 @@ begin
ParseProgram; ParseProgram;
end; end;
procedure TTestResolver.TestRecord_VarSelfFail;
begin
StartProgram(false);
Add([
'type',
' TRec = record',
' r: Trec;',
' end;',
'begin']);
CheckResolverException('type "TRec" is not yet completely defined',nTypeXIsNotYetCompletelyDefined);
end;
procedure TTestResolver.TestAdvRecord;
begin
StartProgram(false);
Add([
'{$modeswitch advancedrecords}',
'type',
' TRec = record',
' procedure DoIt;',
' end;',
'procedure TRec.DoIt;',
'begin',
'end;',
'begin']);
ParseProgram;
end;
procedure TTestResolver.TestAdvRecord_Private;
begin
exit;
StartProgram(false);
Add([
'{$modeswitch advancedrecords}',
'type',
' TRec = record',
' private',
' a: byte;',
' public',
' b: byte;',
' end;',
'var',
' r: TRec;',
'begin',
' r.a:=r.b;']);
ParseProgram;
end;
procedure TTestResolver.TestClass; procedure TTestResolver.TestClass;
begin begin
StartProgram(false); StartProgram(false);

View File

@ -2043,6 +2043,7 @@ Var
P : TPasFunction; P : TPasFunction;
begin begin
Scanner.CurrentModeSwitches:=Scanner.CurrentModeSwitches+[msAdvancedRecords];
TestFields(['x : integer;','class operator assign(a : ta; b : Cardinal) : boolean;','function dosomething3 : Integer;'],'',False); TestFields(['x : integer;','class operator assign(a : ta; b : Cardinal) : boolean;','function dosomething3 : Integer;'],'',False);
AssertEquals('Member count',3,TheRecord.Members.Count); AssertEquals('Member count',3,TheRecord.Members.Count);
AssertField1([]); AssertField1([]);
@ -2057,6 +2058,7 @@ end;
procedure TTestRecordTypeParser.TestFieldAndClassVar; procedure TTestRecordTypeParser.TestFieldAndClassVar;
begin begin
Scanner.CurrentModeSwitches:=Scanner.CurrentModeSwitches+[msAdvancedRecords];
TestFields(['x : integer;','class var y : integer;'],'',False); TestFields(['x : integer;','class var y : integer;'],'',False);
AssertField1([]); AssertField1([]);
AssertTrue('Second field is class var',vmClass in Field2.VarModifiers); AssertTrue('Second field is class var',vmClass in Field2.VarModifiers);
@ -2064,6 +2066,7 @@ end;
procedure TTestRecordTypeParser.TestFieldAndVar; procedure TTestRecordTypeParser.TestFieldAndVar;
begin begin
Scanner.CurrentModeSwitches:=Scanner.CurrentModeSwitches+[msAdvancedRecords];
TestFields(['x : integer;','var y : integer;'],'',False); TestFields(['x : integer;','var y : integer;'],'',False);
AssertField1([]); AssertField1([]);
AssertTrue('Second field is regular var',not (vmClass in Field2.VarModifiers)); AssertTrue('Second field is regular var',not (vmClass in Field2.VarModifiers));

View File

@ -128,6 +128,7 @@ type
procedure TestM_Hint_FunctionResultRecord; procedure TestM_Hint_FunctionResultRecord;
procedure TestM_Hint_FunctionResultPassRecordElement; procedure TestM_Hint_FunctionResultPassRecordElement;
procedure TestM_Hint_FunctionResultAssembler; procedure TestM_Hint_FunctionResultAssembler;
procedure TestM_Hint_FunctionResultExit;
procedure TestM_Hint_AbsoluteVar; procedure TestM_Hint_AbsoluteVar;
// whole program optimization // whole program optimization
@ -2158,6 +2159,20 @@ begin
CheckUseAnalyzerUnexpectedHints; CheckUseAnalyzerUnexpectedHints;
end; end;
procedure TTestUseAnalyzer.TestM_Hint_FunctionResultExit;
begin
StartProgram(false);
Add([
'function GetIt: longint;',
'begin',
' exit(3);',
'end;',
'begin',
' GetIt;']);
AnalyzeProgram;
CheckUseAnalyzerUnexpectedHints;
end;
procedure TTestUseAnalyzer.TestM_Hint_AbsoluteVar; procedure TTestUseAnalyzer.TestM_Hint_AbsoluteVar;
begin begin
StartProgram(false); StartProgram(false);