Exemplo n.º 1
0
        /// <summary>
        /// Emits address as in &amp; 
        /// 
        /// May introduce a temp which it will return. (otherwise returns null)
        /// </summary>
        private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addressKind)
        {
            switch (expression.Kind)
            {
                case BoundKind.RefValueOperator:
                    EmitRefValueAddress((BoundRefValueOperator)expression);
                    break;

                case BoundKind.Local:
                    EmitLocalAddress((BoundLocal)expression);
                    break;

                case BoundKind.Dup:
                    Debug.Assert(((BoundDup)expression).RefKind != RefKind.None, "taking address of a stack value?");
                    builder.EmitOpCode(ILOpCode.Dup);
                    break;

                case BoundKind.Parameter:
                    EmitParameterAddress((BoundParameter)expression);
                    break;

                case BoundKind.FieldAccess:
                    return EmitFieldAddress((BoundFieldAccess)expression);

                case BoundKind.ArrayAccess:
                    //arrays are covariant, but elements can be written to.
                    //the flag tells that we do not intend to use the address for writing.
                    EmitArrayElementAddress((BoundArrayAccess)expression, addressKind);
                    break;

                case BoundKind.ThisReference:
                    Debug.Assert(expression.Type.IsValueType, "only valuetypes may need a ref to this");
                    builder.EmitOpCode(ILOpCode.Ldarg_0);
                    break;

                case BoundKind.PreviousSubmissionReference:
                    // script references are lowered to a this reference and a field access
                    throw ExceptionUtilities.UnexpectedValue(expression.Kind);

                case BoundKind.BaseReference:
                    Debug.Assert(false, "base is always a reference type, why one may need a reference to it?");
                    break;

                case BoundKind.Sequence:
                    return EmitSequenceAddress((BoundSequence)expression, addressKind);

                case BoundKind.PointerIndirectionOperator:
                    // The address of a dereferenced address is that address.
                    BoundExpression operand = ((BoundPointerIndirectionOperator)expression).Operand;
                    Debug.Assert(operand.Type.IsPointerType());
                    EmitExpression(operand, used: true);
                    break;

                default:
                    Debug.Assert(!HasHome(expression));
                    return EmitAddressOfTempClone(expression);
            }

            return null;
        }
Exemplo n.º 2
0
        private BoundExpression BindElementAccessCore(ElementAccessExpressionSyntax node, BoundExpression expr, IList<BoundExpression> arguments, IList<string> argumentNames)
        {
            Debug.Assert(node != null);
            Debug.Assert(expr != null);
            Debug.Assert(arguments != null);
            Debug.Assert(argumentNames != null);

            // UNDONE: Suppose we have an indexed property P on an instance c. Suppose the 
            // UNDONE: type of the property is int[].  When binding c.P[123] we must 
            // UNDONE: treat this as an invocation of the indexed property, not as a
            // UNDONE: dereference of the array returned by the property.

            //if (expr.isPROP() && expr.asPROP().IsUnboundIndexedProperty() && 
            //    !IsPropertyBindingInsideBindIndexerContext(node.Expression))
            //{
            //    return BindIndexerAccess(node, expr, arguments, argumentNames);
            //}

            var exprType = expr.GetExpressionType();
            // UNDONE: Ensure that the type of the expression has members defined.
            if (exprType is ArrayTypeSymbol)
            {
                return BindArrayAccess(node, expr, arguments, argumentNames);
            }
            else if (exprType is PointerTypeSymbol)
            {
                return BindPointerElementAccess(node, expr, arguments, argumentNames);
            }
            else
            {
                return BindIndexerAccess(node, expr, arguments, argumentNames);
            }
        }
Exemplo n.º 3
0
 public BoundIfStatement(BoundExpression condition, BoundStatement consequence, BoundStatement alternativeOpt)
     : base(BoundNodeKind.IfStatement)
 {
     Condition = condition;
     Consequence = consequence;
     AlternativeOpt = alternativeOpt;
 }
        private static bool IsSafeForReordering(BoundExpression expression, RefKind kind)
        {
            // To be safe for reordering an expression must not cause any observable side effect *or
            // observe any side effect*. Accessing a local by value, for example, is possibly not
            // safe for reordering because reading a local can give a different result if reordered
            // with respect to a write elsewhere.

            var current = expression;
            while (true)
            {
                if (current.ConstantValue != null)
                {
                    return true;
                }

                switch (current.Kind)
                {
                    default:
                        return false;
                    case BoundKind.Parameter:
                    case BoundKind.Local:
                        // A ref to a local variable or formal parameter is safe to reorder; it
                        // never has a side effect or consumes one.
                        return kind != RefKind.None;
                    case BoundKind.Conversion:
                        {
                            BoundConversion conv = (BoundConversion)current;
                            switch (conv.ConversionKind)
                            {
                                case ConversionKind.AnonymousFunction:
                                case ConversionKind.ImplicitConstant:
                                case ConversionKind.MethodGroup:
                                case ConversionKind.NullLiteral:
                                    return true;
                                case ConversionKind.Boxing:
                                case ConversionKind.Dynamic:
                                case ConversionKind.ExplicitEnumeration:
                                case ConversionKind.ExplicitNullable:
                                case ConversionKind.ExplicitNumeric:
                                case ConversionKind.ExplicitReference:
                                case ConversionKind.Identity:
                                case ConversionKind.ImplicitEnumeration:
                                case ConversionKind.ImplicitNullable:
                                case ConversionKind.ImplicitNumeric:
                                case ConversionKind.ImplicitReference:
                                case ConversionKind.Unboxing:
                                    current = conv.Operand;
                                    break;
                                case ConversionKind.ExplicitUserDefined:
                                case ConversionKind.ImplicitUserDefined:
                                    return false;
                                default:
                                    Debug.Fail("Unhandled conversion kind in reordering logic");
                                    return false;
                            }
                            break;
                        }
                }
            }
        }
Exemplo n.º 5
0
 public BoundForStatement(BoundMultipleVariableDeclarations declaration, BoundExpression initializer, BoundExpression condition, BoundExpression incrementor, BoundStatement body)
     : base(BoundNodeKind.ForStatement)
 {
     Declarations = declaration;
     Initializer = initializer;
     Condition = condition;
     Incrementor = incrementor;
     Body = body;
 }
Exemplo n.º 6
0
        private static BoundStatement RewriteIfStatement(
            SyntaxNode syntax,  
            BoundExpression rewrittenCondition, 
            BoundStatement rewrittenConsequence, 
            BoundStatement rewrittenAlternativeOpt, 
            bool hasErrors)
        {
            var afterif = new GeneratedLabelSymbol("afterif");

            // if (condition) 
            //   consequence;  
            //
            // becomes
            //
            // GotoIfFalse condition afterif;
            // consequence;
            // afterif:

            if (rewrittenAlternativeOpt == null)
            {
                return BoundStatementList.Synthesized(syntax, 
                    new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif),
                    rewrittenConsequence,
                    new BoundLabelStatement(syntax, afterif));
            }

            // if (condition)
            //     consequence;
            // else 
            //     alternative
            //
            // becomes
            //
            // GotoIfFalse condition alt;
            // consequence
            // goto afterif;
            // alt:
            // alternative;
            // afterif:

            var alt = new GeneratedLabelSymbol("alternative");
            return BoundStatementList.Synthesized(syntax, hasErrors,
                new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt),
                rewrittenConsequence,
                new BoundGotoStatement(syntax, afterif),
                new BoundLabelStatement(syntax, alt),
                rewrittenAlternativeOpt,
                new BoundLabelStatement(syntax, afterif));
        }
Exemplo n.º 7
0
        private void EmitExpressionCoreWithStackGuard(BoundExpression expression, bool used)
        {
            Debug.Assert(_recursionDepth == 1);

            try
            {
                EmitExpressionCore(expression, used);
                Debug.Assert(_recursionDepth == 1);
            }
            catch (Exception ex) when (StackGuard.IsInsufficientExecutionStackException(ex))
            {
                _diagnostics.Add(ErrorCode.ERR_InsufficientStack,
                                 BoundTreeVisitor.CancelledByStackGuardException.GetTooLongOrComplexExpressionErrorLocation(expression));
                throw new EmitCancelledException();
            }
        }
 public static string GetErrorReportingName(BoundExpression expression)
 {
     switch(expression.Kind)
     {
         case BoundKind.Literal:
             if (expression.ConstantValue.IsNull)
                 return "<null>";
             break;
         case BoundKind.Lambda:
         case BoundKind.UnboundLambda:
             return "lambda expression"; // UNDONE: or "anonymous method"
         case BoundKind.MethodGroup:
             return "method group";
     }
     return GetErrorReportingName(expression.GetExpressionType());
 }
Exemplo n.º 9
0
        private BoundExpression BindArrayAccess(ElementAccessExpressionSyntax node, BoundExpression expr, IList<BoundExpression> arguments, IList<string> argumentNames)
        {
            Debug.Assert(node != null);
            Debug.Assert(expr != null);
            Debug.Assert(arguments != null);
            Debug.Assert(argumentNames != null);

            // For an array access, the primary-no-array-creation-expression of the element-access must
            // be a value of an array-type. Furthermore, the argument-list of an array access is not
            // allowed to contain named arguments.The number of expressions in the argument-list must 
            // be the same as the rank of the array-type, and each expression must be of type 
            // int, uint, long, ulong, or must be implicitly convertible to one or more of these types.

            if (argumentNames.Any(x => x != null))
            {
                Error(ErrorCode.ERR_NamedArgumentForArray, node);
            }

            var arrayType = (ArrayTypeSymbol)expr.GetExpressionType();

            // Note that the spec says to determine which of {int, uint, long, ulong} *each*
            // index expression is convertible to. That is not what C# 1 through 4
            // did; the implementations instead determined which of those four
            // types *all* of the index expressions converted to. 



            int rank = arrayType.Rank;

            if (arguments.Count != arrayType.Rank)
            {
                Error(ErrorCode.ERR_BadIndexCount, node, rank);
                return BoundArrayAccess.AsError(node, expr, arguments, arrayType.ElementType);
            }

            var convertedArguments = arguments.Select(x => ConvertToArrayIndex(x)).ToList();

            return new BoundArrayAccess(node, expr, convertedArguments, arrayType.ElementType);
        }
