Example #1
0
        /// <summary>
        /// Returns the type to be used as a field type; generates errors in case the type is not
        /// supported for anonymous type fields.
        /// </summary>
        private TypeSymbol GetAnonymousTypeFieldType(BoundExpression expression, CSharpSyntaxNode errorSyntax, DiagnosticBag diagnostics, ref bool hasError)
        {
            object     errorArg       = null;
            TypeSymbol expressionType = expression.Type;

            if (!expression.HasAnyErrors)
            {
                if (expression.HasExpressionType())
                {
                    if (expressionType.SpecialType == SpecialType.System_Void)
                    {
                        errorArg       = expressionType;
                        expressionType = CreateErrorType(SyntaxFacts.GetText(SyntaxKind.VoidKeyword));
                    }
                    else if (expressionType.IsUnsafe())
                    {
                        errorArg = expressionType;
                        // CONSIDER: we could use an explicit error type instead of the unsafe type.
                    }
                    else if (expressionType.IsRestrictedType())
                    {
                        errorArg = expressionType;
                    }
                }
                else
                {
                    if (expression.Kind == BoundKind.UnboundLambda)
                    {
                        errorArg = ((UnboundLambda)expression).MessageID.Localize();
                    }
                    else if (expression.Kind == BoundKind.MethodGroup)
                    {
                        errorArg = MessageID.IDS_MethodGroup.Localize();
                    }
                    else
                    {
                        Debug.Assert(expression.IsLiteralNull(), "How did we successfully bind an expression without a type?");
                        errorArg = MessageID.IDS_NULL.Localize();
                    }
                }
            }

            if ((object)expressionType == null)
            {
                expressionType = CreateErrorType("error");
            }

            if (errorArg != null)
            {
                hasError = true;
                Error(diagnostics, ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, errorSyntax, errorArg);
                // NOTE: ERR_QueryRangeVariableAssignedBadValue is being generated
                //       by query binding code and never reach this point
            }

            return(expressionType);
        }
Example #2
0
 protected override Conversion ClassifyNullConversionFromExpression(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     if (sourceExpression.Kind == BoundKind.Literal && sourceExpression.IsLiteralNull())
     {
         Conversion result;
         if (ClassifyVoNullLiteralConversion(sourceExpression, destination, out result) != ConversionKind.NoConversion)
         {
             return(result);
         }
     }
     return(Conversion.NoConversion);
 }
        private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right)
        {
            bool   isChecked, isLifted, requiresLifted;
            string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted);

            // Fix up the null value for a nullable comparison vs null
            if ((object)left.Type == null && left.IsLiteralNull())
            {
                left = _bound.Default(right.Type);
            }
            if ((object)right.Type == null && right.IsLiteralNull())
            {
                right = _bound.Default(left.Type);
            }


            // Enums are handled as per their promoted underlying type
            switch (opKind.OperandTypes())
            {
            case BinaryOperatorKind.EnumAndUnderlying:
            case BinaryOperatorKind.UnderlyingAndEnum:
            case BinaryOperatorKind.Enum:
            {
                var enumOperand  = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left;
                var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType());
                if (opKind.IsLifted())
                {
                    promotedType = _nullableType.Construct(promotedType);
                }

                var loweredLeft  = VisitAndPromoteEnumOperand(left, promotedType, isChecked);
                var loweredRight = VisitAndPromoteEnumOperand(right, promotedType, isChecked);

                var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight);
                return(Demote(result, type, isChecked));
            }

            default:
            {
                var loweredLeft  = Visit(left);
                var loweredRight = Visit(right);
                return(MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight));
            }
            }
        }
