public override bool Equals(Symbol other, TypeCompareKind compareKind)
        {
            if (other == (object)this)
            {
                return(true);
            }

            if (!(other is LocalSymbol otherLocal))
            {
                return(false);
            }

            SourceLocalSymbol?otherSource = otherLocal switch
            {
                UpdatedContainingSymbolAndNullableAnnotationLocal updated => updated._underlyingLocal,
                SourceLocalSymbol source => source,
                             _ => null
            };

            if (otherSource is null || !_underlyingLocal.Equals(otherSource, compareKind))
            {
                return(false);
            }

            var ignoreNullable = (compareKind & TypeCompareKind.AllNullableIgnoreOptions) != 0;

            return(ignoreNullable ||
                   (TypeWithAnnotations.Equals(otherLocal.TypeWithAnnotations, compareKind) &&
                    ContainingSymbol.Equals(otherLocal.ContainingSymbol, compareKind)));
        }
Пример #2
0
 internal UpdatedContainingSymbolAndNullableAnnotationLocal(
     SourceLocalSymbol underlyingLocal,
     Symbol updatedContainingSymbol,
     TypeWithAnnotations updatedType
     ) : this(underlyingLocal, updatedContainingSymbol, updatedType, assertContaining : true)
 {
 }
Пример #3
0
 private UpdatedContainingSymbolAndNullableAnnotationLocal(SourceLocalSymbol underlyingLocal, Symbol updatedContainingSymbol, TypeWithAnnotations updatedType, bool assertContaining)
 {
     RoslynDebug.Assert(underlyingLocal is object);
     RoslynDebug.Assert(updatedContainingSymbol is object);
     Debug.Assert(!assertContaining || updatedContainingSymbol.Equals(underlyingLocal.ContainingSymbol, TypeCompareKind.AllNullableIgnoreOptions));
     ContainingSymbol    = updatedContainingSymbol;
     TypeWithAnnotations = updatedType;
     _underlyingLocal    = underlyingLocal;
 }
Пример #4
0
 /// <summary>
 /// Creates a new <see cref="UpdatedContainingSymbolAndNullableAnnotationLocal"/> for testing purposes,
 /// which does not verify that the containing symbol matches the original containing symbol.
 /// </summary>
 internal static UpdatedContainingSymbolAndNullableAnnotationLocal CreateForTest(
     SourceLocalSymbol underlyingLocal,
     Symbol updatedContainingSymbol,
     TypeWithAnnotations updatedType
     )
 {
     return(new UpdatedContainingSymbolAndNullableAnnotationLocal(
                underlyingLocal,
                updatedContainingSymbol,
                updatedType,
                assertContaining: false
                ));
 }
