Exemplo n.º 1
0
        //
        // 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);
        }
Exemplo n.º 2
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);
        }