Example #4
0
        private static ConversionKind ClassifyNullLiteralConversion(BoundExpression source, TypeSymbol destination)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)destination != null);

            if (!source.IsLiteralNull())
            {
                return(ConversionKind.NoConversion);
            }

            // SPEC: An implicit conversion exists from the null literal to any nullable type.
            if (destination.IsNullableType())
            {
                // The spec defines a "null literal conversion" specifically as a conversion from
                // null to nullable type.
                return(ConversionKind.NullLiteral);
            }

            // SPEC: An implicit conversion exists from the null literal to any reference type.
            // SPEC: An implicit conversion exists from the null literal to type parameter T,
            // SPEC: provided T is known to be a reference type. [...] The conversion [is] classified
            // SPEC: as implicit reference conversion.

            if (destination.IsReferenceType)
            {
                return(ConversionKind.ImplicitReference);
            }

            // SPEC: The set of implicit conversions is extended to include...
            // SPEC: ... from the null literal to any pointer type.

            if (destination is PointerTypeSymbol)
            {
                return(ConversionKind.NullToPointer);
            }

            return(ConversionKind.NoConversion);
        }
        /// <summary>
        /// Returns the type to be used as a field type; generates errors in case the type is not
        /// supported for anonymous type fields.
        /// </summary>
        private TypeSymbol GetAnonymousTypeFieldType(BoundExpression expression, CSharpSyntaxNode errorSyntax, DiagnosticBag diagnostics, ref bool hasError)
        {
            object errorArg = null;
            TypeSymbol expressionType = expression.Type;

            if (!expression.HasAnyErrors)
            {
                if (expression.HasExpressionType())
                {
                    if (expressionType.SpecialType == SpecialType.System_Void)
                    {
                        errorArg = expressionType;
                        expressionType = CreateErrorType(SyntaxFacts.GetText(SyntaxKind.VoidKeyword));
                    }
                    else if (expressionType.IsUnsafe())
                    {
                        errorArg = expressionType;
                        // CONSIDER: we could use an explicit error type instead of the unsafe type.
                    }
                    else if (expressionType.IsRestrictedType())
                    {
                        errorArg = expressionType;
                    }
                }
                else
                {
                    if (expression.Kind == BoundKind.UnboundLambda)
                    {
                        errorArg = ((UnboundLambda)expression).MessageID.Localize();
                    }
                    else if (expression.Kind == BoundKind.MethodGroup)
                    {
                        errorArg = MessageID.IDS_MethodGroup.Localize();
                    }
                    else
                    {
                        Debug.Assert(expression.IsLiteralNull(), "How did we successfully bind an expression without a type?");
                        errorArg = MessageID.IDS_NULL.Localize();
                    }
                }
            }

            if ((object)expressionType == null)
            {
                expressionType = CreateErrorType("error");
            }

            if (errorArg != null)
            {
                hasError = true;
                Error(diagnostics, ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, errorSyntax, errorArg);
                // NOTE: ERR_QueryRangeVariableAssignedBadValue is being generated 
                //       by query binding code and never reach this point
            }

            return expressionType;
        }
        private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right)
        {
            bool isChecked, isLifted, requiresLifted;
            string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted);

            // Fix up the null value for a nullable comparison vs null
            if ((object)left.Type == null && left.IsLiteralNull())
            {
                left = _bound.Default(right.Type);
            }
            if ((object)right.Type == null && right.IsLiteralNull())
            {
                right = _bound.Default(left.Type);
            }

            var loweredLeft = Visit(left);
            var loweredRight = Visit(right);

            // Enums are handled as per their promoted underlying type
            switch (opKind.OperandTypes())
            {
                case BinaryOperatorKind.Enum:
                case BinaryOperatorKind.EnumAndUnderlying:
                case BinaryOperatorKind.UnderlyingAndEnum:
                    {
                        var enumOperand = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left;
                        var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType());
                        if (opKind.IsLifted())
                        {
                            promotedType = _nullableType.Construct(promotedType);
                        }

                        loweredLeft = PromoteEnumOperand(left, loweredLeft, promotedType, isChecked);
                        loweredRight = PromoteEnumOperand(right, loweredRight, promotedType, isChecked);

                        var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight);
                        return Demote(result, type, isChecked);
                    }
                default:
                    return MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight);
            }
        }
