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;
        }
            public override Stream CreateStream(DiagnosticBag diagnostics)
            {
                Debug.Assert(_streamToDispose == null);

                try
                {
                    try
                    {
                        return OpenFileStream();
                    }
                    catch (IOException e)
                    {
                        // Other process is reading the file preventing us to write to it.
                        // We attempt to rename and delete the file in case the reader opened it with FileShare.Delete flag that
                        // allows the file to be deleted by other processes.
                        //
                        // Note that if the file is marked "readonly" or the current user doesn't have sufficient privileges
                        // the exception thrown is UnauthorizedAccessException, not IOException, so we won't attempt to delete the file.

                        try
                        {
                            const int eWin32SharingViolation = unchecked((int)0x80070020);

                            if (PathUtilities.IsUnixLikePlatform)
                            {
                                // Unix & Mac are simple: just delete the file in the directory. 
                                // The memory mapped content remains available for the reader.
                                PortableShim.File.Delete(_filePath);
                            }
                            else if (e.HResult == eWin32SharingViolation)
                            {
                                // On Windows File.Delete only marks the file for deletion, but doens't remove it from the directory.
                                var newFilePath = Path.Combine(Path.GetDirectoryName(_filePath), Guid.NewGuid().ToString() + "_" + Path.GetFileName(_filePath));

                                // Try to rename the existing file. This fails unless the file is open with FileShare.Delete.
                                PortableShim.File.Move(_filePath, newFilePath);

                                // hide the renamed file:
                                PortableShim.File.SetAttributes(newFilePath, PortableShim.FileAttributes.Hidden);

                                // Mark the renamed file for deletion, so that it's deleted as soon as the current reader is finished reading it
                                PortableShim.File.Delete(newFilePath);
                            }
                        }
                        catch
                        {
                            // report the original exception
                            ReportOpenFileDiagnostic(diagnostics, e);
                            return null;
                        }

                        return OpenFileStream();
                    }
                }
                catch (Exception e)
                {
                    ReportOpenFileDiagnostic(diagnostics, e);
                    return null;
                }
            }
Beispiel #3
0
        /// <summary>
        /// Rewrite an async method into a state machine type.
        /// </summary>
        internal static BoundStatement Rewrite(
            BoundStatement body,
            MethodSymbol method,
            int methodOrdinal,
            VariableSlotAllocator slotAllocatorOpt,
            TypeCompilationState compilationState,
            DiagnosticBag diagnostics,
            out AsyncStateMachine stateMachineType)
        {
            if (!method.IsAsync)
            {
                stateMachineType = null;
                return body;
            }

            // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class.
            var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct;

            var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics);

            stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind);
            compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType);
            var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics);

            if (!rewriter.VerifyPresenceOfRequiredAPIs())
            {
                return body;
            }

            return rewriter.Rewrite();
        }
Beispiel #4
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()));
        }
 internal override BoundExpression GetValue(BoundPseudoVariable variable, DiagnosticBag diagnostics)
 {
     var method = GetIntrinsicMethod(_compilation, ExpressionCompilerConstants.GetVariableValueMethodName);
     var local = variable.LocalSymbol;
     var expr = InvokeGetMethod(method, variable.Syntax, local.Name);
     return ConvertToLocalType(_compilation, expr, local.Type, diagnostics);
 }
Beispiel #6
0
        /// <summary>
        /// Rewrite an iterator method into a state machine class.
        /// </summary>
        /// <param name="body">The original body of the method</param>
        /// <param name="method">The method's identity</param>
        /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param>
        /// <param name="diagnostics">Diagnostic bag for diagnostics.</param>
        /// <param name="generateDebugInfo"></param>
        internal static BoundStatement Rewrite(
            BoundStatement body,
            MethodSymbol method,
            TypeCompilationState compilationState,
            DiagnosticBag diagnostics,
            bool generateDebugInfo)
        {
            TypeSymbol elementType = method.IteratorElementType;
            if ((object)elementType == null)
            {
                return body;
            }

            // Figure out what kind of iterator we are generating.
            bool isEnumerable;
            switch (method.ReturnType.OriginalDefinition.SpecialType)
            {
                case SpecialType.System_Collections_IEnumerable:
                case SpecialType.System_Collections_Generic_IEnumerable_T:
                    isEnumerable = true;
                    break;

                case SpecialType.System_Collections_IEnumerator:
                case SpecialType.System_Collections_Generic_IEnumerator_T:
                    isEnumerable = false;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType);
            }

            var iteratorClass = new IteratorStateMachine(method, isEnumerable, elementType, compilationState);
            return new IteratorRewriter(body, method, isEnumerable, iteratorClass, compilationState, diagnostics, generateDebugInfo).Rewrite();
        }
Beispiel #7
0
 private void EnsureSwitchGoverningExpressionAndDiagnosticsBound()
 {
     var switchGoverningDiagnostics = new DiagnosticBag();
     var boundSwitchExpression = BindSwitchExpression(SwitchSyntax.Expression, switchGoverningDiagnostics);
     _switchGoverningDiagnostics = switchGoverningDiagnostics;
     Interlocked.CompareExchange(ref _switchGoverningExpression, boundSwitchExpression, null);
 }
Beispiel #8
0
        private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
        {
            BoundStatement initializer;
            if (node.Declaration != null)
            {
                Debug.Assert(node.Initializers.Count == 0);
                if (node.Declaration.IsDeconstructionDeclaration)
                {
                    initializer = originalBinder.BindDeconstructionDeclaration(node.Declaration, node.Declaration, diagnostics);
                }
                else
                {
                    ImmutableArray<BoundLocalDeclaration> unused;
                    initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused);
                }
            }
            else
            {
                initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics);
            }

            var condition = (node.Condition != null) ? originalBinder.BindBooleanExpression(node.Condition, diagnostics) : null;
            var increment = originalBinder.BindStatementExpressionList(node.Incrementors, diagnostics);
            var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics);

            Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node));
            return new BoundForStatement(node,
                                         this.Locals,
                                         initializer,
                                         condition,
                                         increment,
                                         body,
                                         this.BreakLabel,
                                         this.ContinueLabel);
        }
