Example #1
0
        public override void EmitStatement(EmitContext ec)
        {
            var storey = (AsyncTaskStorey)Storey;

            storey.Instance.Emit(ec);
            ec.Emit(OpCodes.Call, storey.StateMachineMethod.Spec);

            if (storey.Task != null)
            {
                //
                // async.$builder.Task;
                //
                var pe_task = new PropertyExpr(storey.Task, loc)
                {
                    InstanceExpression = new FieldExpr(storey.Builder, loc)
                    {
                        InstanceExpression = storey.Instance
                    },
                    Getter = storey.Task.Get
                };

                pe_task.Emit(ec);
            }

            ec.Emit(OpCodes.Ret);
        }
Example #2
0
 internal static bool EmitStack(EmitContext ec, PropertyExpr property, string name, bool isadr)
 {
     if (property.PropertyInfo.Get == null)
     {
         ec.Report.Error(3664, "Asm code : the property " + name + " does not have a get accessor or does not exist");
         return(false);
     }
     if (isadr)
     {
         ec.Report.Error(3664, "Asm code : the property " + name + " could not be used as POPARG");
         return(false);
     }
     ec.Emit(OpCodes.Call, property.PropertyInfo.Get);
     //ec.Emit(OpCodes.Stloc_0);
     //ec.Emit(OpCodes.Ldloc_0);
     return(true);
 }
Example #3
0
        public override void EmitStatement(EmitContext ec)
        {
            var storey = (AsyncTaskStorey)Storey;

            storey.Instance.Emit(ec);

            var move_next_entry = storey.StateMachineMethod.Spec;

            if (storey.MemberName.Arity > 0)
            {
                move_next_entry = MemberCache.GetMember(storey.Instance.Type, move_next_entry);
            }

            ec.Emit(OpCodes.Call, move_next_entry);

            //
            // Emits return <async-storey-instance>.$builder.Task;
            //
            if (storey.Task != null)
            {
                var builder_field = storey.Builder.Spec;
                var task_get      = storey.Task.Get;

                if (storey.MemberName.Arity > 0)
                {
                    builder_field = MemberCache.GetMember(storey.Instance.Type, builder_field);
                    task_get      = MemberCache.GetMember(builder_field.MemberType, task_get);
                }

                var pe_task = new PropertyExpr(storey.Task, loc)
                {
                    InstanceExpression = new FieldExpr(builder_field, loc)
                    {
                        InstanceExpression = storey.Instance
                    },
                    Getter = task_get
                };

                pe_task.Emit(ec);
            }

            ec.Emit(OpCodes.Ret);
        }
Example #4
0
        public void EmitInitializer(EmitContext ec)
        {
            //
            // Some predefined types are missing
            //
            if (builder == null)
            {
                return;
            }

            var instance      = (TemporaryVariableReference)Instance;
            var builder_field = builder.Spec;

            if (MemberName.Arity > 0)
            {
                builder_field = MemberCache.GetMember(instance.Type, builder_field);
            }

            //
            // Inflated factory method when task is of generic type
            //
            if (builder_factory.DeclaringType.IsGeneric)
            {
                var task_return_type = return_type.TypeArguments;
                var bt = builder_factory.DeclaringType.MakeGenericType(Module, task_return_type);
                builder_factory = MemberCache.GetMember(bt, builder_factory);
                builder_start   = MemberCache.GetMember(bt, builder_start);
            }

            //
            // stateMachine.$builder = AsyncTaskMethodBuilder<{task-type}>.Create();
            //
            instance.AddressOf(ec, AddressOp.Store);
            ec.Emit(OpCodes.Call, builder_factory);
            ec.Emit(OpCodes.Stfld, builder_field);

            //
            // stateMachine.$builder.Start<{storey-type}>(ref stateMachine);
            //
            instance.AddressOf(ec, AddressOp.Store);
            ec.Emit(OpCodes.Ldflda, builder_field);
            if (Task != null)
            {
                ec.Emit(OpCodes.Dup);
            }
            instance.AddressOf(ec, AddressOp.Store);
            ec.Emit(OpCodes.Call, builder_start.MakeGenericMethod(Module, instance.Type));

            //
            // Emits return stateMachine.$builder.Task;
            //
            if (Task != null)
            {
                var task_get = Task.Get;

                if (MemberName.Arity > 0)
                {
                    task_get = MemberCache.GetMember(builder_field.MemberType, task_get);
                }

                var pe_task = new PropertyExpr(Task, Location)
                {
                    InstanceExpression = EmptyExpression.Null,                          // Comes from the dup above
                    Getter             = task_get
                };

                pe_task.Emit(ec);
            }
        }
