Beispiel #1
0
        /// <summary>
        /// Parse expression. Returns null if there are any errors.
        /// </summary>
        internal static ExpressionSyntax ParseExpression(
            this string expr,
            DiagnosticBag diagnostics,
            bool allowFormatSpecifiers,
            out ReadOnlyCollection<string> formatSpecifiers)
        {
            // Remove trailing semi-colon if any. This is to support copy/paste
            // of (simple cases of) RHS of assignment in Watch window, not to
            // allow arbitrary syntax after the semi-colon, not even comments.
            if (RemoveSemicolonIfAny(ref expr))
            {
                // Format specifiers are not expected before a semi-colon.
                allowFormatSpecifiers = false;
            }

            var syntax = ParseDebuggerExpression(expr, consumeFullText: !allowFormatSpecifiers);
            diagnostics.AddRange(syntax.GetDiagnostics());
            formatSpecifiers = null;
            if (allowFormatSpecifiers)
            {
                var builder = ArrayBuilder<string>.GetInstance();
                if (ParseFormatSpecifiers(builder, expr, syntax.FullWidth, diagnostics) &&
                    (builder.Count > 0))
                {
                    formatSpecifiers = new ReadOnlyCollection<string>(builder.ToArray());
                }
                builder.Free();
            }
            return diagnostics.HasAnyErrors() ? null : syntax;
        }
Beispiel #2
0
        internal static ExpressionSyntax ParseAssignment(
            this string target,
            string expr,
            DiagnosticBag diagnostics)
        {
            var text = SourceText.From(expr);
            var expression = SyntaxHelpers.ParseDebuggerExpressionInternal(text, consumeFullText: true);
            // We're creating a SyntaxTree for just the RHS so that the Diagnostic spans for parse errors
            // will be correct (with respect to the original input text).  If we ever expose a SemanticModel
            // for debugger expressions, we should use this SyntaxTree.
            var syntaxTree = expression.CreateSyntaxTree(text);
            diagnostics.AddRange(syntaxTree.GetDiagnostics());
            if (diagnostics.HasAnyErrors())
            {
                return null;
            }

            // Any Diagnostic spans produced in binding will be offset by the length of the "target" expression text.
            // If we want to support live squiggles in debugger windows, SemanticModel, etc, we'll want to address this.
            var targetSyntax = SyntaxHelpers.ParseDebuggerExpressionInternal(SourceText.From(target), consumeFullText: true);
            Debug.Assert(!targetSyntax.GetDiagnostics().Any(), "The target of an assignment should never contain Diagnostics if we're being allowed to assign to it in the debugger.");

            var assignment = InternalSyntax.SyntaxFactory.AssignmentExpression(
                SyntaxKind.SimpleAssignmentExpression,
                targetSyntax,
                InternalSyntax.SyntaxFactory.Token(SyntaxKind.EqualsToken),
                expression);
            return assignment.MakeDebuggerExpression(SourceText.From(assignment.ToString()));
        }
Beispiel #3
0
        internal static void BindFieldInitializers(
            SourceMemberContainerTypeSymbol typeSymbol,
            MethodSymbol scriptCtor,
            ImmutableArray<FieldInitializers> fieldInitializers,
            bool generateDebugInfo,
            DiagnosticBag diagnostics,
            ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering
        {
            DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance();
            try
            {
                ConsList<Imports> firstDebugImports;

                processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers,
                    diagsForInstanceInitializers, generateDebugInfo, out firstDebugImports);

                processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
                processedInitializers.FirstDebugImports = firstDebugImports;
            }
            finally
            {
                diagnostics.AddRange(diagsForInstanceInitializers);
                diagsForInstanceInitializers.Free();
            }
        }
Beispiel #4
0
        internal void GrabDiagnostics(DiagnosticBag addTo)
        {
            // force lazy init
            ComputeParameters();
            ComputeReturnType();

            var diags = ImmutableInterlocked.InterlockedExchange(ref _diagnostics, default(ImmutableArray<Diagnostic>));
            if (!diags.IsDefault)
            {
                addTo.AddRange(diags);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Builds a delegate that will execute just this scripts code.
        /// </summary>
        public Func<object[], object> Build(
            Script script,
            DiagnosticBag diagnostics,
            CancellationToken cancellationToken)
        {
            var compilation = script.GetCompilation();

            using (var peStream = new MemoryStream())
            {
                var emitResult = compilation.Emit(
                    peStream: peStream,
                    pdbStream: null,
                    xmlDocumentationStream: null,
                    win32Resources: null,
                    manifestResources: null,
                    options: EmitOptions.Default,
                    cancellationToken: cancellationToken);

                diagnostics.AddRange(emitResult.Diagnostics);

                if (!emitResult.Success)
                {
                    return null;
                }

                // let the loader know where to find assemblies:
                foreach (var referencedAssembly in compilation.GetBoundReferenceManager().GetReferencedAssemblies())
                {
                    var path = (referencedAssembly.Key as PortableExecutableReference)?.FilePath;
                    if (path != null)
                    {
                        // TODO: Should the #r resolver return contract metadata and runtime assembly path -
                        // Contract assembly used in the compiler, RT assembly path here.
                        _assemblyLoader.RegisterDependency(referencedAssembly.Value.Identity, path);
                    }
                }

                peStream.Position = 0;

                var assembly = _assemblyLoader.Load(peStream, pdbStream: null);

                // TODO: GetEntryPoint currently doesn't work for scripts/submissions.
                // See https://github.com/dotnet/roslyn/issues/3719.
                // var entryPoint = compilation.GetEntryPoint(cancellationToken);
                var entryPointMethod = GetEntryPointRuntimeMethod(emitResult.EntryPointOpt, assembly, cancellationToken);

                return entryPointMethod.CreateDelegate<Func<object[], object>>();
            }
        }
 internal static void BindFieldInitializers(
     CSharpCompilation compilation,
     SynthesizedInteractiveInitializerMethod scriptInitializerOpt,
     ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers,
     DiagnosticBag diagnostics,
     ref ProcessedFieldInitializers processedInitializers)
 {
     var diagsForInstanceInitializers = DiagnosticBag.GetInstance();
     ImportChain firstImportChain;
     processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain);
     processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
     processedInitializers.FirstImportChain = firstImportChain;
     diagnostics.AddRange(diagsForInstanceInitializers);
     diagsForInstanceInitializers.Free();
 }
Beispiel #7
0
        protected BoundExpression BindTargetExpression(DiagnosticBag diagnostics)
        {
            if (lazyExpressionAndDiagnostics == null)
            {
                // Filter out method group in conversion.
                DiagnosticBag expressionDiagnostics = DiagnosticBag.GetInstance();
                BoundExpression boundExpression = this.BindValue(TargetExpressionSyntax, expressionDiagnostics, Binder.BindValueKind.RValueOrMethodGroup);
                Interlocked.CompareExchange(ref lazyExpressionAndDiagnostics, new ExpressionAndDiagnostics(boundExpression, expressionDiagnostics.ToReadOnlyAndFree()), null);
            }
            Debug.Assert(lazyExpressionAndDiagnostics != null);

            if (diagnostics != null)
            {
                diagnostics.AddRange(lazyExpressionAndDiagnostics.Diagnostics);
            }

            return lazyExpressionAndDiagnostics.Expression;
        }
        internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
        {
            // If it is a valid C# 6 switch statement, we use the old binder to bind it.
            if (!UseV7SwitchBinder) return base.BindSwitchExpressionAndSections(node, originalBinder, diagnostics);

            Debug.Assert(SwitchSyntax.Equals(node));

            // Bind switch expression and set the switch governing type.
            var boundSwitchExpression = SwitchGoverningExpression;
            diagnostics.AddRange(SwitchGoverningDiagnostics);

            BoundPatternSwitchLabel defaultLabel;
            ImmutableArray<BoundPatternSwitchSection> switchSections = BindPatternSwitchSections(boundSwitchExpression, node.Sections, originalBinder, out defaultLabel, diagnostics);
            var locals = GetDeclaredLocalsForScope(node);
            var functions = GetDeclaredLocalFunctionsForScope(node);
            return new BoundPatternSwitchStatement(
                node, boundSwitchExpression,
                locals, functions, switchSections, defaultLabel, this.BreakLabel, this);
        }
        internal static void BindFieldInitializers(
            CSharpCompilation compilation,
            SynthesizedInteractiveInitializerMethod scriptInitializerOpt,
            ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers,
            DiagnosticBag diagnostics,
            bool setReturnType, // Remove once static fields are errors in submissions.
            ref ProcessedFieldInitializers processedInitializers)
        {
            if (setReturnType && ((object)scriptInitializerOpt != null))
            {
                SetScriptInitializerReturnType(compilation, scriptInitializerOpt, fieldInitializers, diagnostics);
            }

            var diagsForInstanceInitializers = DiagnosticBag.GetInstance();
            ImportChain firstImportChain;
            processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain);
            processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
            processedInitializers.FirstImportChain = firstImportChain;
            diagnostics.AddRange(diagsForInstanceInitializers);
            diagsForInstanceInitializers.Free();
        }
Beispiel #10
0
        internal static void BindFieldInitializers(
            SourceMemberContainerTypeSymbol typeSymbol,
            MethodSymbol scriptCtor,
            ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers,
            DiagnosticBag diagnostics,
            ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering
        {
            DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance();
            try
            {
                ImportChain firstImportChain;

                processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers,
                    diagsForInstanceInitializers, out firstImportChain);

                processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
                processedInitializers.FirstImportChain = firstImportChain;
            }
            finally
            {
                diagnostics.AddRange(diagsForInstanceInitializers);
                diagsForInstanceInitializers.Free();
            }
        }