Beispiel #9
0
        /// <summary>
        /// Determine the effective base type, effective interface set, and set of type
        /// parameters (excluding cycles) from the type parameter constraints. Conflicts
        /// within the constraints and constraint types are returned as diagnostics.
        /// 'inherited' should be true if the type parameters are from an overridden
        /// generic method. In those cases, additional constraint checks are applied.
        /// </summary>
        public static TypeParameterBounds ResolveBounds(
            this TypeParameterSymbol typeParameter,
            AssemblySymbol corLibrary,
            ConsList<TypeParameterSymbol> inProgress,
            ImmutableArray<TypeSymbol> constraintTypes,
            bool inherited,
            CSharpCompilation currentCompilation,
            DiagnosticBag diagnostics)
        {
            var diagnosticsBuilder = ArrayBuilder<TypeParameterDiagnosticInfo>.GetInstance();
            ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null;
            var bounds = typeParameter.ResolveBounds(corLibrary, inProgress, constraintTypes, inherited, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);

            if (useSiteDiagnosticsBuilder != null)
            {
                diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder);
            }

            foreach (var pair in diagnosticsBuilder)
            {
                diagnostics.Add(new CSDiagnostic(pair.DiagnosticInfo, pair.TypeParameter.Locations[0]));
            }

            diagnosticsBuilder.Free();
            return bounds;
        }
 private ImmutableArray<Symbol> BindQualifiedCref(QualifiedCrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
 {
     // NOTE: we won't check whether container is an error type - we'll just let BindMemberCref fail
     // and report a blanket diagnostic.
     NamespaceOrTypeSymbol container = BindNamespaceOrTypeSymbolInCref(syntax.Container);
     return BindMemberCref(syntax.Member, container, out ambiguityWinner, diagnostics);
 }
        public void ImplicitlyTypedArrayLocal()
        {
            var compilation = CreateCompilationWithMscorlib(@"
class M {}

class C 
{ 
     public void F()
     {
        var a = new[] { new M() };
     }
}
");

            compilation.VerifyDiagnostics();

            var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("F").Single();    
            var diagnostics = new DiagnosticBag();
            var block = Compiler.BindMethodBody(method, diagnostics);

            var locDecl =(BoundLocalDeclaration)block.Statements.Single();
            var localA = (ArrayTypeSymbol)locDecl.DeclaredType.Display;
    
            var typeM = compilation.GlobalNamespace.GetMember<TypeSymbol>("M");

            Assert.Equal(typeM, localA.ElementType);
        }
        public static SourcePropertyAccessorSymbol CreateAccessorSymbol(
            NamedTypeSymbol containingType,
            SourcePropertySymbol property,
            DeclarationModifiers propertyModifiers,
            string propertyName,
            ArrowExpressionClauseSyntax syntax,
            PropertySymbol explicitlyImplementedPropertyOpt,
            string aliasQualifierOpt,
            DiagnosticBag diagnostics)
        {
            string name;
            ImmutableArray<MethodSymbol> explicitInterfaceImplementations;
            GetNameAndExplicitInterfaceImplementations(
                explicitlyImplementedPropertyOpt,
                propertyName,
                property.IsCompilationOutputWinMdObj(),
                aliasQualifierOpt,
                isGetMethod: true,
                name: out name,
                explicitInterfaceImplementations:
                out explicitInterfaceImplementations);

            return new SourcePropertyAccessorSymbol(
                containingType,
                name,
                property,
                propertyModifiers,
                explicitInterfaceImplementations,
                syntax.Expression.GetLocation(),
                syntax,
                diagnostics);
        }
 internal ImmutableArray<Symbol> BindCref(CrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
 {
     ImmutableArray<Symbol> symbols = BindCrefInternal(syntax, out ambiguityWinner, diagnostics);
     Debug.Assert(!symbols.IsDefault, "Prefer empty to null.");
     Debug.Assert((symbols.Length > 1) == ((object)ambiguityWinner != null), "ambiguityWinner should be set iff more than one symbol is returned.");
     return symbols;
 }
 internal static NamespaceSymbol BuildSymbol(
     this MergedNamespaceDeclaration declaration,
     NamespaceOrTypeSymbol parent,
     DiagnosticBag diagnostics)
 {
     return new SourceNamespaceSymbol(parent, declaration, diagnostics);
 }
            protected override ReadOnlyArray<ParameterSymbol> MakeParameters(
                Binder binder,
                DelegateDeclarationSyntax syntax,
                out bool isExtensionMethod,
                out bool isVararg,
                DiagnosticBag diagnostics,
                CancellationToken cancellationToken)
            {
                isExtensionMethod = false;
                isVararg = false;
                var delegateBinder = binder as DelegateBinder;
                var parameters = ArrayBuilder<ParameterSymbol>.GetInstance();
                int ordinal = 0;
                foreach (var p in delegateBinder.invoke.Parameters)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    if (p.RefKind != RefKind.None)
                    {
                        parameters.Add(new SynthesizedParameterSymbol(this, p.Type, ordinal++, p.RefKind, p.Name));
                    }
                }

                parameters.Add(new SynthesizedParameterSymbol(this, binder.GetSpecialType(SpecialType.System_IAsyncResult, diagnostics, syntax), ordinal++, RefKind.None, "result"));
                return parameters.ToReadOnlyAndFree();
            }
        internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitializerMethod initializerMethod, DiagnosticBag diagnostics)
        {
            var containingType = initializerMethod.ContainingType;
            var compilation = containingType.DeclaringCompilation;
            if (compilation.IsSubmission)
            {
                var submissionArrayType = compilation.CreateArrayTypeSymbol(compilation.GetSpecialType(SpecialType.System_Object));
                ReportUseSiteDiagnostics(submissionArrayType, diagnostics);
                return new SubmissionEntryPoint(
                    containingType,
                    initializerMethod.ReturnType,
                    submissionArrayType);
            }
            else
            {
                var taskType = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task);
#if DEBUG
                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                Debug.Assert(taskType.IsErrorType() || initializerMethod.ReturnType.IsDerivedFrom(taskType, ignoreDynamic: true, useSiteDiagnostics: ref useSiteDiagnostics));
#endif
                ReportUseSiteDiagnostics(taskType, diagnostics);
                var getAwaiterMethod = taskType.IsErrorType() ?
                    null :
                    GetRequiredMethod(taskType, WellKnownMemberNames.GetAwaiter, diagnostics);
                var getResultMethod = ((object)getAwaiterMethod == null) ?
                    null :
                    GetRequiredMethod(getAwaiterMethod.ReturnType, WellKnownMemberNames.GetResult, diagnostics);
                return new ScriptEntryPoint(
                    containingType,
                    compilation.GetSpecialType(SpecialType.System_Void),
                    getAwaiterMethod,
                    getResultMethod);
            }
        }
        internal AsyncMethodToStateMachineRewriter(
            MethodSymbol method,
            int methodOrdinal,
            AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
            SyntheticBoundNodeFactory F,
            FieldSymbol state,
            FieldSymbol builder,
            IReadOnlySet<Symbol> hoistedVariables,
            IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies,
            SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals,
            VariableSlotAllocator slotAllocatorOpt,
            int nextFreeHoistedLocalSlot,
            DiagnosticBag diagnostics)
            : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false)
        {
            _method = method;
            _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
            _asyncMethodBuilderField = builder;
            _exprReturnLabel = F.GenerateLabel("exprReturn");
            _exitLabel = F.GenerateLabel("exitLabel");

            _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue)
                : null;

            _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal);
            _awaiterFields = new Dictionary<TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicComparer);
            _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0;
        }
        /// <summary>
        /// Traverses the symbol table processing XML documentation comments and optionally writing them to
        /// a provided stream.
        /// </summary>
        /// <param name="compilation">Compilation that owns the symbol table.</param>
        /// <param name="assemblyName">Assembly name override, if specified. Otherwise the <see cref="ISymbol.Name"/> of the source assembly is used.</param>
        /// <param name="xmlDocStream">Stream to which XML will be written, if specified.</param>
        /// <param name="diagnostics">Will be supplemented with documentation comment diagnostics.</param>
        /// <param name="cancellationToken">To stop traversing the symbol table early.</param>
        /// <param name="filterTree">Only report diagnostics from this syntax tree, if non-null.</param>
        /// <param name="filterSpanWithinTree">If <paramref name="filterTree"/> and filterSpanWithinTree is non-null, report diagnostics within this span in the <paramref name="filterTree"/>.</param>
        public static void WriteDocumentationCommentXml(CSharpCompilation compilation, string assemblyName, Stream xmlDocStream, DiagnosticBag diagnostics, CancellationToken cancellationToken, SyntaxTree filterTree = null, TextSpan? filterSpanWithinTree = null)
        {
            StreamWriter writer = null;
            if (xmlDocStream != null && xmlDocStream.CanWrite)
            {
                writer = new StreamWriter(
                    stream: xmlDocStream,
                    encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false),
                    bufferSize: 0x400, // Default.
                    leaveOpen: true); // Don't close caller's stream.
            }

            using (writer)
            {
                var compiler = new DocumentationCommentCompiler(assemblyName ?? compilation.SourceAssembly.Name, compilation, writer, filterTree, filterSpanWithinTree,
                    processIncludes: true, isForSingleSymbol: false, diagnostics: diagnostics, cancellationToken: cancellationToken);
                compiler.Visit(compilation.SourceAssembly.GlobalNamespace);
                Debug.Assert(compiler._indentDepth == 0);
            }

            if (filterTree != null)
            {
                // Will respect the DocumentationMode.
                UnprocessedDocumentationCommentFinder.ReportUnprocessed(filterTree, filterSpanWithinTree, diagnostics, cancellationToken);
            }
            else
            {
                foreach (SyntaxTree tree in compilation.SyntaxTrees)
                {
                    // Will respect the DocumentationMode.
                    UnprocessedDocumentationCommentFinder.ReportUnprocessed(tree, null, diagnostics, cancellationToken);
                }
            }
        }
