|
@@ -1726,7 +1726,7 @@ type
|
|
procedure AddGenericTemplateIdentifiers(GenericTemplateTypes: TFPList;
|
|
procedure AddGenericTemplateIdentifiers(GenericTemplateTypes: TFPList;
|
|
Scope: TPasIdentifierScope);
|
|
Scope: TPasIdentifierScope);
|
|
procedure AddSpecializedTemplateIdentifiers(GenericTemplateTypes: TFPList;
|
|
procedure AddSpecializedTemplateIdentifiers(GenericTemplateTypes: TFPList;
|
|
- SpecializedTypes: TPasTypeArray; Scope: TPasIdentifierScope);
|
|
|
|
|
|
+ ParamTypes: TPasTypeArray; Scope: TPasIdentifierScope);
|
|
function GetSpecializedType(El: TPasSpecializeType): TPasGenericType;
|
|
function GetSpecializedType(El: TPasSpecializeType): TPasGenericType;
|
|
function CheckSpecializeConstraints(El : TPasSpecializeType): boolean; virtual; // false = not fully specialized
|
|
function CheckSpecializeConstraints(El : TPasSpecializeType): boolean; virtual; // false = not fully specialized
|
|
function CreateSpecializedType(El: TPasSpecializeType;
|
|
function CreateSpecializedType(El: TPasSpecializeType;
|
|
@@ -14486,16 +14486,16 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TPasResolver.AddSpecializedTemplateIdentifiers(
|
|
procedure TPasResolver.AddSpecializedTemplateIdentifiers(
|
|
- GenericTemplateTypes: TFPList; SpecializedTypes: TPasTypeArray;
|
|
|
|
|
|
+ GenericTemplateTypes: TFPList; ParamTypes: TPasTypeArray;
|
|
Scope: TPasIdentifierScope);
|
|
Scope: TPasIdentifierScope);
|
|
var
|
|
var
|
|
i: Integer;
|
|
i: Integer;
|
|
TemplType: TPasGenericTemplateType;
|
|
TemplType: TPasGenericTemplateType;
|
|
begin
|
|
begin
|
|
- for i:=0 to length(SpecializedTypes)-1 do
|
|
|
|
|
|
+ for i:=0 to length(ParamTypes)-1 do
|
|
begin
|
|
begin
|
|
TemplType:=TPasGenericTemplateType(GenericTemplateTypes[i]);
|
|
TemplType:=TPasGenericTemplateType(GenericTemplateTypes[i]);
|
|
- AddIdentifier(Scope,TemplType.Name,SpecializedTypes[i],pikSimple);
|
|
|
|
|
|
+ AddIdentifier(Scope,TemplType.Name,ParamTypes[i],pikSimple);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -14534,8 +14534,8 @@ begin
|
|
|
|
|
|
if not CheckSpecializeConstraints(El) then
|
|
if not CheckSpecializeConstraints(El) then
|
|
begin
|
|
begin
|
|
- // not fully specialized -> use generic type
|
|
|
|
- // e.g. the TAnc<T> in "type TGen<T> = class(TAnc<T>)"
|
|
|
|
|
|
+ // El is actually the GenericType
|
|
|
|
+ // e.g. "type A<T> = class v: A<T> end;"
|
|
exit(GenericType);
|
|
exit(GenericType);
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -14591,48 +14591,94 @@ end;
|
|
|
|
|
|
function TPasResolver.CheckSpecializeConstraints(El: TPasSpecializeType
|
|
function TPasResolver.CheckSpecializeConstraints(El: TPasSpecializeType
|
|
): boolean;
|
|
): boolean;
|
|
-var
|
|
|
|
- Params, GenericTemplateList: TFPList;
|
|
|
|
- i, j: Integer;
|
|
|
|
- P, ParentEl: TPasElement;
|
|
|
|
- ParamType, DestType: TPasType;
|
|
|
|
- ResolvedEl, ResolvedConstraint: TPasResolverResult;
|
|
|
|
- GenTempl: TPasGenericTemplateType;
|
|
|
|
- ConExpr: TPasExpr;
|
|
|
|
- ConstraintClass: TPasClassType;
|
|
|
|
- ConToken: TToken;
|
|
|
|
-begin
|
|
|
|
- Result:=false;
|
|
|
|
- Params:=El.Params;
|
|
|
|
- DestType:=El.DestType;
|
|
|
|
- if not (DestType is TPasGenericType) then
|
|
|
|
- RaiseMsg(20190726193025,nXExpectedButYFound,sXExpectedButYFound,['generic type',DestType.Name],El);
|
|
|
|
- GenericTemplateList:=TPasGenericType(DestType).GenericTemplateTypes;
|
|
|
|
- if GenericTemplateList=nil then
|
|
|
|
- RaiseMsg(20190726193048,nXExpectedButYFound,sXExpectedButYFound,['generic templates',DestType.Name],El);
|
|
|
|
- if GenericTemplateList.Count<>Params.Count then
|
|
|
|
- RaiseMsg(20190726193107,nXExpectedButYFound,sXExpectedButYFound,['type with '+IntToStr(Params.Count)+' generic templates',DestType.Name],El);
|
|
|
|
|
|
|
|
- // check constraints
|
|
|
|
- Result:=true;
|
|
|
|
- for i:=0 to Params.Count-1 do
|
|
|
|
- begin
|
|
|
|
- P:=TPasElement(Params[i]);
|
|
|
|
- ComputeElement(P,ResolvedEl,[rcType]);
|
|
|
|
- if not (ResolvedEl.IdentEl is TPasType) then
|
|
|
|
- RaiseMsg(20190725195434,nXExpectedButYFound,sXExpectedButYFound,['type',GetResolverResultDescription(ResolvedEl)],P);
|
|
|
|
- ParamType:=TPasType(ResolvedEl.IdentEl);
|
|
|
|
- if ParamType is TPasGenericTemplateType then
|
|
|
|
|
|
+ procedure CheckTemplateFitsTemplate(ParamTemplType,
|
|
|
|
+ GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement);
|
|
|
|
+ var
|
|
|
|
+ ParamConstraints: TPasExprArray;
|
|
|
|
+ j, k: Integer;
|
|
|
|
+ ConExpr, ParamConstraintExpr: TPasExpr;
|
|
|
|
+ ConToken: TToken;
|
|
|
|
+ ResolvedConstraint, ResolvedParamCon: TPasResolverResult;
|
|
|
|
+ ConstraintClass, ParamClassType: TPasClassType;
|
|
|
|
+ begin
|
|
|
|
+ // specialize via template type (not fully specialized)
|
|
|
|
+ ParamConstraints:=ParamTemplType.Constraints;
|
|
|
|
+ for j:=0 to length(GenTempl.Constraints)-1 do
|
|
begin
|
|
begin
|
|
- // not fully specialized
|
|
|
|
- {$IFDEF VerbosePasResolver}
|
|
|
|
- writeln('TPasResolver.CheckSpecializeConstraints ',GetObjName(El),' i=',i,' P=',GetObjName(P),' ParamType=',GetObjName(ParamType));
|
|
|
|
- {$ENDIF}
|
|
|
|
- Result:=false;
|
|
|
|
- // ToDo: check if both constraints fit
|
|
|
|
- continue;
|
|
|
|
|
|
+ ConExpr:=GenTempl.Constraints[j];
|
|
|
|
+ ConToken:=GetGenericConstraintKeyword(ConExpr);
|
|
|
|
+ if ConToken<>tkEOF then
|
|
|
|
+ begin
|
|
|
|
+ // constraint is keyword
|
|
|
|
+ // -> check if keyword is in ParamConstraints
|
|
|
|
+ k:=length(ParamConstraints)-1;
|
|
|
|
+ while (k>=0) and (GetGenericConstraintKeyword(ParamConstraints[k])<>ConToken) do
|
|
|
|
+ dec(k);
|
|
|
|
+ if k<0 then
|
|
|
|
+ RaiseMsg(20190816230021,nTypeParamXIsMissingConstraintY,
|
|
|
|
+ sTypeParamXIsMissingConstraintY,[ParamTemplType.Name,TokenInfos[ConToken]],ErrorPos);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ // constraint is identifier
|
|
|
|
+ ComputeElement(ConExpr,ResolvedConstraint,[rcType]);
|
|
|
|
+ if ResolvedConstraint.IdentEl=nil then
|
|
|
|
+ RaiseMsg(20190816231846,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],ConExpr);
|
|
|
|
+ if not (ResolvedConstraint.LoTypeEl is TPasClassType) then
|
|
|
|
+ RaiseMsg(20190816231849,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],ConExpr);
|
|
|
|
+ ConstraintClass:=TPasClassType(ResolvedConstraint.LoTypeEl);
|
|
|
|
+ // constraint is class/interface type
|
|
|
|
+ // -> check if one of ParamConstraints fits the constraint type
|
|
|
|
+ // i.e. ParamConstraints must be more strict than target constraints
|
|
|
|
+ k:=length(ParamConstraints)-1;
|
|
|
|
+ while k>=0 do
|
|
|
|
+ begin
|
|
|
|
+ ParamConstraintExpr:=ParamConstraints[k];
|
|
|
|
+ ConToken:=GetGenericConstraintKeyword(ParamConstraintExpr);
|
|
|
|
+ if ConToken=tkEOF then
|
|
|
|
+ begin
|
|
|
|
+ ComputeElement(ParamConstraintExpr,ResolvedParamCon,[rcType]);
|
|
|
|
+ if not (ResolvedParamCon.IdentEl is TPasClassType) then
|
|
|
|
+ RaiseMsg(20190816232459,nXExpectedButYFound,sXExpectedButYFound,['type',GetResolverResultDescription(ResolvedParamCon)],ParamConstraintExpr);
|
|
|
|
+ ParamClassType:=TPasClassType(ResolvedParamCon.IdentEl);
|
|
|
|
+ if (ConstraintClass.ObjKind=okInterface)
|
|
|
|
+ and (ParamClassType.ObjKind=okClass) then
|
|
|
|
+ begin
|
|
|
|
+ if GetClassImplementsIntf(ParamClassType,ConstraintClass)<>nil then
|
|
|
|
+ break;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ if CheckClassIsClass(ParamClassType,ConstraintClass)<cIncompatible then
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ dec(k);
|
|
|
|
+ end;
|
|
|
|
+ if k<0 then
|
|
|
|
+ begin
|
|
|
|
+ if ConstraintClass.ObjKind=okInterface then
|
|
|
|
+ RaiseMsg(20190816233102,nTypeParamXMustSupportIntfY,
|
|
|
|
+ sTypeParamXMustSupportIntfY,[ParamTemplType.Name,GetTypeDescription(ConstraintClass)],ErrorPos)
|
|
|
|
+ else
|
|
|
|
+ RaiseMsg(20190816230021,nTypeParamXIsNotCompatibleWithY,
|
|
|
|
+ sTypeParamXIsNotCompatibleWithY,[ParamTemplType.Name,GetTypeDescription(ConstraintClass)],ErrorPos);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
- GenTempl:=TPasGenericTemplateType(GenericTemplateList[i]);
|
|
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure CheckTypeFitsTemplate(ParamType: TPasType;
|
|
|
|
+ GenTempl: TPasGenericTemplateType; ErrorPos: TPasElement);
|
|
|
|
+ var
|
|
|
|
+ j: Integer;
|
|
|
|
+ ConExpr: TPasExpr;
|
|
|
|
+ ConToken: TToken;
|
|
|
|
+ ResolvedConstraint: TPasResolverResult;
|
|
|
|
+ ConstraintClass: TPasClassType;
|
|
|
|
+ begin
|
|
|
|
+ // check if the specialized ParamType fits the constraints
|
|
for j:=0 to length(GenTempl.Constraints)-1 do
|
|
for j:=0 to length(GenTempl.Constraints)-1 do
|
|
begin
|
|
begin
|
|
ConExpr:=GenTempl.Constraints[j];
|
|
ConExpr:=GenTempl.Constraints[j];
|
|
@@ -14641,22 +14687,22 @@ begin
|
|
tkrecord:
|
|
tkrecord:
|
|
begin
|
|
begin
|
|
if not (ParamType is TPasRecordType) then
|
|
if not (ParamType is TPasRecordType) then
|
|
- RaiseXExpectedButTypeYFound(20190725200015,'record type',ParamType,P);
|
|
|
|
|
|
+ RaiseXExpectedButTypeYFound(20190725200015,'record type',ParamType,ErrorPos);
|
|
continue;
|
|
continue;
|
|
end;
|
|
end;
|
|
tkclass,tkconstructor:
|
|
tkclass,tkconstructor:
|
|
begin
|
|
begin
|
|
if not (ParamType is TPasClassType) then
|
|
if not (ParamType is TPasClassType) then
|
|
- RaiseXExpectedButTypeYFound(20190726133231,'class type',ParamType,P);
|
|
|
|
|
|
+ RaiseXExpectedButTypeYFound(20190726133231,'class type',ParamType,ErrorPos);
|
|
if TPasClassType(ParamType).ObjKind<>okClass then
|
|
if TPasClassType(ParamType).ObjKind<>okClass then
|
|
- RaiseXExpectedButTypeYFound(20190726133232,'class type',ParamType,P);
|
|
|
|
|
|
+ RaiseXExpectedButTypeYFound(20190726133232,'class type',ParamType,ErrorPos);
|
|
if TPasClassType(ParamType).IsExternal then
|
|
if TPasClassType(ParamType).IsExternal then
|
|
- RaiseXExpectedButTypeYFound(20190726133233,'non external class type',ParamType,P);
|
|
|
|
|
|
+ RaiseXExpectedButTypeYFound(20190726133233,'non external class type',ParamType,ErrorPos);
|
|
if ConToken=tkconstructor then
|
|
if ConToken=tkconstructor then
|
|
begin
|
|
begin
|
|
// check if ParamType has the default constructor
|
|
// check if ParamType has the default constructor
|
|
// ToDo
|
|
// ToDo
|
|
- RaiseMsg(20190726133722,nXIsNotSupported,sXIsNotSupported,['constraint keyword construcor'],P);
|
|
|
|
|
|
+ RaiseMsg(20190726133722,nXIsNotSupported,sXIsNotSupported,['constraint keyword construcor'],ConExpr);
|
|
end;
|
|
end;
|
|
continue;
|
|
continue;
|
|
end;
|
|
end;
|
|
@@ -14666,45 +14712,77 @@ begin
|
|
// Param must be a class
|
|
// Param must be a class
|
|
ComputeElement(ConExpr,ResolvedConstraint,[rcType]);
|
|
ComputeElement(ConExpr,ResolvedConstraint,[rcType]);
|
|
if ResolvedConstraint.IdentEl=nil then
|
|
if ResolvedConstraint.IdentEl=nil then
|
|
- RaiseMsg(20190726134037,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],P);
|
|
|
|
|
|
+ RaiseMsg(20190726134037,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],ConExpr);
|
|
if not (ResolvedConstraint.LoTypeEl is TPasClassType) then
|
|
if not (ResolvedConstraint.LoTypeEl is TPasClassType) then
|
|
- RaiseMsg(20190726134223,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],P);
|
|
|
|
|
|
+ RaiseMsg(20190726134223,nXIsNotAValidConstraint,sXIsNotAValidConstraint,[GetElementSourcePosStr(ConExpr)],ConExpr);
|
|
ConstraintClass:=TPasClassType(ResolvedConstraint.LoTypeEl);
|
|
ConstraintClass:=TPasClassType(ResolvedConstraint.LoTypeEl);
|
|
if not (ParamType is TPasClassType) then
|
|
if not (ParamType is TPasClassType) then
|
|
- RaiseIncompatibleType(20190726135859,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,P);
|
|
|
|
|
|
+ RaiseIncompatibleType(20190726135859,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,ErrorPos);
|
|
case ConstraintClass.ObjKind of
|
|
case ConstraintClass.ObjKind of
|
|
okClass:
|
|
okClass:
|
|
// Param must be a ConstraintClass
|
|
// Param must be a ConstraintClass
|
|
if CheckClassIsClass(ParamType,ConstraintClass)=cIncompatible then
|
|
if CheckClassIsClass(ParamType,ConstraintClass)=cIncompatible then
|
|
- RaiseIncompatibleType(20190726135309,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,P);
|
|
|
|
|
|
+ RaiseIncompatibleType(20190726135309,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,ErrorPos);
|
|
okInterface:
|
|
okInterface:
|
|
// ParamType must implement ConstraintClass
|
|
// ParamType must implement ConstraintClass
|
|
if GetClassImplementsIntf(TPasClassType(ParamType),ConstraintClass)=nil then
|
|
if GetClassImplementsIntf(TPasClassType(ParamType),ConstraintClass)=nil then
|
|
- RaiseIncompatibleType(20190726135458,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,P);
|
|
|
|
|
|
+ RaiseIncompatibleType(20190726135458,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,ErrorPos);
|
|
else
|
|
else
|
|
- RaiseIncompatibleType(20190726135310,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,P);
|
|
|
|
|
|
+ RaiseIncompatibleType(20190726135310,nIncompatibleTypesGotExpected,[''],ParamType,ConstraintClass,ErrorPos);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
- end; // end case
|
|
|
|
|
|
+ end;// case-end
|
|
|
|
+ end;// for-end
|
|
|
|
+ end;
|
|
|
|
|
|
- end; // end for
|
|
|
|
- end;
|
|
|
|
|
|
+var
|
|
|
|
+ Params, GenericTemplateList: TFPList;
|
|
|
|
+ i: Integer;
|
|
|
|
+ P, ErrorPos: TPasElement;
|
|
|
|
+ ParamType, DestType: TPasType;
|
|
|
|
+ ResolvedEl: TPasResolverResult;
|
|
|
|
+ GenTempl: TPasGenericTemplateType;
|
|
|
|
+begin
|
|
|
|
+ Result:=false;
|
|
|
|
+ Params:=El.Params;
|
|
|
|
+ DestType:=El.DestType;
|
|
|
|
+ if not (DestType is TPasGenericType) then
|
|
|
|
+ RaiseMsg(20190726193025,nXExpectedButYFound,sXExpectedButYFound,['generic type',DestType.Name],El);
|
|
|
|
+ GenericTemplateList:=TPasGenericType(DestType).GenericTemplateTypes;
|
|
|
|
+ if GenericTemplateList=nil then
|
|
|
|
+ RaiseMsg(20190726193048,nXExpectedButYFound,sXExpectedButYFound,['generic templates',DestType.Name],El);
|
|
|
|
+ if GenericTemplateList.Count<>Params.Count then
|
|
|
|
+ RaiseMsg(20190726193107,nXExpectedButYFound,sXExpectedButYFound,['type with '+IntToStr(Params.Count)+' generic templates',DestType.Name],El);
|
|
|
|
|
|
- if Result then
|
|
|
|
|
|
+ // check constraints
|
|
|
|
+ for i:=0 to Params.Count-1 do
|
|
begin
|
|
begin
|
|
- // check ParentEl types are specialized
|
|
|
|
- ParentEl:=DestType.Parent;
|
|
|
|
- while ParentEl<>nil do
|
|
|
|
|
|
+ GenTempl:=TPasGenericTemplateType(GenericTemplateList[i]);
|
|
|
|
+ P:=TPasElement(Params[i]);
|
|
|
|
+ if P.Parent=El then
|
|
|
|
+ ErrorPos:=P
|
|
|
|
+ else
|
|
|
|
+ ErrorPos:=El;
|
|
|
|
+ // check if P fits into GenTempl
|
|
|
|
+ ComputeElement(P,ResolvedEl,[rcType]);
|
|
|
|
+ if not (ResolvedEl.IdentEl is TPasType) then
|
|
|
|
+ RaiseMsg(20190725195434,nXExpectedButYFound,sXExpectedButYFound,['type',GetResolverResultDescription(ResolvedEl)],P);
|
|
|
|
+ ParamType:=ResolvedEl.LoTypeEl;
|
|
|
|
+ if ParamType=GenTempl then
|
|
|
|
+ // circle
|
|
|
|
+ // e.g. type A<S,T> = class
|
|
|
|
+ // v: A<S,T>; // circle, do not specialize
|
|
|
|
+ // u: A<S,word>; // specialize
|
|
|
|
+ // end;
|
|
|
|
+ else if ParamType is TPasGenericTemplateType then
|
|
|
|
+ begin
|
|
|
|
+ CheckTemplateFitsTemplate(TPasGenericTemplateType(ParamType),GenTempl,ErrorPos);
|
|
|
|
+ Result:=true;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- if (ParentEl is TPasGenericType)
|
|
|
|
- and (GetTypeParameterCount(TPasGenericType(ParentEl))>0) then
|
|
|
|
- begin
|
|
|
|
- {$IFDEF VerbosePasResolver}
|
|
|
|
- //writeln('TPasResolver.CheckSpecializeConstraints El=',GetObjName(El),' not specialized Parent=',GetObjName(ParentEl));
|
|
|
|
- {$ENDIF}
|
|
|
|
- exit(false); // parent is not specialized
|
|
|
|
- end;
|
|
|
|
- ParentEl:=ParentEl.Parent;
|
|
|
|
|
|
+ CheckTypeFitsTemplate(ParamType,GenTempl,ErrorPos);
|
|
|
|
+ Result:=true;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|