Example #7
0
        private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics,
            BoundExpression left, BoundExpression right, ref int compoundStringLength)
        {
            BinaryOperatorKind kind = SyntaxKindToBinaryOperatorKind(node.Kind());

            // If either operand is bad, don't try to do binary operator overload resolution; that will just
            // make cascading errors.  

            if (left.HasAnyErrors || right.HasAnyErrors)
            {
                // NOTE: no user-defined conversion candidates
                return new BoundBinaryOperator(node, kind, left, right, ConstantValue.NotAvailable, null, LookupResultKind.Empty, GetBinaryOperatorErrorType(kind, diagnostics, node), true);
            }

            TypeSymbol leftType = left.Type;
            TypeSymbol rightType = right.Type;

            if ((object)leftType != null && leftType.IsDynamic() || (object)rightType != null && rightType.IsDynamic())
            {
                return BindDynamicBinaryOperator(node, kind, left, right, diagnostics);
            }

            // SPEC OMISSION: The C# 2.0 spec had a line in it that noted that the expressions "null == null"
            // SPEC OMISSION: and "null != null" were to be automatically treated as the appropriate constant;
            // SPEC OMISSION: overload resolution was to be skipped.  That's because a strict reading
            // SPEC OMISSION: of the overload resolution spec shows that overload resolution would give an
            // SPEC OMISSION: ambiguity error for this case; the expression is ambiguous between the int?,
            // SPEC OMISSION: bool? and string versions of equality.  This line was accidentally edited
            // SPEC OMISSION: out of the C# 3 specification; we should re-insert it. 

            bool leftNull = left.IsLiteralNull();
            bool rightNull = right.IsLiteralNull();
            bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;

            if (isEquality && leftNull && rightNull)
            {
                return new BoundLiteral(node, ConstantValue.Create(kind == BinaryOperatorKind.Equal), GetSpecialType(SpecialType.System_Boolean, diagnostics, node));
            }

            // SPEC: For an operation of one of the forms x == null, null == x, x != null, null != x,
            // SPEC: where x is an expression of nullable type, if operator overload resolution
            // SPEC: fails to find an applicable operator, the result is instead computed from
            // SPEC: the HasValue property of x.

            // Note that the spec says "fails to find an applicable operator", not "fails to
            // find a unique best applicable operator." For example:
            // struct X { 
            //   public static bool operator ==(X? x, double? y) {...}
            //   public static bool operator ==(X? x, decimal? y) {...}
            //
            // The comparison "x == null" should produce an ambiguity error rather
            // that being bound as !x.HasValue. 
            //

            LookupResultKind resultKind;
            ImmutableArray<MethodSymbol> originalUserDefinedOperators;
            var best = this.BinaryOperatorOverloadResolution(kind, left, right, node, diagnostics, out resultKind, out originalUserDefinedOperators);

            // However, as an implementation detail, we never "fail to find an applicable 
            // operator" during overload resolution if we have x == null, etc. We always
            // find at least the reference conversion object == object; the overload resolution
            // code does not reject that.  Therefore what we should do is only bind 
            // "x == null" as a nullable-to-null comparison if overload resolution chooses
            // the reference conversion.

            BoundExpression resultLeft = left;
            BoundExpression resultRight = right;
            MethodSymbol resultMethod = null;
            ConstantValue resultConstant = null;
            BinaryOperatorKind resultOperatorKind;
            TypeSymbol resultType;
            bool hasErrors;

            if (!best.HasValue)
            {
                resultOperatorKind = kind;
                resultType = CreateErrorType();
                hasErrors = true;
            }
            else
            {
                var signature = best.Signature;

                bool isObjectEquality = signature.Kind == BinaryOperatorKind.ObjectEqual || signature.Kind == BinaryOperatorKind.ObjectNotEqual;

                bool isNullableEquality = (object)signature.Method == null &&
                    (signature.Kind.Operator() == BinaryOperatorKind.Equal || signature.Kind.Operator() == BinaryOperatorKind.NotEqual) &&
                    (leftNull && (object)rightType != null && rightType.IsNullableType() ||
                    rightNull && (object)leftType != null && leftType.IsNullableType());

                if (isNullableEquality)
                {
                    resultOperatorKind = kind | BinaryOperatorKind.NullableNull;
                    resultType = GetSpecialType(SpecialType.System_Boolean, diagnostics, node);
                    hasErrors = false;
                }
                else
                {
                    resultOperatorKind = signature.Kind;
                    resultType = signature.ReturnType;
                    resultMethod = signature.Method;
                    resultLeft = CreateConversion(left, best.LeftConversion, signature.LeftType, diagnostics);
                    resultRight = CreateConversion(right, best.RightConversion, signature.RightType, diagnostics);
                    resultConstant = FoldBinaryOperator(node, resultOperatorKind, resultLeft, resultRight, resultType.SpecialType, diagnostics, ref compoundStringLength);
                    HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                    hasErrors = isObjectEquality && !BuiltInOperators.IsValidObjectEquality(Conversions, leftType, leftNull, rightType, rightNull, ref useSiteDiagnostics);
                    diagnostics.Add(node, useSiteDiagnostics);
                }
            }

            if (hasErrors)
            {
                ReportBinaryOperatorError(node, diagnostics, node.OperatorToken, left, right, resultKind);
                resultOperatorKind &= ~BinaryOperatorKind.TypeMask;
            }

            switch (node.Kind())
            {
                case SyntaxKind.EqualsExpression:
                case SyntaxKind.NotEqualsExpression:
                case SyntaxKind.LessThanExpression:
                case SyntaxKind.LessThanOrEqualExpression:
                case SyntaxKind.GreaterThanExpression:
                case SyntaxKind.GreaterThanOrEqualExpression:
                    break;
                default:
                    if (leftType.IsVoidPointer() || rightType.IsVoidPointer())
                    {
                        // CONSIDER: dev10 cascades this, but roslyn doesn't have to.
                        Error(diagnostics, ErrorCode.ERR_VoidError, node);
                        hasErrors = true;
                    }
                    break;
            }

            hasErrors = hasErrors || resultConstant != null && resultConstant.IsBad;

            return new BoundBinaryOperator(
                node,
                resultOperatorKind.WithOverflowChecksIfApplicable(CheckOverflowAtRuntime),
                resultLeft,
                resultRight,
                resultConstant,
                resultMethod,
                resultKind,
                originalUserDefinedOperators,
                resultType,
                hasErrors);
        }
