fix #2640
This commit is contained in:
parent
a03d33b586
commit
0d3a4e3b9e
58
TestSuite/override-where.pas
Normal file
58
TestSuite/override-where.pas
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// issue#2640
|
||||
type
|
||||
CustomClass = class public x := 5; end;
|
||||
EnumSynonym = System.Enum;
|
||||
|
||||
t1 = class
|
||||
|
||||
procedure OK1<T>(o: T); virtual; where T: CustomClass; begin Writeln(o) end;
|
||||
|
||||
procedure OK2<T>(o: T); virtual; where T: CustomClass, constructor; begin Writeln(o) end;
|
||||
|
||||
procedure OK3<T>(o: T); virtual; where T: CustomClass, constructor; begin Writeln(o) end;
|
||||
|
||||
procedure OK4<T>(o: T); virtual; where T: CustomClass; begin Writeln(o) end;
|
||||
|
||||
procedure OK5<T>(o: T); virtual; where T: EnumSynonym, record; begin Writeln(o) end;
|
||||
|
||||
end;
|
||||
t2 = class(t1)
|
||||
|
||||
procedure OK1<T>(o: T); override; begin Writeln(o) end;
|
||||
|
||||
procedure OK2<T>(o: T); override; where T: CustomClass; begin Writeln(o) end;
|
||||
|
||||
procedure OK3<T>(o: T); override; where T: constructor; begin Writeln(o) end;
|
||||
|
||||
procedure OK4<T>(o: T); override; where T: class; begin Writeln(o) end;
|
||||
|
||||
procedure OK5<T>(o: T); override; where T: record; begin Writeln(o) end;
|
||||
|
||||
end;
|
||||
|
||||
begin
|
||||
var a := new t1;
|
||||
var b := new t2;
|
||||
|
||||
a.OK1(new CustomClass);
|
||||
b.OK1(0);
|
||||
Writeln('~'*30);
|
||||
|
||||
a.OK2(new CustomClass);
|
||||
b.OK2(new CustomClass);
|
||||
Writeln('~'*30);
|
||||
|
||||
a.OK3(new CustomClass);
|
||||
b.OK3(new object);
|
||||
Writeln('~'*30);
|
||||
|
||||
a.OK4(new CustomClass);
|
||||
b.OK4(new object);
|
||||
Writeln('~'*30);
|
||||
|
||||
var my_enum: (ME_1, ME_2);
|
||||
a.OK5(my_enum);
|
||||
b.OK5(my_enum);
|
||||
Writeln('~'*30);
|
||||
|
||||
end.
|
||||
|
|
@ -1056,23 +1056,23 @@ namespace TreeConverter.LambdaExpressions.Closure
|
|||
types = new where_type_specificator_list()
|
||||
};
|
||||
|
||||
if (el.is_class)
|
||||
if (el.base_class != null && el.base_class != SystemLibrary.object_type)
|
||||
{
|
||||
var d = LambdaHelper.ConvertSemanticTypeToSyntaxType(el.base_class);
|
||||
whereDef.types.Add(d);
|
||||
}
|
||||
else if (el.is_class)
|
||||
{
|
||||
var d = new declaration_specificator(DeclarationSpecificator.WhereDefClass, "class");
|
||||
whereDef.types.Add(d);
|
||||
}
|
||||
|
||||
if (el.is_value)
|
||||
{
|
||||
var d = new declaration_specificator(DeclarationSpecificator.WhereDefValueType, "record");
|
||||
whereDef.types.Add(d);
|
||||
}
|
||||
|
||||
if (el.base_class != null && el.base_class != SystemLibrary.object_type)
|
||||
{
|
||||
var d = LambdaHelper.ConvertSemanticTypeToSyntaxType(el.base_class);
|
||||
whereDef.types.Add(d);
|
||||
}
|
||||
|
||||
foreach (var interf in el.implementing_interfaces)
|
||||
{
|
||||
var d = LambdaHelper.ConvertSemanticTypeToSyntaxType(interf);
|
||||
|
|
|
|||
|
|
@ -12925,6 +12925,12 @@ namespace PascalABCCompiler.TreeConverter
|
|||
private void add_generic_eliminations(common_type_node param, List<SyntaxTree.type_definition> specificators)
|
||||
{
|
||||
Hashtable used_interfs = new Hashtable();
|
||||
// System.Enum это класс, но его наследники - записи
|
||||
// Если указать "where T: Enum, record" - станет нельзя применять T=Enum, с ошибкой что Enum не запись
|
||||
// Но чтобы в секции where override метода можно было указать record без System.Enum
|
||||
// И чтобы можно было передавать конкретные энумы (которые записи), когда record не указан во where
|
||||
// Разрешил стрелять себе в ногу, указывая Enum вместе с record или class
|
||||
var base_is_enum = false;
|
||||
for (int i = 0; i < specificators.Count; ++i)
|
||||
{
|
||||
SyntaxTree.declaration_specificator ds = specificators[i] as SyntaxTree.declaration_specificator;
|
||||
|
|
@ -12933,7 +12939,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
switch (ds.specificator)
|
||||
{
|
||||
case SyntaxTree.DeclarationSpecificator.WhereDefClass:
|
||||
if (i == 0)
|
||||
if (i == 0 || i == 1 && base_is_enum)
|
||||
{
|
||||
param.is_class = true;
|
||||
}
|
||||
|
|
@ -12943,7 +12949,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
}
|
||||
break;
|
||||
case SyntaxTree.DeclarationSpecificator.WhereDefValueType:
|
||||
if (i == 0)
|
||||
if (i == 0 || i == 1 && base_is_enum)
|
||||
{
|
||||
param.internal_is_value = true;
|
||||
}
|
||||
|
|
@ -13014,6 +13020,10 @@ namespace PascalABCCompiler.TreeConverter
|
|||
AddError(get_location(specificators[i]), "STATIC_CLASS_CAN_NOT_BE_USED_AS_PARENT_SPECIFICATOR");
|
||||
check_cycle_inheritance(param, spec_type);
|
||||
param.SetBaseType(spec_type);
|
||||
base_is_enum = spec_type == SystemLibrary.SystemLibrary.enum_base_type;
|
||||
// Чтобы в секции where override метода можно было указать class вместо конкретного типа
|
||||
// Иначе CLR падает с TypeLoadException
|
||||
if (!base_is_enum) param.is_class = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14236,8 +14246,32 @@ namespace PascalABCCompiler.TreeConverter
|
|||
cmn.polymorphic_state = SemanticTree.polymorphic_state.ps_virtual_abstract;
|
||||
|
||||
}
|
||||
if (is_override && _procedure_attributes_list.Parent is procedure_header ph && ph.where_defs != null)
|
||||
AddError(cmn.loc, "OVERRIDE_METHODS_CANNOT_CONTAIN_WHERE_SECTION");
|
||||
if (is_override && (_procedure_attributes_list.Parent as procedure_header)?.where_defs is where_definition_list where_node)
|
||||
{
|
||||
var where_loc = get_location(where_node);
|
||||
|
||||
var gen_pars1 = cmn.overrided_method.get_generic_params_list();
|
||||
var gen_pars2 = cmn.get_generic_params_list();
|
||||
System.Diagnostics.Debug.Assert(gen_pars1.Count == gen_pars2.Count);
|
||||
|
||||
for (int par_i = 0; par_i < gen_pars1.Count; par_i++)
|
||||
{
|
||||
var gen_par1 = gen_pars1[par_i] as common_type_node;
|
||||
var gen_par2 = gen_pars2[par_i] as common_type_node;
|
||||
|
||||
if (gen_par2.base_type != SystemLibrary.SystemLibrary.object_type && !convertion_data_and_alghoritms.eq_type_nodes(gen_par2.base_type, gen_par1.base_type, true))
|
||||
AddError(where_loc, "OVERRIDE_WHERE_TYPE_MUST_BE_SAME", gen_par2.name, gen_par1.base_type.PrintableName);
|
||||
|
||||
if (gen_par2.has_explicit_default_constructor && !gen_par1.has_explicit_default_constructor)
|
||||
AddError(where_loc, "OVERRIDE_WHERE_UNEXPECTED_X", gen_par2.name, "constructor");
|
||||
if (gen_par2.is_class && !gen_par1.is_class)
|
||||
AddError(where_loc, "OVERRIDE_WHERE_UNEXPECTED_X", gen_par2.name, "class");
|
||||
if (gen_par2.is_value && !gen_par1.is_value)
|
||||
AddError(where_loc, "OVERRIDE_WHERE_UNEXPECTED_X", gen_par2.name, "record");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cmn.field_access_level < cmn.overrided_method.field_access_level)
|
||||
AddError(cmn.loc, "CAN_NOT_BE_DOWN_ACCESS_LEVEL_FOR_METH");
|
||||
|
|
|
|||
|
|
@ -153,14 +153,6 @@ namespace PascalABCCompiler.TreeRealization
|
|||
generic_parameter_eliminations gpe = gpe_list[i];
|
||||
type_node tn = tparams[i];
|
||||
|
||||
if (gpe.is_class && !tn.is_class && !(tn.is_generic_parameter && tn.base_type != null && tn.base_type.is_class))
|
||||
{
|
||||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_REFERENCE_TYPE", tn.PrintableName);
|
||||
}
|
||||
if (gpe.is_value && (!tn.is_value || tn.BaseFullName != null && tn.BaseFullName.StartsWith("System.Nullable")) /*&& !tn.is_generic_parameter*/)
|
||||
{
|
||||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_VALUE_TYPE", tn.PrintableName);
|
||||
}
|
||||
if (gpe.base_class != null && gpe.base_class != SystemLibrary.SystemLibrary.object_type && !tn.is_value)
|
||||
{
|
||||
type_node base_type = generic_convertions.determine_type(gpe.base_class, tparams, method_param_types);
|
||||
|
|
@ -172,6 +164,14 @@ namespace PascalABCCompiler.TreeRealization
|
|||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_DERIVED_FROM_{1}", tn.PrintableName, base_type.name);
|
||||
}
|
||||
}
|
||||
if (gpe.is_class && !tn.is_class && !(tn.is_generic_parameter && tn.base_type != null && tn.base_type.is_class))
|
||||
{
|
||||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_REFERENCE_TYPE", tn.PrintableName);
|
||||
}
|
||||
if (gpe.is_value && (!tn.is_value || tn.BaseFullName != null && tn.BaseFullName.StartsWith("System.Nullable")) /*&& !tn.is_generic_parameter*/)
|
||||
{
|
||||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_VALUE_TYPE", tn.PrintableName);
|
||||
}
|
||||
if (gpe.base_class != null && gpe.base_class != SystemLibrary.SystemLibrary.object_type && tn.is_value && !gpe.base_class.is_value && gpe.base_class != SystemLibrary.SystemLibrary.value_type && gpe.base_class != SystemLibrary.SystemLibrary.enum_base_type)
|
||||
{
|
||||
return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_REFERENCE_TYPE", tn.PrintableName);
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ PROCEDURE_TYPE_SHOULD_BE_REPLACED_BY_TYPE_NAME_IN_THIS_CONTEXT=Procedure type sh
|
|||
ACCESS_TO_ENUM_CONST_THROUGH_OBJECT=Enum constant can not be accessed through an object
|
||||
ONE_DIM_ARRAY_OR_LIST_EXPECTED=One-dimensional array or list expected
|
||||
TUPLE_TYPE_ELEMENTS_COUNT_MUST_BE_LESSEQUAL_7=Number of elements in tuple type must be less than 8
|
||||
OVERRIDE_METHODS_CANNOT_CONTAIN_WHERE_SECTION=Methods with override modifier can't contain where section
|
||||
Ìåòîäû ñ ìîäèôèêàòîðîì override íå ìîãóò ñîäåðæàòü ñîáñòâåííóþ ñåêöèþ where
|
||||
OVERRIDE_WHERE_TYPE_MUST_BE_SAME=Where section of inhereted method expects generic parameter {0} to inherete from exactly {1}
|
||||
OVERRIDE_WHERE_UNEXPECTED_X=Where section of inhereted method for generic parameter {0} didn't have {1} specifier
|
||||
EXPLICIT_CASTS_FOR_LAMBDA_EXPRESSIONS_ARE_FORBIDDEN=Explicit type casts for lambda expressions are forbidden
|
||||
STATIC_CLASS_CANNOT_HAVE_PREDEFINITION=Static class cannot be predefined
|
||||
OPERATIONS_CANNOT_BE_CALLED_USING_THIS_SYNTAX=Operations cannot be called using this syntax
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ PROCEDURE_TYPE_SHOULD_BE_REPLACED_BY_TYPE_NAME_IN_THIS_CONTEXT=Процедур
|
|||
ACCESS_TO_ENUM_CONST_THROUGH_OBJECT=Нельзя обратиться к элементу перечисления через объект
|
||||
ONE_DIM_ARRAY_OR_LIST_EXPECTED=Ожидался одномерный массив или список
|
||||
TUPLE_TYPE_ELEMENTS_COUNT_MUST_BE_LESSEQUAL_7=Количество элементов в типе кортежа не должно быть больше 7
|
||||
OVERRIDE_METHODS_CANNOT_CONTAIN_WHERE_SECTION=Методы с модификатором override не могут содержать собственную секцию where
|
||||
OVERRIDE_WHERE_TYPE_MUST_BE_SAME=Секция where метода предка ожидает что шаблонный параметр {0} будет наследовать от именно {1}
|
||||
OVERRIDE_WHERE_UNEXPECTED_X=Секция where метода предка для шаблонного параметра {0} не имела спецификатора {1}
|
||||
EXPLICIT_CASTS_FOR_LAMBDA_EXPRESSIONS_ARE_FORBIDDEN=Явные приведения типов для лямбда-выражений запрещены
|
||||
STATIC_CLASS_CANNOT_HAVE_PREDEFINITION=Статический класс не может иметь предописание
|
||||
OPERATIONS_CANNOT_BE_CALLED_USING_THIS_SYNTAX=Операции нельзя вызывать, используя данный синтаксис
|
||||
|
|
|
|||
Loading…
Reference in a new issue