Beispiel #19
0
        public void EmbedAllMembersOfImplementedInterface(CSharpSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
        {
            Debug.Assert(UnderlyingNamedType.IsInterfaceType());

            if (embeddedAllMembersOfImplementedInterface)
            {
                return;
            }

            embeddedAllMembersOfImplementedInterface = true;

            // Embed all members
            foreach (MethodSymbol m in UnderlyingNamedType.GetMethodsToEmit())
            {
                if ((object)m != null)
                {
                    TypeManager.EmbedMethod(this, m, syntaxNodeOpt, diagnostics);
                }
            }

            // We also should embed properties and events, but we don't need to do this explicitly here
            // because accessors embed them automatically.

            // Do the same for implemented interfaces.
            foreach (NamedTypeSymbol @interface in UnderlyingNamedType.GetInterfacesToEmit())
            {
                TypeManager.ModuleBeingBuilt.Translate(@interface, syntaxNodeOpt, diagnostics, fromImplements: true);
            }
        }
        protected override void MethodChecks(DiagnosticBag diagnostics)
        {
            var syntax = GetSyntax();
            var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree);
            ParameterListSyntax parameterList = syntax.ParameterList;

            // NOTE: if we asked for the binder for the body of the constructor, we'd risk a stack overflow because
            // we might still be constructing the member list of the containing type.  However, getting the binder
            // for the parameters should be safe.
            var bodyBinder = binderFactory.GetBinder(parameterList).WithContainingMemberOrLambda(this);

            SyntaxToken arglistToken;
            _lazyParameters = ParameterHelpers.MakeParameters(bodyBinder, this, parameterList, true, out arglistToken, diagnostics);
            _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword);
            _lazyReturnType = bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax);

            var location = this.Locations[0];
            if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0))
            {
                diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this);
            }

            this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics);

            if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams))
            {
                diagnostics.Add(ErrorCode.ERR_BadVarargs, location);
            }
        }
        internal SourceMemberFieldSymbol(
            SourceMemberContainerTypeSymbol containingType,
            VariableDeclaratorSyntax declarator,
            DeclarationModifiers modifiers,
            bool modifierErrors,
            DiagnosticBag diagnostics)
            : base(containingType, declarator.Identifier.ValueText, declarator.GetReference(), declarator.Identifier.GetLocation())
        {
            this.modifiers = modifiers;

            this.CheckAccessibility(diagnostics);

            var location = Location;
            if (modifierErrors)
            {
                // skip the following checks
            }
            else if (containingType.IsSealed && (DeclaredAccessibility == Accessibility.Protected || DeclaredAccessibility == Accessibility.ProtectedOrInternal))
            {
                diagnostics.Add(AccessCheck.GetProtectedMemberInSealedTypeError(containingType), location, this);
            }
            else if (IsVolatile && IsReadOnly)
            {
                diagnostics.Add(ErrorCode.ERR_VolatileAndReadonly, location, this);
            }
            else if (containingType.IsStatic && !IsStatic)
            {
                diagnostics.Add(ErrorCode.ERR_InstanceMemberInStaticClass, location, this);
            }

            // TODO: Consider checking presence of core type System.Runtime.CompilerServices.IsVolatile 
            // if there is a volatile modifier. Perhaps an appropriate error should be reported if the 
            // type isn’t available.
        }