Example #8
0
        private static bool IsLegalDynamicOperand(BoundExpression operand)
        {
            Debug.Assert(operand != null);

            TypeSymbol type = operand.Type;

            // Literal null is a legal operand to a dynamic operation. The other typeless expressions --
            // method groups, lambdas, anonymous methods -- are not.

            // If the operand is of a class, interface, delegate, array, struct, enum, nullable 
            // or type param types, it's legal to use in a dynamic expression. In short, the type
            // must be one that is convertible to object.

            if ((object)type == null)
            {
                return operand.IsLiteralNull();
            }

            // Pointer types and very special types are not convertible to object.

            return !type.IsPointerType() && !type.IsRestrictedType() && type.SpecialType != SpecialType.System_Void;
        }
        private BoundExpression RewriteNullableNullEquality(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            TypeSymbol returnType)
        {
            // This handles the case where we have a nullable user-defined struct type compared against null, eg:
            //
            // struct S {} ... S? s = whatever; if (s != null)
            //
            // If S does not define an overloaded != operator then this is lowered to s.HasValue.
            //
            // If the type already has a user-defined or built-in operator then comparing to null is
            // treated as a lifted equality operator.

            Debug.Assert(loweredLeft != null);
            Debug.Assert(loweredRight != null);
            Debug.Assert((object)returnType != null);
            Debug.Assert(returnType.SpecialType == SpecialType.System_Boolean);
            Debug.Assert(loweredLeft.IsLiteralNull() != loweredRight.IsLiteralNull());

            BoundExpression nullable = loweredRight.IsLiteralNull() ? loweredLeft : loweredRight;

            // If the other side is known to always be null then we can simply generate true or false, as appropriate.

            if (NullableNeverHasValue(nullable))
            {
                return MakeLiteral(syntax, ConstantValue.Create(kind == BinaryOperatorKind.NullableNullEqual), returnType);
            }

            BoundExpression nonNullValue = NullableAlwaysHasValue(nullable);
            if (nonNullValue != null)
            {
                // We have something like "if (new int?(M()) != null)". We can optimize this to
                // evaluate M() for its side effects and then result in true or false, as appropriate.

                // TODO: If the expression has no side effects then it can be optimized away here as well.

                return new BoundSequence(
                    syntax: syntax,
                    locals: ImmutableArray<LocalSymbol>.Empty,
                    sideEffects: ImmutableArray.Create<BoundExpression>(nonNullValue),
                    value: MakeBooleanConstant(syntax, kind == BinaryOperatorKind.NullableNullNotEqual),
                    type: returnType);
            }

            // arr?.Length == null
            var conditionalAccess = nullable as BoundLoweredConditionalAccess;
            if (conditionalAccess != null &&
                (conditionalAccess.WhenNullOpt == null || conditionalAccess.WhenNullOpt.IsDefaultValue()))
            {
                BoundExpression whenNotNull = RewriteNullableNullEquality(
                    syntax,
                    kind,
                    conditionalAccess.WhenNotNull,
                    loweredLeft.IsLiteralNull() ? loweredLeft : loweredRight,
                    returnType);

                var whenNull = kind == BinaryOperatorKind.NullableNullEqual ? MakeBooleanConstant(syntax, true) : null;

                return conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.HasValueMethodOpt, whenNotNull, whenNull, conditionalAccess.Id, whenNotNull.Type);
            }

            BoundExpression call = MakeNullableHasValue(syntax, nullable);
            BoundExpression result = kind == BinaryOperatorKind.NullableNullNotEqual ?
                call :
                new BoundUnaryOperator(syntax, UnaryOperatorKind.BoolLogicalNegation, call, ConstantValue.NotAvailable, null, LookupResultKind.Viable, returnType);

            return result;
        }