Пример #5
0
        private bool IsValidFixedVariableInitializer(TypeSymbol declType, SourceLocalSymbol localSymbol, ref BoundExpression initializerOpt, DiagnosticBag diagnostics)
        {
            Debug.Assert(!ReferenceEquals(declType, null));
            Debug.Assert(declType.IsPointerType());

            if (ReferenceEquals(initializerOpt, null))
            {
                return false;
            }

            TypeSymbol initializerType = initializerOpt.Type;
            CSharpSyntaxNode initializerSyntax = initializerOpt.Syntax;

            if (ReferenceEquals(initializerType, null))
            {
                // Dev10 just reports the assignment conversion error (which must occur, unless the initializer is a null literal).
                initializerOpt = GenerateConversionForAssignment(declType, initializerOpt, diagnostics);
                if (!initializerOpt.HasAnyErrors)
                {
                    Debug.Assert(initializerOpt.Kind == BoundKind.Conversion && ((BoundConversion)initializerOpt).Operand.IsLiteralNull(),
                        "All other typeless expressions should have conversion errors");
                    // CONSIDER: this is a very confusing error message, but it's what Dev10 reports.
                    Error(diagnostics, ErrorCode.ERR_FixedNotNeeded, initializerSyntax);
                }
            }
            else if (initializerType.SpecialType == SpecialType.System_String)
            {
                // See ExpressionBinder::bindPtrToString

                TypeSymbol elementType = this.GetSpecialType(SpecialType.System_Char, diagnostics, initializerSyntax);
                Debug.Assert(!elementType.IsManagedType);

                initializerOpt = GetFixedLocalCollectionInitializer(initializerOpt, elementType, declType, false, diagnostics);

                // The string case is special - we'll pin a synthesized string temp, rather than the pointer local.
                localSymbol.SetSpecificallyNotPinned();

                // UNDONE: ExpressionBinder::CheckFieldUse (something about MarshalByRef)
            }
            else if (initializerType.IsArray())
            {
                // See ExpressionBinder::BindPtrToArray (though most of that functionality is now in LocalRewriter).

                var arrayType = (ArrayTypeSymbol)initializerType;
                TypeSymbol elementType = arrayType.ElementType;

                bool hasErrors = false;
                if (elementType.IsManagedType)
                {
                    Error(diagnostics, ErrorCode.ERR_ManagedAddr, initializerSyntax, elementType);
                    hasErrors = true;
                }

                initializerOpt = GetFixedLocalCollectionInitializer(initializerOpt, elementType, declType, hasErrors, diagnostics);
            }
            else
            {
                if (!initializerOpt.HasAnyErrors)
                {
                    switch (initializerOpt.Kind)
                    {
                        case BoundKind.AddressOfOperator:
                            // OK
                            break;
                        case BoundKind.Conversion:
                            // The following assertion would not be correct because there might be an implicit conversion after (above) the explicit one.
                            //Debug.Assert(((BoundConversion)initializerOpt).ExplicitCastInCode, "The assignment conversion hasn't been applied yet, so this must be from source.");

                            // NOTE: Dev10 specifically doesn't report this error for the array or string cases.
                            Error(diagnostics, ErrorCode.ERR_BadCastInFixed, initializerSyntax);
                            break;
                        case BoundKind.FieldAccess:
                            var fa = (BoundFieldAccess)initializerOpt;
                            if (!fa.FieldSymbol.IsFixed)
                            {
                                Error(diagnostics, ErrorCode.ERR_FixedNotNeeded, initializerSyntax);
                            }
                            break;
                        default:
                            // CONSIDER: this is a very confusing error message, but it's what Dev10 reports.
                            Error(diagnostics, ErrorCode.ERR_FixedNotNeeded, initializerSyntax);
                            break;
                    }
                }

                initializerOpt = GenerateConversionForAssignment(declType, initializerOpt, diagnostics);
            }

            return true;
        }