Beispiel #22
0
        internal override BoundStatement BindLockStatementParts(DiagnosticBag diagnostics)
        {
            // Allow method groups during binding and then rule them out when we check that the expression has
            // a reference type.
            ExpressionSyntax exprSyntax = syntax.Expression;
            BoundExpression expr = expressionHandler.GetExpression(diagnostics);
            TypeSymbol exprType = expr.Type;

            bool hasErrors = false;

            if ((object)exprType == null)
            {
                if (expr.ConstantValue != ConstantValue.Null) // Dev10 allows the null literal.
                {
                    Error(diagnostics, ErrorCode.ERR_LockNeedsReference, exprSyntax, expr.Display);
                    hasErrors = true;
                }
            }
            else if (!exprType.IsReferenceType)
            {
                Error(diagnostics, ErrorCode.ERR_LockNeedsReference, exprSyntax, exprType);
                hasErrors = true;
            }

            BoundStatement stmt = BindPossibleEmbeddedStatement(syntax.Statement, diagnostics);
            return new BoundLockStatement(syntax, expr, stmt, hasErrors);
        }
            protected override BoundExpression BindRangeVariable(SimpleNameSyntax node, RangeVariableSymbol qv, DiagnosticBag diagnostics)
            {
                Debug.Assert(!qv.IsTransparent);

                BoundExpression translation;
                ImmutableArray<string> path;
                if (_rangeVariableMap.TryGetValue(qv, out path))
                {
                    if (path.IsEmpty)
                    {
                        // the range variable maps directly to a use of the parameter of that name
                        var value = base.parameterMap[qv.Name];
                        Debug.Assert(value.Count == 1);
                        translation = new BoundParameter(node, value.Single()) { WasCompilerGenerated = true };
                    }
                    else
                    {
                        // if the query variable map for this variable is non empty, we always start with the current
                        // lambda's first parameter, which is a transparent identifier.
                        Debug.Assert(base.lambdaSymbol.Parameters[0].Name.StartsWith(transparentIdentifierPrefix));
                        translation = new BoundParameter(node, base.lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true };
                        for (int i = path.Length - 1; i >= 0; i--)
                        {
                            var nextField = path[i];
                            translation = SelectField(node, translation, nextField, diagnostics);
                            translation.WasCompilerGenerated = true;
                        }
                    }

                    return new BoundRangeVariable(node, qv, translation, translation.Type);
                }

                return base.BindRangeVariable(node, qv, diagnostics);
            }
        internal void TestOverloadResolutionWithDiff(string source, MetadataReference[] additionalRefs = null)
        {
            // The mechanism of this test is: we build the bound tree for the code passed in and then extract
            // from it the nodes that describe the method symbols. We then compare the description of
            // the symbols given to the comment that follows the call.

            var mscorlibRef = new MetadataImageReference(ProprietaryTestResources.NetFX.v4_0_30316_17626.mscorlib.AsImmutableOrNull(), display: "mscorlib");
            var references = new[] { mscorlibRef }.Concat(additionalRefs ?? SpecializedCollections.EmptyArray<MetadataReference>());

            var compilation = CreateCompilation(source, references, TestOptions.ReleaseDll);

            var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single();
            var diagnostics = new DiagnosticBag();
            var block = MethodCompiler.BindMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics);
            var tree = BoundTreeDumperNodeProducer.MakeTree(block);
            var results = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value)
                .Where(x => x.Text == "method" && x.Value != null)
                .Select(x => x.Value)
                .ToArray());

            // var r = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value).ToArray();

            var expected = string.Join("\n", source
                .Split(new[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries)
                .Where(x => x.Contains("//-"))
                .Select(x => x.Substring(x.IndexOf("//-") + 3))
                .ToArray());

            AssertEx.Equal(expected, results);
        }
 private void ReportInferenceFailure(DiagnosticBag diagnostics)
 {
     var designation = (SingleVariableDesignationSyntax)this.Syntax;
     Binder.Error(
         diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, designation.Identifier,
         designation.Identifier.ValueText);
 }
            internal AsyncMethodToClassRewriter(
                MethodSymbol method,
                AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
                SyntheticBoundNodeFactory F,
                FieldSymbol state,
                FieldSymbol builder,
                HashSet<Symbol> variablesCaptured,
                Dictionary<Symbol, CapturedSymbolReplacement> initialProxies,
                DiagnosticBag diagnostics,
                bool generateDebugInfo)
                : base(F, method, state, variablesCaptured, initialProxies, diagnostics,
                      useFinalizerBookkeeping: false,
                      generateDebugInfo: generateDebugInfo)
            {
                this.method = method;
                this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
                this.asyncMethodBuilderField = builder;
                this.exprReturnLabel = F.GenerateLabel("exprReturn");
                this.exitLabel = F.GenerateLabel("exitLabel");

                this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                    ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName())
                    : null;

                this.dynamicFactory = new LoweredDynamicOperationFactory(F);
            }
        internal SynthesizedInteractiveInitializerMethod(SourceMemberContainerTypeSymbol containingType, DiagnosticBag diagnostics)
        {
            Debug.Assert(containingType.IsScriptClass);

            _containingType = containingType;
            CalculateReturnType(containingType.DeclaringCompilation, diagnostics, out _resultType, out _returnType);
        }
            private BoundExpression SelectField(SimpleNameSyntax node, BoundExpression receiver, string name, DiagnosticBag diagnostics)
            {
                var receiverType = receiver.Type as NamedTypeSymbol;
                if ((object)receiverType == null || !receiverType.IsAnonymousType)
                {
                    // We only construct transparent query variables using anonymous types, so if we're trying to navigate through
                    // some other type, we must have some hinky query API where the types don't match up as expected.
                    // We should report this as an error of some sort.
                    // TODO: DevDiv #737822 - reword error message and add test.
                    var info = new CSDiagnosticInfo(ErrorCode.ERR_UnsupportedTransparentIdentifierAccess, name, receiver.ExpressionSymbol ?? receiverType);
                    Error(diagnostics, info, node);
                    return new BoundBadExpression(
                        node,
                        LookupResultKind.Empty,
                        ImmutableArray.Create<Symbol>(receiver.ExpressionSymbol),
                        ImmutableArray.Create<BoundNode>(receiver),
                        new ExtendedErrorTypeSymbol(this.Compilation, "", 0, info));
                }

                LookupResult lookupResult = LookupResult.GetInstance();
                LookupOptions options = LookupOptions.MustBeInstance;
                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                LookupMembersWithFallback(lookupResult, receiver.Type, name, 0, ref useSiteDiagnostics, basesBeingResolved: null, options: options);
                diagnostics.Add(node, useSiteDiagnostics);

                var result = BindMemberOfType(node, node, name, 0, receiver, default(SeparatedSyntaxList<TypeSyntax>), default(ImmutableArray<TypeSymbol>), lookupResult, BoundMethodGroupFlags.None, diagnostics);
                result.WasCompilerGenerated = true;
                lookupResult.Free();
                return result;
            }
Beispiel #29
0
        internal static DeclarationModifiers CheckModifiers(
            DeclarationModifiers modifiers,
            DeclarationModifiers allowedModifiers,
            Location errorLocation,
            DiagnosticBag diagnostics,
            out bool modifierErrors)
        {
            modifierErrors = false;
            DeclarationModifiers errorModifiers = modifiers & ~allowedModifiers;
            DeclarationModifiers result = modifiers & allowedModifiers;
            while (errorModifiers != DeclarationModifiers.None)
            {
                DeclarationModifiers oneError = errorModifiers & ~(errorModifiers - 1);
                Debug.Assert(oneError != DeclarationModifiers.None);
                errorModifiers = errorModifiers & ~oneError;
                switch (oneError)
                {
                    case DeclarationModifiers.Partial:
                        diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyMethods, errorLocation);
                        break;

                    default:
                        diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, ConvertSingleModifierToSyntaxText(oneError));
                        break;
                }
                modifierErrors = true;
            }

            bool isMethod = (allowedModifiers & (DeclarationModifiers.Partial | DeclarationModifiers.Virtual)) == (DeclarationModifiers.Partial | DeclarationModifiers.Virtual);
            if (isMethod && ((result & (DeclarationModifiers.Partial | DeclarationModifiers.Private)) == (DeclarationModifiers.Partial | DeclarationModifiers.Private)))
            {
                diagnostics.Add(ErrorCode.ERR_PartialMethodInvalidModifier, errorLocation);
            }
            return result;
        }