Beispiel #11
0
        /// <summary>
        /// This method does the following set of operations in the specified order:
        /// (1) GetAttributesToBind: Merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target.
        /// (2) BindAttributeTypes: Bind all the attribute types to enable early decode of certain well-known attributes by type.
        /// (3) EarlyDecodeWellKnownAttributes: Perform early decoding of certain well-known attributes that could be queried by the binder in subsequent steps.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (4) GetAttributes: Bind the attributes (attribute arguments and constructor) using bound attribute types.
        /// (5) DecodeWellKnownAttributes: Decode and validate bound well known attributes.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (6) StoreBoundAttributesAndDoPostValidation:
        ///     (a) Store the bound attributes in lazyCustomAttributes in a thread safe manner.
        ///     (b) Perform some additional post attribute validations, such as
        ///         1) Duplicate attributes, attribute usage target validation, etc.
        ///         2) Post validation for attributes dependent on other attributes
        ///         These validations cannot be performed prior to step 6(a) as we might need to
        ///         perform a GetAttributes() call on a symbol which can introduce a cycle in attribute binding.
        ///         We avoid this cycle by performing such validations in PostDecodeWellKnownAttributes after lazyCustomAttributes have been set.
        ///     NOTE: PostDecodeWellKnownAttributes SHOULD NOT change the symbol state.
        /// </summary>
        /// <remarks>
        /// Current design of early decoding well-known attributes doesn't permit decoding attribute arguments/constructor as this can lead to binding cycles.
        /// For well-known attributes used by the binder, where we need the decoded arguments, we must handle them specially in one of the following possible ways:
        ///   (a) Avoid decoding the attribute arguments during binding and delay the corresponding binder tasks to a separate post-pass executed after binding.
        ///   (b) As the cycles can be caused only when we are binding attribute arguments/constructor, special case the corresponding binder tasks based on the current BinderFlags.
        /// </remarks>
        /// <param name="attributesSyntaxLists"></param>
        /// <param name="lazyCustomAttributesBag"></param>
        /// <param name="symbolPart">Specific part of the symbol to which the attributes apply, or <see cref="AttributeLocation.None"/> if the attributes apply to the symbol itself.</param>
        /// <param name="earlyDecodingOnly">Indicates that only early decoding should be performed.  WARNING: the resulting bag will not be sealed.</param>
        /// <param name="addToDiagnostics">Diagnostic bag to report into. If null, diagnostics will be reported into <see cref="AddDeclarationDiagnostics"/></param>
        /// <param name="binderOpt">Binder to use. If null, <see cref="DeclaringCompilation"/> GetBinderFactory will be used.</param>
        /// <returns>Flag indicating whether lazyCustomAttributes were stored on this thread. Caller should check for this flag and perform NotePartComplete if true.</returns>
        internal bool LoadAndValidateAttributes(
            OneOrMany<SyntaxList<AttributeListSyntax>> attributesSyntaxLists,
            ref CustomAttributesBag<CSharpAttributeData> lazyCustomAttributesBag,
            AttributeLocation symbolPart = AttributeLocation.None,
            bool earlyDecodingOnly = false,
            DiagnosticBag addToDiagnostics = null,
            Binder binderOpt = null)
        {
            var diagnostics = DiagnosticBag.GetInstance();
            var compilation = this.DeclaringCompilation;

            ImmutableArray<Binder> binders;
            ImmutableArray<AttributeSyntax> attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, binderOpt, out binders);
            Debug.Assert(!attributesToBind.IsDefault);

            ImmutableArray<CSharpAttributeData> boundAttributes;
            WellKnownAttributeData wellKnownAttributeData;

            if (attributesToBind.Any())
            {
                Debug.Assert(!binders.IsDefault);
                Debug.Assert(binders.Length == attributesToBind.Length);

                // Initialize the bag so that data decoded from early attributes can be stored onto it.
                if (lazyCustomAttributesBag == null)
                {
                    Interlocked.CompareExchange(ref lazyCustomAttributesBag, new CustomAttributesBag<CSharpAttributeData>(), null);
                }

                // Bind the attribute types and then early decode them.
                int totalAttributesCount = attributesToBind.Length;
                var attributeTypesBuilder = new NamedTypeSymbol[totalAttributesCount];

                Binder.BindAttributeTypes(binders, attributesToBind, this, attributeTypesBuilder, diagnostics);
                ImmutableArray<NamedTypeSymbol> boundAttributeTypes = attributeTypesBuilder.AsImmutableOrNull();

                this.EarlyDecodeWellKnownAttributeTypes(boundAttributeTypes, attributesToBind);
                this.PostEarlyDecodeWellKnownAttributeTypes();

                // Bind the attribute in two stages - early and normal.
                var attributesBuilder = new CSharpAttributeData[totalAttributesCount];

                // Early bind and decode some well-known attributes.
                EarlyWellKnownAttributeData earlyData = this.EarlyDecodeWellKnownAttributes(binders, boundAttributeTypes, attributesToBind, symbolPart, attributesBuilder);
                Debug.Assert(!attributesBuilder.Contains((attr) => attr != null && attr.HasErrors));

                // Store data decoded from early bound well-known attributes.
                // TODO: what if this succeeds on another thread, not ours?
                lazyCustomAttributesBag.SetEarlyDecodedWellKnownAttributeData(earlyData);

                if (earlyDecodingOnly)
                {
                    diagnostics.Free(); //NOTE: dropped.
                    return false;
                }

                // Bind attributes.
                Binder.GetAttributes(binders, attributesToBind, boundAttributeTypes, attributesBuilder, diagnostics);
                boundAttributes = attributesBuilder.AsImmutableOrNull();

                // All attributes must be bound by now.
                Debug.Assert(!boundAttributes.Any((attr) => attr == null));

                // Validate attribute usage and Decode remaining well-known attributes.
                wellKnownAttributeData = this.ValidateAttributeUsageAndDecodeWellKnownAttributes(binders, attributesToBind, boundAttributes, diagnostics, symbolPart);

                // Store data decoded from remaining well-known attributes.
                // TODO: what if this succeeds on another thread but not this thread?
                lazyCustomAttributesBag.SetDecodedWellKnownAttributeData(wellKnownAttributeData);
            }
            else if (earlyDecodingOnly)
            {
                diagnostics.Free(); //NOTE: dropped.
                return false;
            }
            else
            {
                boundAttributes = ImmutableArray<CSharpAttributeData>.Empty;
                wellKnownAttributeData = null;
                Interlocked.CompareExchange(ref lazyCustomAttributesBag, CustomAttributesBag<CSharpAttributeData>.WithEmptyData(), null);
                this.PostEarlyDecodeWellKnownAttributeTypes();
            }

            this.PostDecodeWellKnownAttributes(boundAttributes, attributesToBind, diagnostics, symbolPart, wellKnownAttributeData);

            // Store attributes into the bag.
            bool lazyAttributesStoredOnThisThread = false;
            if (lazyCustomAttributesBag.SetAttributes(boundAttributes))
            {
                this.RecordPresenceOfBadAttributes(boundAttributes);
                if (addToDiagnostics == null)
                {
                    this.AddDeclarationDiagnostics(diagnostics);
                }
                else
                {
                    addToDiagnostics.AddRange(diagnostics);
                }
                lazyAttributesStoredOnThisThread = true;
                if (lazyCustomAttributesBag.IsEmpty) lazyCustomAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty;
            }

            Debug.Assert(lazyCustomAttributesBag.IsSealed);
            diagnostics.Free();
            return lazyAttributesStoredOnThisThread;
        }
Beispiel #12
0
        internal void GrabDiagnostics(DiagnosticBag addTo)
        {
            // force lazy init
            ComputeParameters();
            ComputeReturnType();

            var diags = ImmutableInterlocked.InterlockedExchange(ref _diagnostics, default(ImmutableArray<Diagnostic>));
            if (!diags.IsDefault)
            {
                addTo.AddRange(diags);
                addTo.AddRange(_lazyParametersAndDiagnostics.Diagnostics);
                // Note _lazyParametersAndDiagnostics and _lazyReturnTypeAndDiagnostics
                // are computed always, but _lazyTypeParameterConstraintsAndDiagnostics
                // is only computed if there are constraints.
                if (_lazyTypeParameterConstraintsAndDiagnostics != null)
                {
                    addTo.AddRange(_lazyTypeParameterConstraintsAndDiagnostics.Diagnostics);
                }
                addTo.AddRange(_lazyReturnTypeAndDiagnostics.Diagnostics);
            }
        }
Beispiel #13
0
        public bool GenerateSummaryErrors(DiagnosticBag diagnostics)
        {
            // It is highly likely that "the same" error will be given for two different
            // bindings of the same lambda but with different values for the parameters
            // of the error. For example, if we have x=>x.Blah() where x could be int
            // or string, then the two errors will be "int does not have member Blah" and 
            // "string does not have member Blah", but the locations and errors numbers
            // will be the same.
            //
            // We should first see if there is a set of errors that are "the same" by
            // this definition that occur in every lambda binding; if there are then
            // those are the errors we should report.
            //
            // If there are no errors that are common to *every* binding then we
            // can report the complete set of errors produced by every binding. However,
            // we still wish to avoid duplicates, so we will use the same logic for
            // building the union as the intersection; two errors with the same code
            // and location are to be treated as the same error and only reported once,
            // regardless of how that error is parameterized.
            //
            // The question then rears its head: when given two of "the same" error
            // to report that are nevertheless different in their arguments, which one
            // do we choose? To the user it hardly matters; either one points to the
            // right location in source code. But it surely matters to our testing team;
            // we do not want to be in a position where some small change to our internal
            // representation of lambdas causes tests to break because errors are reported
            // differently.
            //
            // What we need to do is find a *repeatable* arbitrary way to choose between
            // two errors; we can for example simply take the one that is lower in alphabetical
            // order when converted to a string.

            var equalityComparer = new CommonDiagnosticComparer();
            Func<Diagnostic, Diagnostic, int> canonicalComparer = CanonicallyCompareDiagnostics;

            FirstAmongEqualsSet<Diagnostic> intersection = null;
            var convBags = from boundLambda in _bindingCache.Values select boundLambda.Diagnostics;
            var retBags = from boundLambda in _returnInferenceCache.Values select boundLambda.Diagnostics;
            var allBags = convBags.Concat(retBags);

            foreach (ImmutableArray<Diagnostic> bag in allBags)
            {
                if (intersection == null)
                {
                    intersection = new FirstAmongEqualsSet<Diagnostic>(bag, equalityComparer, canonicalComparer);
                }
                else
                {
                    intersection.IntersectWith(bag);
                }
            }

            if (intersection != null)
            {
                foreach (var diagnostic in intersection)
                {
                    if (ErrorFacts.PreventsSuccessfulDelegateConversion((ErrorCode)diagnostic.Code))
                    {
                        diagnostics.AddRange(intersection);
                        return true;
                    }
                }
            }

            FirstAmongEqualsSet<Diagnostic> union = null;

            foreach (ImmutableArray<Diagnostic> bag in allBags)
            {
                if (union == null)
                {
                    union = new FirstAmongEqualsSet<Diagnostic>(bag, equalityComparer, canonicalComparer);
                }
                else
                {
                    union.UnionWith(bag);
                }
            }

            if (union != null)
            {
                foreach (var diagnostic in union)
                {
                    if (ErrorFacts.PreventsSuccessfulDelegateConversion((ErrorCode)diagnostic.Code))
                    {
                        diagnostics.AddRange(union);
                        return true;
                    }
                }
            }

            return false;
        }
Beispiel #14
0
        public static bool ReportDelegateMethodGroupDiagnostics(Binder binder, BoundMethodGroup expr, TypeSymbol targetType, DiagnosticBag diagnostics)
        {
            var invokeMethodOpt = GetDelegateInvokeMethodIfAvailable(targetType);
            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            var resolution = ResolveDelegateMethodGroup(binder, expr, invokeMethodOpt, ref useSiteDiagnostics);

            diagnostics.Add(expr.Syntax, useSiteDiagnostics);

            bool hasErrors = resolution.HasAnyErrors;

            diagnostics.AddRange(resolution.Diagnostics);

            // SPEC VIOLATION: Unfortunately, we cannot exactly implement the specification for
            // the scenario in which an extension method that extends a value type is converted
            // to a delegate. The code we generate that captures a delegate to a static method
            // that is "partially evaluated" with the bound-to-the-delegate first argument
            // requires that the first argument be of reference type.
            //
            // SPEC VIOLATION: Similarly, we cannot capture a method of Nullable<T>, because
            // boxing a Nullable<T> gives a T, not a boxed Nullable<T>.
            //
            // We give special error messages in these situations.

            if (resolution.MethodGroup != null)
            {
                var result = resolution.OverloadResolutionResult;
                if (result != null)
                {
                    if (result.Succeeded)
                    {
                        var method = result.BestResult.Member;
                        Debug.Assert((object)method != null);
                        if (resolution.MethodGroup.IsExtensionMethodGroup)
                        {
                            Debug.Assert(method.IsExtensionMethod);

                            var thisParameter = method.Parameters[0];
                            if (!thisParameter.Type.IsReferenceType)
                            {
                                // Extension method '{0}' defined on value type '{1}' cannot be used to create delegates
                                diagnostics.Add(
                                    ErrorCode.ERR_ValueTypeExtDelegate,
                                    expr.Syntax.Location,
                                    method,
                                    thisParameter.Type);
                                hasErrors = true;
                            }
                        }
                        else if (method.OriginalDefinition.ContainingType.SpecialType == SpecialType.System_Nullable_T && !method.IsOverride)
                        {
                            // CS1728: Cannot bind delegate to '{0}' because it is a member of 'System.Nullable<T>'
                            diagnostics.Add(
                                ErrorCode.ERR_DelegateOnNullable,
                                expr.Syntax.Location,
                                method);
                            hasErrors = true;
                        }
                    }
                    else if (!hasErrors &&
                             !resolution.IsEmpty &&
                             resolution.ResultKind == LookupResultKind.Viable)
                    {
                        var overloadDiagnostics = DiagnosticBag.GetInstance();

                        result.ReportDiagnostics(binder, expr.Syntax.Location, overloadDiagnostics,
                                                 expr.Name,
                                                 resolution.MethodGroup.Receiver, resolution.AnalyzedArguments, resolution.MethodGroup.Methods.ToImmutable(),
                                                 typeContainingConstructor: null, delegateTypeBeingInvoked: null, isMethodGroupConversion: true);

                        if (!overloadDiagnostics.IsEmptyWithoutResolution)
                        {
                            hasErrors = overloadDiagnostics.HasAnyErrors();
                            diagnostics.AddRange(overloadDiagnostics);
                        }

                        overloadDiagnostics.Free();
                    }
                }
            }

            resolution.Free();
            return(hasErrors);
        }