Exemplo n.º 10
0
        private void EmitExpression(BoundExpression expression, bool used)
        {
            if (expression == null)
            {
                return;
            }

            var constantValue = expression.ConstantValue;
            if (constantValue != null)
            {
                if (!used)
                {
                    // unused constants have no side-effects.
                    return;
                }

                if ((object)expression.Type == null || expression.Type.SpecialType != SpecialType.System_Decimal)
                {
                    EmitConstantExpression(expression.Type, constantValue, used, expression.Syntax);
                    return;
                }
            }

            _recursionDepth++;

            if (_recursionDepth > 1)
            {
                StackGuard.EnsureSufficientExecutionStack(_recursionDepth);

                EmitExpressionCore(expression, used);
            }
            else
            {
                EmitExpressionCoreWithStackGuard(expression, used);
            }

            _recursionDepth--;
        }
Exemplo n.º 11
0
 public BoundEqualsValue(BoundExpression value)
     : base(BoundNodeKind.EqualsValue)
 {
     Value = value;
 }
Exemplo n.º 12
0
 public BoundExpressionStatement(BoundExpression expression)
 {
     Expression = expression;
 }
Exemplo n.º 13
0
 private static OverloadResolutionResult <BinaryOperatorSignature> LookupBinaryOperator(BinaryOperatorKind operatorKind, BoundExpression left, BoundExpression right)
 {
     return(BinaryOperator.Resolve(operatorKind, left.Type, right.Type));
 }
Exemplo n.º 14
0
 private static bool IsStackAlloc(BoundExpression expr)
 {
     return
         expr.Kind == BoundKind.StackAllocArrayCreation ||
         expr.Kind == BoundKind.Conversion && ((BoundConversion)expr).Operand.Kind == BoundKind.StackAllocArrayCreation;
 }
Exemplo n.º 15
0
 internal override ImmutableArray <Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     Debug.Assert(boundInitValue != null);
     MakeConstantTuple(inProgress: null, boundInitValue: boundInitValue);
     return(this.constantTuple == null ? default(ImmutableArray <Diagnostic>) : this.constantTuple.Diagnostics);
 }
Exemplo n.º 16
0
        private void InPlaceInit(BoundExpression target, bool used)
        {
            var temp = EmitAddress(target, AddressKind.Writeable);
            Debug.Assert(temp == null, "in-place init target should not create temps");

            _builder.EmitOpCode(ILOpCode.Initobj);    //  intitobj  <MyStruct>
            EmitSymbolToken(target.Type, target.Syntax);

            if (used)
            {
                Debug.Assert(TargetIsNotOnHeap(target), "cannot read-back the target since it could have been modified");
                EmitExpression(target, used);
            }
        }
Exemplo n.º 17
0
 internal override ImmutableBindingDiagnostic <AssemblySymbol> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     Debug.Assert(boundInitValue != null);
     MakeConstantTuple(inProgress: null, boundInitValue: boundInitValue);
     return(_constantTuple == null ? ImmutableBindingDiagnostic <AssemblySymbol> .Empty : _constantTuple.Diagnostics);
 }
Exemplo n.º 18
0
            protected override TypeWithAnnotations InferTypeOfVarVariable(BindingDiagnosticBag diagnostics)
            {
                BoundExpression initializerOpt = this._initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind, _initializer, _initializer);

                return(TypeWithAnnotations.Create(initializerOpt?.Type));
            }
Exemplo n.º 19
0
 internal override ImmutableBindingDiagnostic <AssemblySymbol> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     return(ImmutableBindingDiagnostic <AssemblySymbol> .Empty);
 }
Exemplo n.º 20
0
        public void EmitConvert(BoundExpression expr, TypeSymbol to)
        {
            // bind target expression type
            expr.Access = expr.Access.WithRead(to);

            // constants
            if (expr.ConstantObject.HasValue && to != null)
            {
                EmitConvert(EmitLoadConstant(expr.ConstantObject.Value, to), 0, to);
                return;
            }

            // loads value from place most effectively without runtime type checking
            var place = PlaceOrNull(expr);
            var type  = TryEmitVariableSpecialize(place, expr.TypeRefMask);

            if (type != null)
            {
                EmitConvert(type, 0, to);
                return;
            }

            // avoiding of load of full value
            if (place != null && place.HasAddress)
            {
                if (place.TypeOpt == CoreTypes.PhpNumber)
                {
                    if (to.SpecialType == SpecialType.System_Int64)
                    {
                        // <place>.ToLong()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToLong);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_Double)
                    {
                        // <place>.ToDouble()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToDouble);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_Boolean)
                    {
                        // <place>.ToBoolean()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToBoolean);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_String)
                    {
                        // <place>.ToString(<ctx>)
                        place.EmitLoadAddress(_il);
                        EmitLoadContext();
                        EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToString_Context);
                        return;
                    }
                    if (to == CoreTypes.PhpValue)
                    {
                        // TODO
                    }

                    // TODO: Object, Array
                }
                else if (place.TypeOpt == CoreTypes.PhpValue)
                {
                    if (to.SpecialType == SpecialType.System_Int64)
                    {
                        // <place>.ToLong()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToLong);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_Double)
                    {
                        // <place>.ToDouble()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToDouble);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_Boolean)
                    {
                        // <place>.ToBoolean()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToBoolean);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_String)
                    {
                        // <place>.ToString(<ctx>)
                        place.EmitLoadAddress(_il);
                        EmitLoadContext();
                        EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToString_Context);
                        return;
                    }
                    if (to.SpecialType == SpecialType.System_Object)
                    {
                        // <place>.ToClass()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToClass);
                        return;
                    }
                    //if (to == CoreTypes.PhpArray)
                    //{
                    //    // <place>.AsArray()
                    //    place.EmitLoadAddress(_il);
                    //    EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToArray);
                    //    return;
                    //}
                }
                else if (place.TypeOpt == CoreTypes.Long)
                {
                    if (to.SpecialType == SpecialType.System_String)
                    {
                        // <place>.ToString()
                        place.EmitLoadAddress(_il);
                        EmitCall(ILOpCode.Call, CoreMethods.Operators.Long_ToString);
                        return;
                    }
                }
            }

            //
            EmitConvert(expr.Emit(this), expr.TypeRefMask, to);
        }
 public BoundUpdateLineCountExpression(SyntaxNode syntax, BoundExpression left, BoundUpdateLineCountOperatorKind operatorKind, BoundExpression right)
     : base(syntax) =>
     (this.Left, this.OperatorKind, this.Right) = (left, operatorKind, right);
Exemplo n.º 22
0
        private void EmitSpecialUserDefinedConversion(BoundConversion conversion, bool used, BoundExpression operand)
        {
            var typeTo = (NamedTypeSymbol)conversion.Type;

            if (!TryEmitReadonlySpanAsBlobWrapper(typeTo, operand, used, inPlace: false))
            {
                // there are several reasons that could prevent us from emitting a wrapper
                // in such case we just emit the operand and then invoke the conversion method
                EmitExpression(operand, used);
                if (used)
                {
                    // consumes 1 argument (array) and produces one result (span)
                    _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0);
                    EmitSymbolToken(conversion.SymbolOpt, conversion.Syntax, optArgList: null);
                }
            }
        }
Exemplo n.º 23
0
        private static MethodSymbol InferExtensionMethodTypeArguments(MethodSymbol method, TypeSymbol thisType, CSharpCompilation compilation, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo)
        {
            Debug.Assert(method.IsExtensionMethod);
            Debug.Assert((object)thisType != null);

            if (!method.IsGenericMethod || method != method.ConstructedFrom)
            {
                return(method);
            }

            // We never resolve extension methods on a dynamic receiver.
            if (thisType.IsDynamic())
            {
                return(null);
            }

            var containingAssembly = method.ContainingAssembly;
            var errorNamespace     = containingAssembly.GlobalNamespace;
            var conversions        = new TypeConversions(containingAssembly.CorLibrary);

            // There is absolutely no plausible syntax/tree that we could use for these
            // synthesized literals.  We could be speculatively binding a call to a PE method.
            var syntaxTree = CSharpSyntaxTree.Dummy;
            var syntax     = (CSharpSyntaxNode)syntaxTree.GetRoot();

            // Create an argument value for the "this" argument of specific type,
            // and pass the same bad argument value for all other arguments.
            var thisArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, thisType)
            {
                WasCompilerGenerated = true
            };
            var otherArgumentType  = new ExtendedErrorTypeSymbol(errorNamespace, name: string.Empty, arity: 0, errorInfo: null, unreported: false);
            var otherArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, otherArgumentType)
            {
                WasCompilerGenerated = true
            };

            var paramCount = method.ParameterCount;
            var arguments  = new BoundExpression[paramCount];

            for (int i = 0; i < paramCount; i++)
            {
                var argument = (i == 0) ? thisArgumentValue : otherArgumentValue;
                arguments[i] = argument;
            }

            var typeArgs = MethodTypeInferrer.InferTypeArgumentsFromFirstArgument(
                conversions,
                method,
                arguments.AsImmutable(),
                useSiteInfo: ref useSiteInfo);

            if (typeArgs.IsDefault)
            {
                return(null);
            }

            // For the purpose of constraint checks we use error type symbol in place of type arguments that we couldn't infer from the first argument.
            // This prevents constraint checking from failing for corresponding type parameters.
            int firstNullInTypeArgs       = -1;
            var notInferredTypeParameters = PooledHashSet <TypeParameterSymbol> .GetInstance();

            var typeParams = method.TypeParameters;
            var typeArgsForConstraintsCheck = typeArgs;

            for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++)
            {
                if (!typeArgsForConstraintsCheck[i].HasType)
                {
                    firstNullInTypeArgs = i;
                    var builder = ArrayBuilder <TypeWithAnnotations> .GetInstance();

                    builder.AddRange(typeArgsForConstraintsCheck, firstNullInTypeArgs);

                    for (; i < typeArgsForConstraintsCheck.Length; i++)
                    {
                        var typeArg = typeArgsForConstraintsCheck[i];
                        if (!typeArg.HasType)
                        {
                            notInferredTypeParameters.Add(typeParams[i]);
                            builder.Add(TypeWithAnnotations.Create(ErrorTypeSymbol.UnknownResultType));
                        }
                        else
                        {
                            builder.Add(typeArg);
                        }
                    }

                    typeArgsForConstraintsCheck = builder.ToImmutableAndFree();
                    break;
                }
            }

            // Check constraints.
            var diagnosticsBuilder = ArrayBuilder <TypeParameterDiagnosticInfo> .GetInstance();

            var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck);
            ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null;
            var success = method.CheckConstraints(new ConstraintsHelper.CheckConstraintsArgs(compilation, conversions, includeNullability: false, NoLocation.Singleton, diagnostics: null, template: new CompoundUseSiteInfo <AssemblySymbol>(useSiteInfo)),
                                                  substitution, typeParams, typeArgsForConstraintsCheck, diagnosticsBuilder, nullabilityDiagnosticsBuilderOpt: null,
                                                  ref useSiteDiagnosticsBuilder,
                                                  ignoreTypeConstraintsDependentOnTypeParametersOpt: notInferredTypeParameters.Count > 0 ? notInferredTypeParameters : null);

            diagnosticsBuilder.Free();
            notInferredTypeParameters.Free();

            if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0)
            {
                foreach (var diag in useSiteDiagnosticsBuilder)
                {
                    useSiteInfo.Add(diag.UseSiteInfo);
                }
            }

            if (!success)
            {
                return(null);
            }

            // For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument.
            ImmutableArray <TypeWithAnnotations> typeArgsForConstruct = typeArgs;

            if (typeArgs.Any(t => !t.HasType))
            {
                typeArgsForConstruct = typeArgs.ZipAsArray(
                    method.TypeParameters,
                    (t, tp) => t.HasType ? t : TypeWithAnnotations.Create(tp));
            }

            return(method.Construct(typeArgsForConstruct));
        }
