// // Return container with awaiter definition. It never returns null // but all container member can be null for easier error reporting // public AwaiterDefinition GetAwaiter(TypeSpec type) { AwaiterDefinition awaiter; if (awaiters.TryGetValue(type, out awaiter)) { return(awaiter); } awaiter = new AwaiterDefinition(); // // Predefined: bool IsCompleted { get; } // awaiter.IsCompleted = MemberCache.FindMember(type, MemberFilter.Property("IsCompleted", Compiler.BuiltinTypes.Bool), BindingRestriction.InstanceOnly) as PropertySpec; // // Predefined: GetResult () // // The method return type is also result type of await expression // awaiter.GetResult = MemberCache.FindMember(type, MemberFilter.Method("GetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.InstanceOnly) as MethodSpec; // // Predefined: INotifyCompletion.OnCompleted (System.Action) // var nc = PredefinedTypes.INotifyCompletion; awaiter.INotifyCompletion = !nc.Define() || type.ImplementsInterface(nc.TypeSpec, false); awaiters.Add(type, awaiter); return(awaiter); }
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); }