private void ComputeParameters()
        {
            if (_lazyParameters != null)
            {
                return;
            }

            SyntaxToken arglistToken;
            var         diagnostics = DiagnosticBag.GetInstance();

            var parameters = ParameterHelpers.MakeParameters(
                _binder,
                this,
                _syntax.ParameterList,
                arglistToken: out arglistToken,
                allowRefOrOut: true,
                allowThis: true,
                addRefReadOnlyModifier: false,
                diagnostics: diagnostics);

            var compilation = DeclaringCompilation;

            ParameterHelpers.EnsureIsReadOnlyAttributeExists(compilation, parameters, diagnostics, modifyCompilation: false);
            ParameterHelpers.EnsureNullableAttributeExists(compilation, this, parameters, diagnostics, modifyCompilation: false);
            // Note: we don't need to warn on annotations used in #nullable disable context for local functions, as this is handled in binding already

            var isVararg = arglistToken.Kind() == SyntaxKind.ArgListKeyword;

            if (isVararg)
            {
                diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation());
            }

            if (IsAsync)
            {
                SourceOrdinaryMethodSymbol.ReportAsyncParameterErrors(parameters, diagnostics, this.Locations[0]);
            }

            lock (_declarationDiagnostics)
            {
                if (_lazyParameters != null)
                {
                    diagnostics.Free();
                    return;
                }

                _declarationDiagnostics.AddRangeAndFree(diagnostics);
                _lazyIsVarArg   = isVararg;
                _lazyParameters = parameters;
            }
        }
        private void ComputeParameters()
        {
            if (_lazyParameters != null)
            {
                return;
            }

            SyntaxToken arglistToken;
            var         diagnostics = DiagnosticBag.GetInstance();

            var parameters = ParameterHelpers.MakeParameters(
                _binder,
                this,
                _syntax.ParameterList,
                arglistToken: out arglistToken,
                allowRefOrOut: true,
                allowThis: true,
                addRefReadOnlyModifier: false,
                diagnostics: diagnostics);

            ParameterHelpers.EnsureIsReadOnlyAttributeExists(parameters, diagnostics, modifyCompilationForRefReadOnly: false);

            var isVararg = arglistToken.Kind() == SyntaxKind.ArgListKeyword;

            if (isVararg)
            {
                diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation());
            }

            if (IsAsync)
            {
                SourceOrdinaryMethodSymbol.ReportAsyncParameterErrors(parameters, diagnostics, this.Locations[0]);
            }

            lock (_declarationDiagnostics)
            {
                if (_lazyParameters != null)
                {
                    diagnostics.Free();
                    return;
                }

                _declarationDiagnostics.AddRangeAndFree(diagnostics);
                _lazyIsVarArg   = isVararg;
                _lazyParameters = parameters;
            }
        }