Exemplo n.º 24
0
        /// <summary>
        /// Used to decide if we need to emit call or callvirt.
        /// It basically checks if the receiver expression cannot be null, but it is not 100% precise. 
        /// There are cases where it really can be null, but we do not care.
        /// </summary>
        private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver)
        {
            // It seems none of the ways that could produce a receiver typed as a type param 
            // can guarantee that it is not null.
            if (receiver.Type.IsTypeParameter())
            {
                return false;
            }

            Debug.Assert(receiver.Type.IsVerifierReference(), "this is not a reference");
            Debug.Assert(receiver.Kind != BoundKind.BaseReference, "base should always use call");

            var constVal = receiver.ConstantValue;
            if (constVal != null)
            {
                // only when this is a constant Null, we need a callvirt
                return !constVal.IsNull;
            }

            switch (receiver.Kind)
            {
                case BoundKind.ArrayCreation:
                    return true;

                case BoundKind.ObjectCreationExpression:
                    //NOTE: there are cases involving ProxyAttribute
                    //where newobj may produce null
                    return true;

                case BoundKind.Conversion:
                    var conversion = (BoundConversion)receiver;

                    switch (conversion.ConversionKind)
                    {
                        case ConversionKind.Boxing:
                            //NOTE: boxing can produce null for Nullable, but any call through that
                            //will result in null reference exceptions anyways.
                            return true;

                        case ConversionKind.MethodGroup:
                        case ConversionKind.AnonymousFunction:
                            return true;

                        case ConversionKind.ExplicitReference:
                        case ConversionKind.ImplicitReference:
                            return CanUseCallOnRefTypeReceiver(conversion.Operand);
                    }
                    break;

                case BoundKind.ThisReference:
                    //NOTE: these actually can be null if called from a different language
                    //if that has already happen, we will just propagate the behavior.
                    return true;

                case BoundKind.DelegateCreationExpression:
                    return true;

                case BoundKind.Sequence:
                    var seqValue = ((BoundSequence)(receiver)).Value;
                    return CanUseCallOnRefTypeReceiver(seqValue);

                case BoundKind.AssignmentOperator:
                    var rhs = ((BoundAssignmentOperator)receiver).Right;
                    return CanUseCallOnRefTypeReceiver(rhs);

                case BoundKind.TypeOfOperator:
                    return true;

                case BoundKind.FieldAccess:
                    return ((BoundFieldAccess)receiver).FieldSymbol.IsCapturedFrame;

                case BoundKind.ConditionalReceiver:
                    return true;

                    //TODO: there could be more cases where we can be sure that receiver is not a null.
            }

            return false;
        }
Exemplo n.º 25
0
        // returns true when receiver is already a ref.
        // in such cases calling through a ref could be preferred over 
        // calling through indirectly loaded value.
        private bool IsRef(BoundExpression receiver)
        {
            switch (receiver.Kind)
            {
                case BoundKind.Local:
                    return ((BoundLocal)receiver).LocalSymbol.RefKind != RefKind.None;

                case BoundKind.Parameter:
                    return ((BoundParameter)receiver).ParameterSymbol.RefKind != RefKind.None;

                case BoundKind.Call:
                    return ((BoundCall)receiver).Method.RefKind != RefKind.None;

                case BoundKind.Dup:
                    return ((BoundDup)receiver).RefKind != RefKind.None;

                case BoundKind.Sequence:
                    return IsRef(((BoundSequence)receiver).Value);
            }

            return false;
        }
Exemplo n.º 26
0
 internal override ImmutableArray <Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue) =>
 _underlyingLocal.GetConstantValueDiagnostics(boundInitValue);
Exemplo n.º 27
0
        // partial ctor results are not observable when target is not on the heap.
        // we also must not be in a try, otherwise if ctor throws
        // partially assigned value may be observed in the handler.
        private bool PartialCtorResultCannotEscape(BoundExpression left)
        {
            if (TargetIsNotOnHeap(left))
            {
                if (_tryNestingLevel != 0)
                {
                    var local = left as BoundLocal;
                    if (local != null && !_builder.PossiblyDefinedOutsideOfTry(GetLocal(local)))
                    {
                        // local defined inside immediate Try - cannot escape
                        return true;
                    }

                    // local defined outside of immediate try or it is a parameter - can escape
                    return false;
                }

                // we are not in a try - locals, parameters cannot escape
                return true;
            }

            // left is a reference, partial initializations can escape.
            return false;
        }
Exemplo n.º 28
0
 public BoundBinaryExpression(BoundExpression left, BoundBinaryOperator @operator, BoundExpression right)
 {
     Left     = left;
     Operator = @operator;
     Right    = right;
 }
Exemplo n.º 29
0
 private void EmitArgument(BoundExpression argument, RefKind refKind)
 {
     if (refKind == RefKind.None)
     {
         EmitExpression(argument, true);
     }
     else
     {
         var temp = EmitAddress(argument, AddressKind.Writeable);
         Debug.Assert(temp == null, "passing args byref should not clone them into temps");
     }
 }
Exemplo n.º 30
0
 internal override ImmutableArray<Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     return ImmutableArray<Diagnostic>.Empty;
 }
Exemplo n.º 31
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundExpression originalLeft = node.Left;

            if (originalLeft.Kind != BoundKind.Local)
            {
                return base.VisitAssignmentOperator(node);
            }

            var leftLocal = (BoundLocal)originalLeft;

            BoundExpression originalRight = node.Right;

            if (leftLocal.LocalSymbol.RefKind != RefKind.None &&
                node.RefKind != RefKind.None &&
                NeedsProxy(leftLocal.LocalSymbol))
            {
                Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol));
                Debug.Assert(!IsStackAlloc(originalRight));
                //spilling ref local variables
                throw ExceptionUtilities.Unreachable;
            }

            if (NeedsProxy(leftLocal.LocalSymbol) && !proxies.ContainsKey(leftLocal.LocalSymbol))
            {
                Debug.Assert(leftLocal.LocalSymbol.DeclarationKind == LocalDeclarationKind.None);
                // spilling temp variables
                throw ExceptionUtilities.Unreachable;
            }

            BoundExpression rewrittenLeft = (BoundExpression)this.Visit(leftLocal);
            BoundExpression rewrittenRight = (BoundExpression)this.Visit(originalRight);
            TypeSymbol rewrittenType = VisitType(node.Type);

            // Check if we're assigning the result of stackalloc to a hoisted local.
            // If we are, we need to store the result in a temp local and then assign
            // the value of the local to the field corresponding to the hoisted local.
            // If the receiver of the field is on the stack when the stackalloc happens,
            // popping it will free the memory (?) or otherwise cause verification issues.
            // DevDiv Bugs 59454
            if (rewrittenLeft.Kind != BoundKind.Local && IsStackAlloc(originalRight))
            {
                // From ILGENREC::genAssign:
                // DevDiv Bugs 59454: Handle hoisted local initialized with a stackalloc
                // NOTE: Need to check for cast of stackalloc on RHS.
                // If LHS isLocal, then genAddr is a noop so regular case works fine.

                SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this.CurrentMethod, rewrittenLeft.Syntax, this.CompilationState, this.Diagnostics);
                BoundAssignmentOperator tempAssignment;
                BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment);

                Debug.Assert(node.RefKind == RefKind.None);
                BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.RefKind, rewrittenType);

                return new BoundSequence(
                    node.Syntax,
                    ImmutableArray.Create<LocalSymbol>(tempLocal.LocalSymbol),
                    ImmutableArray.Create<BoundExpression>(tempAssignment),
                    rewrittenAssignment,
                    rewrittenType);
            }

            return node.Update(rewrittenLeft, rewrittenRight, node.RefKind, rewrittenType);
        }