Beispiel #30
0
        /// <summary>
        /// The flow analysis pass.  This pass reports required diagnostics for unreachable
        /// statements and uninitialized variables (through the call to FlowAnalysisWalker.Analyze),
        /// and inserts a final return statement if the end of a void-returning method is reachable.
        /// </summary>
        /// <param name="method">the method to be analyzed</param>
        /// <param name="block">the method's body</param>
        /// <param name="diagnostics">the receiver of the reported diagnostics</param>
        /// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns>
        public static BoundBlock Rewrite(
            MethodSymbol method,
            BoundBlock block,
            DiagnosticBag diagnostics)
        {
            var compilation = method.DeclaringCompilation;

            if (method.ReturnsVoid || (object)method.IteratorElementType != null
                || (method.IsAsync && compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) == method.ReturnType))
            {
                if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics))
                {
                    // we don't analyze synthesized void methods.
                    var sourceMethod = method as SourceMethodSymbol;
                    block = AppendImplicitReturn(block, method, (object)sourceMethod != null ? sourceMethod.BlockSyntax : null);
                }
            }
            else if (Analyze(compilation, method, block, diagnostics))
            {
                // If the method is a lambda expression being converted to a non-void delegate type
                // and the end point is reachable then suppress the error here; a special error
                // will be reported by the lambda binder.
                Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction);

                // If there's more than one location, then the method is partial and we
                // have already reported a non-void partial method error.
                if (method.Locations.Length == 1)
                {
                    diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method);
                }
            }

            return block;
        }
        protected SourceUserDefinedOperatorSymbolBase(
            MethodKind methodKind,
            string name,
            SourceMemberContainerTypeSymbol containingType,
            Location location,
            SyntaxReference syntaxReference,
            SyntaxReference bodySyntaxReference,
            SyntaxTokenList modifiersSyntax,
            DiagnosticBag diagnostics,
            bool isExpressionBodied) :
            base(containingType, syntaxReference, bodySyntaxReference, location)
        {
            _name = name;
            _isExpressionBodied = isExpressionBodied;

            // @t-mawind (is this a good idea?)
            var defaultAccess    = (ContainingType.IsInstance || ContainingType.IsConcept) ? DeclarationModifiers.Public : DeclarationModifiers.Private;
            var allowedModifiers =
                DeclarationModifiers.AccessibilityMask |
                DeclarationModifiers.Static |
                DeclarationModifiers.Extern |
                DeclarationModifiers.Unsafe;

            bool modifierErrors;
            var  declarationModifiers = ModifierUtils.MakeAndCheckNontypeMemberModifiers(
                modifiersSyntax,
                defaultAccess,
                allowedModifiers,
                location,
                diagnostics,
                out modifierErrors);

            this.CheckUnsafeModifier(declarationModifiers, diagnostics);

            if (ContainingType.IsConcept)
            {
                // @t-mawind Is there any easier way of doing this?
                declarationModifiers |= DeclarationModifiers.Abstract;
            }

            // We will bind the formal parameters and the return type lazily. For now,
            // assume that the return type is non-void; when we do the lazy initialization
            // of the parameters and return type we will update the flag if necessary.

            this.MakeFlags(methodKind, declarationModifiers, returnsVoid: false, isExtensionMethod: false);

            if (this.ContainingType.IsInterface && !this.ContainingType.IsConcept)
            {
                // If we have an operator in an interface, we already have reported that fact as
                // an error. No need to cascade the error further.
                return;
            }

            if (this.ContainingType.IsStatic)
            {
                // Similarly if we're in a static class, though we have not reported it yet.

                // CS0715: '{0}': static classes cannot contain user-defined operators
                diagnostics.Add(ErrorCode.ERR_OperatorInStaticClass, location, this);
                return;
            }

            // @t-mawind
            //   If we're in a concept instance, then operators must be public and
            //   _non_ -static.
            if (ContainingType.IsInstance || ContainingType.IsConcept)
            {
                if (DeclaredAccessibility != Accessibility.Public || IsStatic)
                {
                    // CS4038: User-defined concept operator '...' must be declared non-static and public.
                    diagnostics.Add(ErrorCode.ERR_ConceptOperatorsMustBeNonStatic, Locations[0], this);
                }
            }
            else
            {
                // SPEC: An operator declaration must include both a public and a
                // SPEC: static modifier
                if (this.DeclaredAccessibility != Accessibility.Public || !this.IsStatic)
                {
                    // CS0558: User-defined operator '...' must be declared static and public
                    diagnostics.Add(ErrorCode.ERR_OperatorsMustBeStatic, this.Locations[0], this);
                }
            }

            // SPEC: Because an external operator provides no actual implementation,
            // SPEC: its operator body consists of a semicolon. For expression-bodied
            // SPEC: operators, the body is an expression. For all other operators,
            // SPEC: the operator body consists of a block...
            if (bodySyntaxReference != null && IsExtern)
            {
                diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this);
            }
            else if (bodySyntaxReference == null && !IsExtern && !IsAbstract && !IsPartial)
            {
                // Do not report that the body is missing if the operator is marked as
                // partial or abstract; we will already have given an error for that so
                // there's no need to "cascade" the error.
                diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this);
            }

            // SPEC: It is an error for the same modifier to appear multiple times in an
            // SPEC: operator declaration.
            var info = ModifierUtils.CheckAccessibility(this.DeclarationModifiers);

            if (info != null)
            {
                diagnostics.Add(info, location);
            }
        }