Example #5
0
        public void EmitPrologue(EmitContext ec)
        {
            awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(expr.Type);

            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            Label skip_continuation = ec.DefineLabel();

            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                //
                // awaiter = expr.GetAwaiter ();
                //
                fe_awaiter.EmitAssign(ec, expr, false, false);

                Expression completed_expr;
                if (IsDynamic)
                {
                    var rc = new ResolveContext(ec.MemberContext);

                    Arguments dargs = new Arguments(1);
                    dargs.Add(new Argument(fe_awaiter));
                    completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc);

                    dargs = new Arguments(1);
                    dargs.Add(new Argument(completed_expr));
                    completed_expr = new DynamicConversion(ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve(rc);
                }
                else
                {
                    var pe = PropertyExpr.CreatePredefined(awaiter_definition.IsCompleted, loc);
                    pe.InstanceExpression = fe_awaiter;
                    completed_expr        = pe;
                }

                completed_expr.EmitBranchable(ec, skip_continuation, true);
            }

            base.DoEmit(ec);

            //
            // The stack has to be empty before calling await continuation. We handle this
            // by lifting values which would be left on stack into class fields. The process
            // is quite complicated and quite hard to test because any expression can possibly
            // leave a value on the stack.
            //
            // Following assert fails when some of expression called before is missing EmitToField
            // or parent expression fails to find await in children expressions
            //
            ec.AssertEmptyStack();

            var storey = (AsyncTaskStorey)machine_initializer.Storey;

            if (IsDynamic)
            {
                storey.EmitAwaitOnCompletedDynamic(ec, fe_awaiter);
            }
            else
            {
                storey.EmitAwaitOnCompleted(ec, fe_awaiter);
            }

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);
            ec.MarkLabel(skip_continuation);
        }
Example #6
0
			public override bool Resolve (BlockContext ec)
			{
				bool is_dynamic = expr.Type == InternalType.Dynamic;

				if (is_dynamic) {
					expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
				} else if (TypeManager.IsNullableType (expr.Type)) {
					expr = new Nullable.UnwrapCall (expr).Resolve (ec);
				}

				var get_enumerator_mg = ResolveGetEnumerator (ec);
				if (get_enumerator_mg == null) {
					return false;
				}

				var get_enumerator = get_enumerator_mg.BestCandidate;
				enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
				enumerator_variable.Resolve (ec);

				// Prepare bool MoveNext ()
				var move_next_mg = ResolveMoveNext (ec, get_enumerator);
				if (move_next_mg == null) {
					return false;
				}

				move_next_mg.InstanceExpression = enumerator_variable;

				// Prepare ~T~ Current { get; }
				var current_prop = ResolveCurrent (ec, get_enumerator);
				if (current_prop == null) {
					return false;
				}

				var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
				if (current_pe == null)
					return false;

				VarExpr ve = var_type as VarExpr;
				if (ve != null) {
					if (is_dynamic) {
						// Source type is dynamic, set element type to dynamic too
						var_type = new TypeExpression (InternalType.Dynamic, var_type.Location);
					} else {
						// Infer implicitly typed local variable from foreach enumerable type
						var_type = new TypeExpression (current_pe.Type, var_type.Location);
					}
				} else if (is_dynamic) {
					// Explicit cast of dynamic collection elements has to be done at runtime
					current_pe = EmptyCast.Create (current_pe, InternalType.Dynamic);
				}

				var_type = var_type.ResolveAsTypeTerminal (ec, false);
				if (var_type == null)
					return false;

				variable.Type = var_type.Type;

				var init = new Invocation (get_enumerator_mg, null);

				statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
					new Body (var_type.Type, variable, current_pe, statement, loc), loc);

				var enum_type = enumerator_variable.Type;

				//
				// Add Dispose method call when enumerator can be IDisposable
				//
				if (!enum_type.ImplementsInterface (TypeManager.idisposable_type, false)) {
					if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
						//
						// Runtime Dispose check
						//
						var vd = new RuntimeDispose (enumerator_variable.LocalInfo, loc);
						vd.Initializer = init;
						statement = new Using (vd, statement, loc);
					} else {
						//
						// No Dispose call needed
						//
						this.init = new SimpleAssign (enumerator_variable, init);
						this.init.Resolve (ec);
					}
				} else {
					//
					// Static Dispose check
					//
					var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
					vd.Initializer = init;
					statement = new Using (vd, statement, loc);
				}

				return statement.Resolve (ec);
			}
