mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 12:29:18 +02:00
fcl-passrc: check generic constraint
git-svn-id: trunk@42473 -
This commit is contained in:
parent
f35e711024
commit
93c130979f
@ -190,6 +190,9 @@ const
|
|||||||
nIllegalExpressionAfterX = 3124;
|
nIllegalExpressionAfterX = 3124;
|
||||||
nMethodHidesNonVirtualMethodExactly = 3125;
|
nMethodHidesNonVirtualMethodExactly = 3125;
|
||||||
nDuplicatePublishedMethodXAtY = 3126;
|
nDuplicatePublishedMethodXAtY = 3126;
|
||||||
|
nConstraintXSpecifiedMoreThanOnce = 3127;
|
||||||
|
nConstraintXAndConstraintYCannotBeTogether = 3128;
|
||||||
|
nXIsNotAValidConstraint = 3129;
|
||||||
|
|
||||||
// using same IDs as FPC
|
// using same IDs as FPC
|
||||||
nVirtualMethodXHasLowerVisibility = 3250; // was 3050
|
nVirtualMethodXHasLowerVisibility = 3250; // was 3050
|
||||||
@ -327,6 +330,9 @@ resourcestring
|
|||||||
sIllegalExpressionAfterX = 'illegal expression after %s';
|
sIllegalExpressionAfterX = 'illegal expression after %s';
|
||||||
sMethodHidesNonVirtualMethodExactly = 'method hides identifier at "%s". Use reintroduce';
|
sMethodHidesNonVirtualMethodExactly = 'method hides identifier at "%s". Use reintroduce';
|
||||||
sDuplicatePublishedMethodXAtY = 'Duplicate published method "%s" at %s';
|
sDuplicatePublishedMethodXAtY = 'Duplicate published method "%s" at %s';
|
||||||
|
sConstraintXSpecifiedMoreThanOnce = 'Constraint ''%s'' specified more than once';
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether = '''%s'' constraint and ''%s'' constraint cannot be specified together';
|
||||||
|
sXIsNotAValidConstraint = '''%s'' is not a valid constraint';
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TResolveData - base class for data stored in TPasElement.CustomData }
|
{ TResolveData - base class for data stored in TPasElement.CustomData }
|
||||||
|
@ -5821,10 +5821,19 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
Expr: TPasExpr;
|
Expr: TPasExpr;
|
||||||
Value: String;
|
Value: String;
|
||||||
|
IsClass, IsRecord, IsConstructor: Boolean;
|
||||||
|
LastType: TPasType;
|
||||||
|
ResolvedEl: TPasResolverResult;
|
||||||
|
MemberType: TPasMembersType;
|
||||||
|
aClass: TPasClassType;
|
||||||
begin
|
begin
|
||||||
{$IFDEF VerbosePasResolver}
|
{$IFDEF VerbosePasResolver}
|
||||||
writeln('TPasResolver.FinishGenericTemplateType ',GetObjName(El),' El.Parent=',GetObjName(El.Parent),' Constraints=',length(El.Constraints));
|
writeln('TPasResolver.FinishGenericTemplateType ',GetObjName(El),' El.Parent=',GetObjName(El.Parent),' Constraints=',length(El.Constraints));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
IsClass:=false;
|
||||||
|
IsRecord:=false;
|
||||||
|
IsConstructor:=false;
|
||||||
|
LastType:=nil;
|
||||||
for i:=0 to length(El.Constraints)-1 do
|
for i:=0 to length(El.Constraints)-1 do
|
||||||
begin
|
begin
|
||||||
Expr:=El.Constraints[i];
|
Expr:=El.Constraints[i];
|
||||||
@ -5832,8 +5841,102 @@ begin
|
|||||||
begin
|
begin
|
||||||
Value:=TPrimitiveExpr(Expr).Value;
|
Value:=TPrimitiveExpr(Expr).Value;
|
||||||
if SameText(Value,'class') then
|
if SameText(Value,'class') then
|
||||||
; // ToDo
|
begin
|
||||||
end;
|
if IsClass then
|
||||||
|
RaiseMsg(20190720202412,nConstraintXSpecifiedMoreThanOnce,
|
||||||
|
sConstraintXSpecifiedMoreThanOnce,['class'],Expr);
|
||||||
|
if IsRecord then
|
||||||
|
RaiseMsg(20190720202516,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['record','class'],Expr);
|
||||||
|
if LastType<>nil then
|
||||||
|
RaiseMsg(20190720205708,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,'class'],Expr);
|
||||||
|
IsClass:=true;
|
||||||
|
end
|
||||||
|
else if SameText(Value,'record') then
|
||||||
|
begin
|
||||||
|
if IsRecord then
|
||||||
|
RaiseMsg(20190720203028,nConstraintXSpecifiedMoreThanOnce,
|
||||||
|
sConstraintXSpecifiedMoreThanOnce,['record'],Expr);
|
||||||
|
if IsClass then
|
||||||
|
RaiseMsg(20190720203039,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['class','record'],Expr);
|
||||||
|
if IsConstructor then
|
||||||
|
RaiseMsg(20190720203056,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['constructor','record'],Expr);
|
||||||
|
if LastType<>nil then
|
||||||
|
RaiseMsg(20190720205938,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,'record'],Expr);
|
||||||
|
IsRecord:=true;
|
||||||
|
end
|
||||||
|
else if SameText(Value,'constructor') then
|
||||||
|
begin
|
||||||
|
if IsConstructor then
|
||||||
|
RaiseMsg(20190720203123,nConstraintXSpecifiedMoreThanOnce,
|
||||||
|
sConstraintXSpecifiedMoreThanOnce,['constructor'],Expr);
|
||||||
|
if IsRecord then
|
||||||
|
RaiseMsg(20190720203148,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['record','constructor'],Expr);
|
||||||
|
if LastType<>nil then
|
||||||
|
RaiseMsg(20190720210005,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,'constructor'],Expr);
|
||||||
|
IsConstructor:=true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// type identifier: class, record or interface
|
||||||
|
ResolveNameExpr(Expr,Value,rraNone);
|
||||||
|
ComputeElement(Expr,ResolvedEl,[rcType]);
|
||||||
|
if (ResolvedEl.BaseType<>btContext)
|
||||||
|
or not (ResolvedEl.IdentEl is TPasMembersType) then
|
||||||
|
begin
|
||||||
|
RaiseMsg(20190720204604,nXIsNotAValidConstraint,sXIsNotAValidConstraint,
|
||||||
|
[Value],Expr);
|
||||||
|
end;
|
||||||
|
MemberType:=TPasMembersType(ResolvedEl.LoTypeEl);
|
||||||
|
if IsRecord then
|
||||||
|
RaiseMsg(20190720210130,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['record',MemberType.Name],Expr);
|
||||||
|
if IsClass then
|
||||||
|
RaiseMsg(20190720210202,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['class',MemberType.Name],Expr);
|
||||||
|
if IsConstructor then
|
||||||
|
RaiseMsg(20190720210244,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,['constructor',MemberType.Name],Expr);
|
||||||
|
if MemberType is TPasClassType then
|
||||||
|
begin
|
||||||
|
aClass:=TPasClassType(MemberType);
|
||||||
|
case aClass.ObjKind of
|
||||||
|
okClass:
|
||||||
|
begin
|
||||||
|
// there can be at most one classtype constraint
|
||||||
|
if LastType<>nil then
|
||||||
|
RaiseMsg(20190720210351,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,MemberType.Name],Expr);
|
||||||
|
end;
|
||||||
|
okInterface:
|
||||||
|
begin
|
||||||
|
// there can be multiple interfacetype constraint
|
||||||
|
if not (LastType is TPasClassType) then
|
||||||
|
RaiseMsg(20190720211236,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,MemberType.Name],Expr);
|
||||||
|
if TPasClassType(LastType).ObjKind<>okInterface then
|
||||||
|
RaiseMsg(20190720211304,nConstraintXAndConstraintYCannotBeTogether,
|
||||||
|
sConstraintXAndConstraintYCannotBeTogether,[LastType.Name,MemberType.Name],Expr);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseMsg(20190720210919,nXIsNotAValidConstraint,
|
||||||
|
sXIsNotAValidConstraint,[MemberType.Name],Expr);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseMsg(20190720210809,nXIsNotAValidConstraint,
|
||||||
|
sXIsNotAValidConstraint,[MemberType.Name],Expr);
|
||||||
|
LastType:=MemberType;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseMsg(20190720203419,nParserSyntaxError,SParserSyntaxError,[],Expr);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ unit tcresolvegenerics;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, testregistry, tcresolver;
|
Classes, SysUtils, testregistry, tcresolver, PasResolveEval;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -14,7 +14,13 @@ type
|
|||||||
TTestResolveGenerics = Class(TCustomTestResolver)
|
TTestResolveGenerics = Class(TCustomTestResolver)
|
||||||
Published
|
Published
|
||||||
procedure TestGen_GenericFunction; // ToDo
|
procedure TestGen_GenericFunction; // ToDo
|
||||||
|
procedure TestGen_ConstraintStringFail;
|
||||||
procedure TestGen_ConstraintMultiClassFail;
|
procedure TestGen_ConstraintMultiClassFail;
|
||||||
|
// ToDo: constraint keyword record
|
||||||
|
// ToDo: constraint keyword class, constructor, class+constructor
|
||||||
|
// ToDo: constraint Unit2.TBird
|
||||||
|
// ToDo: constraint Unit2.TGen<word>
|
||||||
|
// ToDo: generic array
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -38,6 +44,20 @@ begin
|
|||||||
ParseProgram;
|
ParseProgram;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestResolveGenerics.TestGen_ConstraintStringFail;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'generic function DoIt<T:string>(a: T): T;',
|
||||||
|
'begin',
|
||||||
|
' Result:=a;',
|
||||||
|
'end;',
|
||||||
|
'begin',
|
||||||
|
'']);
|
||||||
|
CheckResolverException('''string'' is not a valid constraint',
|
||||||
|
nXIsNotAValidConstraint);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestResolveGenerics.TestGen_ConstraintMultiClassFail;
|
procedure TTestResolveGenerics.TestGen_ConstraintMultiClassFail;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
@ -51,11 +71,10 @@ begin
|
|||||||
'begin',
|
'begin',
|
||||||
' Result:=a;',
|
' Result:=a;',
|
||||||
'end;',
|
'end;',
|
||||||
'var b: TBird;',
|
|
||||||
'begin',
|
'begin',
|
||||||
//' b:=DoIt<TBird>(3);',
|
|
||||||
'']);
|
'']);
|
||||||
ParseProgram;
|
CheckResolverException('''TBird'' constraint and ''TBear'' constraint cannot be specified together',
|
||||||
|
nConstraintXAndConstraintYCannotBeTogether);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
Loading…
Reference in New Issue
Block a user