Beispiel #15
0
        /// <summary>
        /// Builds a delegate that will execute just this scripts code.
        /// </summary>
        public Func<object[], object> Build(
            Script script,
            DiagnosticBag diagnostics,
            CancellationToken cancellationToken)
        {
            var compilation = script.GetCompilation();
            var options = script.Options;

            DiagnosticBag emitDiagnostics = DiagnosticBag.GetInstance();
            byte[] compiledAssemblyImage;
            MethodInfo entryPoint;

            bool success = compilation.Emit(
                 GetOrCreateDynamicModule(options.IsCollectible),
                assemblyLoader: GetAssemblyLoader(options.IsCollectible),
                assemblySymbolMapper: symbol => MapAssemblySymbol(symbol, options.IsCollectible),
                recoverOnError: true,
                diagnostics: emitDiagnostics,
                cancellationToken: cancellationToken,
                entryPoint: out entryPoint,
                compiledAssemblyImage: out compiledAssemblyImage
             );

            if (diagnostics != null)
            {
                diagnostics.AddRange(emitDiagnostics);
            }

            bool hadEmitErrors = emitDiagnostics.HasAnyErrors();
            emitDiagnostics.Free();

            // emit can fail due to compilation errors or because there is nothing to emit:
            if (!success)
            {
                return null;
            }

            Debug.Assert(entryPoint != null);

            if (compiledAssemblyImage != null)
            {
                // Ref.Emit wasn't able to emit the assembly
                _uncollectibleCodeManager.AddFallBackAssembly(entryPoint.DeclaringType.Assembly);
            }
#if DEBUG
            if (SaveCompiledAssemblies)
            {
                _uncollectibleCodeManager.Save(UncollectibleModuleFileName);
                _collectibleCodeManager.Save(CollectibleModuleFileName);
            }
#endif

            return (Func<object[], object>)Delegate.CreateDelegate(typeof(Func<object[], object>), entryPoint);
        }
        private static BoundExpression CreateAnonymousFunctionConversion(CSharpSyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
        {
            // We have a successful anonymous function conversion; rather than producing a node
            // which is a conversion on top of an unbound lambda, replace it with the bound
            // lambda.

            // UNDONE: Figure out what to do about the error case, where a lambda
            // UNDONE: is converted to a delegate that does not match. What to surface then?

            var unboundLambda = (UnboundLambda)source;
            var boundLambda = unboundLambda.Bind((NamedTypeSymbol)destination);
            diagnostics.AddRange(boundLambda.Diagnostics);

            return new BoundConversion(
                syntax,
                boundLambda,
                conversion,
                @checked: false,
                explicitCastInCode: isCast,
                constantValueOpt: ConstantValue.NotAvailable,
                type: destination)
            { WasCompilerGenerated = source.WasCompilerGenerated };
        }
Beispiel #17
0
        private BoundExpression FinalTranslation(QueryTranslationState state, DiagnosticBag diagnostics)
        {
            Debug.Assert(state.clauses.IsEmpty());
            switch (state.selectOrGroup.Kind())
            {
            case SyntaxKind.SelectClause:
            {
                // A query expression of the form
                //     from x in e select v
                // is translated into
                //     ( e ) . Select ( x => v )
                var selectClause = (SelectClauseSyntax)state.selectOrGroup;
                var x            = state.rangeVariable;
                var e            = state.fromExpression;
                var v            = selectClause.Expression;
                var lambda       = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v);
                var result       = MakeQueryInvocation(state.selectOrGroup, e, "Select", lambda, diagnostics);
                return(MakeQueryClause(selectClause, result, queryInvocation: result));
            }

            case SyntaxKind.GroupClause:
            {
                // A query expression of the form
                //     from x in e group v by k
                // is translated into
                //     ( e ) . GroupBy ( x => k , x => v )
                // except when v is the identifier x, the translation is
                //     ( e ) . GroupBy ( x => k )
                var       groupClause = (GroupClauseSyntax)state.selectOrGroup;
                var       x           = state.rangeVariable;
                var       e           = state.fromExpression;
                var       v           = groupClause.GroupExpression;
                var       k           = groupClause.ByExpression;
                var       vId         = v as IdentifierNameSyntax;
                BoundCall result;
                var       lambdaLeft = MakeQueryUnboundLambda(state.RangeVariableMap(), x, k);

                // this is the unoptimized form (when v is not the identifier x)
                var             d           = DiagnosticBag.GetInstance();
                BoundExpression lambdaRight = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v);
                result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", ImmutableArray.Create(lambdaLeft, lambdaRight), d);
                // k and v appear reversed in the invocation, so we reorder their evaluation
                result = ReverseLastTwoParameterOrder(result);

                BoundExpression unoptimizedForm = null;
                if (vId != null && vId.Identifier.ValueText == x.Name)
                {
                    // The optimized form.  We store the unoptimized form for analysis
                    unoptimizedForm = result;
                    result          = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", lambdaLeft, diagnostics);
                    if (unoptimizedForm.HasAnyErrors && !result.HasAnyErrors)
                    {
                        unoptimizedForm = null;
                    }
                }
                else
                {
                    diagnostics.AddRange(d);
                }

                d.Free();
                return(MakeQueryClause(groupClause, result, queryInvocation: result, unoptimizedForm: unoptimizedForm));
            }

            default:
            {
                // there should have been a syntax error if we get here.
                return(new BoundBadExpression(
                           state.selectOrGroup, LookupResultKind.OverloadResolutionFailure, ImmutableArray <Symbol> .Empty,
                           ImmutableArray.Create(state.fromExpression), state.fromExpression.Type));
            }
            }
        }
        internal static bool EmitCompilation(
            Compilation c,
            IEnumerable<ResourceDescription> manifestResources,
            List<ModuleData> dependencies,
            DiagnosticBag diagnostics,
            bool emitPdb,
            CompilationTestData testData,
            out ImmutableArray<byte> assembly,
            out ImmutableArray<byte> pdb
        )
        {
            assembly = default(ImmutableArray<byte>);
            pdb = default(ImmutableArray<byte>);

            EmitReferences(c, dependencies, diagnostics, emitPdb);

            using (var executableStream = new MemoryStream())
            {
                EmitResult result;
                MemoryStream pdbStream;
                string pdbFilePath;

                if (emitPdb)
                {
                    pdbStream = new MemoryStream();
                    pdbFilePath = c.AssemblyName + ".pdb";
                }
                else
                    {
                    pdbStream = null;
                    pdbFilePath = null;
                    }

                try
                {
                    result = c.Emit(
                        executableStream,
                        outputName: null,
                        pdbFilePath: pdbFilePath,
                        pdbStream: pdbStream,
                        xmlDocStream: null,
                        cancellationToken: default(CancellationToken),
                        win32Resources: null,
                        manifestResources: manifestResources,
                        metadataOnly: false,
                        testData: testData);
                }
                finally
                {
                    if (pdbStream != null)
                {
                        pdb = pdbStream.ToImmutable();
                        pdbStream.Dispose();
                    }
                }

                diagnostics.AddRange(result.Diagnostics);
                assembly = executableStream.ToImmutable();

                return result.Success;
            }
        }
Beispiel #19
0
        protected BoundCall MakeQueryInvocation(CSharpSyntaxNode node, BoundExpression receiver, string methodName, SeparatedSyntaxList <TypeSyntax> typeArgsSyntax, ImmutableArray <TypeWithAnnotations> typeArgs, ImmutableArray <BoundExpression> args, DiagnosticBag diagnostics)
        {
            // clean up the receiver
            var ultimateReceiver = receiver;

            while (ultimateReceiver.Kind == BoundKind.QueryClause)
            {
                ultimateReceiver = ((BoundQueryClause)ultimateReceiver).Value;
            }
            if ((object)ultimateReceiver.Type == null)
            {
                if (ultimateReceiver.HasAnyErrors || node.HasErrors)
                {
                    // report no additional errors
                }
                else if (ultimateReceiver.IsLiteralNull())
                {
                    diagnostics.Add(ErrorCode.ERR_NullNotValid, node.Location);
                }
                else if (ultimateReceiver.IsLiteralDefault())
                {
                    diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, node.Location);
                }
                else if (ultimateReceiver.Kind == BoundKind.NamespaceExpression)
                {
                    diagnostics.Add(ErrorCode.ERR_BadSKunknown, ultimateReceiver.Syntax.Location, ultimateReceiver.Syntax, MessageID.IDS_SK_NAMESPACE.Localize());
                }
                else if (ultimateReceiver.Kind == BoundKind.Lambda || ultimateReceiver.Kind == BoundKind.UnboundLambda)
                {
                    // Could not find an implementation of the query pattern for source type '{0}'.  '{1}' not found.
                    diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, MessageID.IDS_AnonMethod.Localize(), methodName);
                }
                else if (ultimateReceiver.Kind == BoundKind.MethodGroup)
                {
                    var methodGroup = (BoundMethodGroup)ultimateReceiver;
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteDiagnostics: ref useSiteDiagnostics);
                    diagnostics.Add(node, useSiteDiagnostics);
                    diagnostics.AddRange(resolution.Diagnostics);
                    if (resolution.HasAnyErrors)
                    {
                        receiver = this.BindMemberAccessBadResult(methodGroup);
                    }
                    else
                    {
                        Debug.Assert(!resolution.IsEmpty);
                        diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, MessageID.IDS_SK_METHOD.Localize(), methodName);
                    }
                    resolution.Free();
                }

                receiver = new BoundBadExpression(receiver.Syntax, LookupResultKind.NotAValue, ImmutableArray <Symbol> .Empty, ImmutableArray.Create(receiver), CreateErrorType());
            }
            else if (receiver.Type.SpecialType == SpecialType.System_Void)
            {
                if (!receiver.HasAnyErrors && !node.HasErrors)
                {
                    diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, "void", methodName);
                }

                receiver = new BoundBadExpression(receiver.Syntax, LookupResultKind.NotAValue, ImmutableArray <Symbol> .Empty, ImmutableArray.Create(receiver), CreateErrorType());
            }

            return((BoundCall)MakeInvocationExpression(
                       node,
                       receiver,
                       methodName,
                       args,
                       diagnostics,
                       typeArgsSyntax,
                       typeArgs,
                       queryClause: node,
                       // Queries are syntactical rewrites, so we allow fields and properties of delegate types to be invoked,
                       // although no well-known non-generic query method is used atm.
                       allowFieldsAndProperties: true));
        }
Beispiel #20
0
        protected BoundCall MakeQueryInvocation(CSharpSyntaxNode node, BoundExpression receiver, string methodName, SeparatedSyntaxList<TypeSyntax> typeArgsSyntax, ImmutableArray<TypeSymbol> typeArgs, ImmutableArray<BoundExpression> args, DiagnosticBag diagnostics)
        {
            // clean up the receiver
            var ultimateReceiver = receiver;
            while (ultimateReceiver.Kind == BoundKind.QueryClause) ultimateReceiver = ((BoundQueryClause)ultimateReceiver).Value;
            if ((object)ultimateReceiver.Type == null)
            {
                if (ultimateReceiver.HasAnyErrors || node.HasErrors)
                {
                    // report no additional errors
                }
                else if (ultimateReceiver.IsLiteralNull())
                {
                    diagnostics.Add(ErrorCode.ERR_NullNotValid, node.Location);
                }
                else if (ultimateReceiver.Kind == BoundKind.Lambda || ultimateReceiver.Kind == BoundKind.UnboundLambda)
                {
                    // Could not find an implementation of the query pattern for source type '{0}'.  '{1}' not found.
                    diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, MessageID.IDS_AnonMethod.Localize(), methodName);
                }
                else if (ultimateReceiver.Kind == BoundKind.MethodGroup)
                {
                    var methodGroup = (BoundMethodGroup)ultimateReceiver;
                    HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                    var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteDiagnostics: ref useSiteDiagnostics);
                    diagnostics.Add(node, useSiteDiagnostics);
                    diagnostics.AddRange(resolution.Diagnostics);
                    if (resolution.HasAnyErrors)
                    {
                        receiver = this.BindMemberAccessBadResult(methodGroup);
                    }
                    else
                    {
                        Debug.Assert(!resolution.IsEmpty);
                        diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, MessageID.IDS_SK_METHOD.Localize(), methodName);
                    }
                    resolution.Free();
                }

                receiver = new BoundBadExpression(receiver.Syntax, LookupResultKind.NotAValue, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(receiver), CreateErrorType());
            }
            else if (receiver.Type.SpecialType == SpecialType.System_Void)
            {
                if (!receiver.HasAnyErrors && !node.HasErrors)
                {
                    diagnostics.Add(ErrorCode.ERR_QueryNoProvider, node.Location, "void", methodName);
                }

                receiver = new BoundBadExpression(receiver.Syntax, LookupResultKind.NotAValue, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(receiver), CreateErrorType());
            }

            return (BoundCall)MakeInvocationExpression(
                node,
                receiver,
                methodName,
                args,
                diagnostics,
                typeArgsSyntax,
                typeArgs,
                queryClause: node,
                // Queries are syntactical rewrites, so we allow fields and properties of delegate types to be invoked,
                // although no well-known non-generic query method is used atm.
                allowFieldsAndProperties: true);
        }
