attempt to fix GetEnumerator resolving for compiled types
This commit is contained in:
parent
4fd020d084
commit
15a05360a4
|
|
@ -3235,7 +3235,12 @@ namespace PascalABCCompiler.PCU
|
|||
var_definition_node vdn = GetLocalOrNamespaceVariableByOffset(br.ReadInt32());
|
||||
expression_node expr = CreateExpression();
|
||||
statement_node body = CreateStatement();
|
||||
return new foreach_node(vdn, expr, body, null);
|
||||
type_node elementType = null;
|
||||
if (CanReadObject())
|
||||
elementType = GetTypeReference();
|
||||
|
||||
bool isGeneric = br.ReadBoolean();
|
||||
return new foreach_node(vdn, expr, body, elementType, isGeneric, null);
|
||||
}
|
||||
|
||||
private statement_node CreateLock()
|
||||
|
|
|
|||
|
|
@ -3555,6 +3555,9 @@ namespace PascalABCCompiler.PCU
|
|||
bw.Write(GetMemberOffset(fn.ident));
|
||||
VisitExpression(fn.in_what);
|
||||
VisitStatement(fn.what_do);
|
||||
if (CanWriteObject(fn.element_type))
|
||||
WriteTypeReference(fn.element_type);
|
||||
bw.Write(fn.is_generic);
|
||||
}
|
||||
|
||||
private void VisitLock(lock_statement node)
|
||||
|
|
|
|||
|
|
@ -866,58 +866,6 @@ namespace PascalABCCompiler.NETGenerator {
|
|||
return null;
|
||||
}
|
||||
|
||||
public MethodInfo GetEnumeratorMethod(Type t, out Type[] generic_args)
|
||||
{
|
||||
generic_args = null;
|
||||
Type generic_def = null;
|
||||
if (t.IsGenericType && !t.IsGenericTypeDefinition)
|
||||
generic_def = t.GetGenericTypeDefinition();
|
||||
else
|
||||
generic_def = t;
|
||||
if (generic_def.IsArray && generic_def.GetElementType().IsGenericParameter)
|
||||
{
|
||||
return TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator");
|
||||
}
|
||||
if (generic_def.IsArray)
|
||||
{
|
||||
if (IsConstructedGenericType(generic_def.GetElementType()))
|
||||
return TypeBuilder.GetMethod(TypeFactory.IEnumerableGenericType.MakeGenericType(generic_def.GetElementType()), TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator"));
|
||||
else
|
||||
return TypeFactory.IEnumerableGenericType.MakeGenericType(generic_def.GetElementType()).GetMethod("GetEnumerator");
|
||||
}
|
||||
else if (generic_def.IsGenericParameter)
|
||||
{
|
||||
return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
}
|
||||
foreach (Type interf in generic_def.GetInterfaces())
|
||||
{
|
||||
if (interf.IsGenericType && interf.GetGenericTypeDefinition() == TypeFactory.IEnumerableGenericType)
|
||||
{
|
||||
MethodInfo mi = interf.GetGenericTypeDefinition().GetMethod("GetEnumerator");
|
||||
if (generic_def != t)
|
||||
{
|
||||
if (t.GetGenericArguments().Length != interf.GetGenericTypeDefinition().GetGenericArguments().Length)
|
||||
return null;
|
||||
Type gt = interf.GetGenericTypeDefinition().MakeGenericType(t.GetGenericArguments());
|
||||
if (IsConstructedGenericType(gt))
|
||||
return TypeBuilder.GetMethod(gt, mi);
|
||||
else
|
||||
return interf.GetGenericTypeDefinition().MakeGenericType(t.GetGenericArguments()).GetMethod("GetEnumerator");
|
||||
}
|
||||
else if (IsConstructedGenericType(interf))
|
||||
{
|
||||
//return TypeBuilder.GetMethod(TypeFactory.IEnumerableGenericType.MakeGenericType(interf.GetGenericArguments()), TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator"));
|
||||
//return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
generic_args = interf.GetGenericArguments();
|
||||
return TypeBuilder.GetMethod(interf, mi);
|
||||
}
|
||||
else
|
||||
return interf.GetMethod("GetEnumerator");
|
||||
}
|
||||
}
|
||||
return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
}
|
||||
|
||||
public void SetAsProcessing(ICommonTypeNode type)
|
||||
{
|
||||
processing_types[type] = true;
|
||||
|
|
|
|||
|
|
@ -11599,37 +11599,41 @@ namespace PascalABCCompiler.NETGenerator
|
|||
Type var_tp = helper.GetTypeReference(value.VarIdent.type).tp;
|
||||
//(ssyy) 12.04.2008 Поиск IEnumerable не нужен! Это дело семантики!
|
||||
Type in_what_type = helper.GetTypeReference(value.InWhatExpr.type).tp;
|
||||
Type return_type = null;
|
||||
bool is_generic = false;
|
||||
Type[] generic_args = null;
|
||||
MethodInfo enumer_mi = null; //typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
if (/*var_tp.IsValueType &&*/ !var_tp.IsGenericParameter && !(in_what_type.IsArray && in_what_type.GetArrayRank() > 1))
|
||||
Type return_type;
|
||||
//bool is_generic = false;
|
||||
//Type[] generic_args = null;
|
||||
MethodInfo enumer_mi;
|
||||
|
||||
Type elementType = helper.GetTypeReference(value.ElementType).tp;
|
||||
|
||||
bool is_generic = value.IsGeneric;
|
||||
|
||||
if (is_generic)
|
||||
{
|
||||
enumer_mi = helper.GetEnumeratorMethod(in_what_type, out generic_args);
|
||||
if (enumer_mi == null)
|
||||
if (value.ElementType.node_kind == node_kind.compiled)
|
||||
{
|
||||
enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
return_type = enumer_mi.ReturnType;
|
||||
}
|
||||
enumer_mi = TypeFactory.IEnumerableGenericType.MakeGenericType(elementType).GetMethod("GetEnumerator");
|
||||
return_type = enumer_mi.ReturnType;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_generic = enumer_mi.ReturnType.IsGenericType;
|
||||
return_type = enumer_mi.ReturnType;
|
||||
if (in_what_type.IsGenericType && return_type.IsGenericType && !return_type.IsGenericTypeDefinition)
|
||||
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(in_what_type.GetGenericArguments());
|
||||
else if (in_what_type.IsArray && return_type.IsGenericType && !return_type.IsGenericTypeDefinition)
|
||||
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(in_what_type.GetElementType());
|
||||
else if (generic_args != null)
|
||||
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(generic_args);
|
||||
}
|
||||
|
||||
}
|
||||
enumer_mi = TypeBuilder.GetMethod(
|
||||
TypeFactory.IEnumerableGenericType.MakeGenericType(elementType),
|
||||
TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator")
|
||||
);
|
||||
|
||||
return_type = enumer_mi.ReturnType
|
||||
.GetGenericTypeDefinition()
|
||||
.MakeGenericType(elementType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
|
||||
return_type = enumer_mi.ReturnType;
|
||||
}
|
||||
LocalBuilder lb = il.DeclareLocal(return_type);
|
||||
enumer_mi = TypeFactory.IEnumerableType.GetMethod("GetEnumerator");
|
||||
return_type = enumer_mi.ReturnType;
|
||||
}
|
||||
|
||||
LocalBuilder lb = il.DeclareLocal(return_type);
|
||||
if (save_debug_info) lb.SetLocalSymInfo("$enumer$" + uid++);
|
||||
|
||||
value.InWhatExpr.visit(this);
|
||||
|
|
|
|||
|
|
@ -2350,6 +2350,16 @@ namespace PascalABCCompiler.SemanticTree
|
|||
{
|
||||
get;
|
||||
}
|
||||
|
||||
ITypeNode ElementType
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
bool IsGeneric
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILockStatement : IStatementNode, ILocated
|
||||
|
|
|
|||
|
|
@ -641,8 +641,8 @@ namespace TreeConverter.LambdaExpressions.Closure
|
|||
type_node elemType = null;
|
||||
if (inWhat.type == null)
|
||||
inWhat = tmp;
|
||||
bool bb; // здесь bb не нужно. Оно нужно в foreach
|
||||
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType, out bb);
|
||||
bool sys_coll_ienum;
|
||||
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType, out sys_coll_ienum);
|
||||
|
||||
if (_foreach_stmt.type_name == null)
|
||||
{
|
||||
|
|
@ -676,7 +676,7 @@ namespace TreeConverter.LambdaExpressions.Closure
|
|||
if (!(vdn.type is compiled_generic_instance_type_node))
|
||||
_visitor.convertion_data_and_alghoritms.check_convert_type_with_inheritance(vdn.type, elemType, _visitor.get_location(_foreach_stmt.identifier));
|
||||
|
||||
var fn = new foreach_node(vdn, inWhat, null, _visitor.get_location(_foreach_stmt));
|
||||
var fn = new foreach_node(vdn, inWhat, null, elemType, !sys_coll_ienum, _visitor.get_location(_foreach_stmt));
|
||||
_visitor.context.enter_in_cycle(fn);
|
||||
_visitor.context.loop_var_stack.Push(vdn);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ namespace PascalABCCompiler.TreeConverter
|
|||
|
||||
expression_node foreachCollection;
|
||||
var_definition_node foreachVariable;
|
||||
ForeachCheckAndConvert(_foreach_stmt, out foreachCollection, out foreachVariable);
|
||||
type_node elementType;
|
||||
bool isGeneric;
|
||||
ForeachCheckAndConvert(_foreach_stmt, out foreachCollection, out foreachVariable, out elementType, out isGeneric);
|
||||
|
||||
definition_node dnind = null;
|
||||
var_definition_node vdn = null;
|
||||
|
|
@ -54,7 +56,14 @@ namespace PascalABCCompiler.TreeConverter
|
|||
statements_list sl = new statements_list(get_location(_foreach_stmt.stmt));
|
||||
convertion_data_and_alghoritms.statement_list_stack_push(sl);
|
||||
|
||||
foreach_node foreachNode = new foreach_node(foreachVariable, foreachCollection, null, get_location(_foreach_stmt));
|
||||
foreach_node foreachNode = new foreach_node(
|
||||
foreachVariable,
|
||||
foreachCollection,
|
||||
null,
|
||||
elementType,
|
||||
isGeneric,
|
||||
get_location(_foreach_stmt)
|
||||
);
|
||||
|
||||
context.enter_in_cycle(foreachNode);
|
||||
context.loop_var_stack.Push(foreachVariable);
|
||||
|
|
@ -115,8 +124,13 @@ namespace PascalABCCompiler.TreeConverter
|
|||
}
|
||||
|
||||
|
||||
private void ForeachCheckAndConvert(foreach_stmt _foreach_stmt, out expression_node foreachCollection,
|
||||
out var_definition_node foreachVariable)
|
||||
private void ForeachCheckAndConvert(
|
||||
foreach_stmt _foreach_stmt,
|
||||
out expression_node foreachCollection,
|
||||
out var_definition_node foreachVariable,
|
||||
out type_node elementType,
|
||||
out bool isGenereic
|
||||
)
|
||||
{
|
||||
var lambdaSearcher = new LambdaSearcher(_foreach_stmt.in_what);
|
||||
if (lambdaSearcher.CheckIfContainsLambdas())
|
||||
|
|
@ -135,6 +149,9 @@ namespace PascalABCCompiler.TreeConverter
|
|||
if (!FindIEnumerableElementType(foreachCollection.type, ref elem_type, out sys_coll_ienum))
|
||||
AddError(foreachCollection.location, "CAN_NOT_EXECUTE_FOREACH_BY_EXPR_OF_TYPE_{0}", foreachCollection.type.name);
|
||||
|
||||
elementType = elem_type;
|
||||
isGenereic = !sys_coll_ienum;
|
||||
|
||||
var vars = _foreach_stmt.ext as ident_list;
|
||||
if (vars != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ using while_node = PascalABCCompiler.TreeRealization.while_node;
|
|||
using TreeConverter.LambdaExpressions.Closure;
|
||||
using TreeConverter.LambdaExpressions;
|
||||
using PascalABCCompiler.TreeConverter.TreeConversion;
|
||||
using System.Reflection;
|
||||
using PascalABCCompiler.SemanticTree;
|
||||
|
||||
namespace PascalABCCompiler.TreeConverter
|
||||
{
|
||||
|
|
@ -13723,7 +13725,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
cmc.parameters.AddElement(new int_const_node((prm.type.element_type.element_type as short_string_type_node).Length,null));
|
||||
}
|
||||
what_do.statements.AddElement(cmc);
|
||||
foreach_node fn = new foreach_node(var,in_what,what_do,null);
|
||||
foreach_node fn = new foreach_node(var, in_what,what_do, prm.type.element_type, true, null);
|
||||
sl.statements.AddElementFirst(fn);
|
||||
}
|
||||
}
|
||||
|
|
@ -18481,11 +18483,87 @@ namespace PascalABCCompiler.TreeConverter
|
|||
return false;
|
||||
}
|
||||
|
||||
public bool FindIEnumerableElementType(type_node tn, ref type_node elem_type, out bool sys_coll_ienum)
|
||||
private bool IsIEnumInterface(Type t)
|
||||
{
|
||||
var IEnumType = typeof(IEnumerable);
|
||||
var IEnumTypedType = typeof(IEnumerable<>);
|
||||
|
||||
var isIEnumType = (t == IEnumType);
|
||||
var isIEnumTypedType = t.IsGenericType
|
||||
&& (t.GetGenericTypeDefinition() == IEnumTypedType
|
||||
);
|
||||
|
||||
return isIEnumType || isIEnumTypedType;
|
||||
}
|
||||
|
||||
public Type FindIEnumerableInterfaceInCompiledType(Type compiledType)
|
||||
{
|
||||
var IEnumType = typeof(IEnumerable);
|
||||
var IEnumTypedType = typeof(IEnumerable<>);
|
||||
|
||||
// если тип является интерфейсом IEnumerable или IEnumerable<T> то берём его
|
||||
if (IsIEnumInterface(compiledType))
|
||||
return compiledType;
|
||||
|
||||
// иначе ищем подходящие интерфейсы в иерархии
|
||||
var filterdInterfaces = compiledType.FindInterfaces(
|
||||
(item, _) => IsIEnumInterface(item),
|
||||
null
|
||||
);
|
||||
|
||||
var genericInterfaceCount = filterdInterfaces.Count(item => item.IsGenericType);
|
||||
|
||||
if (compiledType.IsInterface)
|
||||
{
|
||||
// интерфейс наследует несколько IEnumerable<T> с разными T
|
||||
// невозможно выбрать. требуется явное приведение
|
||||
if (genericInterfaceCount > 1)
|
||||
return null;
|
||||
|
||||
if (genericInterfaceCount == 1)
|
||||
return filterdInterfaces.First(item => item.IsGenericType);
|
||||
else
|
||||
return IEnumType;
|
||||
}
|
||||
|
||||
// для класса/записи необходимо учитывать явные реализации GetEnumerator
|
||||
var methods = compiledType.GetMethods().Where(item => item.Name == "GetEnumerator").ToArray();
|
||||
|
||||
switch (methods.Length)
|
||||
{
|
||||
case 0:
|
||||
// тип реализует явно несколько IEnumerable<T>
|
||||
// невозможно выбрать. требуется явное приведение
|
||||
if (genericInterfaceCount > 1)
|
||||
return null;
|
||||
// тип реализует и IEnumerable и IEnumerable<T> явно
|
||||
// выбираем IEnumerable<T>
|
||||
if (genericInterfaceCount == 1)
|
||||
return filterdInterfaces.First(item => item.IsGenericType);
|
||||
// явно реализует IEnumerable
|
||||
else
|
||||
return IEnumType;
|
||||
case 1:
|
||||
var method = methods[0];
|
||||
|
||||
if (!method.ReturnType.IsGenericType)
|
||||
return IEnumType;
|
||||
else
|
||||
{
|
||||
var elementType = method.ReturnType.GetGenericArguments().First();
|
||||
return IEnumTypedType.MakeGenericType(elementType);
|
||||
}
|
||||
default:
|
||||
// в типе наследнике перекрыли GetEnumerator
|
||||
// невозможно точно выбрать метод
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindIEnumerableElementType(type_node tn, ref type_node elem_type, out bool sys_coll_ienum)
|
||||
{
|
||||
sys_coll_ienum = false;
|
||||
var IEnstring = "System.Collections.IEnumerable";
|
||||
compiled_type_node ctn = compiled_type_node.get_type_node(NetHelper.NetHelper.FindType(IEnstring));
|
||||
|
||||
if (tn is compiled_type_node || tn is compiled_generic_instance_type_node) // Если этот тип зашит в .NET
|
||||
// IEnumerable<integer>, Range(1,10), Dictionary<string,integer>: tn = compiled_type_node
|
||||
// IEnumerable<T>: tn = compiled_generic_instance_type_node
|
||||
|
|
@ -18496,110 +18574,62 @@ namespace PascalABCCompiler.TreeConverter
|
|||
|
||||
if (tn is compiled_type_node)
|
||||
orig = tn as compiled_type_node;
|
||||
else orig = (tn as compiled_generic_instance_type_node).original_generic as compiled_type_node;
|
||||
//var pars = tn.instance_params;
|
||||
System.Type ct = orig.compiled_type;
|
||||
|
||||
Type r;
|
||||
var IEnTstring = "System.Collections.Generic.IEnumerable`1";
|
||||
//if (ct.ToString().StartsWith(IEnTstring)) // SSM Ошибка!!! IEnumerable`1[] тоже начинается с IEnumerable`1, но это массив!
|
||||
if (ct.Name.Equals("IEnumerable`1"))
|
||||
r = ct;
|
||||
else
|
||||
r = ct.GetInterface(IEnTstring);
|
||||
if (r != null)
|
||||
else
|
||||
orig = (tn as compiled_generic_instance_type_node).original_generic as compiled_type_node;
|
||||
|
||||
// непосредственно тип, от котоого разворачивается foreach
|
||||
Type ct = orig.compiled_type;
|
||||
|
||||
var isEnumeratedType = typeof(IEnumerable).IsAssignableFrom(ct);
|
||||
|
||||
if (!isEnumeratedType)
|
||||
return false;
|
||||
|
||||
// для массива
|
||||
if (tn.element_type != null)
|
||||
{
|
||||
Type arg1 = r.GetGenericArguments().First(); // тип параметра IEnumerable
|
||||
var str = arg1.GetGenericArguments().Count();
|
||||
if (tn is compiled_type_node)
|
||||
{
|
||||
elem_type = compiled_type_node.get_type_node(arg1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg1.GetGenericArguments().Count()>0)
|
||||
{
|
||||
elem_type = compiled_type_node.get_type_node(arg1.GetGenericTypeDefinition());
|
||||
elem_type = elem_type.get_instance(tn.instance_params); // SSM 19/07/15 - работает!!!
|
||||
}
|
||||
else
|
||||
{
|
||||
var ip = tn.instance_params;
|
||||
elem_type = tn.element_type;
|
||||
|
||||
var IGrTstring = "System.Linq.IGrouping`2";
|
||||
if (ct.ToString().StartsWith(IGrTstring))
|
||||
elem_type = ip[1];
|
||||
else
|
||||
{
|
||||
var ln = tn.ImplementingInterfaces;
|
||||
elem_type = null;
|
||||
foreach (var x in ln)
|
||||
{
|
||||
var xctn = x as compiled_generic_instance_type_node;
|
||||
if (xctn != null && xctn.name.StartsWith("IEnumerable<")) // Немного грубовато.
|
||||
{
|
||||
elem_type = xctn.instance_params[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ct.Name == "ValueCollection" && ct.IsNested && ct.GetGenericArguments().Length == 2)
|
||||
{
|
||||
elem_type = ip[1];
|
||||
}
|
||||
else if (elem_type == null)
|
||||
elem_type = ip[0];
|
||||
}
|
||||
|
||||
//var Tname = ip[0].name;
|
||||
//elem_type = convert_strong(new SyntaxTree.named_type_reference(Tname, _foreach_stmt.in_what.source_context));
|
||||
}
|
||||
if (ct.GetArrayRank() > 1)
|
||||
sys_coll_ienum = true;
|
||||
|
||||
//elem_type.instance_params = tn.instance_params;
|
||||
//var ip = tn.instance_params;
|
||||
//var Tname = new string(tn.name.SkipWhile(c => c != '<').Skip(1).TakeWhile(c => c != ',' && c != '>').ToArray());
|
||||
//var Tname = ip[0].name;
|
||||
//var Tname = "System.Collections.Generic.KeyValuePair'2"; // <integer,TClass>
|
||||
//elem_type = convert_strong(new SyntaxTree.named_type_reference(Tname, _foreach_stmt.in_what.source_context));
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// в иных случаях ищем подходящий интерфейс
|
||||
var desiredInterface = FindIEnumerableInterfaceInCompiledType(ct);
|
||||
|
||||
if (desiredInterface == null)
|
||||
return false;
|
||||
|
||||
// обнаружен IEnumerable
|
||||
if (!desiredInterface.IsGenericType)
|
||||
{
|
||||
elem_type = SystemLibrary.SystemLibrary.object_type;
|
||||
sys_coll_ienum = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
var foundElementType = desiredInterface.GetGenericArguments().First();
|
||||
|
||||
if (tn is compiled_type_node)
|
||||
elem_type = compiled_type_node.get_type_node(foundElementType);
|
||||
else
|
||||
{
|
||||
if (tn.element_type != null) // значит, это массив любой размерности - 02.02.16 SSM - еще может быть множество set of T - 22.02.16 SSM
|
||||
{
|
||||
elem_type = tn.element_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
var ttt = tn.ImplementingInterfaces;
|
||||
foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces)
|
||||
{
|
||||
if (itn == ctn)
|
||||
{
|
||||
elem_type = SystemLibrary.SystemLibrary.object_type;
|
||||
sys_coll_ienum = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// для "tn is compiled_generic_instance_type_node" необходимо восстановить стёртые типы
|
||||
var ind = orig.instance_params.FindIndex(item => item.name == foundElementType.Name);
|
||||
elem_type = tn.instance_params[ind];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/*else if (tn is compiled_generic_instance_type_node)
|
||||
{
|
||||
var g = tn as compiled_generic_instance_type_node;
|
||||
var og = g.original_generic;
|
||||
var tt = og.ImplementingInterfaces;
|
||||
if (_foreach_stmt.type_name != null && _foreach_stmt.type_name.GetType()!=typeof(SyntaxTree.no_type_foreach))
|
||||
elem_type = convert_strong(_foreach_stmt.type_name);
|
||||
else
|
||||
{
|
||||
var fn = tn.full_name;
|
||||
}
|
||||
return true;
|
||||
} */
|
||||
else // если мы самостоятельно определяем этот тип - можно реализовать в PascalABC.NET только IEnumerable. // Сейчас уже можно!!!!!
|
||||
// Попытка реализовать IEnumerable<T> натыкается на необходимость определять GetEnumerator, возвращающий IEnumerator и IEnumerator<T>
|
||||
{
|
||||
if (tn == null || tn is null_type_node || tn.ImplementingInterfaces == null)
|
||||
var IEnstring = "System.Collections.IEnumerable";
|
||||
compiled_type_node ctn = compiled_type_node.get_type_node(NetHelper.NetHelper.FindType(IEnstring));
|
||||
|
||||
if (tn == null || tn is null_type_node || tn.ImplementingInterfaces == null)
|
||||
{
|
||||
if (tn != null && tn.base_type != null)
|
||||
return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum);
|
||||
|
|
|
|||
|
|
@ -1754,12 +1754,23 @@ namespace PascalABCCompiler.TreeRealization
|
|||
private var_definition_node _ident;
|
||||
private expression_node _in_what;
|
||||
private statement_node _what_do;
|
||||
private type_node _element_type;
|
||||
private bool _is_generic;
|
||||
|
||||
public foreach_node(var_definition_node _ident, expression_node _in_what, statement_node _what_do, location loc):base(loc)
|
||||
public foreach_node(
|
||||
var_definition_node _ident,
|
||||
expression_node _in_what,
|
||||
statement_node _what_do,
|
||||
type_node _element_type,
|
||||
bool _is_generic,
|
||||
location loc
|
||||
):base(loc)
|
||||
{
|
||||
this._ident = _ident;
|
||||
this._in_what = _in_what;
|
||||
this._what_do = _what_do;
|
||||
this._element_type = _element_type;
|
||||
this._is_generic = _is_generic;
|
||||
}
|
||||
|
||||
public var_definition_node ident
|
||||
|
|
@ -1798,6 +1809,18 @@ namespace PascalABCCompiler.TreeRealization
|
|||
}
|
||||
}
|
||||
|
||||
public type_node element_type
|
||||
{
|
||||
get { return _element_type; }
|
||||
set { _element_type = value; }
|
||||
}
|
||||
|
||||
public bool is_generic
|
||||
{
|
||||
get { return _is_generic; }
|
||||
set { _is_generic = value; }
|
||||
}
|
||||
|
||||
public SemanticTree.IStatementNode Body
|
||||
{
|
||||
get
|
||||
|
|
@ -1821,6 +1844,17 @@ namespace PascalABCCompiler.TreeRealization
|
|||
return _ident;
|
||||
}
|
||||
}
|
||||
|
||||
public SemanticTree.ITypeNode ElementType
|
||||
{
|
||||
get { return _element_type; }
|
||||
}
|
||||
|
||||
public bool IsGeneric
|
||||
{
|
||||
get { return _is_generic; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Тип узла.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Reference in a new issue