Example #7
0
			public override void Emit (EmitContext ec)
			{
				pinned_string.CreateBuilder (ec);

				expr.Emit (ec);
				pinned_string.EmitAssign (ec);

				// TODO: Should use Binary::Add
				pinned_string.Emit (ec);
				ec.Emit (OpCodes.Conv_I);

				PropertyExpr pe = new PropertyExpr (TypeManager.int_get_offset_to_string_data, pinned_string.Location);
				//pe.InstanceExpression = pinned_string;
				pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);

				ec.Emit (OpCodes.Add);
				vi.EmitAssign (ec);
			}
Example #8
0
			public override bool Resolve (BlockContext ec)
			{
				bool is_dynamic = expr.Type == InternalType.Dynamic;
				if (is_dynamic)
					expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);

				var get_enumerator_mg = ResolveGetEnumerator (ec);
				if (get_enumerator_mg == null) {
					return false;
				}

				var get_enumerator = get_enumerator_mg.BestCandidate;
				var enumerator = new TemporaryVariable (get_enumerator.ReturnType, loc);
				enumerator.Resolve (ec);

				// Prepare bool MoveNext ()
				var move_next_mg = ResolveMoveNext (ec, get_enumerator);
				if (move_next_mg == null) {
					return false;
				}

				move_next_mg.InstanceExpression = enumerator;

				// Prepare ~T~ Current { get; }
				var current_prop = ResolveCurrent (ec, get_enumerator);
				if (current_prop == null) {
					return false;
				}

				var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator }.Resolve (ec);
				if (current_pe == null)
					return false;

				VarExpr ve = var_type as VarExpr;
				if (ve != null) {
					// Infer implicitly typed local variable from foreach enumerable type
					var_type = new TypeExpression (current_pe.Type, var_type.Location);
				}

				var_type = var_type.ResolveAsTypeTerminal (ec, false);
				if (var_type == null)
					return false;

				var init = new Invocation (get_enumerator_mg, null);
				init.Resolve (ec);

				statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
					new Body (var_type.Type, variable, current_pe, statement, loc), loc);

				var enum_type = enumerator.Type;

				//
				// Add Dispose method call when enumerator can be IDisposable
				//
				if (!enumerator.Type.ImplementsInterface (TypeManager.idisposable_type)) {
					if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
						//
						// Runtime Dispose check
						//
						var tv = new LocalTemporary (TypeManager.idisposable_type);
						statement = new Dispose (enumerator, tv, init, statement, loc);
					} else {
						//
						// No Dispose call needed
						//
						this.init = new SimpleAssign (enumerator, init);
						this.init.Resolve (ec);
					}
				} else {
					//
					// Static Dispose check
					//
					statement = new Dispose (enumerator, null, init, statement, loc);
				}

				return statement.Resolve (ec);
			}