Beispiel #21
0
        private BoundExpression FinalTranslation(QueryTranslationState state, DiagnosticBag diagnostics)
        {
            Debug.Assert(state.clauses.IsEmpty());
            switch (state.selectOrGroup.Kind())
            {
                case SyntaxKind.SelectClause:
                    {
                        // A query expression of the form
                        //     from x in e select v
                        // is translated into
                        //     ( e ) . Select ( x => v )
                        var selectClause = (SelectClauseSyntax)state.selectOrGroup;
                        var x = state.rangeVariable;
                        var e = state.fromExpression;
                        var v = selectClause.Expression;
                        var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v);
                        var result = MakeQueryInvocation(state.selectOrGroup, e, "Select", lambda, diagnostics);
                        return MakeQueryClause(selectClause, result, queryInvocation: result);
                    }
                case SyntaxKind.GroupClause:
                    {
                        // A query expression of the form
                        //     from x in e group v by k
                        // is translated into
                        //     ( e ) . GroupBy ( x => k , x => v )
                        // except when v is the identifier x, the translation is
                        //     ( e ) . GroupBy ( x => k )
                        var groupClause = (GroupClauseSyntax)state.selectOrGroup;
                        var x = state.rangeVariable;
                        var e = state.fromExpression;
                        var v = groupClause.GroupExpression;
                        var k = groupClause.ByExpression;
                        var vId = v as IdentifierNameSyntax;
                        BoundCall result;
                        var lambdaLeft = MakeQueryUnboundLambda(state.RangeVariableMap(), x, k);

                        // this is the unoptimized form (when v is not the identifier x)
                        var d = DiagnosticBag.GetInstance();
                        BoundExpression lambdaRight = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v);
                        result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", ImmutableArray.Create(lambdaLeft, lambdaRight), d);
                        // k and v appear reversed in the invocation, so we reorder their evaluation
                        result = ReverseLastTwoParameterOrder(result);

                        BoundExpression unoptimizedForm = null;
                        if (vId != null && vId.Identifier.ValueText == x.Name)
                        {
                            // The optimized form.  We store the unoptimized form for analysis
                            unoptimizedForm = result;
                            result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", lambdaLeft, diagnostics);
                            if (unoptimizedForm.HasAnyErrors && !result.HasAnyErrors) unoptimizedForm = null;
                        }
                        else
                        {
                            diagnostics.AddRange(d);
                        }

                        d.Free();
                        return MakeQueryClause(groupClause, result, queryInvocation: result, unoptimizedForm: unoptimizedForm);
                    }
                default:
                    {
                        // there should have been a syntax error if we get here.
                        return new BoundBadExpression(
                            state.selectOrGroup, LookupResultKind.OverloadResolutionFailure, ImmutableArray<Symbol>.Empty,
                            ImmutableArray.Create<BoundNode>(state.fromExpression), state.fromExpression.Type);
                    }
            }
        }
Beispiel #22
0
        /// <summary>
        /// Find the Deconstruct method for the expression on the right, that will fit the number of assignable variables on the left.
        /// Returns an invocation expression if the Deconstruct method is found.
        ///     If so, it outputs placeholders that were coerced to the output types of the resolved Deconstruct method.
        /// The overload resolution is similar to writing `receiver.Deconstruct(out var x1, out var x2, ...)`.
        /// </summary>
        private BoundExpression MakeDeconstructInvocationExpression(
                                    int numCheckedVariables, BoundExpression receiver, CSharpSyntaxNode syntax,
                                    DiagnosticBag diagnostics, out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders)
        {
            var receiverSyntax = receiver.Syntax;

            if (receiver.Type.IsDynamic())
            {
                Error(diagnostics, ErrorCode.ERR_CannotDeconstructDynamic, receiverSyntax);
                outPlaceholders = default(ImmutableArray<BoundDeconstructValuePlaceholder>);

                return BadExpression(receiverSyntax, receiver);
            }

            var analyzedArguments = AnalyzedArguments.GetInstance();
            var outVars = ArrayBuilder<OutDeconstructVarPendingInference>.GetInstance(numCheckedVariables);
            DiagnosticBag bag = null;

            try
            {
                for (int i = 0; i < numCheckedVariables; i++)
                {
                    var variable = new OutDeconstructVarPendingInference(syntax);
                    analyzedArguments.Arguments.Add(variable);
                    analyzedArguments.RefKinds.Add(RefKind.Out);
                    outVars.Add(variable);
                }

                const string methodName = "Deconstruct";
                var memberAccess = BindInstanceMemberAccess(
                                        receiverSyntax, receiverSyntax, receiver, methodName, rightArity: 0,
                                        typeArgumentsSyntax: default(SeparatedSyntaxList<TypeSyntax>), typeArguments: default(ImmutableArray<TypeSymbol>),
                                        invoked: true, diagnostics: diagnostics);

                memberAccess = CheckValue(memberAccess, BindValueKind.RValueOrMethodGroup, diagnostics);
                memberAccess.WasCompilerGenerated = true;

                if (memberAccess.Kind != BoundKind.MethodGroup)
                {
                    return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, receiver);
                }

                // After the overload resolution completes, the last step is to coerce the arguments with inferred types.
                // That step returns placeholder (of correct type) instead of the outVar nodes that were passed in as arguments.
                // So the generated invocation expression will contain placeholders instead of those outVar nodes.
                // Those placeholders are also recorded in the outVar for easy access below, by the `SetInferredType` call on the outVar nodes.
                bag = DiagnosticBag.GetInstance();
                BoundExpression result = BindMethodGroupInvocation(
                                            receiverSyntax, receiverSyntax, methodName, (BoundMethodGroup)memberAccess, analyzedArguments, bag, queryClause: null,
                                            allowUnexpandedForm: true);

                result.WasCompilerGenerated = true;
                diagnostics.AddRange(bag);

                if (bag.HasAnyErrors())
                {
                    return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
                }

                // Verify all the parameters (except "this" for extension methods) are out parameters
                if (result.Kind != BoundKind.Call)
                {
                    return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
                }

                var deconstructMethod = ((BoundCall)result).Method;
                var parameters = deconstructMethod.Parameters;
                for (int i = (deconstructMethod.IsExtensionMethod ? 1 : 0); i < parameters.Length; i++)
                {
                    if (parameters[i].RefKind != RefKind.Out)
                    {
                        return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
                    }
                }

                if (outVars.Any(v => (object)v.Placeholder == null))
                {
                    return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
                }

                outPlaceholders = outVars.SelectAsArray(v => v.Placeholder);

                return result;
            }
            finally
            {
                analyzedArguments.Free();
                outVars.Free();

                if (bag != null)
                {
                    bag.Free();
                }
            }

        }
Beispiel #23
0
        /// <summary>
        /// Check the expression is of the required lvalue and rvalue specified by valueKind.
        /// The method returns the original expression if the expression is of the required
        /// type. Otherwise, an appropriate error is added to the diagnostics bag and the
        /// method returns a BoundBadExpression node. The method returns the original
        /// expression without generating any error if the expression has errors.
        /// </summary>
        private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind, DiagnosticBag diagnostics)
        {
            switch (expr.Kind)
            {
                case BoundKind.PropertyGroup:
                    expr = BindIndexedPropertyAccess((BoundPropertyGroup)expr, mustHaveAllOptionalParameters: false, diagnostics: diagnostics);
                    break;
            }

            bool hasResolutionErrors = false;

            // If this a MethodGroup where an rvalue is not expected or where the caller will not explicitly handle
            // (and resolve) MethodGroups (in short, cases where valueKind != BindValueKind.RValueOrMethodGroup),
            // resolve the MethodGroup here to generate the appropriate errors, otherwise resolution errors (such as
            // "member is inaccessible") will be dropped.
            if (expr.Kind == BoundKind.MethodGroup && valueKind != BindValueKind.RValueOrMethodGroup)
            {
                var methodGroup = (BoundMethodGroup)expr;
                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteDiagnostics: ref useSiteDiagnostics);
                diagnostics.Add(expr.Syntax, useSiteDiagnostics);
                Symbol otherSymbol = null;
                bool resolvedToMethodGroup = resolution.MethodGroup != null;
                if (!expr.HasAnyErrors) diagnostics.AddRange(resolution.Diagnostics); // Suppress cascading.
                hasResolutionErrors = resolution.HasAnyErrors;
                if (hasResolutionErrors)
                {
                    otherSymbol = resolution.OtherSymbol;
                }
                resolution.Free();

                // It's possible the method group is not a method group at all, but simply a
                // delayed lookup that resolved to a non-method member (perhaps an inaccessible
                // field or property), or nothing at all. In those cases, the member should not be exposed as a
                // method group, not even within a BoundBadExpression. Instead, the
                // BoundBadExpression simply refers to the receiver and the resolved symbol (if any).
                if (!resolvedToMethodGroup)
                {
                    Debug.Assert(methodGroup.ResultKind != LookupResultKind.Viable);
                    BoundNode receiver = methodGroup.ReceiverOpt;
                    if ((object)otherSymbol != null && receiver?.Kind == BoundKind.TypeOrValueExpression)
                    {
                        // Since we're not accessing a method, this can't be a Color Color case, so TypeOrValueExpression should not have been used.
                        // CAVEAT: otherSymbol could be invalid in some way (e.g. inaccessible), in which case we would have fallen back on a
                        // method group lookup (to allow for extension methods), which would have required a TypeOrValueExpression.
                        Debug.Assert(methodGroup.LookupError != null);

                        // Since we have a concrete member in hand, we can resolve the receiver.
                        var typeOrValue = (BoundTypeOrValueExpression)receiver;
                        receiver = otherSymbol.IsStatic
                            ? null // no receiver required
                            : typeOrValue.Data.ValueExpression;
                    }
                    return new BoundBadExpression(
                        expr.Syntax,
                        methodGroup.ResultKind,
                        (object)otherSymbol == null ? ImmutableArray<Symbol>.Empty : ImmutableArray.Create(otherSymbol),
                        receiver == null ? ImmutableArray<BoundNode>.Empty : ImmutableArray.Create(receiver),
                        GetNonMethodMemberType(otherSymbol));
                }
            }

            if (!hasResolutionErrors && CheckValueKind(expr, valueKind, diagnostics) ||
                expr.HasAnyErrors && valueKind == BindValueKind.RValueOrMethodGroup)
            {
                return expr;
            }

            var resultKind = (valueKind == BindValueKind.RValue || valueKind == BindValueKind.RValueOrMethodGroup) ?
                LookupResultKind.NotAValue :
                LookupResultKind.NotAVariable;

            return ToBadExpression(expr, resultKind);
        }