Beispiel #3
0
        private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var resultType = (TypeSymbol)GetSpecialType(SpecialType.System_Boolean, diagnostics, node);
            var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
            AliasSymbol alias;
            TypeSymbol targetType;
            {
                // try binding as a type, but back off to binding as an expression if that does not work.
                var tempBag = DiagnosticBag.GetInstance();
                targetType = BindType(node.Right, tempBag, out alias);
                if (targetType?.IsErrorType() == true && tempBag.HasAnyResolvedErrors() &&
                    ((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching))
                {
                    // it did not bind as a type; try binding as a constant expression pattern
                    bool wasExpression;
                    var tempBag2 = DiagnosticBag.GetInstance();
                    var boundConstantPattern = BindConstantPattern(
                        node, operand, operand.Type, node.Right, node.Right.HasErrors, tempBag2, out wasExpression, wasSwitchCase: false);
                    if (wasExpression)
                    {
                        tempBag.Free();
                        diagnostics.AddRangeAndFree(tempBag2);
                        return new BoundIsPatternExpression(node, operand, boundConstantPattern, resultType);
                    }

                    tempBag2.Free();
                }

                diagnostics.AddRangeAndFree(tempBag);
            }

            var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
            var targetTypeKind = targetType.TypeKind;
            if (IsOperandErrors(node, operand, diagnostics) || IsOperatorErrors(node, operand.Type, typeExpression, diagnostics))
            {
                return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            // Is and As operator should have null ConstantValue as they are not constant expressions.
            // However we perform analysis of is/as expressions at bind time to detect if the expression 
            // will always evaluate to a constant to generate warnings (always true/false/null).
            // We also need this analysis result during rewrite to optimize away redundant isinst instructions.
            // We store the conversion from expression's operand type to target type to enable these
            // optimizations during is/as operator rewrite.

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;

            if (operand.ConstantValue == ConstantValue.Null ||
                operand.Kind == BoundKind.MethodGroup ||
                operand.Type.SpecialType == SpecialType.System_Void)
            {
                // warning for cases where the result is always false:
                // (a) "null is TYPE" OR operand evaluates to null 
                // (b) operand is a MethodGroup
                // (c) operand is of void type

                // NOTE:    Dev10 violates the SPEC for case (c) above and generates
                // NOTE:    an error ERR_NoExplicitBuiltinConv if the target type
                // NOTE:    is an open type. According to the specification, the result
                // NOTE:    is always false, but no compile time error occurs.
                // NOTE:    We follow the specification and generate WRN_IsAlwaysFalse
                // NOTE:    instead of an error.
                // NOTE:    See Test SyntaxBinderTests.TestIsOperatorWithTypeParameter

                Error(diagnostics, ErrorCode.WRN_IsAlwaysFalse, node, targetType);
                Conversion conv = Conversions.ClassifyConversionFromExpression(operand, targetType, ref useSiteDiagnostics);
                diagnostics.Add(node, useSiteDiagnostics);
                return new BoundIsOperator(node, operand, typeExpression, conv, resultType);
            }

            if (targetTypeKind == TypeKind.Dynamic)
            {
                // warning for dynamic target type
                Error(diagnostics, ErrorCode.WRN_IsDynamicIsConfusing,
                    node, node.OperatorToken.Text, targetType.Name,
                    GetSpecialType(SpecialType.System_Object, diagnostics, node).Name // a pretty way of getting the string "Object"
                    );
            }

            var operandType = operand.Type;
            Debug.Assert((object)operandType != null);
            if (operandType.TypeKind == TypeKind.Dynamic)
            {
                // if operand has a dynamic type, we do the same thing as though it were an object
                operandType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
            }

            Conversion conversion = Conversions.ClassifyConversion(operandType, targetType, ref useSiteDiagnostics);
            diagnostics.Add(node, useSiteDiagnostics);
            ReportIsOperatorConstantWarnings(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValue);
            return new BoundIsOperator(node, operand, typeExpression, conversion, resultType);
        }
Beispiel #4
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);
        }
Beispiel #5
0
        internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
        {
            Debug.Assert(_switchSyntax.Equals(node));

            if (IsPatternSwitch(node))
            {
                _isPatternSwitch = true;
                return PatternsEnabled
                    ? (BoundStatement)BindPatternSwitch(node, originalBinder, diagnostics)
                    : new BoundBlock(node, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray<BoundStatement>.Empty, true);
            }

            // Bind switch expression and set the switch governing type. If it isn't valid as a traditional
            // switch statement's controlling expression, try to bind it as a pattern-matching switch statement
            var localDiagnostics = DiagnosticBag.GetInstance();
            var boundSwitchExpression = BindSwitchExpressionAndGoverningType(node.Expression, originalBinder, localDiagnostics);
            if (localDiagnostics.HasAnyResolvedErrors() && PatternsEnabled)
            {
                _isPatternSwitch = true;
                return BindPatternSwitch(node, originalBinder, diagnostics);
            }
            _isPatternSwitch = false;
            diagnostics.AddRangeAndFree(localDiagnostics);

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

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

            return new BoundSwitchStatement(node, null, boundSwitchExpression, constantTargetOpt, 
                                            GetDeclaredLocalsForScope(node), 
                                            GetDeclaredLocalFunctionsForScope(node), boundSwitchSections, this.BreakLabel, null);
        }