Beispiel #32
0
        private ImmutableArray <Symbol> BindIndexerMemberCref(IndexerMemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
        {
            const int arity = 0;

            ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, WellKnownMemberNames.Indexer, arity, syntax.Parameters != null, diagnostics);

            if (sortedSymbols.IsEmpty)
            {
                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            // Since only indexers are named WellKnownMemberNames.Indexer.
            Debug.Assert(sortedSymbols.All(SymbolExtensions.IsIndexer));

            // NOTE: guaranteed to be a property, because only indexers are considered.
            return(ProcessCrefMemberLookupResults(
                       sortedSymbols,
                       arity,
                       syntax,
                       typeArgumentListSyntax: null,
                       parameterListSyntax: syntax.Parameters,
                       ambiguityWinner: out ambiguityWinner,
                       diagnostics: diagnostics));
        }
Beispiel #33
0
        private ImmutableArray <Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
        {
            SimpleNameSyntax nameSyntax = syntax.Name as SimpleNameSyntax;

            int    arity;
            string memberName;

            if (nameSyntax != null)
            {
                arity      = nameSyntax.Arity;
                memberName = nameSyntax.Identifier.ValueText;
            }
            else
            {
                // If the name isn't a SimpleNameSyntax, then we must have a type name followed by a parameter list.
                // Thus, we're looking for a constructor.
                Debug.Assert((object)containerOpt == null);

                // Could be an error type, but we'll just lookup fail below.
                containerOpt = BindNamespaceOrTypeSymbolInCref(syntax.Name);

                arity      = 0;
                memberName = WellKnownMemberNames.InstanceConstructorName;
            }

            if (string.IsNullOrEmpty(memberName))
            {
                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics);

            if (sortedSymbols.IsEmpty)
            {
                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            return(ProcessCrefMemberLookupResults(
                       sortedSymbols,
                       arity,
                       syntax,
                       typeArgumentListSyntax: arity == 0 ? null : ((GenericNameSyntax)nameSyntax).TypeArgumentList,
                       parameterListSyntax: syntax.Parameters,
                       ambiguityWinner: out ambiguityWinner,
                       diagnostics: diagnostics));
        }
Beispiel #34
0
        internal ImmutableArray <Symbol> BindCref(CrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
        {
            ImmutableArray <Symbol> symbols = BindCrefInternal(syntax, out ambiguityWinner, diagnostics);

            Debug.Assert(!symbols.IsDefault, "Prefer empty to null.");
            Debug.Assert((symbols.Length > 1) == ((object)ambiguityWinner != null), "ambiguityWinner should be set iff more than one symbol is returned.");
            return(symbols);
        }
Beispiel #35
0
        private ImmutableArray <Symbol> BindMemberCref(MemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics)
        {
            if ((object)containerOpt != null && containerOpt.Kind == SymbolKind.TypeParameter)
            {
                // As in normal lookup (see CreateErrorIfLookupOnTypeParameter), you can't dot into a type parameter
                // (though you can dot into an expression of type parameter type).
                CrefSyntax crefSyntax = GetRootCrefSyntax(syntax);
                var        noTrivia   = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null);
                diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString());

                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            ImmutableArray <Symbol> result;

            switch (syntax.Kind())
            {
            case SyntaxKind.NameMemberCref:
                result = BindNameMemberCref((NameMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics);
                break;

            case SyntaxKind.IndexerMemberCref:
                result = BindIndexerMemberCref((IndexerMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics);
                break;

            case SyntaxKind.OperatorMemberCref:
                result = BindOperatorMemberCref((OperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics);
                break;

            case SyntaxKind.ConversionOperatorMemberCref:
                result = BindConversionOperatorMemberCref((ConversionOperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics);
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(syntax.Kind());
            }

            if (!result.Any())
            {
                CrefSyntax crefSyntax = GetRootCrefSyntax(syntax);
                var        noTrivia   = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null);
                diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString());
            }

            return(result);
        }
        internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
        {
            // Check constraints on return type and parameters. Note: Dev10 uses the
            // method name location for any such errors. We'll do the same for return
            // type errors but for parameter errors, we'll use the parameter location.

            this.ReturnType.CheckAllConstraints(conversions, this.Locations[0], diagnostics);

            foreach (var parameter in this.Parameters)
            {
                parameter.Type.CheckAllConstraints(conversions, parameter.Locations[0], diagnostics);
            }
        }
        private void CheckUserDefinedConversionSignature(DiagnosticBag diagnostics)
        {
            if (this.ReturnsVoid)
            {
                // CS0590: User-defined operators cannot return void
                diagnostics.Add(ErrorCode.ERR_OperatorCantReturnVoid, this.Locations[0]);
            }

            // SPEC: For a given source type S and target type T, if S or T are
            // SPEC: nullable types let S0 and T0 refer to their underlying types,
            // SPEC: otherwise, S0 and T0 are equal to S and T, respectively.

            var source  = this.ParameterTypes[0];
            var target  = this.ReturnType;
            var source0 = source.StrippedType();
            var target0 = target.StrippedType();

            // SPEC: A class or struct is permitted to declare a conversion from S to T
            // SPEC: only if all the following are true:

            // SPEC: Neither S0 nor T0 is an interface type.

            if (source0.IsInterfaceType() || target0.IsInterfaceType())
            {
                // CS0552: '{0}': user-defined conversions to or from an interface are not allowed
                diagnostics.Add(ErrorCode.ERR_ConversionWithInterface, this.Locations[0], this);
                return;
            }

            // SPEC: Either S0 or T0 is the class or struct type in which the operator
            // SPEC: declaration takes place.

            if (source0 != this.ContainingType && target0 != this.ContainingType &&
                // allow conversion between T and Nullable<T> in declaration of Nullable<T>
                source.TupleUnderlyingTypeOrSelf() != this.ContainingType &&
                target.TupleUnderlyingTypeOrSelf() != this.ContainingType)
            {
                // CS0556: User-defined conversion must convert to or from the enclosing type
                diagnostics.Add(ErrorCode.ERR_ConversionNotInvolvingContainedType, this.Locations[0]);
                return;
            }

            // SPEC: * S0 and T0 are different types:

            if ((ContainingType.SpecialType == SpecialType.System_Nullable_T) ? source == target : source0 == target0)
            {
                // CS0555: User-defined operator cannot take an object of the enclosing type
                // and convert to an object of the enclosing type
                diagnostics.Add(ErrorCode.ERR_IdentityConversion, this.Locations[0]);
                return;
            }

            // Those are the easy ones. Now we come to:

            // SPEC:
            // Excluding user-defined conversions, a conversion does not exist from
            // S to T or T to S. For the purposes of these rules, any type parameters
            // associated with S or T are considered to be unique types that have
            // no inheritance relationship with other types, and any constraints on
            // those type parameters are ignored.

            // A counter-intuitive consequence of this rule is that:
            //
            // class X<U> where U : X<U>
            // {
            //     public implicit operator X<U>(U u) { return u; }
            // }
            //
            // is *legal*, even though there is *already* an implicit conversion
            // from U to X<U> because U is constrained to have such a conversion.
            //
            // In discussing the implications of this rule, let's call the
            // containing type (which may be a class or struct) "C". S and T
            // are the source and target types.
            //
            // If we have made it this far in the error analysis we already know that
            // exactly one of S and T is C or C? -- if two or zero were, then we'd
            // have already reported ERR_ConversionNotInvolvingContainedType or
            // ERR_IdentityConversion and returned.
            //
            // WOLOG for the purposes of this discussion let's assume that S is
            // the one that is C or C?, and that T is the one that is neither C nor C?.
            //
            // So the question is: under what circumstances could T-to-S or S-to-T,
            // be a valid conversion, by the definition of valid above?
            //
            // Let's consider what kinds of types T could be. T cannot be an interface
            // because we've already reported an error and returned if it is. If T is
            // a delegate, array, enum, pointer, struct or nullable type then there
            // is no built-in conversion from T to the user-declared class/struct
            // C, or to C?. If T is a type parameter, then by assumption the type
            // parameter has no constraints, and therefore is not convertible to
            // C or C?.
            //
            // That leaves T to be a class. We already know that T is not C, (or C?,
            // since T is a class) and therefore there is no identity conversion from T to S.
            //
            // Suppose S is C and C is a class. Then the only way that there can be a
            // conversion between T and S is if T is a base class of S or S is a base class of T.
            //
            // Suppose S is C and C is a struct. Then the only way that there can be a
            // conversion between T and S is if T is a base class of S. (And T would
            // have to be System.Object or System.ValueType.)
            //
            // Suppose S is C? and C is a struct. Then the only way that there can be a
            // conversion between T and S is again, if T is a base class of S.
            //
            // Summing up:
            //
            // WOLOG, we assume that T is not C or C?, and S is C or C?. The conversion is
            // illegal only if T is a class, and either T is a base class of S, or S is a
            // base class of T.

            if (source.IsDynamic() || target.IsDynamic())
            {
                // '{0}': user-defined conversions to or from the dynamic type are not allowed
                diagnostics.Add(ErrorCode.ERR_BadDynamicConversion, this.Locations[0], this);
                return;
            }

            TypeSymbol same;
            TypeSymbol different;

            if (source0 == this.ContainingType)
            {
                same      = source;
                different = target;
            }
            else
            {
                same      = target;
                different = source;
            }

            if (different.IsClassType())
            {
                // different is a class type:
                Debug.Assert(!different.IsTypeParameter());

                // "same" is the containing class, so it can't be a type parameter
                Debug.Assert(!same.IsTypeParameter());

                HashSet <DiagnosticInfo> useSiteDiagnostics = null;

                if (same.IsDerivedFrom(different, ignoreDynamicAndTupleNames: false, useSiteDiagnostics: ref useSiteDiagnostics)) // tomat: ignoreDynamic should be true, but we don't want to introduce breaking change. See bug 605326.
                {
                    // '{0}': user-defined conversions to or from a base class are not allowed
                    diagnostics.Add(ErrorCode.ERR_ConversionWithBase, this.Locations[0], this);
                }
                else if (different.IsDerivedFrom(same, ignoreDynamicAndTupleNames: false, useSiteDiagnostics: ref useSiteDiagnostics)) // tomat: ignoreDynamic should be true, but we don't want to introduce breaking change. See bug 605326.
                {
                    // '{0}': user-defined conversions to or from a derived class are not allowed
                    diagnostics.Add(ErrorCode.ERR_ConversionWithDerived, this.Locations[0], this);
                }

                diagnostics.Add(this.Locations[0], useSiteDiagnostics);
            }
        }
            protected sealed override TAttributeData PortAttributeIfNeedTo(TAttributeData attrData, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics)
            {
                // Note, when porting attributes, we are not using constructors from original symbol.
                // The constructors might be missing (for example, in metadata case) and doing lookup
                // will ensure that we report appropriate errors.

                if (TypeManager.IsTargetAttribute(UnderlyingMethod, attrData, AttributeDescription.LCIDConversionAttribute))
                {
                    if (attrData.CommonConstructorArguments.Length == 1)
                    {
                        return(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_LCIDConversionAttribute__ctor, attrData, syntaxNodeOpt, diagnostics));
                    }
                }

                return(null);
            }
Beispiel #39
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location, params object[] args)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), location));
 }
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data        = (CommonFieldWellKnownAttributeData)decodedData;
            int?fieldOffset = data != null ? data.Offset : null;

            if (fieldOffset.HasValue)
            {
                if (this.ContainingType.Layout.Kind != LayoutKind.Explicit)
                {
                    Debug.Assert(boundAttributes.Any());

                    // error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)
                    int i = boundAttributes.IndexOfAttribute(this, AttributeDescription.FieldOffsetAttribute);
                    diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadStruct, allAttributeSyntaxNodes[i].Name.Location);
                }
            }
            else if (!this.IsStatic && !this.IsConst)
            {
                if (this.ContainingType.Layout.Kind == LayoutKind.Explicit)
                {
                    // error CS0625: '<field>': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute
                    diagnostics.Add(ErrorCode.ERR_MissingStructOffset, this.ErrorLocation, this.AttributeOwner);
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Beispiel #41
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax, params object[] args)
 {
     Error(diagnostics, code, syntax.GetLocation(), args);
 }
Beispiel #42
0
        internal static void ReportDiagnosticsIfObsolete(
            DiagnosticBag diagnostics,
            Symbol symbol,
            SyntaxNodeOrToken node,
            bool hasBaseReceiver,
            Symbol containingMember,
            NamedTypeSymbol containingType,
            BinderFlags location)
        {
            Debug.Assert((object)symbol != null);

            Debug.Assert(symbol.Kind == SymbolKind.NamedType ||
                         symbol.Kind == SymbolKind.Field ||
                         symbol.Kind == SymbolKind.Method ||
                         symbol.Kind == SymbolKind.Event ||
                         symbol.Kind == SymbolKind.Property);

            // Dev11 also reports on the unconstructed method.  It would be nice to report on
            // the constructed method, but then we wouldn't be able to walk the override chain.
            if (symbol.Kind == SymbolKind.Method)
            {
                symbol = ((MethodSymbol)symbol).ConstructedFrom;
            }

            // There are two reasons to walk up to the least-overridden member:
            //   1) That's the method to which we will actually emit a call.
            //   2) We don't know what virtual dispatch will do at runtime so an
            //      overriding member is basically a shot in the dark.  Better to
            //      just be consistent and always use the least-overridden member.
            Symbol leastOverriddenSymbol = symbol.GetLeastOverriddenMember(containingType);

            bool checkOverridingSymbol = hasBaseReceiver && !ReferenceEquals(symbol, leastOverriddenSymbol);

            if (checkOverridingSymbol)
            {
                // If we have a base receiver, we must be done with declaration binding, so it should
                // be safe to decode diagnostics.  We want to do this since reporting for the overriding
                // member is conditional on reporting for the overridden member (i.e. we need a definite
                // answer so we don't double-report).  You might think that double reporting just results
                // in cascading diagnostics, but it's possible that the second diagnostic is an error
                // while the first is merely a warning.
                leastOverriddenSymbol.GetAttributes();
            }

            ThreeState reportedOnOverridden = ReportDiagnosticsIfObsoleteInternal(diagnostics, leastOverriddenSymbol, node, containingMember, location);

            // CONSIDER: In place of hasBaseReceiver, dev11 also accepts cases where symbol.ContainingType is a "simple type" (e.g. int)
            // or a special by-ref type (e.g. ArgumentHandle).  These cases are probably more important for other checks performed by
            // ExpressionBinder::PostBindMethod, but they do appear to ObsoleteAttribute as well.  We're skipping them because they
            // don't make much sense for ObsoleteAttribute (e.g. this would seem to address the case where int.ToString has been made
            // obsolete but object.ToString has not).

            // If the overridden member was not definitely obsolete and this is a (non-virtual) base member
            // access, then check the overriding symbol as well.
            if (reportedOnOverridden != ThreeState.True && checkOverridingSymbol)
            {
                Debug.Assert(reportedOnOverridden != ThreeState.Unknown, "We forced attribute binding above.");

                ReportDiagnosticsIfObsoleteInternal(diagnostics, symbol, node, containingMember, location);
            }
        }
Beispiel #43
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token, params object[] args)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), token.GetLocation()));
 }