Beispiel #24
0
        /// <summary>
        /// The spec describes an algorithm for finding the following types:
        ///   1) Collection type
        ///   2) Enumerator type
        ///   3) Element type
        ///
        /// The implementation details are a bit difference.  If we're iterating over a string or an array, then we don't need to record anything
        /// but the inferredType (in case the iteration variable is implicitly typed).  If we're iterating over anything else, then we want the
        /// inferred type plus a ForEachEnumeratorInfo.Builder with:
        ///   1) Collection type
        ///   2) Element type
        ///   3) GetEnumerator method of the collection type (return type will be the enumerator type from the spec)
        ///   4) Current property of the enumerator type
        ///   5) MoveNext method of the enumerator type
        ///
        /// The caller will have to do some extra conversion checks before creating a ForEachEnumeratorInfo for the BoundForEachStatement.
        /// </summary>
        /// <param name="builder">Builder to fill in (partially, all but conversions).</param>
        /// <param name="collectionExpr">The expression over which to iterate.</param>
        /// <param name="diagnostics">Populated with binding diagnostics.</param>
        /// <returns>Partially populated (all but conversions) or null if there was an error.</returns>
        private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundExpression collectionExpr, DiagnosticBag diagnostics)
        {
            TypeSymbol collectionExprType = collectionExpr.Type;

            if (collectionExpr.ConstantValue != null && collectionExpr.ConstantValue.IsNull)
            {
                // Spec seems to refer to null literals, but Dev10 reports anything known to be null.
                Debug.Assert(collectionExpr.ConstantValue.IsNull); // only constant value with no type
                diagnostics.Add(ErrorCode.ERR_NullNotValid, _syntax.Expression.Location);

                return(false);
            }

            if ((object)collectionExprType == null) // There's no way to enumerate something without a type.
            {
                // The null literal was caught above, so anything else with a null type is a method group or anonymous function
                diagnostics.Add(ErrorCode.ERR_AnonMethGrpInForEach, _syntax.Expression.Location, collectionExpr.Display);
                // CONSIDER: dev10 also reports ERR_ForEachMissingMember (i.e. failed pattern match).

                return(false);
            }

            if (collectionExpr.ResultKind == LookupResultKind.NotAValue)
            {
                // Short-circuiting to prevent strange behavior in the case where the collection
                // expression is a type expression and the type is enumerable.
                Debug.Assert(collectionExpr.HasAnyErrors); // should already have been reported
                return(false);
            }

            // The spec specifically lists the collection, enumerator, and element types for arrays and dynamic.
            if (collectionExprType.Kind == SymbolKind.ArrayType || collectionExprType.Kind == SymbolKind.DynamicType)
            {
                builder = GetDefaultEnumeratorInfo(builder, diagnostics, collectionExprType);
                return(true);
            }

            bool foundMultipleGenericIEnumerableInterfaces;

            if (SatisfiesGetEnumeratorPattern(ref builder, collectionExprType, diagnostics))
            {
                Debug.Assert((object)builder.GetEnumeratorMethod != null);

                builder.CollectionType = collectionExprType;

                if (SatisfiesForEachPattern(ref builder, diagnostics))
                {
                    builder.ElementType = ((PropertySymbol)builder.CurrentPropertyGetter.AssociatedSymbol).Type;

                    // NOTE: if IDisposable is not available at all, no diagnostics will be reported - we will just assume that
                    // the enumerator is not disposable.  If it has IDisposable in its interface list, there will be a diagnostic there.
                    // If IDisposable is available but its Dispose method is not, then diagnostics will be reported only if the enumerator
                    // is potentially disposable.

                    var        useSiteDiagnosticBag             = DiagnosticBag.GetInstance();
                    TypeSymbol enumeratorType                   = builder.GetEnumeratorMethod.ReturnType;
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    if (!enumeratorType.IsSealed || this.Conversions.ClassifyImplicitConversion(enumeratorType, this.Compilation.GetSpecialType(SpecialType.System_IDisposable), ref useSiteDiagnostics).IsImplicit)
                    {
                        builder.NeedsDisposeMethod = true;
                        diagnostics.AddRange(useSiteDiagnosticBag);
                    }
                    useSiteDiagnosticBag.Free();

                    diagnostics.Add(_syntax, useSiteDiagnostics);
                    return(true);
                }

                MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod;
                diagnostics.Add(ErrorCode.ERR_BadGetEnumerator, _syntax.Expression.Location, getEnumeratorMethod.ReturnType, getEnumeratorMethod);
                return(false);
            }

            if (IsIEnumerable(collectionExprType))
            {
                // This indicates a problem with the special IEnumerable type - it should have satisfied the GetEnumerator pattern.
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName);
                return(false);
            }

            if (AllInterfacesContainsIEnumerable(ref builder, collectionExprType, diagnostics, out foundMultipleGenericIEnumerableInterfaces))
            {
                CSharpSyntaxNode errorLocationSyntax = _syntax.Expression;

                if (foundMultipleGenericIEnumerableInterfaces)
                {
                    diagnostics.Add(ErrorCode.ERR_MultipleIEnumOfT, errorLocationSyntax.Location, collectionExprType, this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T));
                    return(false);
                }

                Debug.Assert((object)builder.CollectionType != null);

                NamedTypeSymbol collectionType = (NamedTypeSymbol)builder.CollectionType;
                if (collectionType.IsGenericType)
                {
                    // If the type is generic, we have to search for the methods
                    Debug.Assert(collectionType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T);
                    builder.ElementType = collectionType.TypeArgumentsNoUseSiteDiagnostics.Single();

                    MethodSymbol getEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator, diagnostics, errorLocationSyntax);
                    if ((object)getEnumeratorMethod != null)
                    {
                        builder.GetEnumeratorMethod = getEnumeratorMethod.AsMember(collectionType);

                        TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType;
                        Debug.Assert(enumeratorType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T);
                        MethodSymbol currentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerator_T__get_Current, diagnostics, errorLocationSyntax);
                        if ((object)currentPropertyGetter != null)
                        {
                            builder.CurrentPropertyGetter = currentPropertyGetter.AsMember((NamedTypeSymbol)enumeratorType);
                        }
                    }

                    builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax); // NOTE: MoveNext is actually inherited from System.Collections.IEnumerator
                }
                else
                {
                    // Non-generic - use special members to avoid re-computing
                    Debug.Assert(collectionType.SpecialType == SpecialType.System_Collections_IEnumerable);
                    builder.ElementType = GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationSyntax);

                    builder.GetEnumeratorMethod   = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, errorLocationSyntax);
                    builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, errorLocationSyntax);
                    builder.MoveNextMethod        = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax);

                    Debug.Assert((object)builder.GetEnumeratorMethod == null ||
                                 builder.GetEnumeratorMethod.ReturnType == GetSpecialType(SpecialType.System_Collections_IEnumerator, diagnostics, errorLocationSyntax));
                }

                // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose).
                builder.NeedsDisposeMethod = true;
                return(true);
            }

            // COMPAT:
            // In some rare cases, like MicroFramework, System.String does not implement foreach pattern.
            // For compat reasons we must still treat System.String as valid to use in a foreach
            // Similarly to the cases with array and dynamic, we will default to IEnumerable for binding purposes.
            // Lowering will not use iterator info with strings, so it is ok.
            if (collectionExprType.SpecialType == SpecialType.System_String)
            {
                builder = GetDefaultEnumeratorInfo(builder, diagnostics, collectionExprType);
                return(true);
            }

            if (!string.IsNullOrEmpty(collectionExprType.Name) || !collectionExpr.HasErrors)
            {
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType.ToDisplayString(), GetEnumeratorMethodName);
            }
            return(false);
        }
        internal static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, DiagnosticBag diagnostics, CancellationToken cancellationToken)
        {
            CSharpCompilationOptions options = compilation.Options;
            if (!options.OutputKind.IsApplication())
            {
                Debug.Assert(compilation.GetEntryPointAndDiagnostics(cancellationToken) == null);
                return compilation.IsSubmission
                    ? DefineScriptEntryPoint(compilation, moduleBeingBuilt, compilation.GetSubmissionReturnType(), hasDeclarationErrors, diagnostics)
                    : null;
            }

            Debug.Assert(!compilation.IsSubmission);
            Debug.Assert(options.OutputKind.IsApplication());

            CSharpCompilation.EntryPoint entryPoint = compilation.GetEntryPointAndDiagnostics(cancellationToken);
            Debug.Assert(entryPoint != null);
            Debug.Assert(!entryPoint.Diagnostics.IsDefault);

            diagnostics.AddRange(entryPoint.Diagnostics);

            if ((object)compilation.ScriptClass != null)
            {
                Debug.Assert((object)entryPoint.MethodSymbol == null);
                return DefineScriptEntryPoint(compilation, moduleBeingBuilt, compilation.GetSpecialType(SpecialType.System_Void), hasDeclarationErrors, diagnostics);
            }

            Debug.Assert((object)entryPoint.MethodSymbol != null || entryPoint.Diagnostics.HasAnyErrors() || !compilation.Options.Errors.IsDefaultOrEmpty);
            return entryPoint.MethodSymbol;
        }
        internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingType, Binder binder, SyntaxTokenList modifiers, VariableDeclaratorSyntax declaratorSyntax, DiagnosticBag diagnostics)
            : base(containingType, declaratorSyntax, modifiers, null, declaratorSyntax.Identifier, diagnostics)
        {
            this.name = declaratorSyntax.Identifier.ValueText;


            var declaratorDiagnostics = DiagnosticBag.GetInstance();
            var declarationSyntax = (VariableDeclarationSyntax)declaratorSyntax.Parent;
            this.type = BindEventType(binder, declarationSyntax.Type, declaratorDiagnostics);

            // The runtime will not treat the accessors of this event as overrides or implementations
            // of those of another event unless both the signatures and the custom modifiers match.
            // Hence, in the case of overrides and *explicit* implementations (not possible for field-like
            // events), we need to copy the custom modifiers that are in the signatures of the 
            // overridden/implemented event accessors. (From source, we know that there can only be one 
            // overridden/implemented event, so there are no conflicts.)  This is unnecessary for implicit 
            // implementations because, if the custom modifiers don't match, we'll insert bridge methods 
            // for the accessors (explicit implementations that delegate to the implicit implementations) 
            // with the correct custom modifiers (see SourceNamedTypeSymbol.ImplementInterfaceMember).

            // If this event is an override, we may need to copy custom modifiers from
            // the overridden event (so that the runtime will recognize it as an override).
            // We check for this case here, while we can still modify the parameters and
            // return type without losing the appearance of immutability.
            if (this.IsOverride)
            {
                EventSymbol overriddenEvent = this.OverriddenEvent;
                if ((object)overriddenEvent != null)
                {
                    CopyEventCustomModifiers(overriddenEvent, ref this.type);
                }
            }

            bool hasInitializer = declaratorSyntax.Initializer != null;
            bool inInterfaceType = containingType.IsInterfaceType();

            if (hasInitializer)
            {
                if (inInterfaceType)
                {
                    diagnostics.Add(ErrorCode.ERR_InterfaceEventInitializer, this.Locations[0], this);
                }
                else if (this.IsAbstract)
                {
                    diagnostics.Add(ErrorCode.ERR_AbstractEventInitializer, this.Locations[0], this);
                }
            }

            // NOTE: if there's an initializer in source, we'd better create a backing field, regardless of
            // whether or not the initializer is legal.
            if (hasInitializer || !(inInterfaceType || this.IsExtern || this.IsAbstract))
            {
                this.associatedField = MakeAssociatedField(declaratorSyntax);
                // Don't initialize this.type - we'll just use the type of the field (which is lazy and handles var)
            }

            // Accessors will assume that Type is available.
            this.addMethod = new SynthesizedFieldLikeEventAccessorSymbol(this, isAdder: true);
            this.removeMethod = new SynthesizedFieldLikeEventAccessorSymbol(this, isAdder: false);

            if (declarationSyntax.Variables[0] == declaratorSyntax)
            {
                // Don't report these diagnostics for every declarator in this declaration.
                diagnostics.AddRange(declaratorDiagnostics);
            }

            declaratorDiagnostics.Free();
        }