Example #9
0
        public void EmitPrologue(EmitContext ec)
        {
            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            //
            // awaiter = expr.GetAwaiter ();
            //
            fe_awaiter.EmitAssign(ec, expr, false, false);

            Label skip_continuation = ec.DefineLabel();

            Expression completed_expr;

            if (IsDynamic)
            {
                var rc = new ResolveContext(ec.MemberContext);

                Arguments dargs = new Arguments(1);
                dargs.Add(new Argument(fe_awaiter));
                completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc);
            }
            else
            {
                var pe = PropertyExpr.CreatePredefined(is_completed, loc);
                pe.InstanceExpression = fe_awaiter;
                completed_expr        = pe;
            }

            completed_expr.EmitBranchable(ec, skip_continuation, true);

            base.DoEmit(ec);

            //
            // The stack has to be empty before calling await continuation. We handle this
            // by lifting values which would be left on stack into class fields. The process
            // is quite complicated and quite hard to test because any expression can possibly
            // leave a value on the stack.
            //
            // Following assert fails when some of expression called before is missing EmitToField
            // or parent expression fails to find await in children expressions
            //
            ec.AssertEmptyStack();

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            if (IsDynamic)
            {
                var rc      = new ResolveContext(ec.MemberContext);
                var mg_expr = new Invocation(new MemberAccess(fe_awaiter, "OnCompleted"), args).Resolve(rc);

                ExpressionStatement es = (ExpressionStatement)mg_expr;
                es.EmitStatement(ec);
            }
            else
            {
                var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);
                mg_completed.InstanceExpression = fe_awaiter;

                //
                // awaiter.OnCompleted (continuation);
                //
                mg_completed.EmitCall(ec, args);
            }

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);
            ec.MarkLabel(skip_continuation);
        }
Example #10
0
        public override bool Resolve(BlockContext bc)
        {
            if (!base.Resolve(bc))
            {
                return(false);
            }

            type = expr.Type;

            //
            // The task result is of dynamic type
            //
            if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
            {
                throw new NotImplementedException("dynamic await");
            }

            //
            // Check whether the expression is awaitable
            //
            Expression ama = new AwaitableMemberAccess(expr).Resolve(bc);

            if (ama == null)
            {
                return(false);
            }

            Arguments args = new Arguments(0);

            var errors_printer = new SessionReportPrinter();
            var old            = bc.Report.SetPrinter(errors_printer);

            ama = new Invocation(ama, args).Resolve(bc);

            if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type))
            {
                bc.Report.SetPrinter(old);
                Error_WrongGetAwaiter(bc, loc, expr.Type);
                return(false);
            }

            var awaiter_type = ama.Type;

            awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(awaiter_type, loc);
            expr    = ama;

            //
            // Predefined: bool IsCompleted { get; }
            //
            var is_completed_ma = new MemberAccess(expr, "IsCompleted").Resolve(bc);

            if (is_completed_ma != null)
            {
                is_completed = is_completed_ma as PropertyExpr;
                if (is_completed != null && is_completed.Type.BuiltinType == BuiltinTypeSpec.Type.Bool && is_completed.IsInstance && is_completed.Getter != null)
                {
                    // valid
                }
                else
                {
                    bc.Report.SetPrinter(old);
                    Error_WrongAwaiterPattern(bc, awaiter_type);
                    return(false);
                }
            }

            bc.Report.SetPrinter(old);

            if (errors_printer.ErrorsCount > 0)
            {
                Error_WrongAwaiterPattern(bc, awaiter_type);
                return(false);
            }

            //
            // Predefined: OnCompleted (Action)
            //
            if (bc.Module.PredefinedTypes.Action.Define())
            {
                on_completed = MemberCache.FindMember(awaiter_type, MemberFilter.Method("OnCompleted", 0,
                                                                                        ParametersCompiled.CreateFullyResolved(bc.Module.PredefinedTypes.Action.TypeSpec), bc.Module.Compiler.BuiltinTypes.Void),
                                                      BindingRestriction.InstanceOnly) as MethodSpec;

                if (on_completed == null)
                {
                    Error_WrongAwaiterPattern(bc, awaiter_type);
                    return(false);
                }
            }

            //
            // Predefined: GetResult ()
            //
            // The method return type is also result type of await expression
            //
            get_result = MemberCache.FindMember(awaiter_type, MemberFilter.Method("GetResult", 0,
                                                                                  ParametersCompiled.EmptyReadOnlyParameters, null),
                                                BindingRestriction.InstanceOnly) as MethodSpec;

            if (get_result == null)
            {
                Error_WrongAwaiterPattern(bc, awaiter_type);
                return(false);
            }

            return(true);
        }
