explicit interface implementation (beta)

bug fix issue #81
This commit is contained in:
Бондарев Иван 2016-02-07 21:54:29 +01:00
parent a6a3d8369e
commit 2bb4d307a6
8 changed files with 185 additions and 17 deletions

View file

@ -6668,7 +6668,6 @@ namespace PascalABCCompiler.NETGenerator
MethodBuilder methb = null;
bool is_prop_acc = IsPropertyAccessor(value);
MethodAttributes attrs = GetMethodAttributes(value, is_prop_acc);
IRuntimeManagedMethodBody irmmb = value.function_code as IRuntimeManagedMethodBody;
if (irmmb != null)
{

View file

@ -0,0 +1,30 @@
type
IEnr = System.Collections.IEnumerator;
IEnb = System.Collections.IEnumerable;
var a : integer;
type My = class(IEnumerable<integer>)
public
function IEnb.GetEnumerator(): IEnr;
begin
a := 1;
end;
function GetEnumerator(): IEnumerator<integer>;
begin
a := 2;
end;
end;
begin
var ien: IEnb := new My;
ien.GetEnumerator;
assert(a=1);
var ien2: IEnumerable<integer> := new My;
ien2.GetEnumerator;
assert(a=2);
a := 0;
var mc := new My;
mc.GetEnumerator();
assert(a=2);
end.

View file

@ -164,7 +164,8 @@ namespace PascalABCCompiler.TreeConverter
//TODO: Можно сделать возможность объявления вложенных типов.
public common_type_node _ctn; // SSM - пытаюсь выходить из класса и входить заново
private common_function_node_stack _func_stack=new common_function_node_stack();
private type_node _explicit_interface_type;
internal common_function_node_stack func_stack
{
get
@ -584,7 +585,21 @@ namespace PascalABCCompiler.TreeConverter
return (_func_stack.top());
}
}
public type_node converted_explicit_interface_type
{
get
{
return _explicit_interface_type;
}
//ssyy
set
{
_explicit_interface_type = value;
}
//\ssyy
}
public common_type_node converted_type
{
get
@ -894,7 +909,22 @@ namespace PascalABCCompiler.TreeConverter
public void leave_type_method()
{
if (_compiled_tn != null)
if (_explicit_interface_type != null)
{
function_node fn = top_function;
SymbolInfo si = _ctn.Scope.FindOnlyInType(fn.name, null);
function_node compar;
while (si != null)
{
compar = si.sym_info as function_node;
if (fn != compar && convertion_data_and_alghoritms.function_eq_params(fn, compar, false))
//if (fn is common_namespace_function_node && compar is common_namespace_function_node && (fn as common_namespace_function_node).comprehensive_namespace == (compar as common_namespace_function_node).comprehensive_namespace)
AddError(new FunctionDuplicateDefinition(compar, fn));
si = si.Next;
}
}
else if (_compiled_tn != null)
{
function_node fn = top_function;
SymbolInfo si = _compiled_tn.scope.FindOnlyInType(fn.name, null);
@ -909,8 +939,10 @@ namespace PascalABCCompiler.TreeConverter
si = si.Next;
}
}
_ctn = null;
if (_explicit_interface_type == null)
_ctn = null;
_compiled_tn = null;
_explicit_interface_type = null;
}
private readonly System.Collections.Generic.Stack<common_type_node> type_stack = new System.Collections.Generic.Stack<common_type_node>();
@ -2701,12 +2733,26 @@ _cmn.types.AddElement(tctn);*/
}
}
}
//Проверка типа на наличие функции из интерфейса
private void check_implement_function(common_type_node cnode, function_node meth, type_node interf)
{
//Ищем все функции с нужным именем в типе и его предках
SymbolInfo si = cnode.find_in_type(meth.name, cnode.Scope);
SymbolInfo tmp_si = null;
if (meth is compiled_function_node)
tmp_si = cnode.find_in_type((meth as compiled_function_node).cont_type.BaseFullName + "." + meth.name, cnode.Scope);
else if (meth is common_method_node)
tmp_si = cnode.find_in_type((meth as common_method_node).cont_type.BaseFullName + "." + meth.name, cnode.Scope);
if (tmp_si != null)
{
SymbolInfo tmp_si2 = tmp_si;
while (tmp_si2.Next != null)
tmp_si2 = tmp_si2.Next;
tmp_si.Next = si;
si = tmp_si;
}
function_node fn = null;
while (si != null)
{
@ -2724,7 +2770,7 @@ _cmn.types.AddElement(tctn);*/
{
if (fn_common.name != meth.name)
{
syntax_tree_visitor.AddError(fn_common.loc, "AMBIGUITY_BETWEEN_NAMES_{0}_AND_{1}" ,fn_common.name, meth.name);
syntax_tree_visitor.AddError(fn_common.loc, "AMBIGUITY_BETWEEN_NAMES_{0}_AND_{1}", fn_common.name, meth.name);
}
}
else
@ -2732,7 +2778,7 @@ _cmn.types.AddElement(tctn);*/
fn_common.SetName(meth.name);
fn_common.name_case_fixed = true;
}
}
break;
}
@ -2781,7 +2827,7 @@ _cmn.types.AddElement(tctn);*/
{
AddError(new DerivedFromInterfaceMethodMustBePublicAndNonStatic(
cnode.name, interf.name,
Tools.GetFullMethodHeaderString(meth),cnode.is_value_type, cnode.loc));
Tools.GetFullMethodHeaderString(meth), cnode.is_value_type, cnode.loc));
}
//Проверка пройдена!
@ -3022,7 +3068,11 @@ _cmn.types.AddElement(tctn);*/
bool in_unit = false;
if (_func_stack.size<=1)
{
if (_ctn!=null)
if (_explicit_interface_type != null)
{
si = _explicit_interface_type.find_in_type(fn.name);
}
else if (_ctn!=null)
{
si=_ctn.Scope.FindOnlyInScope(fn.name);
if (_ctn is compiled_generic_instance_type_node && fn is common_namespace_function_node)
@ -3115,7 +3165,17 @@ _cmn.types.AddElement(tctn);*/
AddError(new FunctionDuplicateDefinition(compar, fn));
}
else
AddError(new FunctionDuplicateDefinition(compar, fn));
{
if (fn is common_method_node && compar is common_method_node)
{
common_method_node cmn1 = fn as common_method_node;
common_method_node cmn2 = compar as common_method_node;
if (cmn1.explicit_interface == cmn2.explicit_interface)
AddError(new FunctionDuplicateDefinition(compar, fn));
}
else
AddError(new FunctionDuplicateDefinition(compar, fn));
}
}
si = si.Next;
continue;
@ -3349,7 +3409,7 @@ _cmn.types.AddElement(tctn);*/
//si.sym_info=fn;
break;
}
if (fn is common_method_node && !predef_find && syntax_tree_visitor.current_converted_method_not_in_class_defined)
if (fn is common_method_node && !predef_find && syntax_tree_visitor.current_converted_method_not_in_class_defined && _explicit_interface_type == null)
{
AddError(new NoMethodInClassWithThisParams(fn as common_method_node, (fn as common_method_node).cont_type, fn.loc));
}