Example #10
0
        protected void GenerateImplicitConversionError(DiagnosticBag diagnostics, CSharpSyntaxNode syntax,
            Conversion conversion, BoundExpression expression, TypeSymbol targetType)
        {
            Debug.Assert(expression != null);
            Debug.Assert((object)targetType != null);

            if (targetType.TypeKind == TypeKind.Error)
            {
                return;
            }

            if (expression.Kind == BoundKind.BadExpression)
            {
                return;
            }

            if (expression.Kind == BoundKind.UnboundLambda)
            {
                GenerateAnonymousFunctionConversionError(diagnostics, syntax, (UnboundLambda)expression, targetType);
                return;
            }

            var sourceType = expression.Type;
            if ((object)sourceType != null)
            {
                GenerateImplicitConversionError(diagnostics, this.Compilation, syntax, conversion, sourceType, targetType, expression.ConstantValue);
                return;
            }

            if (expression.IsLiteralNull())
            {
                if (targetType.TypeKind == TypeKind.TypeParameter)
                {
                    Error(diagnostics, ErrorCode.ERR_TypeVarCantBeNull, syntax, targetType);
                    return;
                }
                if (targetType.IsValueType)
                {
                    Error(diagnostics, ErrorCode.ERR_ValueCantBeNull, syntax, targetType);
                    return;
                }
            }

            if (expression.Kind == BoundKind.MethodGroup)
            {
                var methodGroup = (BoundMethodGroup)expression;
                if (!Conversions.ReportDelegateMethodGroupDiagnostics(this, methodGroup, targetType, diagnostics))
                {
                    var nodeForSquiggle = syntax;
                    while (nodeForSquiggle.Kind() == SyntaxKind.ParenthesizedExpression)
                    {
                        nodeForSquiggle = ((ParenthesizedExpressionSyntax)nodeForSquiggle).Expression;
                    }

                    if (nodeForSquiggle.Kind() == SyntaxKind.SimpleMemberAccessExpression || nodeForSquiggle.Kind() == SyntaxKind.PointerMemberAccessExpression)
                    {
                        nodeForSquiggle = ((MemberAccessExpressionSyntax)nodeForSquiggle).Name;
                    }

                    var location = nodeForSquiggle.Location;

                    if (ReportDelegateInvokeUseSiteDiagnostic(diagnostics, targetType, location))
                    {
                        return;
                    }

                    Error(diagnostics,
                        targetType.IsDelegateType() ? ErrorCode.ERR_MethDelegateMismatch : ErrorCode.ERR_MethGrpToNonDel,
                        location, methodGroup.Name, targetType);
                }

                return;
            }

            Debug.Assert(expression.HasAnyErrors && expression.Kind != BoundKind.UnboundLambda, "Missing a case in implicit conversion error reporting");
        }
Example #11
0
        protected void GenerateImplicitConversionError(
            DiagnosticBag diagnostics, 
            CSharpSyntaxNode syntax,
            Conversion conversion, 
            BoundExpression operand, 
            TypeSymbol targetType)
        {
            Debug.Assert(operand != null);
            Debug.Assert((object)targetType != null);

            if (targetType.TypeKind == TypeKind.Error)
            {
                return;
            }

            if (operand.Kind == BoundKind.BadExpression)
            {
                return;
            }

            if (operand.Kind == BoundKind.UnboundLambda)
            {
                GenerateAnonymousFunctionConversionError(diagnostics, syntax, (UnboundLambda)operand, targetType);
                return;
            }

            if (operand.Kind == BoundKind.TupleLiteral)
            {
                var tuple = (BoundTupleLiteral)operand;
                var targetElementTypes = default(ImmutableArray<TypeSymbol>);

                // If target is a tuple or compatible type with the same number of elements,
                // report errors for tuple arguments that failed to convert, which would be more useful.
                if (targetType.TryGetElementTypesIfTupleOrCompatible(out targetElementTypes) && 
                    targetElementTypes.Length == tuple.Arguments.Length)
                {
                    GenerateImplicitConversionErrorsForTupleLiteralArguments(diagnostics, tuple.Arguments, targetElementTypes);
                    return;
                }

                // target is not compatible with source and source does not have a type
                if ((object)tuple.Type == null)
                {
                    Error(diagnostics, ErrorCode.ERR_ConversionNotTupleCompatible, syntax, tuple.Arguments.Length, targetType);
                    return;
                }

                // Otherwise it is just a regular conversion failure from T1 to T2.
            }

            var sourceType = operand.Type;
            if ((object)sourceType != null)
            {
                GenerateImplicitConversionError(diagnostics, this.Compilation, syntax, conversion, sourceType, targetType, operand.ConstantValue);
                return;
            }
            
            if (operand.IsLiteralNull())
            {
                if (targetType.TypeKind == TypeKind.TypeParameter)
                {
                    Error(diagnostics, ErrorCode.ERR_TypeVarCantBeNull, syntax, targetType);
                    return;
                }
                if (targetType.IsValueType)
                {
                    Error(diagnostics, ErrorCode.ERR_ValueCantBeNull, syntax, targetType);
                    return;
                }
            }

            if (operand.Kind == BoundKind.MethodGroup)
            {
                var methodGroup = (BoundMethodGroup)operand;
                if (!Conversions.ReportDelegateMethodGroupDiagnostics(this, methodGroup, targetType, diagnostics))
                {
                    var nodeForSquiggle = syntax;
                    while (nodeForSquiggle.Kind() == SyntaxKind.ParenthesizedExpression)
                    {
                        nodeForSquiggle = ((ParenthesizedExpressionSyntax)nodeForSquiggle).Expression;
                    }

                    if (nodeForSquiggle.Kind() == SyntaxKind.SimpleMemberAccessExpression || nodeForSquiggle.Kind() == SyntaxKind.PointerMemberAccessExpression)
                    {
                        nodeForSquiggle = ((MemberAccessExpressionSyntax)nodeForSquiggle).Name;
                    }

                    var location = nodeForSquiggle.Location;

                    if (ReportDelegateInvokeUseSiteDiagnostic(diagnostics, targetType, location))
                    {
                        return;
                    }

                    Error(diagnostics,
                        targetType.IsDelegateType() ? ErrorCode.ERR_MethDelegateMismatch : ErrorCode.ERR_MethGrpToNonDel,
                        location, methodGroup.Name, targetType);
                }

                return;
            }

            Debug.Assert(operand.HasAnyErrors && operand.Kind != BoundKind.UnboundLambda, "Missing a case in implicit conversion error reporting");
        }