Example #11
0
			bool TryType (EmitContext ec, Type t)
			{
				MethodGroupExpr mg = Expression.MemberLookup (
					ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
					Expression.AllBindingFlags, loc) as MethodGroupExpr;
				if (mg == null)
					return false;

				MethodInfo result = null;
				MethodInfo tmp_move_next = null;
				PropertyExpr tmp_get_cur = null;
				Type tmp_enumerator_type = enumerator_type;
				foreach (MethodInfo mi in mg.Methods) {
					if (TypeManager.GetParameterData (mi).Count != 0)
						continue;
			
					// Check whether GetEnumerator is public
					if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
						continue;

					if (IsOverride (mi))
						continue;

					enumerator_found = true;

					if (!GetEnumeratorFilter (ec, mi))
						continue;

					if (result != null) {
						if (TypeManager.IsGenericType (result.ReturnType)) {
							if (!TypeManager.IsGenericType (mi.ReturnType))
								continue;

							MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
							Report.SymbolRelatedToPreviousError (t);
							Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
								     "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
								     TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
							return false;
						}

						// Always prefer generics enumerators
						if (!TypeManager.IsGenericType (mi.ReturnType)) {
							if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
							    TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
								continue;

							Report.SymbolRelatedToPreviousError (result);
							Report.SymbolRelatedToPreviousError (mi);
							Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
									TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
							return false;
						}
					}
					result = mi;
					tmp_move_next = move_next;
					tmp_get_cur = get_current;
					tmp_enumerator_type = enumerator_type;
					if (mi.DeclaringType == t)
						break;
				}

				if (result != null) {
					move_next = tmp_move_next;
					get_current = tmp_get_cur;
					enumerator_type = tmp_enumerator_type;
					MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
					get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);

					if (t != expr.Type) {
						expr = Convert.ExplicitConversion (
							ec, expr, t, loc);
						if (expr == null)
							throw new InternalErrorException ();
					}

					get_enumerator.InstanceExpression = expr;
					get_enumerator.IsBase = t != expr.Type;

					return true;
				}

				return false;
			}		
Example #12
0
			//
			// Retrieves a `public T get_Current ()' method from the Type `t'
			//
			bool FetchGetCurrent (EmitContext ec, Type t)
			{
				PropertyExpr pe = Expression.MemberLookup (
					ec.ContainerType, t, "Current", MemberTypes.Property,
					Expression.AllBindingFlags, loc) as PropertyExpr;
				if (pe == null)
					return false;

				get_current = pe;
				return true;
			}