View file

@ -112,7 +112,15 @@ namespace PascalABCCompiler.TreeConverter
internal void AddError(location loc, string ErrResourceString, params object[] values)
{
ErrorsList.Add(new SimpleSemanticError(loc, ErrResourceString, values));
Errors.Error err = new SimpleSemanticError(loc, ErrResourceString, values);
if (ThrowCompilationError)
{
throw err;
}
else
{
ErrorsList.Add(err);
}
}
internal void AddWarning(Errors.CompilerWarning err)
@ -9102,11 +9110,12 @@ namespace PascalABCCompiler.TreeConverter
if(is_operator)
op=(_method_name.meth_name as SyntaxTree.operator_name_ident).operator_type;
_method_name.meth_name = ConvertOperatorNameToIdent(_method_name.meth_name);
bool explicit_impl = false;
if ((context.converting_block() != block_type.namespace_block) && (_method_name.class_name != null))
{
AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name,
get_location(_method_name.class_name)));
/*AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name,
get_location(_method_name.class_name)));*/
explicit_impl = true;
}
if (is_operator && op==SyntaxTree.Operators.AddressOf && SemanticRules.AddressOfOperatorNonOverloaded)
{
@ -9123,7 +9132,22 @@ namespace PascalABCCompiler.TreeConverter
{
num_template_args = ttn.template_args.idents.Count;
}
common_type_node current_conv_type = context.converted_type;
def_temp = context.enter_in_type_method(_method_name, _method_name.class_name.name, loc_type_name, num_template_args);
if (explicit_impl)
{
context.converted_type = current_conv_type;
if (def_temp is type_node && (def_temp as type_node).IsInterface)
{
context.converted_explicit_interface_type = def_temp as type_node;
SymbolInfo si = context.converted_explicit_interface_type.find_in_type(_method_name.meth_name.name);
if (si == null)
AddError(new UndefinedNameReference(_method_name.meth_name.name, get_location(_method_name.meth_name)));
}
else
AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name,
get_location(_method_name.class_name)));
}
tp = def_temp as common_type_node;
template_class tc = def_temp as template_class;
//SyntaxTree.template_type_name ttn = _method_name.class_name as SyntaxTree.template_type_name;
@ -9256,7 +9280,12 @@ namespace PascalABCCompiler.TreeConverter
if (current_function_header != null && current_function_header.proc_attributes != null && has_extensionmethod_attr(current_function_header.proc_attributes.proc_attributes))
context.create_function(_method_name.meth_name.name, loc_name, false);
else
context.create_function(_method_name.meth_name.name, loc_name);
{
if (!explicit_impl)
context.create_function(_method_name.meth_name.name, loc_name);
else
context.create_function(context.converted_explicit_interface_type.BaseFullName+"."+_method_name.meth_name.name, loc_name);
}
}
context.extension_method = false;
context.top_function.IsOperator = is_operator;
@ -11242,6 +11271,7 @@ namespace PascalABCCompiler.TreeConverter
hard_node_test_and_visit(_procedure_definition.proc_header);
}
//\lroman//
//ssyy
if (context.converted_template_type != null)
@ -11260,6 +11290,8 @@ namespace PascalABCCompiler.TreeConverter
{
return;
}
if (context.converted_explicit_interface_type != null)
(context.top_function as common_method_node).explicit_interface = context.converted_explicit_interface_type;
if (has_dll_import_attribute(context.top_function))
{
if (_procedure_definition.proc_body != null)
@ -18506,6 +18538,8 @@ namespace PascalABCCompiler.TreeConverter
public override void visit(SyntaxTree.same_type_node st) // SSM 22/06/13
{
expression_node en = convert_strong(st.ex);
if (en == null)
AddError(get_location(st.ex),"CANNOT_EVALUATE_FUNCTION_TYPE");
return_value(en.type);
}

View file

@ -1283,6 +1283,7 @@ namespace PascalABCCompiler.TreeRealization
private SemanticTree.field_access_level _field_access_level;
private SemanticTree.polymorphic_state _polymorphic_state;
private type_node _explicit_interface;
private bool _is_constructor;
public bool first_statement = true;
public bool inherited_ctor_called = false;
@ -1290,6 +1291,18 @@ namespace PascalABCCompiler.TreeRealization
private bool _is_final = false;
public type_node explicit_interface
{
get
{
return _explicit_interface;
}
set
{
_explicit_interface = value;
}
}
public bool IsStatic
{
get
@ -1597,6 +1610,7 @@ namespace PascalABCCompiler.TreeRealization
private int _num_of_default_parameters;
private bool _is_extension_method=false;
private compiled_type_node connected_to_type;
private List<compiled_type_node> _generic_params;
private static System.Collections.Generic.Dictionary<System.Reflection.MethodInfo, compiled_function_node> compiled_methods =
new System.Collections.Generic.Dictionary<System.Reflection.MethodInfo, compiled_function_node>();

View file

@ -342,6 +342,14 @@ namespace PascalABCCompiler.TreeRealization
}
}
public virtual string BaseFullName
{
get
{
return full_name;
}
}
/// <summary>
/// Свойство по умолчанию.
/// </summary>
@ -1732,6 +1740,14 @@ namespace PascalABCCompiler.TreeRealization
}
}
public override string BaseFullName
{
get
{
return this.comprehensive_namespace.namespace_full_name + "." + name;
}
}
public override string PrintableName
{
get
@ -3451,6 +3467,17 @@ namespace PascalABCCompiler.TreeRealization
return base.PrintableName;
}
}
public override string BaseFullName
{
get
{
Type t = _compiled_type;
if (t.IsGenericType)
t = t.GetGenericTypeDefinition();
return t.FullName;
}
}
}
[Serializable]

View file

@ -110,6 +110,8 @@ ILLEGAL_LAMBDA_PARAMETERS_NUMBER=Illegal lambda parameters number
IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA=Unable to infer types in lambda
ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly.
PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed
CANNOT_EVALUATE_FUNCTION_TYPE=Cannot infer the return type of function
TYPE_NAME_EXPECTED=Type name expected
%PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}'

View file

@ -105,6 +105,8 @@ FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod
CANNOT_EVALUATE_FUNCTION_TYPE=Невозможно вывести тип функции
TYPE_NAME_EXPECTED=Ожидался тип
%PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека
ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}'