Exemplo n.º 32
0
 internal override ImmutableArray<Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     Debug.Assert(boundInitValue != null);
     MakeConstantTuple(inProgress: null, boundInitValue: boundInitValue);
     return _constantTuple == null ? ImmutableArray<Diagnostic>.Empty : _constantTuple.Diagnostics;
 }
Exemplo n.º 33
0
 private static bool BaseReferenceInReceiverWasRewritten(BoundExpression originalReceiver, BoundExpression rewrittenReceiver)
 {
     return originalReceiver != null && originalReceiver.Kind == BoundKind.BaseReference &&
            rewrittenReceiver != null && rewrittenReceiver.Kind != BoundKind.BaseReference;
 }
Exemplo n.º 34
0
        internal static BoundExpression ConvertToLocalType(CSharpCompilation compilation, BoundExpression expr, TypeSymbol type, DiagnosticBag diagnostics)
        {
            if (type.IsPointerType())
            {
                var syntax     = expr.Syntax;
                var intPtrType = compilation.GetSpecialType(SpecialType.System_IntPtr);
                Binder.ReportUseSiteDiagnostics(intPtrType, diagnostics, syntax);
                MethodSymbol conversionMethod;
                if (Binder.TryGetSpecialTypeMember(compilation, SpecialMember.System_IntPtr__op_Explicit_ToPointer, syntax, diagnostics, out conversionMethod))
                {
                    var temp = ConvertToLocalTypeHelper(compilation, expr, intPtrType, diagnostics);
                    expr = BoundCall.Synthesized(
                        syntax,
                        receiverOpt: null,
                        method: conversionMethod,
                        arg0: temp,
                        binder: null);
                }
                else
                {
                    return(new BoundBadExpression(
                               syntax,
                               LookupResultKind.Empty,
                               ImmutableArray <Symbol> .Empty,
                               ImmutableArray.Create(expr),
                               type));
                }
            }

            return(ConvertToLocalTypeHelper(compilation, expr, type, diagnostics));
        }
Exemplo n.º 35
0
        private static BoundExpression ConvertToLocalTypeHelper(CSharpCompilation compilation, BoundExpression expr, TypeSymbol type, DiagnosticBag diagnostics)
        {
            // NOTE: This conversion can fail if some of the types involved are from not-yet-loaded modules.
            // For example, if System.Exception hasn't been loaded, then this call will fail for $stowedexception.
            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            var conversion = compilation.Conversions.ClassifyConversionFromExpression(expr, type, ref useSiteDiagnostics);

            diagnostics.Add(expr.Syntax, useSiteDiagnostics);
            Debug.Assert(conversion.IsValid || diagnostics.HasAnyErrors());

            return(BoundConversion.Synthesized(
                       expr.Syntax,
                       expr,
                       conversion,
                       @checked: false,
                       explicitCastInCode: false,
                       conversionGroupOpt: null,
                       constantValueOpt: null,
                       type: type,
                       hasErrors: !conversion.IsValid));
        }
Exemplo n.º 36
0
 public Evaluator(BoundExpression root, Scope scope)
 {
     this.root  = root;
     this.scope = scope;
 }
Exemplo n.º 37
0
 public BoundExpressionStatement(BoundExpression expression) : base(BoundNodeKind.ExpressionStatement)
 {
     Expression = expression;
 }
Exemplo n.º 38
0
        private object EvaluateExpression(BoundExpression node)
        {
            if (node is BoundLiteralExpression n)
            {
                return(n.Value);
            }

            if (node is BoundVariableExpression v)
            {
                var symbol = scope[v.Name];
                return(symbol.Value);
            }

            if (node is BoundAssignementExpression a)
            {
                var value  = EvaluateExpression(a.Expression);
                var symbol = scope[a.Name.Identifier];
                symbol.Value = value;
                return(value);
            }

            if (node is BoundUnaryExpression u)
            {
                var operand = EvaluateExpression(u.Operand);

                switch (u.Op.Kind)
                {
                case BoundUnaryOperatorKind.Identity:
                    return((int)operand);

                case BoundUnaryOperatorKind.Negation:
                    return(-(int)operand);

                case BoundUnaryOperatorKind.LogicalNegation:
                    return(!(bool)operand);

                default:
                    throw new Exception($"Unexpected unary operator {u.Op}");
                }
            }

            if (node is BoundBinaryExpression b)
            {
                var left  = EvaluateExpression(b.Left);
                var right = EvaluateExpression(b.Right);

                switch (b.Op.Kind)
                {
                case BoundBinaryOperatorKind.Addition:
                    return((int)left + (int)right);

                case BoundBinaryOperatorKind.Subtraction:
                    return((int)left - (int)right);

                case BoundBinaryOperatorKind.Multiplication:
                    return((int)left * (int)right);

                case BoundBinaryOperatorKind.Division:
                    return((int)left / (int)right);

                case BoundBinaryOperatorKind.LogicalAnd:
                    return((bool)left && (bool)right);

                case BoundBinaryOperatorKind.LogicalOr:
                    return((bool)left || (bool)right);

                case BoundBinaryOperatorKind.Equals:
                    return(Equals(left, right));

                case BoundBinaryOperatorKind.NotEquals:
                    return(!Equals(left, right));

                default:
                    throw new Exception($"Unexpected binary operator {b.Op}");
                }
            }

            throw new Exception($"Unexpected node {node.Kind}");
        }
Exemplo n.º 39
0
        internal static bool FieldLoadMustUseRef(BoundExpression expr)
        {
            var type = expr.Type;

            // type parameter values must be boxed to get access to fields
            if (type.IsTypeParameter())
            {
                return true;
            }

            // From   Dev12/symbol.cpp
            //  
            //  // Used by ILGEN to determine if the type of this AggregateSymbol is one that the CLR
            //  // will consider ambiguous to an unmanaged pointer when it is on the stack (see VSW #396011)
            //  bool AggregateSymbol::IsCLRAmbigStruct()
            //      . . .
            switch (type.SpecialType)
            {
                // case PT_BYTE:
                case SpecialType.System_Byte:
                // case PT_SHORT:
                case SpecialType.System_Int16:
                // case PT_INT:
                case SpecialType.System_Int32:
                // case PT_LONG:
                case SpecialType.System_Int64:
                // case PT_CHAR:
                case SpecialType.System_Char:
                // case PT_BOOL:
                case SpecialType.System_Boolean:
                // case PT_SBYTE:
                case SpecialType.System_SByte:
                // case PT_USHORT:
                case SpecialType.System_UInt16:
                // case PT_UINT:
                case SpecialType.System_UInt32:
                // case PT_ULONG:
                case SpecialType.System_UInt64:
                // case PT_INTPTR:
                case SpecialType.System_IntPtr:
                // case PT_UINTPTR:
                case SpecialType.System_UIntPtr:
                // case PT_FLOAT:
                case SpecialType.System_Single:
                // case PT_DOUBLE:
                case SpecialType.System_Double:
                // case PT_TYPEHANDLE:
                case SpecialType.System_RuntimeTypeHandle:
                // case PT_FIELDHANDLE:
                case SpecialType.System_RuntimeFieldHandle:
                // case PT_METHODHANDLE:
                case SpecialType.System_RuntimeMethodHandle:
                //case PT_ARGUMENTHANDLE:
                case SpecialType.System_RuntimeArgumentHandle:
                    return true;
            }

            // this is for value__
            // I do not know how to hit this, since value__ is not bindable in C#, but Dev12 has code to handle this
            return type.IsEnumType();
        }