Beispiel #44
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), location));
 }
Beispiel #45
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax, params object[] args)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), syntax.Location));
 }
Beispiel #46
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax)
 {
     Error(diagnostics, code, syntax.GetLocation());
 }
Beispiel #47
0
 internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, Location location)
 {
     diagnostics.Add(new CSDiagnostic(info, location));
 }
Beispiel #48
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), token.GetLocation()));
 }
Beispiel #49
0
 /// <summary>
 /// Get the element type of this iterator.
 /// </summary>
 /// <param name="node">Node to report diagnostics, if any, such as "yield statement cannot be used
 /// inside a lambda expression"</param>
 /// <param name="diagnostics">Where to place any diagnostics</param>
 /// <returns>Element type of the current iterator, or an error type.</returns>
 internal virtual TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics)
 {
     return(Next.GetIteratorElementType(node, diagnostics));
 }
Beispiel #50
0
 internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax)
 {
     diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), syntax.Location));
 }
Beispiel #51
0
        /// <summary>
        /// Finds the GetResult method of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters.
        /// </remarks>
        private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out MethodSymbol getResultMethod, out BoundExpression getAwaiterGetResultCall)
        {
            var awaiterType = awaiterExpression.Type;

            getAwaiterGetResultCall = MakeInvocationExpression(node, awaiterExpression, WellKnownMemberNames.GetResult, ImmutableArray <BoundExpression> .Empty, diagnostics);
            if (getAwaiterGetResultCall.HasAnyErrors)
            {
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            if (getAwaiterGetResultCall.Kind != BoundKind.Call)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            getResultMethod = ((BoundCall)getAwaiterGetResultCall).Method;
            if (getResultMethod.IsExtensionMethod)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            if (HasOptionalOrVariableParameters(getResultMethod) || getResultMethod.IsConditional)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            // The lack of a GetResult method will be reported by ValidateGetResult().
            return(true);
        }
Beispiel #52
0
 internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, CSharpSyntaxNode syntax)
 {
     diagnostics.Add(new CSDiagnostic(info, syntax.Location));
 }
