diff --git a/Compiler/PCU/PCUFileFormatVersion.cs b/Compiler/PCU/PCUFileFormatVersion.cs index df9533567..0bdbc719a 100644 --- a/Compiler/PCU/PCUFileFormatVersion.cs +++ b/Compiler/PCU/PCUFileFormatVersion.cs @@ -1,11 +1,12 @@ // Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) -//ѕри внесении изменений в структуру PCU файла версию увеличить на 1 + +// при внесении изменений в структуру PCU файла версию увеличить на 1 namespace PascalABCCompiler.PCU { public static class PCUFileFormatVersion { - public static System.Int16 Version = 120; + public static System.Int16 Version = 121; } } diff --git a/Compiler/PCU/PCUReader.cs b/Compiler/PCU/PCUReader.cs index aa8199172..f53de45b7 100644 --- a/Compiler/PCU/PCUReader.cs +++ b/Compiler/PCU/PCUReader.cs @@ -3238,7 +3238,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() diff --git a/Compiler/PCU/PCUWriter.cs b/Compiler/PCU/PCUWriter.cs index e75c2e3e9..70a0c25bf 100644 --- a/Compiler/PCU/PCUWriter.cs +++ b/Compiler/PCU/PCUWriter.cs @@ -3558,6 +3558,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) diff --git a/NETGenerator/Helpers.cs b/NETGenerator/Helpers.cs index f47f9ed49..411f80c17 100644 --- a/NETGenerator/Helpers.cs +++ b/NETGenerator/Helpers.cs @@ -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; diff --git a/NETGenerator/NETGenerator.cs b/NETGenerator/NETGenerator.cs index cbd3a9fd1..ed53c5e8a 100644 --- a/NETGenerator/NETGenerator.cs +++ b/NETGenerator/NETGenerator.cs @@ -1755,7 +1755,18 @@ namespace PascalABCCompiler.NETGenerator private void AddTypeWithoutConvert(ICommonTypeNode t) { if (helper.GetTypeReference(t) != null) return; - TypeBuilder tb = mb.DefineType(BuildTypeName(t.name), ConvertAttributes(t), t.is_value_type?TypeFactory.ValueType:null, new Type[0]); + TypeBuilder tb = null; + try + { + tb = mb.DefineType(BuildTypeName(t.name), ConvertAttributes(t), t.is_value_type ? TypeFactory.ValueType : null, new Type[0]); + } + catch (ArgumentException ex) + { + if (ex.Message.IndexOf("fullname") != -1) + throw new PascalABCCompiler.Errors.CommonCompilerError(ex.Message.Replace("System.ArgumentException: ", ""), t.Location.document.file_name, t.Location.begin_line_num, t.Location.begin_column_num); + throw ex; + } + helper.AddType(t, tb); //(ssyy) обрабатываем generics if (t.is_generic_type_definition) @@ -8268,7 +8279,7 @@ namespace PascalABCCompiler.NETGenerator private bool EmitBox(IExpressionNode from, Type LocalType) { - if ((from.type.is_value_type || from.type.is_generic_parameter) && !(from is SemanticTree.INullConstantNode) && (LocalType == TypeFactory.ObjectType || TypeIsInterface(LocalType))) + if ((from.type.is_value_type || from.type.is_generic_parameter) && !(from is SemanticTree.INullConstantNode) && (LocalType == TypeFactory.ObjectType || TypeIsInterface(LocalType) || LocalType == TypeFactory.EnumType)) { il.Emit(OpCodes.Box, helper.GetTypeReference(from.type).tp);//упаковка return true; @@ -9850,6 +9861,10 @@ namespace PascalABCCompiler.NETGenerator case basic_function_type.ior: il.Emit(OpCodes.Or); break; case basic_function_type.ixor: il.Emit(OpCodes.Xor); break; + case basic_function_type.enumsand: il.Emit(OpCodes.And); break; + case basic_function_type.enumsor: il.Emit(OpCodes.Or); break; + case basic_function_type.enumsxor: il.Emit(OpCodes.Xor); break; + case basic_function_type.land: il.Emit(OpCodes.And); break; case basic_function_type.lor: il.Emit(OpCodes.Or); break; case basic_function_type.lxor: il.Emit(OpCodes.Xor); break; @@ -11601,40 +11616,46 @@ namespace PascalABCCompiler.NETGenerator public override void visit(IForeachNode value) { VarInfo vi = helper.GetVariable(value.VarIdent); - //Type interf = helper.GetTypeReference(value.InWhatExpr.type).tp; - 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; + 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) + // если элемент перечисления объявлен в коде + // или типоаргумент элемента перечисления объявлен в коде + // например IEnumerable, array of MyType + if (helper.IsConstructedGenericType(elementType)) { - enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes); - return_type = enumer_mi.ReturnType; + enumer_mi = TypeBuilder.GetMethod( + TypeFactory.IEnumerableGenericType.MakeGenericType(elementType), + TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator") + ); + + // IEnumerator + return_type = enumer_mi.ReturnType + .GetGenericTypeDefinition() + .MakeGenericType(elementType); } + // для полностью скомпилированных типов TypeBuilder не требуется + // IEnumerable, array of string else { - is_generic = enumer_mi.ReturnType.IsGenericType; + enumer_mi = TypeFactory.IEnumerableGenericType.MakeGenericType(elementType).GetMethod("GetEnumerator"); 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); } - } else { - enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes); + 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++); diff --git a/SemanticTree/SemanticTree.cs b/SemanticTree/SemanticTree.cs index 29dcd0b91..769d3e436 100644 --- a/SemanticTree/SemanticTree.cs +++ b/SemanticTree/SemanticTree.cs @@ -64,7 +64,7 @@ namespace PascalABCCompiler.SemanticTree //write,writei,writed,writec,writeb,read,readi,readd,readc,readb,expd,absd,absi //temporary functions (Нужны только на начальном этапе отладки. Потом обязательно удалить.) objtoobj, boolinc, booldec, boolsinc, boolsdec, booltoi, enumgr, enumgreq, enumsm, enumsmeq, booltob, booltosb, booltos, booltous, booltoui, booltol, booltoul, - ltop, ptol + ltop, ptol, enumsand, enumsor, enumsxor }; public enum runtime_statement_type { invoke_delegate, ctor_delegate, begin_invoke_delegate, end_invoke_delegate }; @@ -2350,6 +2350,16 @@ namespace PascalABCCompiler.SemanticTree { get; } + + ITypeNode ElementType + { + get; + } + + bool IsGeneric + { + get; + } } public interface ILockStatement : IStatementNode, ILocated diff --git a/TestSuite/enum10.pas b/TestSuite/enum10.pas new file mode 100644 index 000000000..728ac9f18 --- /dev/null +++ b/TestSuite/enum10.pas @@ -0,0 +1,12 @@ +type + Days = (mon,Tue,Wed,Thi,Fri,Sat,Sun); + +procedure MyPrint(obj: object); +begin + assert(obj.ToString() = 'Fri'); +end; +begin + var en: System.Enum; + en := fri; + MyPrint(en); +end. \ No newline at end of file diff --git a/TestSuite/enum9.pas b/TestSuite/enum9.pas new file mode 100644 index 000000000..9d2124e48 --- /dev/null +++ b/TestSuite/enum9.pas @@ -0,0 +1,19 @@ +type + Days = ( + None = 0, // 0 + Monday = 1, // 1 + Tuesday = 2, // 2 + Wednesday = 4, // 4 + Thursday = 8, // 8 + Friday = 16, // 16 + Saturday = 32, // 32 + Sunday = 64, // 64 + Weekend = Saturday or Sunday + ); + +begin + var d : Days := Saturday; + var meetingDays := Days.Monday or Days.Friday; + assert((d and Days.Weekend) = Saturday); + assert((meetingDays and Days.Friday) = Days.Friday); +end. \ No newline at end of file diff --git a/TestSuite/errors/err0540_foreach_resolver.pas b/TestSuite/errors/err0540_foreach_resolver.pas new file mode 100644 index 000000000..f57f7c1b2 --- /dev/null +++ b/TestSuite/errors/err0540_foreach_resolver.pas @@ -0,0 +1,20 @@ +//!Невозможно выполнить оператор foreach или yield sequence по выражению типа c1 + +uses System.Collections, System.Collections.Generic; + +type + c1 = class (IEnumerable, IEnumerable) + public + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + end; + +begin + foreach var item in new c1 do ; +end. \ No newline at end of file diff --git a/TestSuite/errors/err0542.pas b/TestSuite/errors/err0542.pas new file mode 100644 index 000000000..bf191b3c0 --- /dev/null +++ b/TestSuite/errors/err0542.pas @@ -0,0 +1,6 @@ +type + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = class end; + +begin + System.Reflection.Assembly.GetEntryAssembly.GetTypes.Single(t->t.Name.StartsWith('a'*50)).FullName.Println.Length.Print; +end. \ No newline at end of file diff --git a/TestSuite/foreach_resolver1.pas b/TestSuite/foreach_resolver1.pas new file mode 100644 index 000000000..c61937fea --- /dev/null +++ b/TestSuite/foreach_resolver1.pas @@ -0,0 +1,48 @@ +{$reference 'foreach_resolver_lib.dll'} + +type + c0 = class + procedure pr:= exit; + end; + +begin + var v1:= new c1; + v1._element:= new c0; + + foreach var item in v1 do + item.pr; + + Assert(check); + check:= false; + + var v2:= new c2; + v2._element:= 'myStr'; + foreach var item in v2 do + item.Replace('my', 'your'); + + Assert(check); + check:= false; + + var v3:= new c3; + v3._element:= 'myStr'; + foreach var item in v3 do + print(item); + + Assert(check); + check:= false; + + var v4:= new c4; + v4._element:= 'myStr'; + foreach var item in v4 do + item.Replace('my', 'your'); + + Assert(check); + check:= false; + + var v5:= new c5; + v5._element:= 4; + foreach var item in v5 do + Assert(item = 4); + + Assert(check); +end. \ No newline at end of file diff --git a/TestSuite/foreach_resolver2.pas b/TestSuite/foreach_resolver2.pas new file mode 100644 index 000000000..70333207e --- /dev/null +++ b/TestSuite/foreach_resolver2.pas @@ -0,0 +1,67 @@ +uses System.Collections, System.Collections.Generic; + +type + c1 = class (IEnumerable) + public + + function IEnumerable.GetEnumerator: IEnumerator; + begin + Assert(false); + end; + + function GetEnumerator: IEnumerator; + begin + result:= Seq&().GetEnumerator; + end; + end; + + c2 = class (IEnumerable) + public + function GetEnumerator: IEnumerator; + begin + result:= Seq&().GetEnumerator; + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin + Assert(false); + end; + end; + + c3 = class (IEnumerable, IEnumerable) + public + function GetEnumerator: IEnumerator; + begin + result:= Seq&().GetEnumerator; + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin + Assert(false); + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin + Assert(false); + end; + end; + + c4 = class (c2) + + end; + +begin + + var v1:= new c1; + foreach var item in v1 do ; + + var v2:= new c2; + foreach var item in v2 do ; + + var v3:= new c3; + foreach var item in v3 do ; + + var v4:= new c4; + foreach var item in v4 do ; + +end. \ No newline at end of file diff --git a/TestSuite/foreach_resolver_lib.dll b/TestSuite/foreach_resolver_lib.dll new file mode 100644 index 000000000..e56056d11 Binary files /dev/null and b/TestSuite/foreach_resolver_lib.dll differ diff --git a/TestSuite/foreach_resolver_lib.pas b/TestSuite/foreach_resolver_lib.pas new file mode 100644 index 000000000..3f629a79e --- /dev/null +++ b/TestSuite/foreach_resolver_lib.pas @@ -0,0 +1,58 @@ +library foreach_resolver_lib; + uses System.Collections, System.Collections.Generic; + + var check:= false; + + type + c1 = class (IEnumerable, IEnumerable) + public + _element: T2; + + function GetEnumerator: IEnumerator; + begin + check:= true; + result:= lst( _element ).GetEnumerator; + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + end; + + c2 = class (IEnumerable, IEnumerable) + public + _element: string; + + function GetEnumerator: IEnumerator; + begin + check:= true; + result:= lst(_element).GetEnumerator; + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + end; + + c3 = class (IEnumerable) + public + _element: object; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + + function GetEnumerator: IEnumerator; + begin + check:= true; + result:= |_element|.GetEnumerator; + end; + end; + + c4 = class (c2) end; + + c5 = class (c1) end; +end. \ No newline at end of file diff --git a/TestSuite/nullable18.pas b/TestSuite/nullable18.pas new file mode 100644 index 000000000..e1ad0be1b --- /dev/null +++ b/TestSuite/nullable18.pas @@ -0,0 +1,6 @@ +begin + var a := |default(integer?),nil,1|; + assert(a[1] = nil); + assert(a[0] = nil); + assert(a[2] = 1); +end. \ No newline at end of file diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs index 545daadf7..b4ed54b74 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs @@ -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); diff --git a/TreeConverter/SystemLib/static_executors.cs b/TreeConverter/SystemLib/static_executors.cs index f237b679e..2d61a219e 100644 --- a/TreeConverter/SystemLib/static_executors.cs +++ b/TreeConverter/SystemLib/static_executors.cs @@ -2683,12 +2683,18 @@ namespace PascalABCCompiler.SystemLibrary int_const_node left = parameters[0] as int_const_node; if (left == null) { - return null; + if (parameters[0] is enum_const_node ecn) + left = new int_const_node(ecn.constant_value, ecn.location); + else + return null; } int_const_node right = parameters[1] as int_const_node; if (right == null) { - return null; + if (parameters[1] is enum_const_node ecn) + right = new int_const_node(ecn.constant_value, ecn.location); + else + return null; } return (make_int_const(((left.constant_value) | (right.constant_value)), call_location)); } diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs index 0a30a594d..a8f25cd54 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs @@ -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) { diff --git a/TreeConverter/TreeConversion/compilation_context.cs b/TreeConverter/TreeConversion/compilation_context.cs index 95fde5f7e..d7d581c87 100644 --- a/TreeConverter/TreeConversion/compilation_context.cs +++ b/TreeConverter/TreeConversion/compilation_context.cs @@ -2052,8 +2052,11 @@ namespace PascalABCCompiler.TreeConverter SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.greq_name,tctn,SemanticTree.basic_function_type.enumgreq,SystemLibrary.SystemLibrary.bool_type); SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.sm_name,tctn,SemanticTree.basic_function_type.enumsm,SystemLibrary.SystemLibrary.bool_type); SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.smeq_name,tctn,SemanticTree.basic_function_type.enumsmeq,SystemLibrary.SystemLibrary.bool_type); - - SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.byte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itob,false); + SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.or_name, tctn, SemanticTree.basic_function_type.enumsor, tctn); + SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.and_name, tctn, SemanticTree.basic_function_type.enumsand, tctn); + SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.xor_name, tctn, SemanticTree.basic_function_type.enumsxor, tctn); + + SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.byte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itob,false); SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.sbyte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itosb,false); SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.short_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itos,false); SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.ushort_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itous,false); diff --git a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs index 0958f3a2b..21eb03f53 100644 --- a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs +++ b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs @@ -3285,7 +3285,8 @@ namespace PascalABCCompiler.TreeConverter ret_type = types[i]; else if (tc == type_compare.non_comparable_type) { - AddError(lst[i].location, "UNCOMPARABLE_TYPES_IN_ARRAY_CONST"); + if (!can_convert_type(types[i], ret_type)) + AddError(lst[i].location, "UNCOMPARABLE_TYPES_IN_ARRAY_CONST"); } } diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 6da486b2a..0fd47d29b 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -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 { @@ -1178,7 +1180,12 @@ namespace PascalABCCompiler.TreeConverter left_type = SystemLibrary.SystemLibrary.integer_type; left.type = left_type; } - + + if (right_type == null && right is enum_const_node) + { + right_type = SystemLibrary.SystemLibrary.integer_type; + right.type = right_type; + } if (left_type.semantic_node_type == semantic_node_type.delegated_method) { @@ -3653,7 +3660,11 @@ namespace PascalABCCompiler.TreeConverter cdn.const_value = new enum_const_node(num++, null, get_location(id)); else { - constant_node cn = convert_strong_to_constant_node(en.value,SystemLibrary.SystemLibrary.integer_type); + constant_node cn = convert_strong_to_constant_node(en.value, SystemLibrary.SystemLibrary.integer_type); + if (cn is basic_function_call_as_constant bfcc && bfcc.method_call.function_node.compile_time_executor != null) + { + cn = convert_strong_to_constant_node(bfcc.method_call.function_node.compile_time_executor(bfcc.location, bfcc.method_call.parameters.ToArray()), SystemLibrary.SystemLibrary.integer_type); + } check_for_strong_constant(cn,get_location(en.value)); cdn.const_value = new enum_const_node((cn as int_const_node).constant_value,null,get_location(id)); } @@ -3661,6 +3672,12 @@ namespace PascalABCCompiler.TreeConverter } common_type_node ctn = context.create_enum_type(null, get_location(_enum_type_definition)); //_enum_type_definition.values num = 0; + foreach (constant_definition_node cdn in cnsts) + { + cdn.const_value.type = ctn; + } + + int i = 0; foreach (SyntaxTree.enumerator en in _enum_type_definition.enumerators.enumerators) { SyntaxTree.ident id = (en.name as named_type_reference).FirstIdent; @@ -3669,14 +3686,12 @@ namespace PascalABCCompiler.TreeConverter cdn.const_value = new enum_const_node(num++, null, get_location(id)); else { - constant_node cn = convert_strong_to_constant_node(en.value,SystemLibrary.SystemLibrary.integer_type); - check_for_strong_constant(cn,get_location(en.value)); - cdn.const_value = new enum_const_node((cn as int_const_node).constant_value,null,get_location(id)); + cdn.const_value = cnsts[i].const_value; } cdn.const_value.type = ctn; + i++; } - foreach (constant_definition_node cdn in cnsts) - cdn.const_value.type = ctn; + internal_interface ii = SystemLibrary.SystemLibrary.integer_type.get_internal_interface(internal_interface_kind.ordinal_interface); ordinal_type_interface oti_old = (ordinal_type_interface)ii; enum_const_node lower_value = new enum_const_node(0, ctn, ctn.loc); @@ -3686,6 +3701,7 @@ namespace PascalABCCompiler.TreeConverter oti_old.lower_eq_method, oti_old.greater_eq_method, oti_old.lower_method, oti_old.greater_method, lower_value, upper_value, oti_old.value_to_int, oti_old.ordinal_type_to_int); ctn.add_internal_interface(oti_new); + //foreach (constant_definition_node cdn in cnsts) // cdn.const_value.type = ctn; //context.leave_block(); @@ -13723,7 +13739,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); } } @@ -18488,179 +18504,328 @@ namespace PascalABCCompiler.TreeConverter return false; } + private bool IsIEnumerableInterface(Type t) + { + var IEnumType = typeof(IEnumerable); + var IEnumTypedType = typeof(IEnumerable<>); + + var isIEnumType = (t == IEnumType); + var isIEnumTypedType = t.IsGenericType + && (t.GetGenericTypeDefinition() == IEnumTypedType + ); + + return isIEnumType || isIEnumTypedType; + } + + private bool IsIEnumeratorInterface(Type t) + { + var IEnumType = typeof(IEnumerator); + var IEnumTypedType = typeof(IEnumerator<>); + + var isIEnumType = (t == IEnumType); + var isIEnumTypedType = t.IsGenericType + && (t.GetGenericTypeDefinition() == IEnumTypedType + ); + + return isIEnumType || isIEnumTypedType; + } + + private Type FindIEnumerableInterfaceInCompiledType(Type compiledType) + { + var IEnumType = typeof(IEnumerable); + var IEnumTypedType = typeof(IEnumerable<>); + + // если тип является интерфейсом IEnumerable или IEnumerable то берём его + if (IsIEnumerableInterface(compiledType)) + return compiledType; + + // иначе ищем подходящие интерфейсы в иерархии + var filteredInterfaces = compiledType.FindInterfaces( + (item, _) => IsIEnumerableInterface(item), + null + ); + + var genericInterfaceCount = filteredInterfaces.Count(item => item.IsGenericType); + + if (compiledType.IsInterface) + { + // интерфейс наследует несколько IEnumerable с разными T + // невозможно выбрать. требуется явное приведение + if (genericInterfaceCount > 1) + return null; + + if (genericInterfaceCount == 1) + return filteredInterfaces.First(item => item.IsGenericType); + else + return IEnumType; + } + + // для класса/записи необходимо учитывать явные реализации GetEnumerator + var methods = compiledType.GetMethods().Where(item => + item.Name == "GetEnumerator" + && item.GetParameters().Length == 0 + && IsIEnumeratorInterface(item.ReturnType) + ).ToArray(); + + switch (methods.Length) + { + case 0: + // тип реализует явно несколько IEnumerable + // невозможно выбрать. требуется явное приведение + if (genericInterfaceCount > 1) + return null; + // тип реализует и IEnumerable и IEnumerable явно + // выбираем IEnumerable + if (genericInterfaceCount == 1) + return filteredInterfaces.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; + } + } + + private bool IsIEnumerableInterface(type_node t) + { + compiled_type_node orig; + + if (t is compiled_type_node) + orig = t as compiled_type_node; + else if (t is compiled_generic_instance_type_node) + orig = (t as compiled_generic_instance_type_node).original_generic as compiled_type_node; + else + return false; + + return IsIEnumerableInterface(orig.compiled_type); + } + + /// + /// Собирает интерфейсы, реализованные типом и его предками + /// + private List CollectInterfacesFromTypeNode(type_node node) + { + var result = new List(); + result.AddRange(node.ImplementingInterfaces); + + if (node.base_type != null) + { + var interfInBase = CollectInterfacesFromTypeNode(node.base_type); + result.AddRange(interfInBase); + } + + return result.Cast().ToList(); + } + + private bool IsIEnumeratorInterface(type_node t) + { + compiled_type_node orig; + + if (t is compiled_type_node) + orig = t as compiled_type_node; + else if (t is compiled_generic_instance_type_node) + orig = (t as compiled_generic_instance_type_node).original_generic as compiled_type_node; + else + return false; + + return IsIEnumeratorInterface(orig.compiled_type); + } + + private type_node FindIEnumerableInterfaceInTypeNode(type_node node) + { + var IEnumType = compiled_type_node.get_type_node( typeof(IEnumerable) ); + var IEnumTypedType = compiled_type_node.get_type_node( typeof(IEnumerable<>) ); + + var filteredInterfaces = CollectInterfacesFromTypeNode(node) + .Where(item => IsIEnumerableInterface(item)) + .ToArray(); + + var genericInterfaceCount = filteredInterfaces.Count(item => item.is_generic_type_instance); + + if (node.IsInterface) + { + // интерфейс наследует несколько IEnumerable с разными T + // невозможно выбрать. требуется явное приведение + if (genericInterfaceCount > 1) + return null; + + if (genericInterfaceCount == 1) + return filteredInterfaces.First(item => item.is_generic_type_instance); + else + return IEnumType; + } + + var commonType = (common_type_node)node; + + var methods = commonType.methods.Where(item => + item.name.Equals("GetEnumerator", StringComparison.OrdinalIgnoreCase) + && item.parameters.Count == 0 + && IsIEnumeratorInterface(item.return_value_type) + ).ToArray(); + + switch (methods.Length) + { + case 0: + // тип реализует явно несколько IEnumerable + // невозможно выбрать. требуется явное приведение + if (genericInterfaceCount > 1) + return null; + // тип реализует и IEnumerable и IEnumerable явно + // выбираем IEnumerable + if (genericInterfaceCount == 1) + return filteredInterfaces.First(item => item.is_generic_type_instance); + // явно реализует IEnumerable + else + return IEnumType; + case 1: + var method = methods[0]; + + if (!method.return_value_type.is_generic_type_instance) + return IEnumType; + else + return IEnumTypedType.get_instance(method.return_value_type.instance_params); + 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, Range(1,10), Dictionary: tn = compiled_type_node - // IEnumerable: tn = compiled_generic_instance_type_node - // FibGen = class(IEnumerable,IEnumerator): tn = common_type_node, en = compiled_type_node - // array of Person: tn = common_type_node + + // поиск в типе, объявленном в другой сборке + // и тип и типоаргументы объявлены в другой сборке + // Dictionary: tn = compiled_type_node + // IEnumerable: tn = compiled_type_node + // + // тип объявлен в другой сборке, а типоаргументы в коде + // Dictionary: tn = compiled_generic_instance_type_node + // IEnumerable: tn = compiled_generic_instance_type_node (например в generic подпрогамме) + if (tn is compiled_type_node || tn is compiled_generic_instance_type_node) { compiled_type_node orig; 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 = tn.element_type; + + if (ct.GetArrayRank() > 1) + sys_coll_ienum = 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 + { + // для "tn is compiled_generic_instance_type_node" необходимо восстановить стёртые типы + // orig.instance_params содержит имена типоаргументов при объявлении + // tn.instance_params содержит фактические типоаргументы + // остаётся найти нужный индекс в orig и взять аргумент из tn + + if (foundElementType.IsGenericParameter) { - elem_type = compiled_type_node.get_type_node(arg1); + var ind = orig.instance_params.FindIndex(item => item.name == foundElementType.Name); + elem_type = tn.instance_params[ind]; } 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; + // значит элемент последовательности сам является generic типом + // нужно сопоставить все типоаргументы из orig типоаргументам из tn + // нельзя просто брать все, тк их количество может отличаться - 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)); - } + var declaredTypes = foundElementType + .GetGenericArguments() + .Select(item=> item.Name) + .ToArray(); - //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"; // - //elem_type = convert_strong(new SyntaxTree.named_type_reference(Tname, _foreach_stmt.in_what.source_context)); - } - return true; - } - 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 actualTypes = tn.instance_params + .Where((item, i) => declaredTypes.Contains(orig.instance_params[i].name)) + .ToList(); - 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; - } + elem_type = compiled_type_node.get_type_node( foundElementType.GetGenericTypeDefinition() ); + elem_type = elem_type.get_instance(actualTypes); } } - } - /*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 натыкается на необходимость определять GetEnumerator, возвращающий IEnumerator и IEnumerator - { - 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); - return false; - } + } - if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file) // еще может быть множество set of T - 22.02.16 SSM + // поиск в типе, объявленном в коде + // также сюда попадают set of T даже если они подтягиваются из библиотеки + else + { + // массивы и set of T + if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file) { elem_type = tn.element_type; + + if ((tn as common_type_node).rank != 1) + sys_coll_ienum = true; + return true; } - foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // Ищем интерфейс IEnumerable и возвращаем T в качестве elem_type - { - if (itn is compiled_generic_instance_type_node) - { - var itnc = (itn as compiled_generic_instance_type_node); - var tt = (itnc.original_generic as compiled_type_node).compiled_type; - if (tt == typeof(System.Collections.Generic.IEnumerable<>)) - { - elem_type = itnc.generic_parameters[0] as common_type_node; - return true; - } - } - } + var desiredInterface = FindIEnumerableInterfaceInTypeNode(tn); - foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // если не нашли - ищем интерфейс IEnumerable и возвращаем object в качестве elem_type + if (desiredInterface == null) + return false; + + if (!desiredInterface.is_generic_type_instance) { - if (itn is compiled_type_node) // Именно этот кусок отвечает за IEnumerable и мы его закомментировали - { - var itnc = (itn as compiled_type_node).compiled_type; /* SSM раскомментировал 15.05.2020 - пришла пора*/ - if (itnc.IsGenericType) - { - var my = itnc.GetGenericTypeDefinition();// = typeof(System.Collections.Generic.IEnumerable<>) - if (my == typeof(System.Collections.Generic.IEnumerable<>)) - { - var aarg1 = itnc.GetGenericArguments().First(); - elem_type = compiled_type_node.get_type_node(aarg1); - return true; - } - } - else /* end SSM раскомментировал 15.05.2020 - пришла пора*/ - if (itn == ctn) - { - elem_type = SystemLibrary.SystemLibrary.object_type; - sys_coll_ienum = true; - return true; - } - } + elem_type = SystemLibrary.SystemLibrary.object_type; + sys_coll_ienum = true; } + else + elem_type = desiredInterface.instance_params[0]; + + return true; } - if (tn != null && tn.base_type != null) - return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum); - return false; } private int GenIdNum = 0; diff --git a/TreeConverter/TreeRealization/statements.cs b/TreeConverter/TreeRealization/statements.cs index 4c57148b3..e4666a416 100644 --- a/TreeConverter/TreeRealization/statements.cs +++ b/TreeConverter/TreeRealization/statements.cs @@ -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; } + } + /// /// Тип узла. ///