fcl-passrc: resolver: array of const

git-svn-id: trunk@41326 -
This commit is contained in:
Mattias Gaertner 2019-02-15 22:37:36 +00:00
parent cd03f5326d
commit 28e509f8f9
5 changed files with 343 additions and 99 deletions

View File

@ -183,6 +183,7 @@ const
nHelpersCannotBeUsedAsTypes = 3117;
nBitWiseOperationsAre32Bit = 3118;
nImplictConversionUnicodeToAnsi = 3119;
nWrongTypeXInArrayConstructor = 3120;
// using same IDs as FPC
nVirtualMethodXHasLowerVisibility = 3250; // was 3050
@ -313,6 +314,7 @@ resourcestring
sHelpersCannotBeUsedAsTypes = 'helpers cannot be used as types';
sBitWiseOperationsAre32Bit = 'Bitwise operations are 32-bit';
sImplictConversionUnicodeToAnsi = 'Implicit string type conversion with potential data loss from "UnicodeString" to "AnsiString"';
sWrongTypeXInArrayConstructor = 'Wrong type "%s" in array constructor';
type
{ TResolveData - base class for data stored in TPasElement.CustomData }

View File

@ -745,11 +745,13 @@ type
FAssertMsgConstructor: TPasConstructor;
FRangeErrorClass: TPasClassType;
FRangeErrorConstructor: TPasConstructor;
FSystemTVarRec: TPasRecordType;
procedure SetAssertClass(const AValue: TPasClassType);
procedure SetAssertDefConstructor(const AValue: TPasConstructor);
procedure SetAssertMsgConstructor(const AValue: TPasConstructor);
procedure SetRangeErrorClass(const AValue: TPasClassType);
procedure SetRangeErrorConstructor(const AValue: TPasConstructor);
procedure SetSystemTVarRec(const AValue: TPasRecordType);
public
FirstName: string; // the 'unit1' in 'unit1', or 'ns' in 'ns.unit1'
PendingResolvers: TFPList; // list of TPasResolver waiting for the unit interface
@ -765,6 +767,7 @@ type
property AssertMsgConstructor: TPasConstructor read FAssertMsgConstructor write SetAssertMsgConstructor;
property RangeErrorClass: TPasClassType read FRangeErrorClass write SetRangeErrorClass;
property RangeErrorConstructor: TPasConstructor read FRangeErrorConstructor write SetRangeErrorConstructor;
property SystemTVarRec: TPasRecordType read FSystemTVarRec write SetSystemTVarRec;
end;
TPasModuleScopeClass = class of TPasModuleScope;
@ -1228,7 +1231,7 @@ type
ExprEl: TPasExpr;
Flags: TPasResolverResultFlags;
end;
PPasResolvedElement = ^TPasResolverResult;
PPasResolverResult = ^TPasResolverResult;
type
TPasResolverComputeFlag = (
@ -1528,10 +1531,11 @@ type
procedure FinishArgument(El: TPasArgument); virtual;
procedure FinishAncestors(aClass: TPasClassType); virtual;
procedure FinishMethodResolution(El: TPasMethodResolution); virtual;
procedure FinishProcParamAccess(ProcType: TPasProcedureType; Params: TParamsExpr); virtual;
procedure FinishPropertyParamAccess(Params: TParamsExpr;
Prop: TPasProperty);
procedure FinishCallArgAccess(Expr: TPasExpr; Access: TResolvedRefAccess);
procedure FinishInitialFinalization(El: TPasImplBlock);
Prop: TPasProperty); virtual;
procedure FinishCallArgAccess(Expr: TPasExpr; Access: TResolvedRefAccess); virtual;
procedure FinishInitialFinalization(El: TPasImplBlock); virtual;
procedure EmitTypeHints(PosEl: TPasElement; aType: TPasType); virtual;
function EmitElementHints(PosEl, El: TPasElement): boolean; virtual;
procedure StoreScannerFlagsInProc(ProcScope: TPasProcedureScope);
@ -1604,6 +1608,8 @@ type
ErrorEl: TPasElement): boolean; virtual;
procedure FindAssertExceptionConstructors(ErrorEl: TPasElement); virtual;
procedure FindRangeErrorConstructors(ErrorEl: TPasElement); virtual;
function FindTVarRec(ErrorEl: TPasElement): TPasRecordType; virtual;
function GetTVarRec(El: TPasArrayType): TPasRecordType; virtual;
protected
fExprEvaluator: TResExprEvaluator;
procedure OnExprEvalLog(Sender: TResExprEvaluator; const id: TMaxPrecInt;
@ -1999,6 +2005,8 @@ type
function IsDynArray(TypeEl: TPasType; OptionalOpenArray: boolean = true): boolean;
function IsOpenArray(TypeEl: TPasType): boolean;
function IsDynOrOpenArray(TypeEl: TPasType): boolean;
function IsArrayOfConst(TypeEl: TPasType): boolean;
function GetArrayElType(ArrType: TPasArrayType): TPasType;
function IsVarInit(Expr: TPasExpr): boolean;
function IsEmptyArrayExpr(const ResolvedEl: TPasResolverResult): boolean;
function IsClassMethod(El: TPasElement): boolean;
@ -3713,6 +3721,16 @@ begin
FRangeErrorConstructor.AddRef{$IFDEF CheckPasTreeRefCount}('TPasModuleScope.SetRangeErrorConstructor'){$ENDIF};
end;
procedure TPasModuleScope.SetSystemTVarRec(const AValue: TPasRecordType);
begin
if FSystemTVarRec=AValue then Exit;
if FSystemTVarRec<>nil then
FSystemTVarRec.Release{$IFDEF CheckPasTreeRefCount}('TPasModuleScope.SetSystemTVarRec'){$ENDIF};
FSystemTVarRec:=AValue;
if FSystemTVarRec<>nil then
FSystemTVarRec.AddRef{$IFDEF CheckPasTreeRefCount}('TPasModuleScope.SetSystemTVarRec'){$ENDIF};
end;
constructor TPasModuleScope.Create;
begin
inherited Create;
@ -3726,6 +3744,7 @@ begin
AssertMsgConstructor:=nil;
RangeErrorClass:=nil;
RangeErrorConstructor:=nil;
SystemTVarRec:=nil;
FreeAndNil(PendingResolvers);
inherited Destroy;
end;
@ -5406,6 +5425,8 @@ begin
RaiseMsg(20170415165455,nCannotNestAnonymousX,sCannotNestAnonymousX,[GetElementTypeName(El)],El);
if not (Parent.Parent is TPasDeclarations) then
RaiseMsg(20170416094735,nCannotNestAnonymousX,sCannotNestAnonymousX,[GetElementTypeName(El)],El);
if El.Parent<>Parent then
RaiseNotYetImplemented(20190215085011,Parent);
// give anonymous sub type a name
El.Name:=Parent.Name+AnonymousElTypePostfix;
{$IFDEF VerbosePasResolver}
@ -5729,9 +5750,17 @@ begin
RaiseXExpectedButYFound(20170216151609,'range',GetElementTypeName(RangeResolved.IdentEl),Expr);
end;
if El.ElType=nil then
RaiseNotYetImplemented(20171005235610,El,'array of const');
CheckUseAsType(El.ElType,20190123095401,El);
FinishSubElementType(El,El.ElType);
begin
// array of const
if length(El.Ranges)>0 then
RaiseNotYetImplemented(20190215102529,El);
FindTVarRec(El);
end
else
begin
CheckUseAsType(El.ElType,20190123095401,El);
FinishSubElementType(El,El.ElType);
end;
end;
procedure TPasResolver.FinishResourcestring(El: TPasResString);
@ -7452,6 +7481,27 @@ begin
// El.ImplementationProc is resolved in FinishClassType
end;
procedure TPasResolver.FinishProcParamAccess(ProcType: TPasProcedureType;
Params: TParamsExpr);
var
ParamAccess: TResolvedRefAccess;
i: Integer;
ArrParams: TPasExprArray;
begin
ArrParams:=Params.Params;
for i:=0 to length(ArrParams)-1 do
begin
ParamAccess:=rraRead;
if i<ProcType.Args.Count then
case TPasArgument(ProcType.Args[i]).Access of
argVar: ParamAccess:=rraVarParam;
argOut: ParamAccess:=rraOutParam;
end;
AccessExpr(ArrParams[i],ParamAccess);
end;
CheckCallProcCompatibility(ProcType,Params,false,true);
end;
procedure TPasResolver.FinishPropertyParamAccess(Params: TParamsExpr;
Prop: TPasProperty);
var
@ -8064,7 +8114,7 @@ var
InRange, VarRange: TResEvalValue;
InRangeInt, VarRangeInt: TResEvalRangeInt;
bt: TResolverBaseType;
TypeEl: TPasType;
TypeEl, ElType: TPasType;
C: TClass;
begin
CreateScope(Loop,TPasForLoopScope);
@ -8150,7 +8200,8 @@ begin
C:=TypeEl.ClassType;
if C=TPasArrayType then
begin
ComputeElement(TPasArrayType(TypeEl).ElType,StartResolved,[rcType]);
ElType:=GetArrayElType(TPasArrayType(TypeEl));
ComputeElement(ElType,StartResolved,[rcType]);
StartResolved.Flags:=OrigStartResolved.Flags*[rrfReadable,rrfWritable];
if CheckAssignResCompatibility(VarResolved,StartResolved,Loop.StartExpr,true)=cIncompatible then
RaiseIncompatibleTypeRes(20171112210138,nIncompatibleTypesGotExpected,
@ -9080,8 +9131,8 @@ begin
ComputeElement(SubParams,ResolvedEl,[rcNoImplicitProc,rcSetReferenceFlags]);
if IsProcedureType(ResolvedEl,true) then
begin
CheckCallProcCompatibility(TPasProcedureType(ResolvedEl.LoTypeEl),Params,true);
CreateReference(TPasProcedureType(ResolvedEl.LoTypeEl),Value,Access);
FinishProcParamAccess(TPasProcedureType(ResolvedEl.LoTypeEl),Params);
exit;
end
end;
@ -9095,31 +9146,6 @@ end;
procedure TPasResolver.ResolveFuncParamsExprName(NameExpr: TPasExpr;
Params: TParamsExpr; Access: TResolvedRefAccess);
procedure FinishProcParams(ProcType: TPasProcedureType);
var
ParamAccess: TResolvedRefAccess;
i: Integer;
begin
if not (Access in [rraRead,rraParamToUnknownProc]) then
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExpr.FinishProcParams Params=',GetObjName(Params),' NameEl=',GetObjName(NameExpr),' Access=',Access);
{$ENDIF}
RaiseMsg(20170306104440,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Params);
end;
for i:=0 to length(Params.Params)-1 do
begin
ParamAccess:=rraRead;
if i<ProcType.Args.Count then
case TPasArgument(ProcType.Args[i]).Access of
argVar: ParamAccess:=rraVarParam;
argOut: ParamAccess:=rraOutParam;
end;
AccessExpr(Params.Params[i],ParamAccess);
end;
CheckCallProcCompatibility(ProcType,Params,false,true);
end;
procedure FinishUntypedParams(ParamAccess: TResolvedRefAccess);
var
i: Integer;
@ -9243,8 +9269,17 @@ begin
// set param expression Access flags
if FoundEl is TPasProcedure then
begin
// now it is known which overloaded proc to call
FinishProcParams(TPasProcedure(FoundEl).ProcType)
if not (Access in [rraRead,rraParamToUnknownProc]) then
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExprName Params=',GetObjName(Params),' NameExpr=',GetObjName(NameExpr),' Access=',Access);
{$ENDIF}
RaiseMsg(20170306104440,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Params);
end;
FinishProcParamAccess(TPasProcedure(FoundEl).ProcType,Params);
end
else if FoundEl is TPasType then
begin
TypeEl:=ResolveAliasType(TPasType(FoundEl));
@ -9307,7 +9342,14 @@ begin
TypeEl:=ResolvedEl.LoTypeEl;
if TypeEl is TPasProcedureType then
begin
FinishProcParams(TPasProcedureType(TypeEl));
if not (Access in [rraRead,rraParamToUnknownProc]) then
begin
{$IFDEF VerbosePasResolver}
writeln('TPasResolver.ResolveFuncParamsExprName Params=',GetObjName(Params),' NameExpr=',GetObjName(NameExpr),' Access=',Access);
{$ENDIF}
RaiseMsg(20190215195439,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Params);
end;
FinishProcParamAccess(TPasProcedureType(TypeEl),Params);
exit;
end;
{$IFDEF VerbosePasResolver}
@ -9912,6 +9954,8 @@ procedure TPasResolver.MarkArrayExprRecursive(Expr: TPasExpr;
inc(RgIndex);
if RgIndex>length(ArrayType.Ranges) then
begin
if ArrayType.ElType=nil then
exit; // elements are not arrays
ComputeElement(ArrayType.ElType,ResolvedElType,[rcType]);
if (ResolvedElType.BaseType=btContext)
and (ResolvedElType.LoTypeEl is TPasArrayType) then
@ -11337,7 +11381,7 @@ procedure TPasResolver.ComputeArrayParams(Params: TParamsExpr; out
end;
var
TypeEl: TPasType;
TypeEl, ElType: TPasType;
ArrayEl: TPasArrayType;
ArgNo: Integer;
OrigResolved: TPasResolverResult;
@ -11426,7 +11470,8 @@ begin
ArrayEl:=NoNil(ResolveAliasType(ArrayEl.ElType)) as TPasArrayType;
until false;
OrigResolved:=ResolvedEl;
ComputeElement(ArrayEl.ElType,ResolvedEl,Flags,StartEl);
ElType:=GetArrayElType(ArrayEl);
ComputeElement(ElType,ResolvedEl,Flags,StartEl);
// identifier and value is the array itself
ResolvedEl.IdentEl:=OrigResolved.IdentEl;
ResolvedEl.ExprEl:=OrigResolved.ExprEl;
@ -12710,6 +12755,51 @@ begin
ModScope.RangeErrorConstructor:=aConstructor;
end;
function TPasResolver.FindTVarRec(ErrorEl: TPasElement): TPasRecordType;
var
aMod, UtilsMod: TPasModule;
SectionScope: TPasSectionScope;
Identifier: TPasIdentifier;
El: TPasElement;
ModScope: TPasModuleScope;
begin
aMod:=RootElement;
ModScope:=aMod.CustomData as TPasModuleScope;
Result:=ModScope.SystemTVarRec;
if Result<>nil then exit;
// find unit in uses clauses
UtilsMod:=FindUsedUnit('system',aMod);
if UtilsMod=nil then
RaiseIdentifierNotFound(20190215101210,'System.TVarRec',ErrorEl);
// find class in interface
if UtilsMod.InterfaceSection=nil then
RaiseIdentifierNotFound(20190215101231,'System.TVarRec',ErrorEl);
SectionScope:=NoNil(UtilsMod.InterfaceSection.CustomData) as TPasSectionScope;
Identifier:=SectionScope.FindLocalIdentifier('TVarRec');
if Identifier=nil then
RaiseIdentifierNotFound(20190215101253,'System.TVarRec',ErrorEl);
El:=Identifier.Element;
if not (El is TPasRecordType) then
RaiseXExpectedButYFound(20190215101310,'record TVarRec',GetElementTypeName(El),ErrorEl);
Result:=TPasRecordType(El);
ModScope.SystemTVarRec:=Result;
end;
function TPasResolver.GetTVarRec(El: TPasArrayType): TPasRecordType;
var
aModule: TPasModule;
ModScope: TPasModuleScope;
begin
aModule:=El.GetModule;
ModScope:=aModule.CustomData as TPasModuleScope;
Result:=ModScope.SystemTVarRec;
if Result=nil then
RaiseNotYetImplemented(20190215111924,El,'missing System.TVarRec');
end;
procedure TPasResolver.OnExprEvalLog(Sender: TResExprEvaluator;
const id: TMaxPrecInt; MsgType: TMessageType; MsgNumber: integer;
const Fmt: String; Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
@ -14580,6 +14670,8 @@ var
Param: TPasExpr;
ParamResolved, ElTypeResolved, FirstElTypeResolved: TPasResolverResult;
i: Integer;
ArrType: TPasArrayType;
ElType: TPasType;
begin
Result:=cIncompatible;
if not CheckBuiltInMinParamCount(Proc,Expr,1,RaiseOnError) then
@ -14598,7 +14690,11 @@ begin
if ParamResolved.BaseType=btContext then
begin
if IsDynArray(ParamResolved.LoTypeEl) then
ComputeElement(TPasArrayType(ParamResolved.LoTypeEl).ElType,ElTypeResolved,[rcType]);
begin
ArrType:=TPasArrayType(ParamResolved.LoTypeEl);
ElType:=GetArrayElType(ArrType);
ComputeElement(ElType,ElTypeResolved,[rcType]);
end;
end
else if ParamResolved.BaseType in [btArrayLit,btArrayOrSet] then
SetResolverValueExpr(ElTypeResolved,ParamResolved.SubType,
@ -14793,6 +14889,8 @@ var
Params: TParamsExpr;
Param, ItemParam: TPasExpr;
ItemResolved, ParamResolved, ElTypeResolved: TPasResolverResult;
ArrType: TPasArrayType;
ElType: TPasType;
begin
Result:=cIncompatible;
if not CheckBuiltInMinParamCount(Proc,Expr,3,RaiseOnError) then
@ -14817,7 +14915,9 @@ begin
if (ParamResolved.BaseType<>btContext)
or not IsDynArray(ParamResolved.LoTypeEl) then
exit(CheckRaiseTypeArgNo(20170329172024,2,Param,ParamResolved,'dynamic array',RaiseOnError));
ComputeElement(TPasArrayType(ParamResolved.LoTypeEl).ElType,ElTypeResolved,[rcType]);
ArrType:=TPasArrayType(ParamResolved.LoTypeEl);
ElType:=GetArrayElType(ArrType);
ComputeElement(ElType,ElTypeResolved,[rcType]);
if CheckAssignResCompatibility(ElTypeResolved,ItemResolved,ItemParam,RaiseOnError)=cIncompatible then
exit(cIncompatible);
@ -14837,6 +14937,7 @@ var
P: TPasExprArray;
Param0, Param1: TPasExpr;
ArrayResolved, ElTypeResolved: TPasResolverResult;
ElType: TPasType;
begin
if Proc=nil then ;
P:=Params.Params;
@ -14853,7 +14954,8 @@ begin
if (ArrayResolved.BaseType<>btContext)
or not IsDynArray(ArrayResolved.LoTypeEl) then
RaiseNotYetImplemented(20180622144039,Param1);
ComputeElement(TPasArrayType(ArrayResolved.LoTypeEl).ElType,ElTypeResolved,[rcType]);
ElType:=GetArrayElType(TPasArrayType(ArrayResolved.LoTypeEl));
ComputeElement(ElType,ElTypeResolved,[rcType]);
if (ElTypeResolved.BaseType=btContext)
and (ElTypeResolved.LoTypeEl.ClassType=TPasArrayType) then
MarkArrayExprRecursive(Param0,TPasArrayType(ElTypeResolved.LoTypeEl));
@ -18082,7 +18184,7 @@ begin
exit(false);
if length(Arr1.Ranges)>0 then
RaiseNotYetImplemented(20170328093733,Arr1.Ranges[0],'anonymous static array');
Result:=CheckElTypeCompatibility(Arr1.ElType,Arr2.ElType,ResolveAlias);
Result:=CheckElTypeCompatibility(GetArrayElType(Arr1),GetArrayElType(Arr2),ResolveAlias);
exit;
end;
@ -19574,9 +19676,14 @@ begin
ArrayEl:=TPasArrayType(T.LoTypeEl);
if length(ArrayEl.Ranges)=0 then
begin
Result:='array of '+ArrayEl.ElType.Name;
if IsOpenArray(ArrayEl) then
Result:='open '+Result;
if ArrayEl.ElType=nil then
Result:='array of const'
else
begin
Result:='array of '+ArrayEl.ElType.Name;
if IsOpenArray(ArrayEl) then
Result:='open '+Result;
end;
end
else
Result:='static array[] of '+ArrayEl.ElType.Name;
@ -19610,6 +19717,8 @@ function TPasResolver.GetTypeDescription(aType: TPasType; AddPath: boolean): str
begin
if length(TPasArrayType(aType).Ranges)>0 then
Result:='static array'
else if TPasArrayType(aType).ElType=nil then
Result:='array of const'
else if IsOpenArray(aType) then
Result:='open array'
else
@ -19900,12 +20009,13 @@ var
SrcResolved, DstResolved: TPasResolverResult;
LArray, RArray: TPasArrayType;
GotDesc, ExpDesc: String;
CurTVarRec: TPasRecordType;
function RaiseIncompatType: integer;
function RaiseIncompatType(Id: TMaxPrecInt): integer;
begin
Result:=cIncompatible;
if not RaiseOnIncompatible then exit;
RaiseIncompatibleTypeRes(20170216152505,nIncompatibleTypesGotExpected,
RaiseIncompatibleTypeRes(Id,nIncompatibleTypesGotExpected,
[],RHS,LHS,ErrorEl);
end;
@ -19932,7 +20042,7 @@ begin
begin
Result:=cIncompatible;
if not (rrfReadable in RHS.Flags) then
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112914));
if TPasClassType(LTypeEl).ObjKind=TPasClassType(RTypeEl).ObjKind then
Result:=CheckSrcIsADstType(RHS,LHS)
else if TPasClassType(LTypeEl).ObjKind=okInterface then
@ -19950,7 +20060,7 @@ begin
[],RTypeEl,LTypeEl,ErrorEl);
end
else
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112919));
end
else if LTypeEl.ClassType=TPasClassOfType then
begin
@ -20020,15 +20130,7 @@ begin
begin
// DynOrOpenArr:=array
RArray:=TPasArrayType(RTypeEl);
if length(RArray.Ranges)>1 then
begin
// DynOrOpenArr:=MultiDimStaticArr -> no
if RaiseOnIncompatible then
RaiseIncompatibleTypeDesc(20180620115235,nIncompatibleTypesGotExpected,
[],'multi dimensional static array','dynamic array',ErrorEl);
exit(cIncompatible);
end
else if length(RArray.Ranges)>0 then
if length(RArray.Ranges)=1 then
begin
// DynOrOpenArr:=SingleDimStaticArr
if (msDelphi in CurrentParser.CurrentModeswitches)
@ -20042,6 +20144,14 @@ begin
exit(cIncompatible);
end;
end
else if length(RArray.Ranges)>1 then
begin
// DynOrOpenArr:=MultiDimStaticArr -> no
if RaiseOnIncompatible then
RaiseIncompatibleTypeDesc(20180620115235,nIncompatibleTypesGotExpected,
[],'multi dimensional static array','dynamic array',ErrorEl);
exit(cIncompatible);
end
else if not (proOpenAsDynArrays in Options) then
begin
if IsOpenArray(LArray) then
@ -20061,16 +20171,33 @@ begin
and (LArray<>RArray) then
begin
// Delphi does not allow assigning arrays with same element types
if RaiseOnIncompatible then
RaiseIncompatibleTypeRes(20180620115515,nIncompatibleTypesGotExpected,
[],RHS,LHS,ErrorEl);
exit(cIncompatible);
exit(RaiseIncompatType(20190215112626));
end;
end;
end;
// check element type
if CheckElTypeCompatibility(LArray.ElType,RArray.ElType,prraAlias) then
if LArray.ElType=nil then
begin
// ArrayOfConst:=SingleDimArr
if RArray.ElType=nil then
// ArrayOfConst:=ArrayOfConst
Result:=cExact
else
begin
CurTVarRec:=GetTVarRec(LArray);
if ResolveAliasType(RArray.ElType)=CurTVarRec then
// ArrayOfConst:=ArrayOfTVarRec
Result:=cExact
else
// ArrayOfConst:=SingleDimArr
exit(RaiseIncompatType(20190215112715));
end;
end
else if RArray.ElType=nil then
// ArrayOfNonConst:=ArrayOfConst
exit(RaiseIncompatType(20190215112907))
else if CheckElTypeCompatibility(LArray.ElType,RArray.ElType,prraAlias) then
Result:=cExact
else if RaiseOnIncompatible then
begin
@ -20118,7 +20245,7 @@ begin
exit(cIncompatible);
end
else
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112924));
end
else if LTypeEl.ClassType=TPasPointerType then
begin
@ -20128,7 +20255,7 @@ begin
Result:=CheckAssignCompatibilityPointerType(TPasPointerType(LTypeEl).DestType,
TPasPointerType(RTypeEl).DestType,ErrorEl,false);
if Result=cIncompatible then
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112927));
end;
end
else
@ -20139,9 +20266,9 @@ begin
{$ENDIF}
if Result=-1 then
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112931));
if not (rrfReadable in RHS.Flags) then
exit(RaiseIncompatType);
exit(RaiseIncompatType(20190215112934));
end;
function TPasResolver.CheckAssignCompatibilityArrayType(const LHS,
@ -20356,9 +20483,9 @@ function TPasResolver.CheckAssignCompatibilityArrayType(const LHS,
exit;
end;
// dynarr:=dynarr -> check element type
ComputeElement(ArrType.ElType,ElTypeResolved,[rcType]);
ComputeElement(GetArrayElType(ArrType),ElTypeResolved,[rcType]);
Include(ElTypeResolved.Flags,rrfWritable);
ComputeElement(RArrayType.ElType,ValueResolved,[rcType]);
ComputeElement(GetArrayElType(RArrayType),ValueResolved,[rcType]);
Include(ValueResolved.Flags,rrfReadable);
Result:=CheckAssignResCompatibility(ElTypeResolved,ValueResolved,ErrorEl,RaiseOnIncompatible);
exit;
@ -20540,6 +20667,12 @@ begin
if (LHS.BaseType<>btContext) or (not (LHS.LoTypeEl is TPasArrayType)) then
RaiseInternalError(20170222230012);
LArrType:=TPasArrayType(LHS.LoTypeEl);
if (LArrType.ElType=nil) and (rrfReadable in RHS.Flags)
and (RHS.BaseType in [btArrayLit,btArrayOrSet]) then
begin
// ArrayOfConst:=[]
exit(cExact);
end;
CheckRange(LArrType,0,RHS,ErrorEl);
@ -21101,7 +21234,7 @@ function TPasResolver.CheckTypeCastArray(FromType, ToType: TPasArrayType;
ElTypeResolved.BaseType:=btNone;
exit(true);
end;
ComputeElement(ArrType.ElType,ElTypeResolved,[rcType]);
ComputeElement(GetArrayElType(ArrType),ElTypeResolved,[rcType]);
if (ElTypeResolved.BaseType<>btContext)
or (ElTypeResolved.LoTypeEl.ClassType<>TPasArrayType) then
exit(false);
@ -22082,6 +22215,8 @@ begin
exit(false);
if length(TPasArrayType(TypeEl).Ranges)<>0 then
exit(false);
if TPasArrayType(TypeEl).ElType=nil then
exit(true);// array of const is a dynamic array of TVarRec
if OptionalOpenArray and (proOpenAsDynArrays in Options) then
Result:=true
else
@ -22094,7 +22229,8 @@ begin
and (TypeEl.ClassType=TPasArrayType)
and (length(TPasArrayType(TypeEl).Ranges)=0)
and (TypeEl.Parent<>nil)
and (TypeEl.Parent.ClassType=TPasArgument);
and (TypeEl.Parent.ClassType=TPasArgument)
and (TPasArrayType(TypeEl).ElType<>nil);
end;
function TPasResolver.IsDynOrOpenArray(TypeEl: TPasType): boolean;
@ -22104,6 +22240,19 @@ begin
and (length(TPasArrayType(TypeEl).Ranges)=0);
end;
function TPasResolver.IsArrayOfConst(TypeEl: TPasType): boolean;
begin
Result:=(TypeEl<>nil) and (TypeEl.ClassType=TPasArrayType)
and (TPasArrayType(TypeEl).ElType=nil);
end;
function TPasResolver.GetArrayElType(ArrType: TPasArrayType): TPasType;
begin
Result:=ArrType.ElType;
if Result=nil then
Result:=GetTVarRec(ArrType);
end;
function TPasResolver.IsVarInit(Expr: TPasExpr): boolean;
var
C: TClass;

View File

@ -250,7 +250,7 @@ type
procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
UseFull: boolean); virtual;
procedure UseTypeInfo(El: TPasElement); virtual;
procedure UseModule(aModule: TPasModule; Mode: TPAUseMode); virtual;
function UseModule(aModule: TPasModule; Mode: TPAUseMode): boolean; virtual;
procedure UseSection(Section: TPasSection; Mode: TPAUseMode); virtual;
procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
procedure UseImplElement(El: TPasImplElement); virtual;
@ -1135,7 +1135,7 @@ begin
UseElement(El,rraNone,true);
end;
procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
function TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode): boolean;
procedure UseInitFinal(ImplBlock: TPasImplBlock);
var
@ -1154,7 +1154,8 @@ procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
var
ModScope: TPasModuleScope;
begin
if ElementVisited(aModule,Mode) then exit;
if ElementVisited(aModule,Mode) then exit(false);
Result:=true;
{$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode{$IFDEF pas2js},' ',aModule.PasElementId{$ENDIF});
@ -1179,6 +1180,10 @@ begin
UseClassOrRecType(ModScope.RangeErrorClass,paumElement);
if ModScope.RangeErrorConstructor<>nil then
UseProcedure(ModScope.RangeErrorConstructor);
// no need to use here ModScope.AssertClass, it is used by Assert
// no need to use here ModScope.AssertMsgConstructor
// no need to use here ModScope.AssertDefConstructor
// no need to use here ModScope.SystemTVarRec
if Mode=paumElement then
// e.g. a reference: unitname.identifier

View File

@ -1892,32 +1892,42 @@ begin
case CurToken of
tkSquaredBraceOpen:
begin
repeat
NextToken;
if po_arrayrangeexpr in Options then
begin
RangeExpr:=DoParseExpression(Result);
Result.AddRange(RangeExpr);
end
else if CurToken<>tkSquaredBraceClose then
S:=S+CurTokenText;
if CurToken=tkSquaredBraceClose then
break
else if CurToken=tkComma then
continue
else if po_arrayrangeexpr in Options then
ParseExcTokenError(']');
until false;
Result.IndexRange:=S;
ExpectToken(tkOf);
Result.ElType := ParseType(Result,CurSourcePos);
// static array
if Parent is TPasArgument then
ParseExcTokenError('of');
repeat
NextToken;
if po_arrayrangeexpr in Options then
begin
RangeExpr:=DoParseExpression(Result);
Result.AddRange(RangeExpr);
end
else if CurToken<>tkSquaredBraceClose then
S:=S+CurTokenText;
if CurToken=tkSquaredBraceClose then
break
else if CurToken=tkComma then
continue
else if po_arrayrangeexpr in Options then
ParseExcTokenError(']');
until false;
Result.IndexRange:=S;
ExpectToken(tkOf);
Result.ElType := ParseType(Result,CurSourcePos);
end;
tkOf:
begin
NextToken;
if CurToken = tkConst then
// array of const
begin
if not (Parent is TPasArgument) then
ParseExcExpectedIdentifier;
end
else
begin
if (CurToken=tkarray) and (Parent is TPasArgument) then
ParseExcExpectedIdentifier;
UngetToken;
Result.ElType := ParseType(Result,CurSourcePos);
end;

View File

@ -103,7 +103,8 @@ type
PTestResolverReferenceData = ^TTestResolverReferenceData;
TSystemUnitPart = (
supTObject
supTObject,
supTVarRec
);
TSystemUnitParts = set of TSystemUnitPart;
@ -800,9 +801,12 @@ type
Procedure TestArray_ConstDynArrayWrite;
Procedure TestArray_ConstOpenArrayWriteFail;
Procedure TestArray_ForIn;
Procedure TestArray_Arg_AnonymousStaticFail;
Procedure TestArray_Arg_AnonymousMultiDimFail;
// array of const
Procedure TestArrayOfConst;
Procedure TestArrayOfConst_PassDynArrayOfIntFail;
// static arrays
Procedure TestArrayIntRange_OutOfRange;
@ -2074,6 +2078,20 @@ begin
' function ToString: String; virtual;',
' end;']);
end;
if supTVarRec in Parts then
begin
Intf.AddStrings([
'const',
' vtInteger = 0;',
' vtBoolean = 1;',
'type',
' PVarRec = ^TVarRec;',
' TVarRec = record',
' case VType : sizeint of',
' vtInteger : (VInteger: Longint);',
' vtBoolean : (VBoolean: Boolean);',
' end;']);
end;
Intf.Add('var');
Intf.Add(' ExitCode: Longint = 0;');
@ -14324,14 +14342,74 @@ begin
CheckParamsExpr_pkSet_Markers;
end;
procedure TTestResolver.TestArrayOfConst;
procedure TTestResolver.TestArray_Arg_AnonymousStaticFail;
begin
StartProgram(false);
Add([
'procedure DoIt(args: array of const);',
'begin end;',
'procedure DoIt(args: array[1..2] of word);',
'begin',
'end;',
'begin']);
CheckResolverException('not yet implemented: :TPasArrayType [20171005235610] array of const',nNotYetImplemented);
CheckParserException('Expected "of"',nParserExpectTokenError);
end;
procedure TTestResolver.TestArray_Arg_AnonymousMultiDimFail;
begin
StartProgram(false);
Add([
'procedure DoIt(args: array of array of word);',
'begin',
'end;',
'begin']);
CheckParserException(SParserExpectedIdentifier,nParserExpectedIdentifier);
end;
procedure TTestResolver.TestArrayOfConst;
begin
StartProgram(true,[supTVarRec]);
Add([
'type',
' TArrOfVarRec = array of TVarRec;',
'procedure DoIt(args: array of const);',
'var',
' i: longint;',
' v: TVarRec;',
' a: TArrOfVarRec;',
'begin',
' DoIt(args);',
' DoIt(a);',
' DoIt([]);',
' DoIt([1]);',
' DoIt([i]);',
' DoIt([true,''foo'',''c'',1.3,nil,@DoIt]);',
' for i:=low(args) to high(args) do begin',
' v:=args[i];',
' case args[i].VType of',
' vtInteger: if length(args)=args[i].VInteger then ;',
' end;',
' end;',
' for v in Args do ;',
' args:=nil;',
' SetLength(args,2);',
'end;',
'begin']);
ParseProgram;
end;
procedure TTestResolver.TestArrayOfConst_PassDynArrayOfIntFail;
begin
StartProgram(true,[supTVarRec]);
Add([
'type',
' TArr = array of word;',
'procedure DoIt(args: array of const);',
'begin',
'end;',
'var a: TArr;',
'begin',
' DoIt(a)']);
CheckResolverException('Incompatible type arg no. 1: Got "TArr", expected "array of const"',
nIncompatibleTypeArgNo);
end;
procedure TTestResolver.TestArrayIntRange_OutOfRange;