Beispiel #27
0
        internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
        {
            Debug.Assert(SwitchSyntax.Equals(node));

            // Bind switch expression and set the switch governing type.
            var boundSwitchExpression = this.SwitchGoverningExpression;
            diagnostics.AddRange(this.SwitchGoverningDiagnostics);

            // Switch expression might be a constant expression.
            // For this scenario we can determine the target label of the switch statement
            // at compile time.            
            LabelSymbol constantTargetOpt = null;
            var constantValue = boundSwitchExpression.ConstantValue;
            if (constantValue != null)
            {
                constantTargetOpt = BindConstantJumpTarget(constantValue, node);
            }
            else if (!node.Sections.Any())
            {
                // empty switch block, set the break label as target
                constantTargetOpt = this.BreakLabel;
            }

            // Bind switch section
            ImmutableArray<BoundSwitchSection> boundSwitchSections = BindSwitchSections(node.Sections, originalBinder, diagnostics);

            return new BoundSwitchStatement(node, null, boundSwitchExpression, constantTargetOpt, 
                                            GetDeclaredLocalsForScope(node), 
                                            GetDeclaredLocalFunctionsForScope(node), boundSwitchSections, this.BreakLabel, null);
        }
        private ImmutableArray<SynthesizedExplicitImplementationForwardingMethod> ComputeInterfaceImplementations(
            DiagnosticBag diagnostics,
            CancellationToken cancellationToken)
        {
            if (this.IsInterface)
            {
                return ImmutableArray<SynthesizedExplicitImplementationForwardingMethod>.Empty;
            }

            var synthesizedImplementations = ArrayBuilder<SynthesizedExplicitImplementationForwardingMethod>.GetInstance();

            // NOTE: We can't iterator over this collection directly, since it is not ordered.  Instead we 
            // iterate over AllInterfaces and filter out the interfaces that are not in this set.  This is 
            // preferable to doing the DFS ourselves because both AllInterfaces and 
            // InterfacesAndTheirBaseInterfaces are cached and used in multiple places.
            ImmutableHashSet<NamedTypeSymbol> interfacesAndTheirBases = this.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics;

            foreach (var @interface in this.AllInterfacesNoUseSiteDiagnostics)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (!interfacesAndTheirBases.Contains(@interface))
                {
                    continue;
                }

                bool? hasImportedBaseTypeDeclaringInterface = null;

                foreach (var interfaceMember in @interface.GetMembersUnordered())
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    // Only require implementations for members that can be implemented in C#.
                    SymbolKind interfaceMemberKind = interfaceMember.Kind;
                    switch (interfaceMemberKind)
                    {
                        case SymbolKind.Method:
                        case SymbolKind.Property:
                        case SymbolKind.Event:
                            if (interfaceMember.IsStatic)
                            {
                                continue;
                            }
                            break;
                        default:
                            continue;
                    }

                    var implementingMemberAndDiagnostics = this.FindImplementationForInterfaceMemberWithDiagnostics(interfaceMember);
                    var implementingMember = implementingMemberAndDiagnostics.Symbol;
                    var synthesizedImplementation = this.SynthesizeInterfaceMemberImplementation(implementingMemberAndDiagnostics, interfaceMember);

                    bool wasImplementingMemberFound = (object)implementingMember != null;

                    if ((object)synthesizedImplementation != null)
                    {
                        synthesizedImplementations.Add(synthesizedImplementation);
                    }

                    if (wasImplementingMemberFound && interfaceMemberKind == SymbolKind.Event)
                    {
                        // NOTE: unlike dev11, we're including a related location for the implementing type, because
                        // otherwise the only error location will be in the containing type of the implementing event
                        // (i.e. no indication of which type's interface list is actually problematic).

                        EventSymbol interfaceEvent = (EventSymbol)interfaceMember;
                        EventSymbol implementingEvent = (EventSymbol)implementingMember;
                        EventSymbol maybeWinRTEvent;
                        EventSymbol maybeRegularEvent;

                        if (interfaceEvent.IsWindowsRuntimeEvent)
                        {
                            maybeWinRTEvent = interfaceEvent; // Definitely WinRT.
                            maybeRegularEvent = implementingEvent; // Maybe regular.
                        }
                        else
                        {
                            maybeWinRTEvent = implementingEvent; // Maybe WinRT.
                            maybeRegularEvent = interfaceEvent; // Definitely regular.
                        }

                        if (interfaceEvent.IsWindowsRuntimeEvent != implementingEvent.IsWindowsRuntimeEvent)
                        {
                            // At this point (and not before), we know that maybeWinRTEvent is definitely a WinRT event and maybeRegularEvent is definitely a regular event.
                            var args = new object[] { implementingEvent, interfaceEvent, maybeWinRTEvent, maybeRegularEvent };
                            var info = new CSDiagnosticInfo(ErrorCode.ERR_MixingWinRTEventWithRegular, args, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<Location>(this.Locations[0]));
                            diagnostics.Add(info, implementingEvent.Locations[0]);
                        }
                    }

                    // Dev10: If a whole property is missing, report the property.  If the property is present, but an accessor
                    // is missing, report just the accessor.

                    var associatedPropertyOrEvent = interfaceMemberKind == SymbolKind.Method ? ((MethodSymbol)interfaceMember).AssociatedSymbol : null;
                    if ((object)associatedPropertyOrEvent == null ||
                        ReportAccessorOfInterfacePropertyOrEvent(associatedPropertyOrEvent) ||
                        (wasImplementingMemberFound && !implementingMember.IsAccessor()))
                    {
                        //we're here because 
                        //(a) the interface member is not an accessor, or 
                        //(b) the interface member is an accessor of an interesting (see ReportAccessorOfInterfacePropertyOrEvent) property or event, or
                        //(c) the implementing member exists and is not an accessor.

                        if (implementingMemberAndDiagnostics.Diagnostics.Any())
                        {
                            diagnostics.AddRange(implementingMemberAndDiagnostics.Diagnostics);
                        }
                        else if (!wasImplementingMemberFound)
                        {
                            // NOTE: An alternative approach would be to keep track of this while searching for the implementing member.
                            // In some cases, we might even be able to stop looking and just accept that a base type has things covered
                            // (though we'd have to be careful about losing diagnostics and we might produce fewer bridge methods).
                            // However, this approach has the advantage that there is no cost unless we encounter a base type that
                            // claims to implement an interface, but we can't figure out how (i.e. free in nearly all cases).
                            hasImportedBaseTypeDeclaringInterface = hasImportedBaseTypeDeclaringInterface ?? HasImportedBaseTypeDeclaringInterface(@interface);

                            // If a base type from metadata declares that it implements the interface, we'll just trust it.
                            // (See fFoundImport in SymbolPreparer::CheckInterfaceMethodImplementation.)
                            if (!hasImportedBaseTypeDeclaringInterface.GetValueOrDefault())
                            {
                                // CONSIDER: Dev10 does not emit this diagnostic for interface properties if the
                                // derived type attempts to implement an accessor directly as a method.

                                // Suppress for bogus properties and events and for indexed properties.
                                if (!interfaceMember.MustCallMethodsDirectly() && !interfaceMember.IsIndexedProperty())
                                {
                                    DiagnosticInfo useSiteDiagnostic = interfaceMember.GetUseSiteDiagnostic();

                                    if (useSiteDiagnostic != null && useSiteDiagnostic.DefaultSeverity == DiagnosticSeverity.Error)
                                    {
                                        diagnostics.Add(useSiteDiagnostic, GetImplementsLocation(@interface));
                                    }
                                    else
                                    {
                                        diagnostics.Add(ErrorCode.ERR_UnimplementedInterfaceMember, GetImplementsLocation(@interface) ?? this.Locations[0], this, interfaceMember);
                                    }
                                }
                            }
                        }
                        else if (interfaceMemberKind == SymbolKind.Method)
                        {
                            // Don't report use site errors on properties - we'll report them on each of their accessors.

                            // Don't report use site errors for implementations in other types unless 
                            // a synthesized implementation is needed that invokes the base method.
                            // We can do so only if there are no use-site errors.

                            if ((object)synthesizedImplementation != null || implementingMember.ContainingType == this)
                            {
                                DiagnosticInfo useSiteDiagnostic = interfaceMember.GetUseSiteDiagnostic();
                                // CAVEAT: don't report ERR_ByRefReturnUnsupported since by-ref return types are 
                                // specifically allowed for the purposes of interface implementation (for C++ interop).
                                // However, if there's a reference to the interface member in source, then we do want
                                // to produce a use site error.
                                if (useSiteDiagnostic != null && (ErrorCode)useSiteDiagnostic.Code != ErrorCode.ERR_ByRefReturnUnsupported)
                                {
                                    // Don't report a use site error with a location in another compilation.  For example,
                                    // if the error is that a base type in another assembly implemented an interface member
                                    // on our behalf and the use site error is that the current assembly does not reference
                                    // some required assembly, then we want to report the error in the current assembly -
                                    // not in the implementing assembly.
                                    Location location = implementingMember.IsFromCompilation(this.DeclaringCompilation)
                                        ? implementingMember.Locations[0]
                                        : this.Locations[0];
                                    Symbol.ReportUseSiteDiagnostic(useSiteDiagnostic, diagnostics, location);
                                }
                            }
                        }
                    }
                }
            }

            return synthesizedImplementations.ToImmutableAndFree();
        }