Пример #6
0
        protected BoundLocalDeclaration BindVariableDeclaration(
            SourceLocalSymbol localSymbol,
            LocalDeclarationKind kind,
            bool isVar,
            VariableDeclaratorSyntax declarator,
            TypeSyntax typeSyntax,
            TypeSymbol declTypeOpt,
            AliasSymbol aliasOpt,
            DiagnosticBag diagnostics,
            CSharpSyntaxNode associatedSyntaxNode = null)
        {
            Debug.Assert(declarator != null);
            Debug.Assert((object)declTypeOpt != null || isVar);
            Debug.Assert(typeSyntax != null);

            var localDiagnostics = DiagnosticBag.GetInstance();
            // if we are not given desired syntax, we use declarator
            associatedSyntaxNode = associatedSyntaxNode ?? declarator;

            bool hasErrors = false;

            BoundExpression initializerOpt;

            // Check for variable declaration errors.
            hasErrors |= this.ValidateDeclarationNameConflictsInScope(localSymbol, localDiagnostics);

            EqualsValueClauseSyntax equalsValueClauseSyntax = declarator.Initializer;
            if (isVar)
            {
                aliasOpt = null;

                var binder = new ImplicitlyTypedLocalBinder(this, localSymbol);
                initializerOpt = binder.BindInferredVariableInitializer(localDiagnostics, equalsValueClauseSyntax, declarator);

                // If we got a good result then swap the inferred type for the "var" 
                if ((object)initializerOpt?.Type != null)
                {
                    declTypeOpt = initializerOpt.Type;

                    if (declTypeOpt.SpecialType == SpecialType.System_Void)
                    {
                        Error(localDiagnostics, ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, declarator, declTypeOpt);
                        declTypeOpt = CreateErrorType("var");
                        hasErrors = true;
                    }

                    if (!declTypeOpt.IsErrorType())
                    {
                        if (declTypeOpt.IsStatic)
                        {
                            Error(localDiagnostics, ErrorCode.ERR_VarDeclIsStaticClass, typeSyntax, initializerOpt.Type);
                            hasErrors = true;
                        }
                    }
                }
                else
                {
                    declTypeOpt = CreateErrorType("var");
                    hasErrors = true;
                }
            }
            else
            {
                if (ReferenceEquals(equalsValueClauseSyntax, null))
                {
                    initializerOpt = null;
                }
                else
                {
                    // Basically inlined BindVariableInitializer, but with conversion optional.
                    initializerOpt = BindPossibleArrayInitializer(equalsValueClauseSyntax.Value, declTypeOpt, localDiagnostics);
                    if (kind != LocalDeclarationKind.FixedVariable)
                    {
                        // If this is for a fixed statement, we'll do our own conversion since there are some special cases.
                        initializerOpt = GenerateConversionForAssignment(declTypeOpt, initializerOpt, localDiagnostics);
                    }
                }
            }

            Debug.Assert((object)declTypeOpt != null);

            if (kind == LocalDeclarationKind.FixedVariable)
            {
                // NOTE: this is an error, but it won't prevent further binding.
                if (isVar)
                {
                    if (!hasErrors)
                    {
                        Error(localDiagnostics, ErrorCode.ERR_ImplicitlyTypedLocalCannotBeFixed, declarator);
                        hasErrors = true;
                    }
                }

                if (!declTypeOpt.IsPointerType())
                {
                    if (!hasErrors)
                    {
                        Error(localDiagnostics, ErrorCode.ERR_BadFixedInitType, declarator);
                        hasErrors = true;
                    }
                }
                else if (!IsValidFixedVariableInitializer(declTypeOpt, localSymbol, ref initializerOpt, localDiagnostics))
                {
                    hasErrors = true;
                }
            }

            if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method
                && ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync
                && declTypeOpt.IsRestrictedType())
            {
                Error(localDiagnostics, ErrorCode.ERR_BadSpecialByRefLocal, typeSyntax, declTypeOpt);
                hasErrors = true;
            }

            DeclareLocalVariable(
                localSymbol,
                declarator.Identifier,
                declTypeOpt);

            Debug.Assert((object)localSymbol != null);

            ImmutableArray<BoundExpression> arguments = BindDeclaratorArguments(declarator, localDiagnostics);

            if (kind == LocalDeclarationKind.FixedVariable || kind == LocalDeclarationKind.UsingVariable)
            {
                // CONSIDER: The error message is "you must provide an initializer in a fixed 
                // CONSIDER: or using declaration". The error message could be targetted to 
                // CONSIDER: the actual situation. "you must provide an initializer in a 
                // CONSIDER: 'fixed' declaration."

                if (initializerOpt == null)
                {
                    Error(localDiagnostics, ErrorCode.ERR_FixedMustInit, declarator);
                    hasErrors = true;
                }
            }
            else if (kind == LocalDeclarationKind.Constant && initializerOpt != null && !localDiagnostics.HasAnyResolvedErrors())
            {
                var constantValueDiagnostics = localSymbol.GetConstantValueDiagnostics(initializerOpt);
                foreach (var diagnostic in constantValueDiagnostics)
                {
                    diagnostics.Add(diagnostic);
                    hasErrors = true;
                }
            }

            diagnostics.AddRangeAndFree(localDiagnostics);
            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt);
            return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors);
        }
Пример #7
0
        internal static void DeclareLocalVariable(
            SourceLocalSymbol symbol,
            SyntaxToken identifierToken,
            TypeSymbol type)
        {
            // In the original compiler this
            // method has many side effects; it sets the type
            // of the local symbol, it gives errors if the local
            // is a duplicate, it creates new symbols for lambda
            // expressions, puts stuff in caches, and so on.

            Debug.Assert((object)symbol != null);
            Debug.Assert(symbol.IdentifierToken == identifierToken);
            symbol.SetTypeSymbol(type);
            // UNDONE: Can we come up with a way to set the type of a local which does
            // UNDONE: not duplicate work and does not mutate the symbol?
        }