Example #12
0
        public BoundExpression Convert(TypeSymbol type, BoundExpression arg, Conversion conversion, bool isChecked = false)
        {
            // NOTE: We can see user-defined conversions at this point because there are places in the bound tree where
            // the binder stashes Conversion objects for later consumption (e.g. foreach, nullable, increment).
            if ((object)conversion.Method != null && conversion.Method.Parameters[0].Type != arg.Type)
            {
                arg = Convert(conversion.Method.Parameters[0].Type, arg);
            }

            if (conversion.Kind == ConversionKind.ImplicitReference && arg.IsLiteralNull())
            {
                return Null(type);
            }

            return new BoundConversion(Syntax, arg, conversion, isChecked, true, null, type) { WasCompilerGenerated = true };
        }
Example #13
0
        private static bool NullableNeverHasValue(BoundExpression expression)
        {
            // CONSIDER: A sequence of side effects with an always-null expression as its value
            // CONSIDER: can be optimized also. Should we?

            if (expression.IsLiteralNull())
            {
                return true;
            }

            if (!expression.Type.IsNullableType())
            {
                return false;
            }

            // default(int?) never has a value.
            if (expression.Kind == BoundKind.DefaultOperator)
            {
                return true;
            }

            // new int?() never has a value if there is no argument.
            if (expression.Kind == BoundKind.ObjectCreationExpression)
            {
                if (((BoundObjectCreationExpression)expression).Arguments.Length == 0)
                {
                    return true;
                }
            }

            return false;
        }
Example #14
0
        /// <summary>
        /// Produce an element-wise comparison and logic to ensure the result is a bool type.
        ///
        /// If an element-wise comparison doesn't return bool, then:
        /// - if it is dynamic, we'll do `!(comparisonResult.false)` or `comparisonResult.true`
        /// - if it implicitly converts to bool, we'll just do the conversion
        /// - otherwise, we'll do `!(comparisonResult.false)` or `comparisonResult.true` (as we'd do for `if` or `while`)
        /// </summary>
        private BoundExpression RewriteTupleSingleOperator(TupleBinaryOperatorInfo.Single single,
                                                           BoundExpression left, BoundExpression right, TypeSymbol boolType, BinaryOperatorKind operatorKind)
        {
            if (single.Kind.IsDynamic())
            {
                // Produce
                // !((left == right).op_false)
                // (left != right).op_true

                BoundExpression dynamicResult = _dynamicFactory.MakeDynamicBinaryOperator(single.Kind, left, right, isCompoundAssignment: false, _compilation.DynamicType).ToExpression();
                if (operatorKind == BinaryOperatorKind.Equal)
                {
                    return(_factory.Not(MakeUnaryOperator(UnaryOperatorKind.DynamicFalse, left.Syntax, method: null, dynamicResult, boolType)));
                }
                else
                {
                    return(MakeUnaryOperator(UnaryOperatorKind.DynamicTrue, left.Syntax, method: null, dynamicResult, boolType));
                }
            }

            if (left.IsLiteralNull() && right.IsLiteralNull())
            {
                // For `null == null` this is special-cased during initial binding
                return(new BoundLiteral(left.Syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.Equal), boolType));
            }

            // We leave both operands in nullable-null conversions unconverted, MakeBinaryOperator has special for null-literal
            bool            isNullableNullConversion = single.Kind.OperandTypes() == BinaryOperatorKind.NullableNull;
            BoundExpression convertedLeft            = isNullableNullConversion
                ? left
                : MakeConversionNode(left.Syntax, left, single.LeftConversion, single.LeftConvertedTypeOpt, @checked: false);

            BoundExpression convertedRight = isNullableNullConversion
                ? right
                : MakeConversionNode(right.Syntax, right, single.RightConversion, single.RightConvertedTypeOpt, @checked: false);

            BoundExpression        binary         = MakeBinaryOperator(_factory.Syntax, single.Kind, convertedLeft, convertedRight, single.MethodSymbolOpt?.ReturnType ?? boolType, single.MethodSymbolOpt);
            UnaryOperatorSignature boolOperator   = single.BoolOperator;
            Conversion             boolConversion = single.ConversionForBool;

            BoundExpression result;

            if (boolOperator.Kind != UnaryOperatorKind.Error)
            {
                // Produce
                // !((left == right).op_false)
                // (left != right).op_true
                BoundExpression convertedBinary = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolOperator.OperandType, @checked: false);

                Debug.Assert(boolOperator.ReturnType.SpecialType == SpecialType.System_Boolean);
                result = MakeUnaryOperator(boolOperator.Kind, binary.Syntax, boolOperator.Method, convertedBinary, boolType);

                if (operatorKind == BinaryOperatorKind.Equal)
                {
                    result = _factory.Not(result);
                }
            }
            else if (!boolConversion.IsIdentity)
            {
                // Produce
                // (bool)(left == right)
                // (bool)(left != right)
                result = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolType, @checked: false);
            }
            else
            {
                result = binary;
            }

            return(result);
        }