Beispiel #29
0
        internal void GenerateAnonymousFunctionConversionError(DiagnosticBag diagnostics, CSharpSyntaxNode syntax,
            UnboundLambda anonymousFunction, TypeSymbol targetType)
        {
            Debug.Assert((object)targetType != null);
            Debug.Assert(anonymousFunction != null);

            // Is the target type simply bad?

            // If the target type is an error then we've already reported a diagnostic. Don't bother
            // reporting the conversion error.
            if (targetType.IsErrorType() || syntax.HasErrors)
            {
                return;
            }

            // CONSIDER: Instead of computing this again, cache the reason why the conversion failed in
            // CONSIDER: the Conversion result, and simply report that.

            var reason = Conversions.IsAnonymousFunctionCompatibleWithType(anonymousFunction, targetType);

            // It is possible that the conversion from lambda to delegate is just fine, and 
            // that we ended up here because the target type, though itself is not an error
            // type, contains a type argument which is an error type. For example, converting
            // (Foo foo)=>{} to Action<Foo> is a perfectly legal conversion even if Foo is undefined!
            // In that case we have already reported an error that Foo is undefined, so just bail out.

            if (reason == LambdaConversionResult.Success)
            {
                return;
            }

            var id = anonymousFunction.MessageID.Localize();

            if (reason == LambdaConversionResult.BadTargetType)
            {
                if (ReportDelegateInvokeUseSiteDiagnostic(diagnostics, targetType, node: syntax))
                {
                    return;
                }

                // Cannot convert {0} to type '{1}' because it is not a delegate type
                Error(diagnostics, ErrorCode.ERR_AnonMethToNonDel, syntax, id, targetType);
                return;
            }

            if (reason == LambdaConversionResult.ExpressionTreeMustHaveDelegateTypeArgument)
            {
                Debug.Assert(targetType.IsExpressionTree());
                Error(diagnostics, ErrorCode.ERR_ExpressionTreeMustHaveDelegate, syntax, ((NamedTypeSymbol)targetType).TypeArgumentsNoUseSiteDiagnostics[0]);
                return;
            }

            if (reason == LambdaConversionResult.ExpressionTreeFromAnonymousMethod)
            {
                Debug.Assert(targetType.IsExpressionTree());
                Error(diagnostics, ErrorCode.ERR_AnonymousMethodToExpressionTree, syntax);
                return;
            }

            // At this point we know that we have either a delegate type or an expression type for the target.

            var delegateType = targetType.GetDelegateType();

            // The target type is a vaid delegate or expression tree type. Is there something wrong with the 
            // parameter list?

            // First off, is there a parameter list at all?

            if (reason == LambdaConversionResult.MissingSignatureWithOutParameter)
            {
                // COMPATIBILITY: The C# 4 compiler produces two errors for:
                //
                // delegate void D (out int x);
                // ...
                // D d = delegate {};
                //
                // error CS1676: Parameter 1 must be declared with the 'out' keyword
                // error CS1688: Cannot convert anonymous method block without a parameter list 
                // to delegate type 'D' because it has one or more out parameters
                //
                // This seems redundant, (because there is no "parameter 1" in the source code)
                // and unnecessary. I propose that we eliminate the first error.

                Error(diagnostics, ErrorCode.ERR_CantConvAnonMethNoParams, syntax, targetType);
                return;
            }

            // There is a parameter list. Does it have the right number of elements?

            if (reason == LambdaConversionResult.BadParameterCount)
            {
                // Delegate '{0}' does not take {1} arguments
                Error(diagnostics, ErrorCode.ERR_BadDelArgCount, syntax, targetType, anonymousFunction.ParameterCount);
                return;
            }

            // The parameter list exists and had the right number of parameters. Were any of its types bad?

            // If any parameter type of the lambda is an error type then suppress 
            // further errors. We've already reported errors on the bad type.
            if (anonymousFunction.HasExplicitlyTypedParameterList)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    if (anonymousFunction.ParameterType(i).IsErrorType())
                    {
                        return;
                    }
                }
            }

            // The parameter list exists and had the right number of parameters. Were any of its types
            // mismatched with the delegate parameter types?

            // The simplest possible case is (x, y, z)=>whatever where the target type has a ref or out parameter.

            var delegateParameters = delegateType.DelegateParameters();
            if (reason == LambdaConversionResult.RefInImplicitlyTypedLambda)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    var delegateRefKind = delegateParameters[i].RefKind;
                    if (delegateRefKind != RefKind.None)
                    {
                        // Parameter {0} must be declared with the '{1}' keyword
                        Error(diagnostics, ErrorCode.ERR_BadParamRef, anonymousFunction.ParameterLocation(i),
                            i + 1, delegateRefKind.ToDisplayString());
                    }
                }
                return;
            }

            // See the comments in IsAnonymousFunctionCompatibleWithDelegate for an explanation of this one.
            if (reason == LambdaConversionResult.StaticTypeInImplicitlyTypedLambda)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    if (delegateParameters[i].Type.IsStatic)
                    {
                        // {0}: Static types cannot be used as parameter
                        Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, anonymousFunction.ParameterLocation(i), delegateParameters[i].Type);
                    }
                }
                return;
            }

            // Otherwise, there might be a more complex reason why the parameter types are mismatched.

            if (reason == LambdaConversionResult.MismatchedParameterType)
            {
                // Cannot convert {0} to delegate type '{1}' because the parameter types do not match the delegate parameter types
                Error(diagnostics, ErrorCode.ERR_CantConvAnonMethParams, syntax, id, targetType);
                Debug.Assert(anonymousFunction.ParameterCount == delegateParameters.Length);
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    var lambdaParameterType = anonymousFunction.ParameterType(i);
                    if (lambdaParameterType.IsErrorType())
                    {
                        continue;
                    }

                    var lambdaParameterLocation = anonymousFunction.ParameterLocation(i);
                    var lambdaRefKind = anonymousFunction.RefKind(i);
                    var delegateParameterType = delegateParameters[i].Type;
                    var delegateRefKind = delegateParameters[i].RefKind;

                    if (!lambdaParameterType.Equals(delegateParameterType, ignoreCustomModifiers: true, ignoreDynamic: true))
                    {
                        SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, lambdaParameterType, delegateParameterType);

                        // Parameter {0} is declared as type '{1}{2}' but should be '{3}{4}'
                        Error(diagnostics, ErrorCode.ERR_BadParamType, lambdaParameterLocation,
                            i + 1, lambdaRefKind.ToPrefix(), distinguisher.First, delegateRefKind.ToPrefix(), distinguisher.Second);
                    }
                    else if (lambdaRefKind != delegateRefKind)
                    {
                        if (delegateRefKind == RefKind.None)
                        {
                            // Parameter {0} should not be declared with the '{1}' keyword
                            Error(diagnostics, ErrorCode.ERR_BadParamExtraRef, lambdaParameterLocation, i + 1, lambdaRefKind.ToDisplayString());
                        }
                        else
                        {
                            // Parameter {0} must be declared with the '{1}' keyword
                            Error(diagnostics, ErrorCode.ERR_BadParamRef, lambdaParameterLocation, i + 1, delegateRefKind.ToDisplayString());
                        }
                    }
                }
                return;
            }

            if (reason == LambdaConversionResult.BindingFailed)
            {
                var bindingResult = anonymousFunction.Bind(delegateType);
                Debug.Assert(ErrorFacts.PreventsSuccessfulDelegateConversion(bindingResult.Diagnostics));
                diagnostics.AddRange(bindingResult.Diagnostics);
                return;
            }

            // UNDONE: LambdaConversionResult.VoidExpressionLambdaMustBeStatementExpression:

            Debug.Assert(false, "Missing case in lambda conversion error reporting");
        }
Beispiel #30
0
 internal override void AddDeclarationDiagnostics(DiagnosticBag diagnostics)
 => _declarationDiagnostics.AddRange(diagnostics);
        internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics,
            bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray<NamespaceScope> namespaceScopes)
        {
            // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings.
            Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened");

            bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync;
            var module = compilationState.ModuleBuilder;
            var compilation = module.Compilation;
            var localSlotManager = module.CreateLocalSlotManager(method);

            ILBuilder builder = new ILBuilder(module, localSlotManager, optimize);
            DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance();
            try
            {
                AsyncMethodBodyDebugInfo asyncDebugInfo = null;
                if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method?
                {
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints);
                }
                else
                {
                    int asyncCatchHandlerOffset;
                    ImmutableArray<int> asyncYieldPoints;
                    ImmutableArray<int> asyncResumePoints;
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints,
                        out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints);
                    asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints);
                }

                var localVariables = builder.LocalSlotManager.LocalsInOrder();

                if (localVariables.Length > 0xFFFE)
                {
                    diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First());
                }

                if (diagnosticsForThisMethod.HasAnyErrors())
                {
                    // we are done here. Since there were errors we should not emit anything.
                    return null;
                }

                // We will only save the IL builders when running tests.
                if (module.SaveTestData)
                {
                    module.SetMethodTestData(method, builder.GetSnapshot());
                }

                // Only compiler-generated MoveNext methods have iterator scopes.  See if this is one.
                bool hasIteratorScopes =
                    method.Locations.IsEmpty && method.Name == "MoveNext" &&
                    (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) ||
                     method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol));

                var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray<LocalScope>.Empty;

                var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method);
                return new MethodBody(
                    builder.RealizedIL,
                    builder.MaxStack,
                    method,
                    localVariables,
                    builder.RealizedSequencePoints,
                    debugDocumentProvider,
                    builder.RealizedExceptionHandlers,
                    builder.GetAllScopes(),
                    Microsoft.Cci.CustomDebugInfoKind.CSharpStyle,
                    builder.HasDynamicLocal,
                    namespaceScopes,
                    (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName,
                    iteratorScopes,
                    asyncMethodDebugInfo: asyncDebugInfo
                );
            }
            finally
            {
                // Basic blocks contain poolable builders for IL and sequence points. Free those back
                // to their pools.
                builder.FreeBasicBlocks();

                // Remember diagnostics.
                diagnostics.AddRange(diagnosticsForThisMethod);
                diagnosticsForThisMethod.Free();
            }
        }
Beispiel #32
0
 /// <summary>
 /// Parse statement. Returns null if there are any errors.
 /// </summary>
 internal static StatementSyntax ParseStatement(
     this string expr,
     DiagnosticBag diagnostics)
 {
     var syntax = ParseDebuggerStatement(expr);
     diagnostics.AddRange(syntax.GetDiagnostics());
     return diagnostics.HasAnyErrors() ? null : syntax;
 }
Beispiel #33
0
        internal static EmitOutput? EmitCompilationCore(
            Compilation compilation,
            IEnumerable<ResourceDescription> manifestResources,
            DiagnosticBag diagnostics,
            CompilationTestData testData
        )
        {
            using (var executableStream = new MemoryStream())
            {
                var pdb = default(ImmutableArray<byte>);
                var assembly = default(ImmutableArray<byte>);
                var pdbStream = MonoHelpers.IsRunningOnMono()
                    ? null
                    : new MemoryStream();

                EmitResult result;
                try
                {
                    result = compilation.Emit(
                        executableStream,
                        pdbStream: pdbStream,
                        xmlDocumentationStream: null,
                        win32Resources: null,
                        manifestResources: manifestResources,
                        options: EmitOptions.Default,
                        debugEntryPoint: null,
                        testData: testData,
                        cancellationToken: default(CancellationToken));
                }
                finally
                {
                    if (pdbStream != null)
                    {
                        pdb = pdbStream.ToImmutable();
                        pdbStream.Dispose();
                    }
                }

                diagnostics.AddRange(result.Diagnostics);
                assembly = executableStream.ToImmutable();

                if (result.Success)
                {
                    return new EmitOutput(assembly, pdb);
                }

                return null;
            }
        }