Exemplo n.º 40
0
        internal static bool ReportDefaultParameterErrors(
            Binder binder,
            Symbol owner,
            ParameterSyntax parameterSyntax,
            SourceParameterSymbol parameter,
            BoundExpression defaultExpression,
            DiagnosticBag diagnostics)
        {
            bool hasErrors = false;

            // SPEC VIOLATION: The spec says that the conversion from the initializer to the
            // parameter type is required to be either an identity or a nullable conversion, but
            // that is not right:
            //
            // void M(short myShort = 10) {}
            // * not an identity or nullable conversion but should be legal
            //
            // void M(object obj = (dynamic)null) {}
            // * an identity conversion, but should be illegal
            //
            // void M(MyStruct? myStruct = default(MyStruct)) {}
            // * a nullable conversion, but must be illegal because we cannot generate metadata for it
            //
            // Even if the expression is thoroughly illegal, we still want to bind it and
            // stick it in the parameter because we want to be able to analyze it for
            // IntelliSense purposes.

            TypeSymbol parameterType = parameter.Type;
            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            Conversion conversion = binder.Conversions.ClassifyImplicitConversionFromExpression(defaultExpression, parameterType, ref useSiteDiagnostics);

            diagnostics.Add(defaultExpression.Syntax, useSiteDiagnostics);

            var refKind = GetModifiers(parameterSyntax.Modifiers, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword);

            // CONSIDER: We are inconsistent here regarding where the error is reported; is it
            // CONSIDER: reported on the parameter name, or on the value of the initializer?
            // CONSIDER: Consider making this consistent.

            if (refKind == RefKind.Ref || refKind == RefKind.Out)
            {
                // error CS1741: A ref or out parameter cannot have a default value
                diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, refnessKeyword.GetLocation());
                hasErrors = true;
            }
            else if (paramsKeyword.Kind() == SyntaxKind.ParamsKeyword)
            {
                // error CS1751: Cannot specify a default value for a parameter array
                diagnostics.Add(ErrorCode.ERR_DefaultValueForParamsParameter, paramsKeyword.GetLocation());
                hasErrors = true;
            }
            else if (thisKeyword.Kind() == SyntaxKind.ThisKeyword)
            {
                // Only need to report CS1743 for the first parameter. The caller will
                // have reported CS1100 if 'this' appeared on another parameter.
                if (parameter.Ordinal == 0)
                {
                    // error CS1743: Cannot specify a default value for the 'this' parameter
                    diagnostics.Add(ErrorCode.ERR_DefaultValueForExtensionParameter, thisKeyword.GetLocation());
                    hasErrors = true;
                }
            }
            else if (!defaultExpression.HasAnyErrors && !IsValidDefaultValue(defaultExpression))
            {
                // error CS1736: Default parameter value for '{0}' must be a compile-time constant
                diagnostics.Add(ErrorCode.ERR_DefaultValueMustBeConstant, parameterSyntax.Default.Value.Location, parameterSyntax.Identifier.ValueText);
                hasErrors = true;
            }
            else if (!conversion.Exists ||
                     conversion.IsUserDefined ||
                     conversion.IsIdentity && parameterType.SpecialType == SpecialType.System_Object && defaultExpression.Type.IsDynamic())
            {
                // If we had no implicit conversion, or a user-defined conversion, report an error.
                //
                // Even though "object x = (dynamic)null" is a legal identity conversion, we do not allow it.
                // CONSIDER: We could. Doesn't hurt anything.

                // error CS1750: A value of type '{0}' cannot be used as a default parameter because there are no standard conversions to type '{1}'
                diagnostics.Add(ErrorCode.ERR_NoConversionForDefaultParam, parameterSyntax.Identifier.GetLocation(),
                                defaultExpression.Display, parameterType);

                hasErrors = true;
            }
            else if (conversion.IsReference &&
                     (parameterType.SpecialType == SpecialType.System_Object || parameterType.Kind == SymbolKind.DynamicType) &&
                     (object)defaultExpression.Type != null &&
                     defaultExpression.Type.SpecialType == SpecialType.System_String ||
                     conversion.IsBoxing)
            {
                // We don't allow object x = "hello", object x = 123, dynamic x = "hello", etc.
                // error CS1763: '{0}' is of type '{1}'. A default parameter value of a reference type other than string can only be initialized with null
                diagnostics.Add(ErrorCode.ERR_NotNullRefDefaultParameter, parameterSyntax.Identifier.GetLocation(),
                                parameterSyntax.Identifier.ValueText, parameterType);

                hasErrors = true;
            }
            else if (conversion.IsNullable && !defaultExpression.Type.IsNullableType() &&
                     !(parameterType.GetNullableUnderlyingType().IsEnumType() || parameterType.GetNullableUnderlyingType().IsIntrinsicType()))
            {
                // We can do:
                // M(int? x = default(int))
                // M(int? x = default(int?))
                // M(MyEnum? e = default(enum))
                // M(MyEnum? e = default(enum?))
                // M(MyStruct? s = default(MyStruct?))
                //
                // but we cannot do:
                //
                // M(MyStruct? s = default(MyStruct))

                // error CS1770:
                // A value of type '{0}' cannot be used as default parameter for nullable parameter '{1}' because '{0}' is not a simple type
                diagnostics.Add(ErrorCode.ERR_NoConversionForNubDefaultParam, parameterSyntax.Identifier.GetLocation(),
                                defaultExpression.Type, parameterSyntax.Identifier.ValueText);

                hasErrors = true;
            }

            // Certain contexts allow default parameter values syntactically but they are ignored during
            // semantic analysis. They are:

            // 1. Explicitly implemented interface methods; since the method will always be called
            //    via the interface, the defaults declared on the implementation will not
            //    be seen at the call site.
            //
            // UNDONE: 2. The "actual" side of a partial method; the default values are taken from the
            // UNDONE:    "declaring" side of the method.
            //
            // UNDONE: 3. An indexer with only one formal parameter; it is illegal to omit every argument
            // UNDONE:    to an indexer.
            //
            // 4. A user-defined operator; it is syntactically impossible to omit the argument.

            if (owner.IsExplicitInterfaceImplementation() ||
                owner.IsPartialImplementation() ||
                owner.IsOperator())
            {
                // CS1066: The default value specified for parameter '{0}' will have no effect because it applies to a
                //         member that is used in contexts that do not allow optional arguments
                diagnostics.Add(ErrorCode.WRN_DefaultValueForUnconsumedLocation,
                                parameterSyntax.Identifier.GetLocation(),
                                parameterSyntax.Identifier.ValueText);
            }

            return(hasErrors);
        }
Exemplo n.º 41
0
        /// <summary>
        /// checks if receiver is effectively ldarg.0
        /// </summary>
        private bool IsThisReceiver(BoundExpression receiver)
        {
            switch (receiver.Kind)
            {
                case BoundKind.ThisReference:
                    return true;

                case BoundKind.Sequence:
                    var seqValue = ((BoundSequence)(receiver)).Value;
                    return IsThisReceiver(seqValue);
            }

            return false;
        }
Exemplo n.º 42
0
        private void EmitExpressionCore(BoundExpression expression, bool used)
        {
            switch (expression.Kind)
            {
                case BoundKind.AssignmentOperator:
                    EmitAssignmentExpression((BoundAssignmentOperator)expression, used ? UseKind.UsedAsValue : UseKind.Unused);
                    break;

                case BoundKind.Call:
                    EmitCallExpression((BoundCall)expression, used ? UseKind.UsedAsValue : UseKind.Unused);
                    break;

                case BoundKind.ObjectCreationExpression:
                    EmitObjectCreationExpression((BoundObjectCreationExpression)expression, used);
                    break;

                case BoundKind.DelegateCreationExpression:
                    EmitDelegateCreationExpression((BoundDelegateCreationExpression)expression, used);
                    break;

                case BoundKind.ArrayCreation:
                    EmitArrayCreationExpression((BoundArrayCreation)expression, used);
                    break;

                case BoundKind.StackAllocArrayCreation:
                    EmitStackAllocArrayCreationExpression((BoundStackAllocArrayCreation)expression, used);
                    break;

                case BoundKind.Conversion:
                    EmitConversionExpression((BoundConversion)expression, used);
                    break;

                case BoundKind.Local:
                    EmitLocalLoad((BoundLocal)expression, used);
                    break;

                case BoundKind.Dup:
                    EmitDupExpression((BoundDup)expression, used);
                    break;

                case BoundKind.Parameter:
                    if (used)  // unused parameter has no side-effects
                    {
                        EmitParameterLoad((BoundParameter)expression);
                    }
                    break;

                case BoundKind.FieldAccess:
                    EmitFieldLoad((BoundFieldAccess)expression, used);
                    break;

                case BoundKind.ArrayAccess:
                    EmitArrayElementLoad((BoundArrayAccess)expression, used);
                    break;

                case BoundKind.ArrayLength:
                    EmitArrayLength((BoundArrayLength)expression, used);
                    break;

                case BoundKind.ThisReference:
                    if (used) // unused this has no side-effects
                    {
                        EmitThisReferenceExpression((BoundThisReference)expression);
                    }
                    break;

                case BoundKind.PreviousSubmissionReference:
                    // Script references are lowered to a this reference and a field access.
                    throw ExceptionUtilities.UnexpectedValue(expression.Kind);

                case BoundKind.BaseReference:
                    if (used) // unused base has no side-effects
                    {
                        var thisType = _method.ContainingType;
                        _builder.EmitOpCode(ILOpCode.Ldarg_0);
                        if (thisType.IsValueType)
                        {
                            EmitLoadIndirect(thisType, expression.Syntax);
                            EmitBox(thisType, expression.Syntax);
                        }
                    }
                    break;

                case BoundKind.Sequence:
                    EmitSequenceExpression((BoundSequence)expression, used);
                    break;

                case BoundKind.SequencePointExpression:
                    EmitSequencePointExpression((BoundSequencePointExpression)expression, used);
                    break;

                case BoundKind.UnaryOperator:
                    EmitUnaryOperatorExpression((BoundUnaryOperator)expression, used);
                    break;

                case BoundKind.BinaryOperator:
                    EmitBinaryOperatorExpression((BoundBinaryOperator)expression, used);
                    break;

                case BoundKind.NullCoalescingOperator:
                    EmitNullCoalescingOperator((BoundNullCoalescingOperator)expression, used);
                    break;

                case BoundKind.IsOperator:
                    EmitIsExpression((BoundIsOperator)expression, used);
                    break;

                case BoundKind.AsOperator:
                    EmitAsExpression((BoundAsOperator)expression, used);
                    break;

                case BoundKind.DefaultOperator:
                    EmitDefaultExpression((BoundDefaultOperator)expression, used);
                    break;

                case BoundKind.TypeOfOperator:
                    if (used) // unused typeof has no side-effects
                    {
                        EmitTypeOfExpression((BoundTypeOfOperator)expression);
                    }
                    break;

                case BoundKind.SizeOfOperator:
                    if (used) // unused sizeof has no side-effects
                    {
                        EmitSizeOfExpression((BoundSizeOfOperator)expression);
                    }
                    break;

                case BoundKind.ModuleVersionId:
                    Debug.Assert(used);
                    EmitModuleVersionIdLoad((BoundModuleVersionId)expression);
                    break;

                case BoundKind.ModuleVersionIdString:
                    Debug.Assert(used);
                    EmitModuleVersionIdStringLoad((BoundModuleVersionIdString)expression);
                    break;

                case BoundKind.InstrumentationPayloadRoot:
                    Debug.Assert(used);
                    EmitInstrumentationPayloadRootLoad((BoundInstrumentationPayloadRoot)expression);
                    break;

                case BoundKind.MethodDefIndex:
                    Debug.Assert(used);
                    EmitMethodDefIndexExpression((BoundMethodDefIndex)expression);
                    break;

                case BoundKind.MaximumMethodDefIndex:
                    Debug.Assert(used);
                    EmitMaximumMethodDefIndexExpression((BoundMaximumMethodDefIndex)expression);
                    break;

                case BoundKind.SourceDocumentIndex:
                    Debug.Assert(used);
                    EmitSourceDocumentIndex((BoundSourceDocumentIndex)expression);
                    break;

                case BoundKind.MethodInfo:
                    if (used)
                    {
                        EmitMethodInfoExpression((BoundMethodInfo)expression);
                    }
                    break;

                case BoundKind.FieldInfo:
                    if (used)
                    {
                        EmitFieldInfoExpression((BoundFieldInfo)expression);
                    }
                    break;

                case BoundKind.ConditionalOperator:
                    EmitConditionalOperator((BoundConditionalOperator)expression, used);
                    break;

                case BoundKind.AddressOfOperator:
                    EmitAddressOfExpression((BoundAddressOfOperator)expression, used);
                    break;

                case BoundKind.PointerIndirectionOperator:
                    EmitPointerIndirectionOperator((BoundPointerIndirectionOperator)expression, used);
                    break;

                case BoundKind.ArgList:
                    EmitArgList(used);
                    break;

                case BoundKind.ArgListOperator:
                    Debug.Assert(used);
                    EmitArgListOperator((BoundArgListOperator)expression);
                    break;

                case BoundKind.RefTypeOperator:
                    EmitRefTypeOperator((BoundRefTypeOperator)expression, used);
                    break;

                case BoundKind.MakeRefOperator:
                    EmitMakeRefOperator((BoundMakeRefOperator)expression, used);
                    break;

                case BoundKind.RefValueOperator:
                    EmitRefValueOperator((BoundRefValueOperator)expression, used);
                    break;

                case BoundKind.LoweredConditionalAccess:
                    EmitLoweredConditionalAccessExpression((BoundLoweredConditionalAccess)expression, used);
                    break;

                case BoundKind.ConditionalReceiver:
                    EmitConditionalReceiver((BoundConditionalReceiver)expression, used);
                    break;

                case BoundKind.ComplexConditionalReceiver:
                    EmitComplexConditionalReceiver((BoundComplexConditionalReceiver)expression, used);
                    break;

                case BoundKind.PseudoVariable:
                    EmitPseudoVariableValue((BoundPseudoVariable)expression, used);
                    break;

                case BoundKind.Void:
                    Debug.Assert(!used);
                    break;

                default:
                    // Code gen should not be invoked if there are errors.
                    Debug.Assert(expression.Kind != BoundKind.BadExpression);

                    // node should have been lowered:
                    throw ExceptionUtilities.UnexpectedValue(expression.Kind);
            }
        }
