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); }
// // 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; }