fcl-passrc: resolver: TGuid record

git-svn-id: trunk@38790 -
This commit is contained in:
Mattias Gaertner 2018-04-19 11:59:32 +00:00
parent 2512550834
commit fb8690428c
5 changed files with 406 additions and 136 deletions

View File

@ -1145,6 +1145,11 @@ type
cLossyConversion = cExact+100000;
cCompatibleWithDefaultParams = cLossyConversion+100000;
cIncompatible = High(integer);
var
cTGUIDToString: integer;
cStringToTGUID: integer;
cInterfaceToTGUID: integer;
cInterfaceToString: integer;
type
TFindCallElData = record
Params: TParamsExpr;
@ -1279,6 +1284,8 @@ type
procedure CheckConditionExpr(El: TPasExpr; const ResolvedEl: TPasResolverResult); virtual;
procedure CheckProcSignatureMatch(DeclProc, ImplProc: TPasProcedure; CheckNames: boolean);
procedure CheckPendingForwardProcs(El: TPasElement);
procedure ComputeUnaryNot(El: TUnaryExpr; var ResolvedEl: TPasResolverResult;
Flags: TPasResolverComputeFlags); virtual;
procedure ComputeBinaryExpr(Bin: TBinaryExpr;
out ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
StartEl: TPasElement);
@ -1568,8 +1575,8 @@ type
const ArrayResolved: TPasResolverResult; RaiseOnError: boolean;
Flags: TPasResolverComputeFlags; StartEl: TPasElement = nil): integer;
function CheckEqualCompatibilityUserType(
const TypeA, TypeB: TPasResolverResult; ErrorEl: TPasElement;
RaiseOnIncompatible: boolean): integer;
const LHS, RHS: TPasResolverResult; ErrorEl: TPasElement;
RaiseOnIncompatible: boolean): integer; // LHS.BaseType=btContext=RHS.BaseType and both rrfReadable
function CheckTypeCast(El: TPasType; Params: TParamsExpr; RaiseOnError: boolean): integer;
function CheckTypeCastRes(const FromResolved, ToResolved: TPasResolverResult;
ErrorEl: TPasElement; RaiseOnError: boolean): integer; virtual;
@ -1645,6 +1652,8 @@ type
function IsInterfaceType(const ResolvedEl: TPasResolverResult;
IntfType: TPasClassInterfaceType): boolean; overload;
function IsInterfaceType(TypeEl: TPasType; IntfType: TPasClassInterfaceType): boolean; overload;
function IsTGUID(RecTypeEl: TPasRecordType): boolean; virtual;
function IsTGUIDString(const ResolvedEl: TPasResolverResult): boolean; virtual;
function ProcNeedsParams(El: TPasProcedureType): boolean;
function IsProcOverride(AncestorProc, DescendantProc: TPasProcedure): boolean;
function GetTopLvlProc(El: TPasElement): TPasProcedure;
@ -8018,6 +8027,14 @@ begin
end;
end;
procedure TPasResolver.ComputeUnaryNot(El: TUnaryExpr;
var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
begin
RaiseMsg(20180208121532,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
[OpcodeStrings[El.OpCode],GetResolverResultDescription(ResolvedEl)],El);
if Flags=[] then ;
end;
procedure TPasResolver.AddModule(El: TPasModule);
var
C: TClass;
@ -9267,6 +9284,11 @@ begin
ResolvedEl.BaseType:=ResolvedTypeEl.BaseType;
ResolvedEl.TypeEl:=ResolvedTypeEl.TypeEl;
if not (rrfReadable in ResolvedEl.Flags) then
begin
// typecast a type to a value, e.g. Pointer(TObject)
ResolvedEl.Flags:=ResolvedEl.Flags+[rrfReadable];
end;
if (DeclEl is TPasClassType) and (ParamTypeEl is TPasClassType)
and (TPasClassType(DeclEl).ObjKind<>TPasClassType(ParamTypeEl).ObjKind) then
begin
@ -11815,6 +11837,12 @@ begin
FBaseTypeLength:=btInt64;
FDynArrayMinIndex:=0;
FDynArrayMaxIndex:=High(int64);
cTGUIDToString:=cTypeConversion+1;
cStringToTGUID:=cTypeConversion+1;
cInterfaceToTGUID:=cTypeConversion+1;
cInterfaceToString:=cTypeConversion+2;
FScopeClass_Class:=TPasClassScope;
FScopeClass_InitialFinalization:=TPasInitialFinalizationScope;
FScopeClass_Module:=TPasModuleScope;
@ -14158,7 +14186,7 @@ var
Handled: Boolean;
C: TClass;
LBT, RBT: TResolverBaseType;
LRange, RValue: TResEvalValue;
LRange, RValue, Value: TResEvalValue;
RightSubResolved: TPasResolverResult;
wc: WideChar;
begin
@ -14260,28 +14288,47 @@ begin
RaiseNotYetImplemented(20171108195216,ErrorEl);
end;
end
else if (LBT in btAllStrings)
and (RBT in btAllStringAndChars) then
case LBT of
btAnsiString:
if RBT in [btAnsiChar,btShortString,btRawByteString] then
Result:=cCompatible
else if (LBT in btAllStrings) then
begin
if (RBT in btAllStringAndChars) then
case LBT of
btAnsiString:
if RBT in [btAnsiChar,btShortString,btRawByteString] then
Result:=cCompatible
else
Result:=cLossyConversion;
btShortString:
if RBT=btAnsiChar then
Result:=cCompatible
else
Result:=cLossyConversion;
btWideString,btUnicodeString:
Result:=cCompatible;
btRawByteString:
if RBT in [btAnsiChar,btAnsiString,btShortString] then
Result:=cCompatible
else
Result:=cLossyConversion;
else
Result:=cLossyConversion;
btShortString:
if RBT=btAnsiChar then
Result:=cCompatible
else
Result:=cLossyConversion;
btWideString,btUnicodeString:
Result:=cCompatible;
btRawByteString:
if RBT in [btAnsiChar,btAnsiString,btShortString] then
Result:=cCompatible
else
Result:=cLossyConversion;
else
RaiseNotYetImplemented(20170417195208,ErrorEl,BaseTypeNames[LBT]);
RaiseNotYetImplemented(20170417195208,ErrorEl,BaseTypeNames[LBT]);
end
else if RBT=btContext then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if RTypeEl.ClassType=TPasClassType then
begin
if (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUIDString(LHS) then
// aGUIDString:=IntfTypeOrVar
exit(cInterfaceToString); // no check for rrfReadable
end
else if RTypeEl.ClassType=TPasRecordType then
begin
if IsTGUID(TPasRecordType(RTypeEl)) then
// aString:=GUID
Result:=cTGUIDToString;
end;
end;
end
else if (LBT in btAllInteger)
and (RBT in btAllInteger) then
@ -14532,6 +14579,25 @@ begin
end;
end;
end;
end
else if TypeEl.ClassType=TPasRecordType then
begin
if (RBT in btAllStrings) and IsTGUID(TPasRecordType(TypeEl))
and (rrfReadable in RHS.Flags) then
begin
// GUIDVar := string, e.g. IObjectInstance: TGuid = '{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}'
Value:=Eval(RHS,[refConst]);
try
if Value=nil then
if RaiseOnIncompatible then
RaiseXExpectedButYFound(20180414105916,'string literal','string', ErrorEl)
else
exit(cIncompatible);
finally
ReleaseEvalValue(Value);
end;
Result:=cStringToTGUID;
end;
end;
end;
end;
@ -14621,7 +14687,7 @@ function TPasResolver.CheckEqualResCompatibility(const LHS,
RHS: TPasResolverResult; LErrorEl: TPasElement; RaiseOnIncompatible: boolean;
RErrorEl: TPasElement): integer;
var
TypeEl, RTypeEl: TPasType;
LTypeEl, RTypeEl: TPasType;
ResolvedEl: TPasResolverResult;
begin
Result:=cIncompatible;
@ -14634,20 +14700,35 @@ begin
begin
if (LHS.BaseType=btContext) then
begin
TypeEl:=ResolveAliasType(LHS.TypeEl);
if (TypeEl.ClassType=TPasClassType)
and (ResolveAliasTypeEl(LHS.IdentEl)=TypeEl) then
LTypeEl:=ResolveAliasType(LHS.TypeEl);
if (LTypeEl.ClassType=TPasClassType)
and (ResolveAliasTypeEl(LHS.IdentEl)=LTypeEl) then
begin
// LHS is class type, e.g. TObject or IInterface
if RHS.BaseType=btNil then
exit(cExact)
else if RHS.BaseType in btAllStrings then
begin
if (rrfReadable in RHS.Flags)
and (TPasClassType(LTypeEl).ObjKind=okInterface)
and IsTGUIDString(RHS) then
// e.g. IUnknown=aGUIDString
exit(cInterfaceToString);
end
else if (RHS.BaseType=btContext) then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if (RTypeEl.ClassType=TPasClassOfType)
and (rrfReadable in RHS.Flags)
and (TPasClassType(TypeEl).ObjKind=okClass) then
and (TPasClassType(LTypeEl).ObjKind=okClass) then
// for example if TImage=ImageClass then
exit(cExact);
exit(cExact)
else if (RTypeEl.ClassType=TPasRecordType)
and (rrfReadable in RHS.Flags)
and (TPasClassType(LTypeEl).ObjKind=okInterface)
and IsTGUID(TPasRecordType(RTypeEl)) then
// e.g. if IUnknown=TGuidVar then
exit(cInterfaceToTGUID);
end;
end;
end;
@ -14661,16 +14742,31 @@ begin
if (RTypeEl.ClassType=TPasClassType)
and (ResolveAliasTypeEl(RHS.IdentEl)=RTypeEl) then
begin
// RHS is class type, e.g. TObject or IInterface
if LHS.BaseType=btNil then
exit(cExact)
else if LHS.BaseType in btAllStrings then
begin
if (rrfReadable in LHS.Flags)
and (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUIDString(LHS) then
// e.g. aGUIDString=IUnknown
exit(cInterfaceToString);
end
else if (LHS.BaseType=btContext) then
begin
TypeEl:=ResolveAliasType(LHS.TypeEl);
if (TypeEl.ClassType=TPasClassOfType)
LTypeEl:=ResolveAliasType(LHS.TypeEl);
if (LTypeEl.ClassType=TPasClassOfType)
and (rrfReadable in LHS.Flags)
and (TPasClassType(RTypeEl).ObjKind=okClass) then
// for example if ImageClass=TImage then
exit(cExact);
exit(cExact)
else if (LTypeEl.ClassType=TPasRecordType)
and (rrfReadable in LHS.Flags)
and (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUID(TPasRecordType(LTypeEl)) then
// e.g. if TGuidVar=IUnknown then
exit(cInterfaceToTGUID);
end;
end;
end;
@ -14716,7 +14812,22 @@ begin
if RHS.BaseType in btAllStringAndChars then
exit(cCompatible)
else if (RHS.BaseType=btRange) and (RHS.SubType in btAllChars) then
exit(cCompatible);
exit(cCompatible)
else if RHS.BaseType=btContext then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if (RTypeEl.ClassType=TPasClassType) then
begin
if (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUIDString(LHS) then
// e.g. aGUIDString=IntfVar
exit(cInterfaceToString);
end
else if (RTypeEl.ClassType=TPasRecordType)
and IsTGUID(TPasRecordType(RTypeEl)) then
// e.g. aString=GuidVar
exit(cTGUIDToString);
end;
end
else if LHS.BaseType=btNil then
begin
@ -14724,12 +14835,12 @@ begin
exit(cExact)
else if RHS.BaseType=btContext then
begin
TypeEl:=RHS.TypeEl;
if (TypeEl.ClassType=TPasClassType)
or (TypeEl.ClassType=TPasClassOfType)
or (TypeEl.ClassType=TPasPointerType)
or (TypeEl is TPasProcedureType)
or IsDynArray(TypeEl) then
LTypeEl:=RHS.TypeEl;
if (LTypeEl.ClassType=TPasClassType)
or (LTypeEl.ClassType=TPasClassOfType)
or (LTypeEl.ClassType=TPasPointerType)
or (LTypeEl is TPasProcedureType)
or IsDynArray(LTypeEl) then
exit(cExact);
end;
if RaiseOnIncompatible then
@ -14744,12 +14855,12 @@ begin
exit(cExact)
else if LHS.BaseType=btContext then
begin
TypeEl:=LHS.TypeEl;
if (TypeEl.ClassType=TPasClassType)
or (TypeEl.ClassType=TPasClassOfType)
or (TypeEl.ClassType=TPasPointerType)
or (TypeEl is TPasProcedureType)
or IsDynArray(TypeEl) then
LTypeEl:=LHS.TypeEl;
if (LTypeEl.ClassType=TPasClassType)
or (LTypeEl.ClassType=TPasClassOfType)
or (LTypeEl.ClassType=TPasPointerType)
or (LTypeEl is TPasProcedureType)
or IsDynArray(LTypeEl) then
exit(cExact);
end;
if RaiseOnIncompatible then
@ -14806,19 +14917,19 @@ begin
end
else if LHS.SubType=btContext then
begin
TypeEl:=ResolveAliasType(LHS.TypeEl);
if TypeEl.ClassType=TPasRangeType then
LTypeEl:=ResolveAliasType(LHS.TypeEl);
if LTypeEl.ClassType=TPasRangeType then
begin
ComputeElement(TPasRangeType(TypeEl).RangeExpr.left,ResolvedEl,[rcConstant]);
ComputeElement(TPasRangeType(LTypeEl).RangeExpr.left,ResolvedEl,[rcConstant]);
if ResolvedEl.BaseType=btContext then
begin
TypeEl:=ResolveAliasType(ResolvedEl.TypeEl);
if TypeEl.ClassType=TPasEnumType then
LTypeEl:=ResolveAliasType(ResolvedEl.TypeEl);
if LTypeEl.ClassType=TPasEnumType then
begin
if RHS.BaseType=btContext then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if (TypeEl=RTypeEl) then
if (LTypeEl=RTypeEl) then
exit(cCompatible);
end;
end;
@ -14828,8 +14939,8 @@ begin
end
else if LHS.BaseType=btContext then
begin
TypeEl:=ResolveAliasType(LHS.TypeEl);
if TypeEl.ClassType=TPasEnumType then
LTypeEl:=ResolveAliasType(LHS.TypeEl);
if LTypeEl.ClassType=TPasEnumType then
begin
if RHS.BaseType=btRange then
begin
@ -14840,11 +14951,49 @@ begin
if ResolvedEl.BaseType=btContext then
begin
RTypeEl:=ResolveAliasType(ResolvedEl.TypeEl);
if TypeEl=RTypeEl then
if LTypeEl=RTypeEl then
exit(cCompatible);
end;
end;
end;
end
else if LTypeEl.ClassType=TPasClassType then
begin
if TPasClassType(LTypeEl).ObjKind=okInterface then
begin
if RHS.BaseType in btAllStrings then
begin
if IsTGUIDString(RHS) then
// e.g. IntfVar=aGUIDString
exit(cInterfaceToString);
end
else if RHS.BaseType=btContext then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if (RTypeEl.ClassType=TPasRecordType)
and IsTGUID(TPasRecordType(RTypeEl)) then
// e.g. IntfVar=GuidVar
exit(cInterfaceToTGUID);
end;
end;
end
else if LTypeEl.ClassType=TPasRecordType then
begin
if IsTGUID(TPasRecordType(LTypeEl)) then
begin
// LHS is TGUID
if (RHS.BaseType in btAllStrings) then
// GuidVar=aString
exit(cTGUIDToString)
else if RHS.BaseType=btContext then
begin
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if (RTypeEl.ClassType=TPasClassType)
and (TPasClassType(RTypeEl).ObjKind=okInterface) then
// GUIDVar=IntfVar
exit(cInterfaceToTGUID);
end;
end;
end;
end;
if RaiseOnIncompatible then
@ -15368,6 +15517,12 @@ begin
end
else if LTypeEl.ClassType=TPasRecordType then
begin
if (RTypeEl is TPasClassType) and (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUID(TPasRecordType(LTypeEl)) then
begin
// GUIDVar := IntfTypeOrVar
exit(cInterfaceToTGUID);
end;
// records of different type
end
else if LTypeEl.ClassType=TPasEnumType then
@ -15696,11 +15851,12 @@ begin
end;
end;
function TPasResolver.CheckEqualCompatibilityUserType(const TypeA,
TypeB: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
function TPasResolver.CheckEqualCompatibilityUserType(const LHS,
RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
): integer;
// LHS.BaseType=btContext=RHS.BaseType and both rrfReadable
var
ElA, ElB: TPasType;
LTypeEl, RTypeEl: TPasType;
AResolved, BResolved: TPasResolverResult;
function IncompatibleElements: integer;
@ -15708,89 +15864,83 @@ var
Result:=cIncompatible;
if not RaiseOnIncompatible then exit;
RaiseIncompatibleType(20170216152513,nIncompatibleTypesGotExpected,
[],ElA,ElB,ErrorEl);
[],LTypeEl,RTypeEl,ErrorEl);
end;
begin
if (TypeA.TypeEl=nil) then
if (LHS.TypeEl=nil) then
RaiseInternalError(20161007223118);
if (TypeB.TypeEl=nil) then
if (RHS.TypeEl=nil) then
RaiseInternalError(20161007223119);
ElA:=ResolveAliasType(TypeA.TypeEl);
ElB:=ResolveAliasType(TypeB.TypeEl);
if ElA=ElB then
LTypeEl:=ResolveAliasType(LHS.TypeEl);
RTypeEl:=ResolveAliasType(RHS.TypeEl);
if LTypeEl=RTypeEl then
exit(cExact);
if ElA.ClassType=TPasClassType then
if LTypeEl.ClassType=TPasClassType then
begin
if TypeA.IdentEl is TPasType then
begin
if (TypeB.IdentEl is TPasType) and (ElA=ElB) then
// e.g. if TFPMemoryImage=TFPMemoryImage then ;
exit(cExact);
if ElB.ClassType=TPasClassOfType then
begin
// e.g. if TFPMemoryImage=ImageClass then ;
Result:=CheckClassIsClass(ElA,TPasClassOfType(ElB).DestType,ErrorEl);
if (Result=cIncompatible) and RaiseOnIncompatible then
RaiseIncompatibleTypeRes(20180324190723,nTypesAreNotRelatedXY,[],TypeA,TypeB,ErrorEl);
exit;
end;
end
else if ElB.ClassType=TPasClassType then
if RTypeEl.ClassType=TPasClassType then
begin
// e.g. if Sender=Button1 then
Result:=CheckSrcIsADstType(TypeA,TypeB,ErrorEl);
Result:=CheckSrcIsADstType(LHS,RHS,ErrorEl);
if Result=cIncompatible then
Result:=CheckSrcIsADstType(TypeB,TypeA,ErrorEl);
Result:=CheckSrcIsADstType(RHS,LHS,ErrorEl);
if (Result=cIncompatible) and RaiseOnIncompatible then
RaiseIncompatibleTypeRes(20180324190757,nTypesAreNotRelatedXY,[],TypeA,TypeB,ErrorEl);
exit;
end;
exit(IncompatibleElements);
end
else if ElA.ClassType=TPasClassOfType then
begin
if ElB.ClassType=TPasClassOfType then
begin
// for example: if ImageClass=ImageClass then
Result:=CheckClassIsClass(TPasClassOfType(ElA).DestType,
TPasClassOfType(ElB).DestType,ErrorEl);
if Result=cIncompatible then
Result:=CheckClassIsClass(TPasClassOfType(ElB).DestType,
TPasClassOfType(ElA).DestType,ErrorEl);
if (Result=cIncompatible) and RaiseOnIncompatible then
RaiseIncompatibleTypeRes(20180324190804,nTypesAreNotRelatedXY,[],TypeA,TypeB,ErrorEl);
RaiseIncompatibleTypeRes(20180324190757,nTypesAreNotRelatedXY,[],LHS,RHS,ErrorEl);
exit;
end
else if TypeB.IdentEl is TPasClassType then
else if RTypeEl.ClassType=TPasRecordType then
begin
// for example: if ImageClass=TFPMemoryImage then
Result:=CheckClassIsClass(TPasClassType(TypeB.IdentEl),
TPasClassOfType(ElA).DestType,ErrorEl);
if (TPasClassType(LTypeEl).ObjKind=okInterface)
and IsTGUID(TPasRecordType(RTypeEl)) then
// IntfVar=GuidVar
exit(cInterfaceToTGUID);
end;
exit(IncompatibleElements);
end
else if LTypeEl.ClassType=TPasClassOfType then
begin
if RTypeEl.ClassType=TPasClassOfType then
begin
// for example: if ImageClass=ImageClass then
Result:=CheckClassIsClass(TPasClassOfType(LTypeEl).DestType,
TPasClassOfType(RTypeEl).DestType,ErrorEl);
if Result=cIncompatible then
Result:=CheckClassIsClass(TPasClassOfType(RTypeEl).DestType,
TPasClassOfType(LTypeEl).DestType,ErrorEl);
if (Result=cIncompatible) and RaiseOnIncompatible then
RaiseIncompatibleTypeRes(20180324190827,nTypesAreNotRelatedXY,[],TypeA,TypeB,ErrorEl);
RaiseIncompatibleTypeRes(20180324190804,nTypesAreNotRelatedXY,[],LHS,RHS,ErrorEl);
exit;
end;
exit(IncompatibleElements);
end
else if ElA.ClassType=TPasEnumType then
else if LTypeEl.ClassType=TPasEnumType then
begin
// enums of different type
if not RaiseOnIncompatible then
exit(cIncompatible);
if ElB.ClassType=TPasEnumValue then
if RTypeEl.ClassType=TPasEnumValue then
RaiseIncompatibleType(20170216152523,nIncompatibleTypesGotExpected,
[],TPasEnumType(ElA),TPasEnumType(ElB),ErrorEl)
[],TPasEnumType(LTypeEl),TPasEnumType(RTypeEl),ErrorEl)
else
exit(IncompatibleElements);
end
else if ElA.ClassType=TPasSetType then
else if LTypeEl.ClassType=TPasRecordType then
begin
if ElB.ClassType=TPasSetType then
if RTypeEl.ClassType=TPasClassType then
begin
ComputeElement(TPasSetType(ElA).EnumType,AResolved,[]);
ComputeElement(TPasSetType(ElB).EnumType,BResolved,[]);
if (TPasClassType(RTypeEl).ObjKind=okInterface)
and IsTGUID(TPasRecordType(LTypeEl)) then
// GuidVar=IntfVar
exit(cInterfaceToTGUID);
end;
end
else if LTypeEl.ClassType=TPasSetType then
begin
if RTypeEl.ClassType=TPasSetType then
begin
ComputeElement(TPasSetType(LTypeEl).EnumType,AResolved,[]);
ComputeElement(TPasSetType(RTypeEl).EnumType,BResolved,[]);
if (AResolved.TypeEl<>nil)
and (AResolved.TypeEl=BResolved.TypeEl) then
exit(cExact);
@ -15807,12 +15957,12 @@ begin
else
exit(IncompatibleElements);
end
else if (ElA is TPasProcedureType) and (rrfReadable in TypeA.Flags) then
else if (LTypeEl is TPasProcedureType) and (rrfReadable in LHS.Flags) then
begin
if (ElB is TPasProcedureType) and (rrfReadable in TypeB.Flags) then
if (RTypeEl is TPasProcedureType) and (rrfReadable in RHS.Flags) then
begin
// e.g. ProcVar1 = ProcVar2
if CheckProcTypeCompatibility(TPasProcedureType(ElA),TPasProcedureType(ElB),
if CheckProcTypeCompatibility(TPasProcedureType(LTypeEl),TPasProcedureType(RTypeEl),
false,nil,false) then
exit(cExact);
end
@ -15987,19 +16137,7 @@ begin
and (not TPasClassType(FromTypeEl).IsExternal) then
begin
// e.g. intftype(classinstvar)
if msDelphi in CurrentParser.CurrentModeswitches then
begin
// delphi: classinstvar must implement intftype
if GetClassImplementsIntf(TPasClassType(FromTypeEl),TPasClassType(ToTypeEl))<>nil then
Result:=cCompatible
else
Result:=cIncompatible;
end
else
begin
// objfpc: is checked at runtime
Result:=cCompatible;
end;
Result:=cCompatible;
end;
end
else if TPasClassType(FromTypeEl).ObjKind=okInterface then
@ -16454,11 +16592,12 @@ begin
RaiseMsg(20170216152532,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
[OpcodeStrings[TUnaryExpr(El).OpCode],GetResolverResultDescription(ResolvedEl)],El);
eopNot:
if ResolvedEl.BaseType in (btAllInteger+btAllBooleans) then
exit
else
RaiseMsg(20180208121532,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
[OpcodeStrings[TUnaryExpr(El).OpCode],GetResolverResultDescription(ResolvedEl)],El);
begin
if ResolvedEl.BaseType in (btAllInteger+btAllBooleans) then
else
ComputeUnaryNot(TUnaryExpr(El),ResolvedEl,Flags);
exit;
end;
eopAddress:
if (ResolvedEl.BaseType=btProc) and (ResolvedEl.IdentEl is TPasProcedure) then
begin
@ -17081,6 +17220,65 @@ begin
and (TPasClassType(TypeEl).InterfaceType=IntfType);
end;
function TPasResolver.IsTGUID(RecTypeEl: TPasRecordType): boolean;
var
Members: TFPList;
El: TPasElement;
begin
Result:=false;
if not SameText(RecTypeEl.Name,'TGUID') then exit;
if SameText(RecTypeEl.GetModule.Name,'system') then exit(true);
Members:=RecTypeEl.Members;
if Members.Count<4 then exit;
El:=TPasElement(Members[0]);
if not SameText(El.Name,'D1') then exit;
El:=TPasElement(Members[1]);
if not SameText(El.Name,'D2') then exit;
El:=TPasElement(Members[2]);
if not SameText(El.Name,'D3') then exit;
El:=TPasElement(Members[3]);
if not SameText(El.Name,'D4') then exit;
Result:=true;
end;
function TPasResolver.IsTGUIDString(const ResolvedEl: TPasResolverResult
): boolean;
var
TypeEl: TPasType;
C: TClass;
IdentEl: TPasElement;
begin
if not (ResolvedEl.BaseType in btAllStrings) then
exit(false);
if (ResolvedEl.ExprEl<>nil) and (ResolvedEl.TypeEl<>nil) then
exit(true); // untyped string literal
IdentEl:=ResolvedEl.IdentEl;
if IdentEl<>nil then
begin
C:=IdentEl.ClassType;
if C.InheritsFrom(TPasVariable) then
TypeEl:=TPasVariable(IdentEl).VarType
else if C=TPasArgument then
TypeEl:=TPasArgument(IdentEl).ArgType
else if C=TPasResultElement then
TypeEl:=TPasResultElement(IdentEl).ResultType
else
TypeEl:=nil;
while TypeEl<>nil do
begin
if TypeEl.ClassType=TPasAliasType then
begin
if SameText(TypeEl.Name,'TGUIDString') then
exit(true);
TypeEl:=TPasAliasType(TypeEl).DestType;
end
else
break;
end;
end;
Result:=false;
end;
function TPasResolver.ProcNeedsParams(El: TPasProcedureType): boolean;
begin
Result:=(El.Args.Count>0) and (TPasArgument(El.Args[0]).ValueExpr=nil);

View File

@ -1585,9 +1585,12 @@ var
begin
if Mode=paumAllExports then exit;
MarkElementAsUsed(El);
if (Mode=paumAllPublic) and not ElementVisited(El,Mode) then
for i:=0 to El.Members.Count-1 do
UseVariable(TObject(El.Members[i]) as TPasVariable,rraNone,true);
if not ElementVisited(El,Mode) then
begin
if (Mode=paumAllPublic) or Resolver.IsTGUID(El) then
for i:=0 to El.Members.Count-1 do
UseVariable(TObject(El.Members[i]) as TPasVariable,rraNone,true);
end;
end;
procedure TPasAnalyzer.UseClassType(El: TPasClassType; Mode: TPAUseMode);

View File

@ -1868,7 +1868,7 @@ var
Ref: TPasElement;
begin
Ref:=Nil;
SS:=(not (po_resolvestandardtypes in FOptions)) and isSimpleTypeToken(Name);
SS:=(not (po_ResolveStandardTypes in FOptions)) and isSimpleTypeToken(Name);
if not SS then
begin
Ref:=Engine.FindElement(Name);

View File

@ -630,6 +630,7 @@ type
Procedure TestClassInterface_Enumerator;
Procedure TestClassInterface_PassTypecastClassToIntfAsVarParamFail;
Procedure TestClassInterface_PassTypecastIntfToClassAsVarParamFail;
Procedure TestClassInterface_GUID;
// with
Procedure TestWithBlock1;
@ -10511,6 +10512,7 @@ begin
' oBird,oBird2: TBird;',
' o: TObject;',
' a: TAlbatros;',
' p: pointer;',
'begin',
' if Assigned(i) then ;',
' if TypeInfo(i)=nil then ;',
@ -10534,6 +10536,7 @@ begin
' if o is IBird then ;', // FPC needs GUID
' if i is TBird then ;',
' if e is TBird then ;',
' p:=i;',
'']);
ParseProgram;
end;
@ -10681,6 +10684,52 @@ begin
CheckResolverException(sVariableIdentifierExpected,nVariableIdentifierExpected);
end;
procedure TTestResolver.TestClassInterface_GUID;
begin
StartProgram(false);
Add([
'{$interfaces corba}',
'type',
' IUnknown = interface',
' [''{F31DB68F-3010-D355-4EBA-CDD4EF4A737C}'']',
' end;',
' TObject = class end;',
' TGUID = record D1,D2,D3,D4: word; end;',
' TAliasGUID = TGUID;',
' TGUIDString = string;',
' TAliasGUIDString = TGUIDString;',
'procedure {#A}DoIt(const g: TAliasGUID); overload;',
'begin end;',
'procedure {#B}DoIt(const s: TAliasGUIDString); overload;',
'begin end;',
'var',
' i: IUnknown;',
' g: TAliasGUID = ''{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}'';',
' s: TAliasGUIDString;',
'begin',
' {@A}DoIt(IUnknown);',
' {@A}DoIt(i);',
' g:=i;',
' g:=IUnknown;',
' g:=''{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}'';',
' s:=g;',
' s:=IUnknown;',
' s:=i;',
' {@B}DoIt(s);',
' if s=IUnknown then ;',
' if IUnknown=s then ;',
' if s=i then ;',
' if i=s then ;',
' if g=IUnknown then ;',
' if IUnknown=g then ;',
' if g=i then ;',
' if i=g then ;',
' if s=g then ;',
' if g=s then ;',
'']);
ParseProgram;
end;
procedure TTestResolver.TestPropertyAssign;
begin
StartProgram(false);

View File

@ -152,6 +152,7 @@ type
procedure TestWP_ClassInterface_Delegation;
procedure TestWP_ClassInterface_COM;
procedure TestWP_ClassInterface_Typeinfo;
procedure TestWP_ClassInterface_TGUID;
// scope references
procedure TestSR_Proc_UnitVar;
@ -2719,6 +2720,25 @@ begin
AnalyzeWholeProgram;
end;
procedure TTestUseAnalyzer.TestWP_ClassInterface_TGUID;
begin
StartProgram(false);
Add([
'{$interfaces corba}',
'type',
' TGuid = record',
' {#d1_used}D1: longword;',
' {#d2_used}D2: word;',
' {#d3_used}D3: word;',
' {#d4_used}D4: array[0..7] of byte;',
' end;',
'var g,h: TGuid;',
'begin',
' if g=h then ;',
'']);
AnalyzeWholeProgram;
end;
procedure TTestUseAnalyzer.TestSR_Proc_UnitVar;
begin
StartUnit(false);