Example #15
0
        private bool IsOperandErrors(CSharpSyntaxNode node, ref BoundExpression operand, DiagnosticBag diagnostics)
        {
            switch (operand.Kind)
            {
                case BoundKind.UnboundLambda:
                case BoundKind.Lambda:
                case BoundKind.MethodGroup:  // New in Roslyn - see DevDiv #864740.
                    // operand for an is or as expression cannot be a lambda expression or method group
                    if (!operand.HasAnyErrors)
                    {
                        Error(diagnostics, ErrorCode.ERR_LambdaInIsAs, node);
                        operand = BadExpression(node, operand);
                    }

                    return true;

                default:
                    if ((object)operand.Type == null && !operand.IsLiteralNull())
                    {
                        if (!operand.HasAnyErrors)
                        {
                            // Operator 'is' cannot be applied to operand of type '(int, <null>)'
                            Error(diagnostics, ErrorCode.ERR_BadUnaryOp, node, SyntaxFacts.GetText(SyntaxKind.IsKeyword), operand.Display);
                        }

                        return true;
                    }

                    break;
            }

            return operand.HasAnyErrors;
        }
        private static ConversionKind ClassifyNullLiteralConversion(BoundExpression source, TypeSymbol destination)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)destination != null);

            if (!source.IsLiteralNull())
            {
                return ConversionKind.NoConversion;
            }

            // SPEC: An implicit conversion exists from the null literal to any nullable type. 
            if (destination.IsNullableType())
            {
                // The spec defines a "null literal conversion" specifically as a conversion from
                // null to nullable type.
                return ConversionKind.NullLiteral;
            }

            // SPEC: An implicit conversion exists from the null literal to any reference type. 
            // SPEC: An implicit conversion exists from the null literal to type parameter T, 
            // SPEC: provided T is known to be a reference type. [...] The conversion [is] classified 
            // SPEC: as implicit reference conversion. 

            if (destination.IsReferenceType)
            {
                return ConversionKind.ImplicitReference;
            }

            // SPEC: The set of implicit conversions is extended to include...
            // SPEC: ... from the null literal to any pointer type.

            if (destination is PointerTypeSymbol)
            {
                return ConversionKind.NullToPointer;
            }

            return ConversionKind.NoConversion;
        }
 private bool UseOnlyReferenceEquality(BoundExpression left, BoundExpression right, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
 {
     return
         BuiltInOperators.IsValidObjectEquality(Conversions, left.Type, left.IsLiteralNull(), right.Type, right.IsLiteralNull(), ref useSiteDiagnostics) &&
         ((object)left.Type == null || (!left.Type.IsDelegateType() && left.Type.SpecialType != SpecialType.System_String && left.Type.SpecialType != SpecialType.System_Delegate)) &&
         ((object)right.Type == null || (!right.Type.IsDelegateType() && right.Type.SpecialType != SpecialType.System_String && right.Type.SpecialType != SpecialType.System_Delegate));
 }
Example #18
0
 public static bool IsLiteralNullOrDefault(this BoundExpression node)
 {
     return(node.IsLiteralNull() || node.IsLiteralDefault());
 }
        private BoundExpression RewriteDelegateOperation(CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, SpecialMember member)
        {
            MethodSymbol method;
            if (operatorKind == BinaryOperatorKind.DelegateEqual || operatorKind == BinaryOperatorKind.DelegateNotEqual)
            {
                method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(member);
                if (loweredRight.IsLiteralNull() ||
                    loweredLeft.IsLiteralNull() ||
                    (object)(method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(member)) == null)
                {
                    // use reference equality in the absence of overloaded operators for System.Delegate.
                    operatorKind = (operatorKind & (~BinaryOperatorKind.Delegate)) | BinaryOperatorKind.Object;
                    return new BoundBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, default(ConstantValue), null, LookupResultKind.Empty, type);
                }
            }
            else
            {
                method = GetSpecialTypeMethod(syntax, member);
            }

            Debug.Assert((object)method != null);
            BoundExpression call = _inExpressionLambda
                ? new BoundBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, null, method, default(LookupResultKind), method.ReturnType)
                : (BoundExpression)BoundCall.Synthesized(syntax, null, method, loweredLeft, loweredRight);
            BoundExpression result = method.ReturnType.SpecialType == SpecialType.System_Delegate ?
                MakeConversionNode(syntax, call, Conversion.ExplicitReference, type, @checked: false) :
                call;
            return result;
        }