Exemplo n.º 43
0
        private bool SafeToGetWriteableReference(BoundExpression left)
        {
            if (!HasHome(left))
            {
                return false;
            }

            // because of array covariance, taking a reference to an element of 
            // generic array may fail even though assignment "arr[i] = default(T)" would always succeed.
            if (left.Kind == BoundKind.ArrayAccess && left.Type.TypeKind == TypeKind.TypeParameter && !left.Type.IsValueType)
            {
                return false;
            }

            if (left.Kind == BoundKind.FieldAccess)
            {
                var fieldAccess = (BoundFieldAccess)left;
                if (fieldAccess.FieldSymbol.IsVolatile ||
                    DiagnosticsPass.IsNonAgileFieldAccess(fieldAccess, _module.Compilation))
                {
                    return false;
                }
            }

            return true;
        }
Exemplo n.º 44
0
        // In special case of loading the sequence of field accesses we can perform all the 
        // necessary field loads using the following IL: 
        //
        //      <expr>.a.b...y.z
        //          |
        //          V
        //      Unbox -or- Load.Ref (<expr>)
        //      Ldflda a
        //      Ldflda b
        //      ...
        //      Ldflda y
        //      Ldfld z
        //
        // Returns 'true' if the receiver was actually emitted this way
        private bool EmitFieldLoadReceiverAddress(BoundExpression receiver)
        {
            if (receiver == null || !receiver.Type.IsValueType)
            {
                return false;
            }
            else if (receiver.Kind == BoundKind.Conversion)
            {
                var conversion = (BoundConversion)receiver;
                if (conversion.ConversionKind == ConversionKind.Unboxing)
                {
                    EmitExpression(conversion.Operand, true);
                    _builder.EmitOpCode(ILOpCode.Unbox);
                    EmitSymbolToken(receiver.Type, receiver.Syntax);
                    return true;
                }
            }
            else if (receiver.Kind == BoundKind.FieldAccess)
            {
                var fieldAccess = (BoundFieldAccess)receiver;
                var field = fieldAccess.FieldSymbol;

                if (!field.IsStatic && EmitFieldLoadReceiverAddress(fieldAccess.ReceiverOpt))
                {
                    Debug.Assert(!field.IsVolatile, "volatile valuetype fields are unexpected");

                    _builder.EmitOpCode(ILOpCode.Ldflda);
                    EmitSymbolToken(field, fieldAccess.Syntax);
                    return true;
                }
            }

            return false;
        }
Exemplo n.º 45
0
        private void InPlaceCtorCall(BoundExpression target, BoundObjectCreationExpression objCreation, bool used)
        {
            var temp = EmitAddress(target, AddressKind.Writeable);
            Debug.Assert(temp == null, "in-place ctor target should not create temps");

            var constructor = objCreation.Constructor;
            EmitArguments(objCreation.Arguments, constructor.Parameters);
            // -2 to adjust for consumed target address and not produced value.
            var stackAdjustment = GetObjCreationStackBehavior(objCreation) - 2;
            _builder.EmitOpCode(ILOpCode.Call, stackAdjustment);
            // for variadic ctors emit expanded ctor token
            EmitSymbolToken(constructor, objCreation.Syntax,
                            constructor.IsVararg ? (BoundArgListOperator)objCreation.Arguments[objCreation.Arguments.Length - 1] : null);

            if (used)
            {
                Debug.Assert(TargetIsNotOnHeap(target), "cannot read-back the target since it could have been modified");
                EmitExpression(target, used: true);
            }
        }
            internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
            {
                AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager;
                SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics);

                //  Method body:
                //
                //  {
                //      return String.Format(
                //          "{ <name1> = {0}", <name2> = {1}", ... <nameN> = {N-1}",
                //          this.backingFld_1, 
                //          this.backingFld_2, 
                //          ...
                //          this.backingFld_N
                //  }

                // Type expression
                AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType;

                //  build arguments
                int fieldCount = anonymousType.Properties.Length;
                BoundExpression retExpression = null;

                if (fieldCount > 0)
                {
                    //  we do have fields, so have to use String.Format(...)
                    BoundExpression[] arguments = new BoundExpression[fieldCount];

                    //  process properties
                    PooledStringBuilder formatString = PooledStringBuilder.GetInstance();
                    for (int i = 0; i < fieldCount; i++)
                    {
                        AnonymousTypePropertySymbol property = anonymousType.Properties[i];

                        // build format string
                        formatString.Builder.AppendFormat(i == 0 ? "{{{{ {0} = {{{1}}}" : ", {0} = {{{1}}}", property.Name, i);

                        // build argument
                        arguments[i] = F.Convert(manager.System_Object,
                                                 new BoundLoweredConditionalAccess(F.Syntax,
                                                                            F.Field(F.This(), property.BackingField),
                                                                            null,
                                                                            F.Call(new BoundConditionalReceiver(
                                                                                F.Syntax, 
                                                                                id: i, 
                                                                                type: property.BackingField.Type), manager.System_Object__ToString),
                                                                            null,
                                                                            id: i,
                                                                            type: manager.System_String),
                                                 ConversionKind.ImplicitReference);
                    }
                    formatString.Builder.Append(" }}");

                    //  add format string argument
                    BoundExpression format = F.Literal(formatString.ToStringAndFree());

                    //  Generate expression for return statement
                    //      retExpression <= System.String.Format(args)
                    var formatMethod = manager.System_String__Format_IFormatProvider;
                    retExpression = F.StaticCall(manager.System_String, formatMethod, F.Null(formatMethod.Parameters[0].Type), format, F.Array(manager.System_Object, arguments));
                }
                else
                {
                    //  this is an empty anonymous type, just return "{ }"
                    retExpression = F.Literal("{ }");
                }

                F.CloseMethod(F.Block(F.Return(retExpression)));
            }
Exemplo n.º 47
0
        // returns True when assignment target is definitely not on the heap
        private static bool TargetIsNotOnHeap(BoundExpression left)
        {
            switch (left.Kind)
            {
                case BoundKind.Parameter:
                    return ((BoundParameter)left).ParameterSymbol.RefKind == RefKind.None;

                case BoundKind.Local:
                    // NOTE: stack locals are either homeless or refs, no need to special case them
                    //       they will never be assigned in-place.
                    return ((BoundLocal)left).LocalSymbol.RefKind == RefKind.None;
            }

            return false;
        }
Exemplo n.º 48
0
        internal static BoundExpression ConvertToLocalType(CSharpCompilation compilation, BoundExpression expr, TypeSymbol type, DiagnosticBag diagnostics)
        {
            if (type.IsPointerType())
            {
                var syntax = expr.Syntax;
                var intPtrType = compilation.GetSpecialType(SpecialType.System_IntPtr);
                Binder.ReportUseSiteDiagnostics(intPtrType, diagnostics, syntax);
                MethodSymbol conversionMethod;
                if (Binder.TryGetSpecialTypeMember(compilation, SpecialMember.System_IntPtr__op_Explicit_ToPointer, syntax, diagnostics, out conversionMethod))
                {
                    var temp = ConvertToLocalTypeHelper(compilation, expr, intPtrType, diagnostics);
                    expr = BoundCall.Synthesized(
                        syntax,
                        receiverOpt: null,
                        method: conversionMethod,
                        arg0: temp);
                }
                else
                {
                    return new BoundBadExpression(
                        syntax,
                        LookupResultKind.Empty,
                        ImmutableArray<Symbol>.Empty,
                        ImmutableArray.Create<BoundNode>(expr),
                        type);
                }
            }

            return ConvertToLocalTypeHelper(compilation, expr, type, diagnostics);
        }
