Пример #1
0
        public override bool Resolve(BlockContext bc)
        {
            if (bc.CurrentBlock is Linq.QueryBlock)
            {
                bc.Report.Error(1995, loc,
                                "The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause");
                return(false);
            }

            if (!base.Resolve(bc))
            {
                return(false);
            }

            type = expr.Type;
            Arguments args = new Arguments(0);

            //
            // The await expression is of dynamic type
            //
            if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
            {
                result_type = type;
                expr        = new Invocation(new MemberAccess(expr, "GetAwaiter"), args).Resolve(bc);
                return(true);
            }

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

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

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

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

            if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type))
            {
                bc.Report.Error(1986, expr.Location,
                                "The `await' operand type `{0}' must have suitable GetAwaiter method",
                                expr.Type.GetSignatureForError());

                return(false);
            }

            var awaiter_type = ama.Type;

            awaiter_definition = bc.Module.GetAwaiter(awaiter_type);

            if (!awaiter_definition.IsValidPattern)
            {
                Error_WrongAwaiterPattern(bc, awaiter_type);
                return(false);
            }

            if (!awaiter_definition.INotifyCompletion)
            {
                bc.Report.Error(4027, loc, "The awaiter type `{0}' must implement interface `{1}'",
                                awaiter_type.GetSignatureForError(), bc.Module.PredefinedTypes.INotifyCompletion.GetSignatureForError());
                return(false);
            }

            expr        = ama;
            result_type = awaiter_definition.GetResult.ReturnType;

            return(true);
        }
Пример #2
0
		//
		// Returns AnonymousMethod container if this anonymous method
		// expression can be implicitly converted to the delegate type `delegate_type'
		//
		public Expression Compatible (ResolveContext ec, TypeSpec type)
		{
			Expression am;
			if (compatibles.TryGetValue (type, out am))
				return am;

			TypeSpec delegate_type = CompatibleChecks (ec, type);
			if (delegate_type == null)
				return null;

			//
			// At this point its the first time we know the return type that is 
			// needed for the anonymous method.  We create the method here.
			//

			var invoke_mb = Delegate.GetInvokeMethod (delegate_type);
			TypeSpec return_type = invoke_mb.ReturnType;

			//
			// Second: the return type of the delegate must be compatible with 
			// the anonymous type.   Instead of doing a pass to examine the block
			// we satisfy the rule by setting the return type on the EmitContext
			// to be the delegate type return type.
			//

			var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
			if (body == null)
				return null;

			bool etree_conversion = delegate_type != type;

			try {
				if (etree_conversion) {
					if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
						//
						// Nested expression tree lambda use same scope as parent
						// lambda, this also means no variable capturing between this
						// and parent scope
						//
						am = body.Compatible (ec, ec.CurrentAnonymousMethod);

						//
						// Quote nested expression tree
						//
						if (am != null)
							am = new Quote (am);
					} else {
						int errors = ec.Report.Errors;

						if (Block.IsAsync) {
							ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees");
						}

						using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) {
							am = body.Compatible (ec);
						}

						//
						// Rewrite expressions into expression tree when targeting Expression<T>
						//
						if (am != null && errors == ec.Report.Errors)
							am = CreateExpressionTree (ec, delegate_type);
					}
				} else {
					am = body.Compatible (ec);

					if (body.DirectMethodGroupConversion != null) {
						var errors_printer = new SessionReportPrinter ();
						var old = ec.Report.SetPrinter (errors_printer);
						var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) {
							AllowSpecialMethodsInvocation = true
						}.Resolve (ec);
						ec.Report.SetPrinter (old);
						if (expr != null && errors_printer.ErrorsCount == 0)
							am = expr;
					}
				}
			} catch (CompletionResult) {
				throw;
			} catch (FatalException) {
				throw;
			} catch (Exception e) {
				throw new InternalErrorException (e, loc);
			}

			if (!ec.IsInProbingMode && !etree_conversion) {
				compatibles.Add (type, am ?? EmptyExpression.Null);
			}

			return am;
		}