Example #20
0
        private BoundExpression VisitBinaryOperator(BoundBinaryOperator node)
        {
            var  opKind         = node.OperatorKind;
            var  op             = opKind & BinaryOperatorKind.OpMask;
            var  isChecked      = (opKind & BinaryOperatorKind.Checked) != 0;
            var  isLogical      = (opKind & BinaryOperatorKind.Logical) != 0;
            var  isLifted       = (opKind & BinaryOperatorKind.Lifted) != 0;
            bool requiresLifted = false;

            string opname;

            switch (op)
            {
            case BinaryOperatorKind.Addition: opname = isChecked ? "AddChecked" : "Add"; break;

            case BinaryOperatorKind.Multiplication: opname = isChecked ? "MultiplyChecked" : "Multiply"; break;

            case BinaryOperatorKind.Subtraction: opname = isChecked ? "SubtractChecked" : "Subtract"; break;

            case BinaryOperatorKind.Division: opname = "Divide"; break;

            case BinaryOperatorKind.Remainder: opname = "Modulo"; break;

            case BinaryOperatorKind.And: opname = isLogical ? "AndAlso" : "And"; break;

            case BinaryOperatorKind.Xor: opname = "ExclusiveOr"; break;

            case BinaryOperatorKind.Or: opname = isLogical ? "OrElse" : "Or"; break;

            case BinaryOperatorKind.LeftShift: opname = "LeftShift"; break;

            case BinaryOperatorKind.RightShift: opname = "RightShift"; break;

            case BinaryOperatorKind.Equal: opname = "Equal"; requiresLifted = true; break;

            case BinaryOperatorKind.NotEqual: opname = "NotEqual"; requiresLifted = true; break;

            case BinaryOperatorKind.LessThan: opname = "LessThan"; requiresLifted = true; break;

            case BinaryOperatorKind.LessThanOrEqual: opname = "LessThanOrEqual"; requiresLifted = true; break;

            case BinaryOperatorKind.GreaterThan: opname = "GreaterThan"; requiresLifted = true; break;

            case BinaryOperatorKind.GreaterThanOrEqual: opname = "GreaterThanOrEqual"; requiresLifted = true; break;

            default:
                throw ExceptionUtilities.UnexpectedValue(op);
            }

            BoundExpression left  = node.Left;
            BoundExpression right = node.Right;

            // Fix up the null value for a nullable comparison vs null
            if ((object)left.Type == null && left.IsLiteralNull())
            {
                left = Bound.Default(right.Type);
            }
            if ((object)right.Type == null && right.IsLiteralNull())
            {
                right = Bound.Default(left.Type);
            }

            var loweredLeft  = Visit(left);
            var loweredRight = Visit(right);

            // Enums are handled as per their promoted underlying type
            switch (node.OperatorKind.OperandTypes())
            {
            case BinaryOperatorKind.Enum:
            case BinaryOperatorKind.EnumAndUnderlying:
            case BinaryOperatorKind.UnderlyingAndEnum:
            {
                var enumOperand  = (node.OperatorKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left;
                var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType());
                if (isLifted)
                {
                    promotedType = NullableType.Construct(promotedType);
                }
                loweredLeft  = Convert(loweredLeft, left.Type, promotedType, isChecked, false);
                loweredRight = Convert(loweredRight, right.Type, promotedType, isChecked, false);
                var result = MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight);
                return(Demote(result, node.Type, isChecked));
            }

            default:
                return(MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight));
            }
        }