Exemplo n.º 49
0
        // Implicit casts are not emitted. As a result verifier may operate on a different 
        // types from the types of operands when performing stack merges in coalesce/ternary.
        // Such differences are in general irrelevant since merging rules work the same way
        // for base and derived types.
        //
        // Situation becomes more complicated with delegates, arrays and interfaces since they 
        // allow implicit casts from types that do not derive from them. In such cases
        // we may need to introduce static casts in the code to prod the verifier to the 
        // right direction
        //
        // This helper returns actual type of array|interface|delegate expression ignoring implicit 
        // casts. This would be the effective stack merge type in the verifier.
        // 
        // NOTE: In cases where stack merge type cannot be determined, we just return null.
        //       We still must assume that it can be an array, delegate or interface though.
        private TypeSymbol StackMergeType(BoundExpression expr)
        {
            // these cases are not interesting. Merge type is the same or derived. No difference.
            if (!(expr.Type.IsArray() || expr.Type.IsInterfaceType() || expr.Type.IsDelegateType()))
            {
                return expr.Type;
            }

            // Dig through casts. We only need to check for expressions that -
            // 1) implicit casts
            // 2) transparently return operands, so we need to dig deeper
            // 3) stack values
            switch (expr.Kind)
            {
                case BoundKind.Conversion:
                    var conversion = (BoundConversion)expr;
                    var conversionKind = conversion.ConversionKind;
                    if (conversionKind.IsImplicitConversion() &&
                        conversionKind != ConversionKind.MethodGroup &&
                        conversionKind != ConversionKind.NullLiteral)
                    {
                        return StackMergeType(conversion.Operand);
                    }
                    break;

                case BoundKind.AssignmentOperator:
                    var assignment = (BoundAssignmentOperator)expr;
                    return StackMergeType(assignment.Right);

                case BoundKind.Sequence:
                    var sequence = (BoundSequence)expr;
                    return StackMergeType(sequence.Value);

                case BoundKind.Local:
                    var local = (BoundLocal)expr;
                    if (this.IsStackLocal(local.LocalSymbol))
                    {
                        // stack value, we cannot be sure what it is
                        return null;
                    }
                    break;

                case BoundKind.Dup:
                    // stack value, we cannot be sure what it is
                    return null;
            }

            return expr.Type;
        }
Exemplo n.º 50
0
 private static OverloadResolutionResult <UnaryOperatorSignature> LookupUnaryOperator(UnaryOperatorKind operatorKind, BoundExpression operand)
 {
     return(UnaryOperator.Resolve(operatorKind, operand.Type));
 }
Exemplo n.º 51
0
        internal static ConstantValue GetAndValidateConstantValue(
            BoundExpression boundValue,
            Symbol thisSymbol,
            TypeSymbol typeSymbol,
            Location initValueNodeLocation,
            DiagnosticBag diagnostics)
        {
            var value = ConstantValue.Bad;

            if (!boundValue.HasAnyErrors)
            {
                if (typeSymbol.TypeKind == TypeKind.TypeParameter)
                {
                    diagnostics.Add(ErrorCode.ERR_InvalidConstantDeclarationType, initValueNodeLocation, thisSymbol, typeSymbol);
                }
                else
                {
                    bool hasDynamicConversion  = false;
                    var  unconvertedBoundValue = boundValue;
                    while (unconvertedBoundValue.Kind == BoundKind.Conversion)
                    {
                        var conversion = (BoundConversion)unconvertedBoundValue;
                        hasDynamicConversion  = hasDynamicConversion || conversion.ConversionKind.IsDynamic();
                        unconvertedBoundValue = conversion.Operand;
                    }

                    // If we have already computed the unconverted constant value, then this call is cheap
                    // because BoundConversions store their constant values (i.e. not recomputing anything).
                    var constantValue = boundValue.ConstantValue;

                    var unconvertedConstantValue = unconvertedBoundValue.ConstantValue;
                    if (unconvertedConstantValue != null &&
                        !unconvertedConstantValue.IsNull &&
                        typeSymbol.IsReferenceType &&
                        typeSymbol.SpecialType != SpecialType.System_String)
                    {
                        // Suppose we are in this case:
                        //
                        // const object x = "some_string"
                        //
                        // A constant of type object can only be initialized to
                        // null; it may not contain an implicit reference conversion
                        // from string.
                        //
                        // Give a special error for that case.
                        diagnostics.Add(ErrorCode.ERR_NotNullConstRefField, initValueNodeLocation, thisSymbol, typeSymbol);

                        // If we get here, then the constantValue will likely be null.
                        // However, it seems reasonable to assume that the programmer will correct the error not
                        // by changing the value to "null", but by updating the type of the constant.  Consequently,
                        // we retain the unconverted constant value so that it can propagate through the rest of
                        // constant folding.
                        constantValue = constantValue ?? unconvertedConstantValue;
                    }

                    if (constantValue != null && !hasDynamicConversion)
                    {
                        value = constantValue;
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.ERR_NotConstantExpression, initValueNodeLocation, thisSymbol);
                    }
                }
            }

            return(value);
        }
Exemplo n.º 52
0
 internal override ImmutableArray <Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue)
 {
     return(default(ImmutableArray <Diagnostic>));
 }
Exemplo n.º 53
0
        private LocalDefinition EmitFieldLoadReceiver(BoundExpression receiver)
        {
            // ldfld can work with structs directly or with their addresses
            // accessing via address is typically same or cheaper, but not for homeless values, obviously
            // there are also cases where we must emit receiver as a reference
            if (FieldLoadMustUseRef(receiver) || FieldLoadPrefersRef(receiver))
            {
                return EmitFieldLoadReceiverAddress(receiver) ? null : EmitReceiverRef(receiver);
            }

            EmitExpression(receiver, true);
            return null;
        }
Exemplo n.º 54
0
 public BoundIfStatement(BoundExpression condition, BoundStatement thenStatement, BoundStatement elseStatement)
 {
     Condition     = condition;
     ThenStatement = thenStatement;
     ElseStatement = elseStatement;
 }
Exemplo n.º 55
0
        // ldfld can work with structs directly or with their addresses
        // In some cases it results in same native code emitted, but in some cases JIT pushes values for real
        // resulting in much worse code (on x64 in particular).
        // So, we will always prefer references here except when receiver is a struct non-ref local or parameter. 
        private bool FieldLoadPrefersRef(BoundExpression receiver)
        {
            // only fields of structs can be accessed via value
            if (!receiver.Type.IsVerifierValue())
            {
                return true;
            }

            // can unbox directly into a ref.
            if (receiver.Kind == BoundKind.Conversion && ((BoundConversion)receiver).ConversionKind == ConversionKind.Unboxing)
            {
                return true;
            }

            // can we take address at all?
            if (!HasHome(receiver))
            {
                return false;
            }

            switch (receiver.Kind)
            {
                case BoundKind.Parameter:
                    // prefer ldarg over ldarga
                    return ((BoundParameter)receiver).ParameterSymbol.RefKind != RefKind.None;

                case BoundKind.Local:
                    // prefer ldloc over ldloca
                    return ((BoundLocal)receiver).LocalSymbol.RefKind != RefKind.None;

                case BoundKind.Sequence:
                    return FieldLoadPrefersRef(((BoundSequence)receiver).Value);

                case BoundKind.FieldAccess:
                    var fieldAccess = (BoundFieldAccess)receiver;
                    if (fieldAccess.FieldSymbol.IsStatic)
                    {
                        return true;
                    }

                    if (DiagnosticsPass.IsNonAgileFieldAccess(fieldAccess, _module.Compilation))
                    {
                        return false;
                    }

                    return FieldLoadPrefersRef(fieldAccess.ReceiverOpt);
            }

            return true;
        }
Exemplo n.º 56
0
 public BoundVariableDeclaration(VariableSymbol variable, BoundExpression initializer)
 {
     Variable    = variable;
     Initializer = initializer;
 }