Beispiel #53
0
 internal void ReportBadAwaitDiagnostics(SyntaxNode node, Location location, DiagnosticBag diagnostics, ref bool hasErrors)
 {
     hasErrors |= ReportBadAwaitWithoutAsync(location, diagnostics);
     hasErrors |= ReportBadAwaitContext(node, location, diagnostics);
 }
Beispiel #54
0
        internal BoundAwaitableInfo BindAwaitInfo(BoundAwaitableValuePlaceholder placeholder, SyntaxNode node, DiagnosticBag diagnostics, ref bool hasErrors, BoundExpression expressionOpt = null)
        {
            bool hasGetAwaitableErrors = !GetAwaitableExpressionInfo(
                expressionOpt ?? placeholder,
                placeholder,
                out bool isDynamic,
                out BoundExpression getAwaiter,
                out PropertySymbol isCompleted,
                out MethodSymbol getResult,
                getAwaiterGetResultCall: out _,
                node,
                diagnostics);

            hasErrors |= hasGetAwaitableErrors;

            return(new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, hasErrors: hasGetAwaitableErrors)
            {
                WasCompilerGenerated = true
            });
        }
Beispiel #55
0
        /// <summary>
        /// Finds the GetAwaiter method of an awaitable expression.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An awaitable expression t has an accessible instance or extension method called GetAwaiter with no
        /// parameters and no type parameters, and a return type A that meets the additional requirements for an
        /// Awaiter.
        /// NOTE: this is an error in the spec.  An extension method of the form
        /// Awaiter&lt;T&gt; GetAwaiter&lt;T&gt;(this Task&lt;T&gt;) may be used.
        /// </remarks>
        private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics, out BoundExpression getAwaiterCall)
        {
            if (expression.Type.IsVoidType())
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArgVoidCall, node);
                getAwaiterCall = null;
                return(false);
            }

            getAwaiterCall = MakeInvocationExpression(node, expression, WellKnownMemberNames.GetAwaiter, ImmutableArray <BoundExpression> .Empty, diagnostics);
            if (getAwaiterCall.HasAnyErrors) // && !expression.HasAnyErrors?
            {
                getAwaiterCall = null;
                return(false);
            }

            if (getAwaiterCall.Kind != BoundKind.Call)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
                getAwaiterCall = null;
                return(false);
            }

            var getAwaiterMethod = ((BoundCall)getAwaiterCall).Method;

            if (getAwaiterMethod is ErrorMethodSymbol ||
                HasOptionalOrVariableParameters(getAwaiterMethod) || // We might have been able to resolve a GetAwaiter overload with optional parameters, so check for that here
                getAwaiterMethod.ReturnsVoid)                        // If GetAwaiter returns void, don't bother checking that it returns an Awaiter.
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
                getAwaiterCall = null;
                return(false);
            }

            return(true);
        }
Beispiel #56
0
        /// <summary>
        /// Checks that the Awaiter implements System.Runtime.CompilerServices.INotifyCompletion.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A implements the interface System.Runtime.CompilerServices.INotifyCompletion.
        /// </remarks>
        private bool AwaiterImplementsINotifyCompletion(TypeSymbol awaiterType, SyntaxNode node, DiagnosticBag diagnostics)
        {
            var INotifyCompletion = GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion, diagnostics, node);
            HashSet <DiagnosticInfo> useSiteDiagnostics = null;

            var conversion = this.Conversions.ClassifyImplicitConversionFromType(awaiterType, INotifyCompletion, ref useSiteDiagnostics);

            if (!conversion.IsImplicit)
            {
                diagnostics.Add(node, useSiteDiagnostics);
                Error(diagnostics, ErrorCode.ERR_DoesntImplementAwaitInterface, node, awaiterType, INotifyCompletion);
                return(false);
            }

            Debug.Assert(conversion.IsValid);
            return(true);
        }
Beispiel #57
0
        private BoundAwaitExpression BindAwait(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics)
        {
            bool hasErrors   = false;
            var  placeholder = new BoundAwaitableValuePlaceholder(expression.Syntax, GetValEscape(expression, LocalScopeDepth), expression.Type);

            ReportBadAwaitDiagnostics(node, node.Location, diagnostics, ref hasErrors);
            var info = BindAwaitInfo(placeholder, node, diagnostics, ref hasErrors, expressionOpt: expression);

            // Spec 7.7.7.2:
            // The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Thus,
            // if the return type of GetResult is void, the await-expression is classified as nothing. If it has a
            // non-void return type T, the await-expression is classified as a value of type T.
            TypeSymbol awaitExpressionType = info.GetResult?.ReturnType ?? (hasErrors ? CreateErrorType() : Compilation.DynamicType);

            return(new BoundAwaitExpression(node, expression, info, awaitExpressionType, hasErrors));
        }
Beispiel #58
0
        /// <summary>
        /// Finds the IsCompleted property of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible, readable instance property IsCompleted of type bool.
        /// </remarks>
        private bool GetIsCompletedProperty(TypeSymbol awaiterType, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out PropertySymbol isCompletedProperty)
        {
            var receiver  = new BoundLiteral(node, ConstantValue.Null, awaiterType);
            var name      = WellKnownMemberNames.IsCompleted;
            var qualified = BindInstanceMemberAccess(node, node, receiver, name, 0, default(SeparatedSyntaxList <TypeSyntax>), default(ImmutableArray <TypeWithAnnotations>), invoked: false, indexed: false, diagnostics);

            if (qualified.HasAnyErrors)
            {
                isCompletedProperty = null;
                return(false);
            }

            if (qualified.Kind != BoundKind.PropertyAccess)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.IsCompleted);
                isCompletedProperty = null;
                return(false);
            }

            isCompletedProperty = ((BoundPropertyAccess)qualified).PropertySymbol;
            if (isCompletedProperty.IsWriteOnly)
            {
                Error(diagnostics, ErrorCode.ERR_PropertyLacksGet, node, isCompletedProperty);
                isCompletedProperty = null;
                return(false);
            }

            if (isCompletedProperty.Type.SpecialType != SpecialType.System_Boolean)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
                isCompletedProperty = null;
                return(false);
            }

            return(true);
        }
Beispiel #59
0
        private BoundExpression BindAwait(AwaitExpressionSyntax node, DiagnosticBag diagnostics)
        {
            BoundExpression expression = BindRValueWithoutTargetType(node.Expression, diagnostics);

            return(BindAwait(expression, node, diagnostics));
        }
Beispiel #60
0
        /// <summary>
        /// Validates the awaited expression, returning true if no errors are found.
        /// </summary>
        private static bool ValidateAwaitedExpression(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics)
        {
            if (expression.HasAnyErrors)
            {
                // The appropriate diagnostics have already been reported.
                return(false);
            }

            if ((object)expression.Type == null)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArgIntrinsic, node, expression.Display);
                return(false);
            }

            return(true);
        }