Example #13
0
			bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
			{
				Type return_type = mi.ReturnType;

				//
				// Ok, we can access it, now make sure that we can do something
				// with this `GetEnumerator'
				//

				if (return_type == TypeManager.ienumerator_type ||
				    TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
				    (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
					//
					// If it is not an interface, lets try to find the methods ourselves.
					// For example, if we have:
					// public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
					// We can avoid the iface call. This is a runtime perf boost.
					// even bigger if we have a ValueType, because we avoid the cost
					// of boxing.
					//
					// We have to make sure that both methods exist for us to take
					// this path. If one of the methods does not exist, we will just
					// use the interface. Sadly, this complex if statement is the only
					// way I could do this without a goto
					//

					if (TypeManager.bool_movenext_void == null) {
						TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
							TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
					}

					if (TypeManager.ienumerator_getcurrent == null) {
						TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
							TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
					}

#if GMCS_SOURCE
					//
					// Prefer a generic enumerator over a non-generic one.
					//
					if (return_type.IsInterface && return_type.IsGenericType) {
						enumerator_type = return_type;
						if (!FetchGetCurrent (ec, return_type))
							get_current = new PropertyExpr (
								ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
						if (!FetchMoveNext (return_type))
							move_next = TypeManager.bool_movenext_void;
						return true;
					}
#endif

					if (return_type.IsInterface ||
					    !FetchMoveNext (return_type) ||
					    !FetchGetCurrent (ec, return_type)) {
						enumerator_type = return_type;
						move_next = TypeManager.bool_movenext_void;
						get_current = new PropertyExpr (
							ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
						return true;
					}
				} else {
					//
					// Ok, so they dont return an IEnumerable, we will have to
					// find if they support the GetEnumerator pattern.
					//

					if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
						Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
							TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
						return false;
					}
				}

				enumerator_type = return_type;

				return true;
			}
Example #14
0
            bool TryType(ResolveContext ec, TypeSpec t)
            {
                var mg = Expression.MemberLookup (ec.Compiler, ec.CurrentType, null, t, "GetEnumerator", 0,
                    MemberKind.Method, BindingRestriction.NoOverrides | BindingRestriction.InstanceOnly, loc) as MethodGroupExpr;

                if (mg == null)
                    return false;

                MethodSpec result = null;
                MethodSpec tmp_move_next = null;
                PropertyExpr tmp_get_cur = null;
                TypeSpec tmp_enumerator_type = enumerator_type;
                foreach (MethodSpec mi in mg.Methods) {
                    if (!mi.Parameters.IsEmpty)
                        continue;

                    // Check whether GetEnumerator is public
                    if ((mi.Modifiers & Modifiers.AccessibilityMask) != Modifiers.PUBLIC)
                        continue;

                    enumerator_found = true;

                    if (!GetEnumeratorFilter (ec, mi))
                        continue;

                    if (result != null) {
                        if (TypeManager.IsGenericType (result.ReturnType)) {
                            if (!TypeManager.IsGenericType (mi.ReturnType))
                                continue;

                            ec.Report.SymbolRelatedToPreviousError (t);
                            ec.Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
                                     "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
                                     TypeManager.CSharpName (t), TypeManager.generic_ienumerable_type.GetSignatureForError ());
                            return false;
                        }

                        // Always prefer generics enumerators
                        if (!TypeManager.IsGenericType (mi.ReturnType)) {
                            if (mi.DeclaringType.ImplementsInterface (result.DeclaringType) ||
                                result.DeclaringType.ImplementsInterface (mi.DeclaringType))
                                continue;

                            ec.Report.SymbolRelatedToPreviousError (result);
                            ec.Report.SymbolRelatedToPreviousError (mi);
                            ec.Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
                                    TypeManager.CSharpName (t), "enumerable", result.GetSignatureForError (), mi.GetSignatureForError ());
                            return false;
                        }
                    }
                    result = mi;
                    tmp_move_next = move_next;
                    tmp_get_cur = get_current;
                    tmp_enumerator_type = enumerator_type;
                    if (mi.DeclaringType == t)
                        break;
                }

                if (result != null) {
                    move_next = tmp_move_next;
                    get_current = tmp_get_cur;
                    enumerator_type = tmp_enumerator_type;
                    get_enumerator = new MethodGroupExpr (result, enumerator_type, loc);

                    if (t != expr.Type) {
                        expr = Convert.ExplicitConversion (
                            ec, expr, t, loc);
                        if (expr == null)
                            throw new InternalErrorException ();
                    }

                    get_enumerator.InstanceExpression = expr;
                    get_enumerator.IsBase = t != expr.Type;

                    return true;
                }

                return false;
            }
Example #15
0
            //
            // Retrieves a `public T get_Current ()' method from the Type `t'
            //
            bool FetchGetCurrent(ResolveContext ec, TypeSpec t)
            {
                PropertyExpr pe = Expression.MemberLookup (ec.Compiler,
                    ec.CurrentType, t, "Current", 0, MemberKind.Property,
                    BindingRestriction.AccessibleOnly, loc) as PropertyExpr;
                if (pe == null)
                    return false;

                get_current = pe;
                return true;
            }