Exemplo n.º 57
0
        internal static bool ReportDefaultParameterErrors(
            Binder binder,
            Symbol owner,
            ParameterSyntax parameterSyntax,
            SourceParameterSymbol parameter,
            BoundExpression defaultExpression,
            DiagnosticBag diagnostics)
        {
            bool hasErrors = false;

            // SPEC VIOLATION: The spec says that the conversion from the initializer to the 
            // parameter type is required to be either an identity or a nullable conversion, but
            // that is not right:
            //
            // void M(short myShort = 10) {}
            // * not an identity or nullable conversion but should be legal
            //
            // void M(object obj = (dynamic)null) {}
            // * an identity conversion, but should be illegal
            //
            // void M(MyStruct? myStruct = default(MyStruct)) {}
            // * a nullable conversion, but must be illegal because we cannot generate metadata for it
            // 
            // Even if the expression is thoroughly illegal, we still want to bind it and 
            // stick it in the parameter because we want to be able to analyze it for
            // IntelliSense purposes.

            TypeSymbol parameterType = parameter.Type;
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            Conversion conversion = binder.Conversions.ClassifyImplicitConversionFromExpression(defaultExpression, parameterType, ref useSiteDiagnostics);
            diagnostics.Add(defaultExpression.Syntax, useSiteDiagnostics);

            // SPEC VIOLATION: 
            // By the spec an optional parameter initializer is required to be either:
            // * a constant,
            // * new S() where S is a value type
            // * default(S) where S is a value type.
            // 
            // The native compiler considers default(T) to be a valid
            // initializer regardless of whether T is a value type
            // reference type, type parameter type, and so on.
            // We should consider simply allowing this in the spec.
            //
            // Also when valuetype S has a parameterless constructor, 
            // new S() is clearly not a constant expression and should produce an error

            bool isValidDefaultValue = (defaultExpression.ConstantValue != null) ||
                                        (defaultExpression.Kind == BoundKind.DefaultOperator) ||
                                        (defaultExpression.Kind == BoundKind.ObjectCreationExpression &&
                                                ((BoundObjectCreationExpression)defaultExpression).Constructor.IsDefaultValueTypeConstructor());

            SyntaxToken outKeyword;
            SyntaxToken refKeyword;
            SyntaxToken paramsKeyword;
            SyntaxToken thisKeyword;
            GetModifiers(parameterSyntax.Modifiers, out outKeyword, out refKeyword, out paramsKeyword, out thisKeyword);

            // CONSIDER: We are inconsistent here regarding where the error is reported; is it
            // CONSIDER: reported on the parameter name, or on the value of the initializer?
            // CONSIDER: Consider making this consistent.

            if (outKeyword.Kind() == SyntaxKind.OutKeyword)
            {
                // error CS1741: A ref or out parameter cannot have a default value
                diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, outKeyword.GetLocation());
                hasErrors = true;
            }
            else if (refKeyword.Kind() == SyntaxKind.RefKeyword)
            {
                // error CS1741: A ref or out parameter cannot have a default value
                diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, refKeyword.GetLocation());
                hasErrors = true;
            }
            else if (paramsKeyword.Kind() == SyntaxKind.ParamsKeyword)
            {
                // error CS1751: Cannot specify a default value for a parameter array
                diagnostics.Add(ErrorCode.ERR_DefaultValueForParamsParameter, paramsKeyword.GetLocation());
                hasErrors = true;
            }
            else if (thisKeyword.Kind() == SyntaxKind.ThisKeyword)
            {
                // Only need to report CS1743 for the first parameter. The caller will
                // have reported CS1100 if 'this' appeared on another parameter.
                if (parameter.Ordinal == 0)
                {
                    // error CS1743: Cannot specify a default value for the 'this' parameter
                    diagnostics.Add(ErrorCode.ERR_DefaultValueForExtensionParameter, thisKeyword.GetLocation());
                    hasErrors = true;
                }
            }
            else if (!defaultExpression.HasAnyErrors && !isValidDefaultValue)
            {
                // error CS1736: Default parameter value for '{0}' must be a compile-time constant
                diagnostics.Add(ErrorCode.ERR_DefaultValueMustBeConstant, parameterSyntax.Default.Value.Location, parameterSyntax.Identifier.ValueText);
                hasErrors = true;
            }
            else if (!conversion.Exists ||
                conversion.IsUserDefined ||
                conversion.IsIdentity && parameterType.SpecialType == SpecialType.System_Object && defaultExpression.Type.IsDynamic())
            {
                // If we had no implicit conversion, or a user-defined conversion, report an error.
                //
                // Even though "object x = (dynamic)null" is a legal identity conversion, we do not allow it. 
                // CONSIDER: We could. Doesn't hurt anything.

                // error CS1750: A value of type '{0}' cannot be used as a default parameter because there are no standard conversions to type '{1}'
                diagnostics.Add(ErrorCode.ERR_NoConversionForDefaultParam, parameterSyntax.Identifier.GetLocation(),
                    defaultExpression.Type ?? defaultExpression.Display, parameterType);

                hasErrors = true;
            }
            else if (conversion.IsReference &&
                (parameterType.SpecialType == SpecialType.System_Object || parameterType.Kind == SymbolKind.DynamicType) &&
                (object)defaultExpression.Type != null &&
                defaultExpression.Type.SpecialType == SpecialType.System_String ||
                conversion.IsBoxing)
            {
                // We don't allow object x = "hello", object x = 123, dynamic x = "hello", etc.
                // error CS1763: '{0}' is of type '{1}'. A default parameter value of a reference type other than string can only be initialized with null
                diagnostics.Add(ErrorCode.ERR_NotNullRefDefaultParameter, parameterSyntax.Identifier.GetLocation(),
                    parameterSyntax.Identifier.ValueText, parameterType);

                hasErrors = true;
            }
            else if (conversion.IsNullable && defaultExpression.Kind == BoundKind.DefaultOperator && !defaultExpression.Type.IsNullableType() &&
                !(parameterType.GetNullableUnderlyingType().IsEnumType() || parameterType.GetNullableUnderlyingType().IsIntrinsicType()))
            {
                // We can do:
                // M(int? x = default(int)) 
                // M(int? x = default(int?)) 
                // M(MyEnum? e = default(enum))
                // M(MyEnum? e = default(enum?))
                // M(MyStruct? s = default(MyStruct?))
                //
                // but we cannot do:
                //
                // M(MyStruct? s = default(MyStruct))

                // error CS1770: 
                // A value of type '{0}' cannot be used as default parameter for nullable parameter '{1}' because '{0}' is not a simple type
                diagnostics.Add(ErrorCode.ERR_NoConversionForNubDefaultParam, parameterSyntax.Identifier.GetLocation(),
                    defaultExpression.Type, parameterSyntax.Identifier.ValueText);

                hasErrors = true;
            }

            // Certain contexts allow default parameter values syntactically but they are ignored during
            // semantic analysis. They are:

            // 1. Explicitly implemented interface methods; since the method will always be called
            //    via the interface, the defaults declared on the implementation will not 
            //    be seen at the call site.
            //
            // UNDONE: 2. The "actual" side of a partial method; the default values are taken from the
            // UNDONE:    "declaring" side of the method.
            //
            // UNDONE: 3. An indexer with only one formal parameter; it is illegal to omit every argument
            // UNDONE:    to an indexer.
            //
            // 4. A user-defined operator; it is syntactically impossible to omit the argument.

            if (owner.IsExplicitInterfaceImplementation() ||
                owner.IsPartialImplementation() ||
                owner.IsOperator())
            {
                // CS1066: The default value specified for parameter '{0}' will have no effect because it applies to a 
                //         member that is used in contexts that do not allow optional arguments
                diagnostics.Add(ErrorCode.WRN_DefaultValueForUnconsumedLocation,
                    parameterSyntax.Identifier.GetLocation(),
                    parameterSyntax.Identifier.ValueText);
            }

            return hasErrors;
        }
Exemplo n.º 58
0
        /// <summary>
        /// In case expression is of type <c>Int32</c> or <c>bool</c> or <c>PhpNumber</c>,
        /// converts it to <c>double</c> and leaves the result on evaluation stack. Otherwise
        /// just emits expression and leaves it on evaluation stack.
        /// </summary>
        internal TypeSymbol EmitExprConvertNumberToDouble(BoundExpression expr)
        {
            // emit number literal directly as double
            var constant = expr.ConstantValue;

            if (constant.HasValue)
            {
                if (constant.Value is long)
                {
                    _il.EmitDoubleConstant((long)constant.Value);
                    return(this.CoreTypes.Double);
                }
                if (constant.Value is int)
                {
                    _il.EmitDoubleConstant((int)constant.Value);
                    return(this.CoreTypes.Double);
                }
                if (constant.Value is bool)
                {
                    _il.EmitDoubleConstant((bool)constant.Value ? 1.0 : 0.0);
                    return(this.CoreTypes.Double);
                }
            }

            // emit fast ToDouble() in case of a PhpNumber variable
            var place = PlaceOrNull(expr);
            var type  = TryEmitVariableSpecialize(place, expr.TypeRefMask);

            if (type == null)
            {
                if (place != null && place.HasAddress)
                {
                    if (place.Type == CoreTypes.PhpNumber)
                    {
                        place.EmitLoadAddress(_il);
                        return(EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToDouble)
                               .Expect(SpecialType.System_Double));
                    }
                }

                type = EmitSpecialize(expr);
            }

            Debug.Assert(type != null);

            if (type.SpecialType == SpecialType.System_Int32 ||
                type.SpecialType == SpecialType.System_Int64 ||
                type.SpecialType == SpecialType.System_Boolean)
            {
                _il.EmitOpCode(ILOpCode.Conv_r8);    // int|bool -> long
                type = this.CoreTypes.Double;
            }
            else if (type == CoreTypes.PhpNumber)
            {
                EmitPhpNumberAddr();
                EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToDouble);    // number -> double
                type = this.CoreTypes.Double;
            }

            //
            return(type);
        }
Exemplo n.º 59
0
        private static BoundExpression ConvertToLocalTypeHelper(CSharpCompilation compilation, BoundExpression expr, TypeSymbol type, DiagnosticBag diagnostics)
        {
            // NOTE: This conversion can fail if some of the types involved are from not-yet-loaded modules.
            // For example, if System.Exception hasn't been loaded, then this call will fail for $stowedexception.
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            var conversion = compilation.Conversions.ClassifyConversionFromExpression(expr, type, ref useSiteDiagnostics);
            diagnostics.Add(expr.Syntax, useSiteDiagnostics);
            Debug.Assert(conversion.IsValid || diagnostics.HasAnyErrors());

            return BoundConversion.Synthesized(
                expr.Syntax,
                expr,
                conversion,
                @checked: false,
                explicitCastInCode: false,
                constantValueOpt: null,
                type: type,
                hasErrors: !conversion.IsValid);
        }
Exemplo n.º 60
0
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     BoundExpression expression = (BoundExpression)this.Visit(node.Expression);
     TypeSymbol type = this.VisitType(node.Type);
     return node.Update(expression, VisitMethodSymbol(node.GetAwaiter), VisitPropertySymbol(node.IsCompleted), VisitMethodSymbol(node.GetResult), type);
 }