Beispiel #34
0
        /// <summary>
        /// The spec describes an algorithm for finding the following types:
        ///   1) Collection type
        ///   2) Enumerator type
        ///   3) Element type
        ///   
        /// The implementation details are a bit difference.  If we're iterating over a string or an array, then we don't need to record anything
        /// but the inferredType (in case the iteration variable is implicitly typed).  If we're iterating over anything else, then we want the 
        /// inferred type plus a ForEachEnumeratorInfo.Builder with:
        ///   1) Collection type
        ///   2) Element type
        ///   3) GetEnumerator method of the collection type (return type will be the enumerator type from the spec)
        ///   4) Current property of the enumerator type
        ///   5) MoveNext method of the enumerator type
        ///   
        /// The caller will have to do some extra conversion checks before creating a ForEachEnumeratorInfo for the BoundForEachStatement.
        /// </summary>
        /// <param name="builder">Builder to fill in (partially, all but conversions).</param>
        /// <param name="collectionExpr">The expression over which to iterate.</param>
        /// <param name="diagnostics">Populated with binding diagnostics.</param>
        /// <returns>Partially populated (all but conversions) or null if there was an error.</returns>
        private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundExpression collectionExpr, DiagnosticBag diagnostics)
        {
            TypeSymbol collectionExprType = collectionExpr.Type;

            if (collectionExpr.ConstantValue != null && collectionExpr.ConstantValue.IsNull)
            {
                // Spec seems to refer to null literals, but Dev10 reports anything known to be null.
                Debug.Assert(collectionExpr.ConstantValue.IsNull); // only constant value with no type
                diagnostics.Add(ErrorCode.ERR_NullNotValid, _syntax.Expression.Location);

                return false;
            }

            if ((object)collectionExprType == null) // There's no way to enumerate something without a type.
            {
                // The null literal was caught above, so anything else with a null type is a method group or anonymous function
                diagnostics.Add(ErrorCode.ERR_AnonMethGrpInForEach, _syntax.Expression.Location, collectionExpr.Display);
                // CONSIDER: dev10 also reports ERR_ForEachMissingMember (i.e. failed pattern match).

                return false;
            }

            if (collectionExpr.ResultKind == LookupResultKind.NotAValue)
            {
                // Short-circuiting to prevent strange behavior in the case where the collection
                // expression is a type expression and the type is enumerable.
                Debug.Assert(collectionExpr.HasAnyErrors); // should already have been reported
                return false;
            }

            // The spec specifically lists the collection, enumerator, and element types for arrays and dynamic.
            if (collectionExprType.Kind == SymbolKind.ArrayType || collectionExprType.Kind == SymbolKind.DynamicType)
            {
                builder = GetDefaultEnumeratorInfo(builder, diagnostics, collectionExprType);
                return true;
            }

            bool foundMultipleGenericIEnumerableInterfaces;
            if (SatisfiesGetEnumeratorPattern(ref builder, collectionExprType, diagnostics))
            {
                Debug.Assert((object)builder.GetEnumeratorMethod != null);

                builder.CollectionType = collectionExprType;

                if (SatisfiesForEachPattern(ref builder, diagnostics))
                {
                    builder.ElementType = ((PropertySymbol)builder.CurrentPropertyGetter.AssociatedSymbol).Type;

                    // NOTE: if IDisposable is not available at all, no diagnostics will be reported - we will just assume that
                    // the enumerator is not disposable.  If it has IDisposable in its interface list, there will be a diagnostic there.
                    // If IDisposable is available but its Dispose method is not, then diagnostics will be reported only if the enumerator
                    // is potentially disposable.

                    var useSiteDiagnosticBag = DiagnosticBag.GetInstance();
                    TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType;
                    HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                    if (!enumeratorType.IsSealed || this.Conversions.ClassifyImplicitConversion(enumeratorType, this.Compilation.GetSpecialType(SpecialType.System_IDisposable), ref useSiteDiagnostics).IsImplicit)
                    {
                        builder.NeedsDisposeMethod = true;
                        diagnostics.AddRange(useSiteDiagnosticBag);
                    }
                    useSiteDiagnosticBag.Free();

                    diagnostics.Add(_syntax, useSiteDiagnostics);
                    return true;
                }

                MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod;
                diagnostics.Add(ErrorCode.ERR_BadGetEnumerator, _syntax.Expression.Location, getEnumeratorMethod.ReturnType, getEnumeratorMethod);
                return false;
            }

            if (IsIEnumerable(collectionExprType))
            {
                // This indicates a problem with the special IEnumerable type - it should have satisfied the GetEnumerator pattern.
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName);
                return false;
            }

            if (AllInterfacesContainsIEnumerable(ref builder, collectionExprType, diagnostics, out foundMultipleGenericIEnumerableInterfaces))
            {
                CSharpSyntaxNode errorLocationSyntax = _syntax.Expression;

                if (foundMultipleGenericIEnumerableInterfaces)
                {
                    diagnostics.Add(ErrorCode.ERR_MultipleIEnumOfT, errorLocationSyntax.Location, collectionExprType, this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T));
                    return false;
                }

                Debug.Assert((object)builder.CollectionType != null);

                NamedTypeSymbol collectionType = (NamedTypeSymbol)builder.CollectionType;
                if (collectionType.IsGenericType)
                {
                    // If the type is generic, we have to search for the methods
                    Debug.Assert(collectionType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T);
                    builder.ElementType = collectionType.TypeArgumentsNoUseSiteDiagnostics.Single();

                    MethodSymbol getEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator, diagnostics, errorLocationSyntax);
                    if ((object)getEnumeratorMethod != null)
                    {
                        builder.GetEnumeratorMethod = getEnumeratorMethod.AsMember(collectionType);

                        TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType;
                        Debug.Assert(enumeratorType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T);
                        MethodSymbol currentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerator_T__get_Current, diagnostics, errorLocationSyntax);
                        if ((object)currentPropertyGetter != null)
                        {
                            builder.CurrentPropertyGetter = currentPropertyGetter.AsMember((NamedTypeSymbol)enumeratorType);
                        }
                    }

                    builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax); // NOTE: MoveNext is actually inherited from System.Collections.IEnumerator
                }
                else
                {
                    // Non-generic - use special members to avoid re-computing
                    Debug.Assert(collectionType.SpecialType == SpecialType.System_Collections_IEnumerable);
                    builder.ElementType = GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationSyntax);

                    builder.GetEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, errorLocationSyntax);
                    builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, errorLocationSyntax);
                    builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax);

                    Debug.Assert((object)builder.GetEnumeratorMethod == null ||
                        builder.GetEnumeratorMethod.ReturnType == GetSpecialType(SpecialType.System_Collections_IEnumerator, diagnostics, errorLocationSyntax));
                }

                // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose).
                builder.NeedsDisposeMethod = true;
                return true;
            }

            // COMPAT:
            // In some rare cases, like MicroFramework, System.String does not implement foreach pattern.
            // For compat reasons we must still treat System.String as valid to use in a foreach
            // Similarly to the cases with array and dynamic, we will default to IEnumerable for binding purposes.
            // Lowering will not use iterator info with strings, so it is ok.
            if (collectionExprType.SpecialType == SpecialType.System_String)
            {
                builder = GetDefaultEnumeratorInfo(builder, diagnostics, collectionExprType);
                return true;
            }

            if (!string.IsNullOrEmpty(collectionExprType.Name) || !collectionExpr.HasErrors)
            {
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType.ToDisplayString(), GetEnumeratorMethodName);
            }
            return false;
        }
        public static bool ReportDelegateMethodGroupDiagnostics(Binder binder, BoundMethodGroup expr, TypeSymbol targetType, DiagnosticBag diagnostics)
        {
            var invokeMethodOpt = GetDelegateInvokeMethodIfAvailable(targetType);
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            var resolution = ResolveDelegateMethodGroup(binder, expr, invokeMethodOpt, ref useSiteDiagnostics);
            diagnostics.Add(expr.Syntax, useSiteDiagnostics);

            bool hasErrors = resolution.HasAnyErrors;

            diagnostics.AddRange(resolution.Diagnostics);

            // SPEC VIOLATION: Unfortunately, we cannot exactly implement the specification for
            // the scenario in which an extension method that extends a value type is converted
            // to a delegate. The code we generate that captures a delegate to a static method
            // that is "partially evaluated" with the bound-to-the-delegate first argument
            // requires that the first argument be of reference type.
            //
            // SPEC VIOLATION: Similarly, we cannot capture a method of Nullable<T>, because
            // boxing a Nullable<T> gives a T, not a boxed Nullable<T>.
            //
            // We give special error messages in these situations.

            if (resolution.MethodGroup != null)
            {
                var result = resolution.OverloadResolutionResult;
                if (result != null)
                {
                    if (result.Succeeded)
                    {
                        var method = result.BestResult.Member;
                        Debug.Assert((object)method != null);
                        if (resolution.MethodGroup.IsExtensionMethodGroup)
                        {
                            Debug.Assert(method.IsExtensionMethod);

                            var thisParameter = method.Parameters[0];
                            if (!thisParameter.Type.IsReferenceType)
                            {
                                // Extension method '{0}' defined on value type '{1}' cannot be used to create delegates
                                diagnostics.Add(
                                    ErrorCode.ERR_ValueTypeExtDelegate,
                                    expr.Syntax.Location,
                                    method,
                                    thisParameter.Type);
                                hasErrors = true;
                            }
                        }
                        else if (method.OriginalDefinition.ContainingType.SpecialType == SpecialType.System_Nullable_T && !method.IsOverride)
                        {
                            // CS1728: Cannot bind delegate to '{0}' because it is a member of 'System.Nullable<T>'
                            diagnostics.Add(
                                ErrorCode.ERR_DelegateOnNullable,
                                expr.Syntax.Location,
                                method);
                            hasErrors = true;
                        }
                    }
                    else if (!hasErrors &&
                            !resolution.IsEmpty &&
                            resolution.ResultKind == LookupResultKind.Viable)
                    {
                        var overloadDiagnostics = DiagnosticBag.GetInstance();

                        result.ReportDiagnostics(binder, expr.Syntax.Location, overloadDiagnostics,
                            expr.Name,
                            resolution.MethodGroup.Receiver, resolution.AnalyzedArguments, resolution.MethodGroup.Methods.ToImmutable(),
                            typeContainingConstructor: null, delegateTypeBeingInvoked: null, isMethodGroupConversion: true);

                        if (!overloadDiagnostics.IsEmptyWithoutResolution)
                        {
                            hasErrors = overloadDiagnostics.HasAnyErrors();
                            diagnostics.AddRange(overloadDiagnostics);
                        }

                        overloadDiagnostics.Free();
                    }
                }
            }

            resolution.Free();
            return hasErrors;
        }
            /// <remarks>
            /// This method boils down to Rewrite(XDocument.Load(fileAttrValue).XPathSelectElements(pathAttrValue)).
            /// Everything else is error handling.
            /// </remarks>
            private XNode[] RewriteIncludeElement(XElement includeElement, string currentXmlFilePath, CSharpSyntaxNode originatingSyntax, out string commentMessage)
            {
                Location location = GetIncludeElementLocation(includeElement, ref currentXmlFilePath, ref originatingSyntax);

                Debug.Assert(originatingSyntax != null);

                bool diagnose = originatingSyntax.SyntaxTree.ReportDocumentationCommentDiagnostics();

                if (!EnterIncludeElement(location))
                {
                    // NOTE: these must exist since we're already processed this node elsewhere in the call stack.
                    XAttribute fileAttr      = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName));
                    XAttribute pathAttr      = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName));
                    string     filePathValue = fileAttr.Value;
                    string     xpathValue    = pathAttr.Value;

                    if (diagnose)
                    {
                        _diagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new LocalizableErrorArgument(MessageID.IDS_OperationCausedStackOverflow));
                    }

                    commentMessage = ErrorFacts.GetMessage(MessageID.IDS_XMLNOINCLUDE, CultureInfo.CurrentUICulture);

                    // Don't inspect the children - we're already in a cycle.
                    return(new XNode[] { new XComment(commentMessage), includeElement.Copy(copyAttributeAnnotations: false) });
                }

                DiagnosticBag includeDiagnostics = DiagnosticBag.GetInstance();

                try
                {
                    XAttribute fileAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName));
                    XAttribute pathAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName));

                    bool hasFileAttribute = fileAttr != null;
                    bool hasPathAttribute = pathAttr != null;
                    if (!hasFileAttribute || !hasPathAttribute)
                    {
                        var subMessage = hasFileAttribute ? MessageID.IDS_XMLMISSINGINCLUDEPATH.Localize() : MessageID.IDS_XMLMISSINGINCLUDEFILE.Localize();
                        includeDiagnostics.Add(ErrorCode.WRN_InvalidInclude, location, subMessage);
                        commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLBADINCLUDE);
                        return(null);
                    }

                    string xpathValue    = pathAttr.Value;
                    string filePathValue = fileAttr.Value;

                    var resolver = _compilation.Options.XmlReferenceResolver;
                    if (resolver == null)
                    {
                        includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.XmlReferencesNotSupported)));
                        commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE);
                        return(null);
                    }

                    string resolvedFilePath = resolver.ResolveReference(filePathValue, currentXmlFilePath);

                    if (resolvedFilePath == null)
                    {
                        // NOTE: same behavior as IOException.
                        includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.FileNotFound)));
                        commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE);
                        return(null);
                    }

                    if (_includedFileCache == null)
                    {
                        _includedFileCache = new DocumentationCommentIncludeCache(resolver);
                    }

                    try
                    {
                        XDocument doc;

                        try
                        {
                            doc = _includedFileCache.GetOrMakeDocument(resolvedFilePath);
                        }
                        catch (IOException e)
                        {
                            // NOTE: same behavior as resolvedFilePath == null.
                            includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, e.Message);
                            commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE);
                            return(null);
                        }

                        Debug.Assert(doc != null);

                        string     errorMessage;
                        bool       invalidXPath;
                        XElement[] loadedElements = XmlUtilities.TrySelectElements(doc, xpathValue, out errorMessage, out invalidXPath);
                        if (loadedElements == null)
                        {
                            includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, errorMessage);

                            commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE);
                            if (invalidXPath)
                            {
                                // leave the include node as is
                                return(null);
                            }

                            if (location.IsInSource)
                            {
                                // As in Dev11, return only the comment - drop the include element.
                                return(new XNode[] { new XComment(commentMessage) });
                            }
                            else
                            {
                                commentMessage = null;
                                return(Array.Empty <XNode>());
                            }
                        }

                        if (loadedElements != null && loadedElements.Length > 0)
                        {
                            // change the current XML file path for nodes contained in the document:
                            XNode[] result = RewriteMany(loadedElements, resolvedFilePath, originatingSyntax);

                            // The elements could be rewritten away if they are includes that refer to invalid
                            // (but existing and accessible) XML files.  If this occurs, behave as if we
                            // had failed to find any XPath results (as in Dev11).
                            if (result.Length > 0)
                            {
                                // NOTE: in this case, we do NOT visit the children of the include element -
                                // they are dropped.
                                commentMessage = null;
                                return(result);
                            }
                        }

                        commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLNOINCLUDE);
                        return(null);
                    }
                    catch (XmlException e)
                    {
                        // NOTE: invalid XML is handled differently from other errors - we don't include the include element
                        // in the results and the location is in the included (vs includING) file.

                        Location errorLocation = XmlLocation.Create(e, resolvedFilePath);
                        includeDiagnostics.Add(ErrorCode.WRN_XMLParseIncludeError, errorLocation, GetDescription(e)); //NOTE: location is in included file.

                        if (location.IsInSource)
                        {
                            commentMessage = string.Format(ErrorFacts.GetMessage(MessageID.IDS_XMLIGNORED2, CultureInfo.CurrentUICulture), resolvedFilePath);

                            // As in Dev11, return only the comment - drop the include element.
                            return(new XNode[] { new XComment(commentMessage) });
                        }
                        else
                        {
                            commentMessage = null;
                            return(Array.Empty <XNode>());
                        }
                    }
                }
                finally
                {
                    if (diagnose)
                    {
                        _diagnostics.AddRange(includeDiagnostics);
                    }

                    includeDiagnostics.Free();

                    LeaveIncludeElement(location);
                }
            }