Example #1
0
        private BoundExpression MakeIsOperator(
            BoundIsOperator oldNode,
            SyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType
            )
        {
            if (rewrittenOperand.Kind == BoundKind.MethodGroup)
            {
                var             methodGroup = (BoundMethodGroup)rewrittenOperand;
                BoundExpression?receiver    = methodGroup.ReceiverOpt;
                if (receiver != null && receiver.Kind != BoundKind.ThisReference)
                {
                    // possible side-effect
                    return(RewriteConstantIsOperator(
                               receiver.Syntax,
                               receiver,
                               ConstantValue.False,
                               rewrittenType
                               ));
                }
                else
                {
                    return(MakeLiteral(syntax, ConstantValue.False, rewrittenType));
                }
            }

            var operandType = rewrittenOperand.Type;
            var targetType  = rewrittenTargetType.Type;

            Debug.Assert(operandType is { } || rewrittenOperand.ConstantValue !.IsNull);
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            SyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!_inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    Debug.Assert(constantValue.IsNull);
                    BoundExpression result = rewrittenType.IsNullableType() ? new BoundDefaultExpression(syntax, rewrittenType) : MakeLiteral(syntax, constantValue, rewrittenType);

                    if (rewrittenOperand.ConstantValue != null)
                    {
                        // No need to preserve any side-effects from the operand.
                        // We also can keep the "constant" notion of the result, which
                        // enables some optimizations down the road.
                        return(result);
                    }

                    return(new BoundSequence(
                               syntax: syntax,
                               locals: ImmutableArray <LocalSymbol> .Empty,
                               sideEffects: ImmutableArray.Create <BoundExpression>(rewrittenOperand),
                               value: result,
                               type: rewrittenType));
                }

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return(MakeConversionNode(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
        private BoundExpression MakeIsOperator(
            BoundIsOperator oldNode,
            SyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            if (rewrittenOperand.Kind == BoundKind.MethodGroup)
            {
                var             methodGroup = (BoundMethodGroup)rewrittenOperand;
                BoundExpression receiver    = methodGroup.ReceiverOpt;
                if (receiver != null && receiver.Kind != BoundKind.ThisReference)
                {
                    // possible side-effect
                    return(RewriteConstantIsOperator(receiver.Syntax, receiver, ConstantValue.False, rewrittenType));
                }
                else
                {
                    return(MakeLiteral(syntax, ConstantValue.False, rewrittenType));
                }
            }

            var operandType = rewrittenOperand.Type;
            var targetType  = rewrittenTargetType.Type;

            Debug.Assert((object)operandType != null || rewrittenOperand.ConstantValue.IsNull);
            Debug.Assert((object)targetType != null);

            // TODO: Handle dynamic operand type and target type

            if (!_inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetIsOperatorConstantResult(operandType, targetType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    return(RewriteConstantIsOperator(syntax, rewrittenOperand, constantValue, rewrittenType));
                }
                else if (conversion.IsImplicit)
                {
                    // operand is a reference type with bound identity or implicit conversion
                    // We can replace the "is" instruction with a null check
                    return(MakeNullCheck(syntax, rewrittenOperand, BinaryOperatorKind.NotEqual));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!_inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    Debug.Assert(constantValue.IsNull);
                    BoundExpression result = rewrittenType.IsNullableType() ? new BoundDefaultOperator(syntax, rewrittenType) : MakeLiteral(syntax, constantValue, rewrittenType);

                    if (rewrittenOperand.ConstantValue != null)
                    {
                        // No need to preserve any side-effects from the operand. 
                        // We also can keep the "constant" notion of the result, which
                        // enables some optimizations down the road.
                        return result;
                    }

                    return new BoundSequence(
                        syntax: syntax,
                        locals: ImmutableArray<LocalSymbol>.Empty,
                        sideEffects: ImmutableArray.Create<BoundExpression>(rewrittenOperand),
                        value: result,
                        type: rewrittenType);
                }

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return MakeConversionNode(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false);
                }
            }

            return oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType);
        }
        public override BoundNode VisitIsOperator(BoundIsOperator node)
        {
            BoundExpression     operand    = (BoundExpression)this.Visit(node.Operand);
            BoundTypeExpression targetType = (BoundTypeExpression)this.Visit(node.TargetType);
            TypeSymbol          type       = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return(node.Update(operand, targetType, node.Conversion, type));
            }

            var spill         = (BoundSpillSequence)operand;
            var newIsOperator = node.Update(spill.Value, targetType, node.Conversion, type);

            return(RewriteSpillSequence(spill, newIsOperator));
        }
Example #6
0
        private void XsInsertMissingOptionalArguments(SyntaxNode syntax,
                                                      ImmutableArray <ParameterSymbol> parameters,
                                                      BoundExpression[] arguments,
                                                      ArrayBuilder <RefKind> refKinds,
                                                      ArrayBuilder <LocalSymbol> temps,
                                                      ThreeState enableCallerInfo = ThreeState.Unknown
                                                      )
        {
            Debug.Assert(refKinds.Count == arguments.Length);
            for (int p = 0; p < arguments.Length; ++p)
            {
                if (arguments[p] == null || arguments[p].Syntax.XIsMissingArgument)
                {
                    ParameterSymbol parameter = parameters[p];
                    BoundExpression expr      = GetDefaultParameterValue(syntax, parameter, enableCallerInfo);
                    if (expr is BoundDefaultExpression && parameter.Type == _compilation.UsualType())
                    {
                        var flds = _compilation.UsualType().GetMembers("_NIL");
                        var type = new BoundTypeExpression(syntax, null, _compilation.UsualType());
                        expr = _factory.Field(type, (FieldSymbol)flds[0]);
                    }

                    BoundAssignmentOperator boundAssignmentToTemp;
                    BoundLocal boundTemp = _factory.StoreToTemp(expr, out boundAssignmentToTemp);
                    expr = new BoundSequence(
                        syntax,
                        locals: ImmutableArray <LocalSymbol> .Empty,
                        sideEffects: ImmutableArray.Create <BoundExpression>(boundAssignmentToTemp),
                        value: boundTemp,
                        type: boundTemp.Type);
                    refKinds[p] = parameters[p].RefKind;
                    temps.Add(boundTemp.LocalSymbol);


                    arguments[p] = expr;
                    Debug.Assert(arguments[p].Type == parameter.Type);

                    if (parameters[p].RefKind == RefKind.In)
                    {
                        Debug.Assert(refKinds[p] == RefKind.None);
                        refKinds[p] = RefKind.In;
                    }
                }
            }
        }
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);
                Debug.Assert(constantValue == null || constantValue.IsNull);

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return MakeConversion(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false, constantValueOpt: constantValue);
                }
                else if (constantValue != null)
                {
                    return new BoundSequence(
                        syntax: syntax,
                        locals: ImmutableArray<LocalSymbol>.Empty,
                        sideEffects: ImmutableArray.Create<BoundExpression>(rewrittenOperand),
                        value: MakeLiteral(syntax, constantValue, rewrittenType),
                        type: rewrittenType);
                }
            }

            return oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType);
        }
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);
                Debug.Assert(constantValue == null || constantValue.IsNull);

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return(MakeConversion(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false, constantValueOpt: constantValue));
                }
                else if (constantValue != null)
                {
                    return(new BoundSequence(
                               syntax: syntax,
                               locals: ImmutableArray <LocalSymbol> .Empty,
                               sideEffects: ImmutableArray.Create <BoundExpression>(rewrittenOperand),
                               value: MakeLiteral(syntax, constantValue, rewrittenType),
                               type: rewrittenType));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
        private BoundExpression MakeIsOperator(
            BoundIsOperator oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            if (rewrittenOperand.Kind == BoundKind.MethodGroup)
            {
                var methodGroup = (BoundMethodGroup)rewrittenOperand;
                BoundExpression receiver = methodGroup.ReceiverOpt;
                if (receiver != null && receiver.Kind != BoundKind.ThisReference)
                {
                    // possible side-effect
                    return RewriteConstantIsOperator(receiver.Syntax, receiver, ConstantValue.False, rewrittenType);
                }
                else
                {
                    return MakeLiteral(syntax, ConstantValue.False, rewrittenType);
                }
            }

            var operandType = rewrittenOperand.Type;
            var targetType = rewrittenTargetType.Type;

            Debug.Assert((object)operandType != null || rewrittenOperand.ConstantValue.IsNull);
            Debug.Assert((object)targetType != null);

            // TODO: Handle dynamic operand type and target type

            if (!inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetIsOperatorConstantResult(operandType, targetType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    return RewriteConstantIsOperator(syntax, rewrittenOperand, constantValue, rewrittenType);
                }
                else if (conversion.IsImplicit)
                {
                    // operand is a reference type with bound identity or implicit conversion
                    // We can replace the "is" instruction with a null check

                    Debug.Assert((object)operandType != null);
                    if (operandType.TypeKind == TypeKind.TypeParameter)
                    {
                        // We need to box the type parameter even if it is a known
                        // reference type to ensure there are no verifier errors
                        rewrittenOperand = MakeConversion(
                            syntax: rewrittenOperand.Syntax,
                            rewrittenOperand: rewrittenOperand,
                            conversionKind: ConversionKind.Boxing,
                            rewrittenType: compilation.GetSpecialType(SpecialType.System_Object),
                            @checked: false);
                    }

                    return MakeNullCheck(syntax, rewrittenOperand, BinaryOperatorKind.NotEqual);
                }
            }

            return oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType);
        }
Example #10
0
        private BoundPattern BindDeclarationPattern(
            DeclarationPatternSyntax node,
            BoundExpression operand,
            TypeSymbol operandType,
            bool hasErrors,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(operand != null && operandType != (object)null);

            var typeSyntax = node.Type;

            bool isVar;
            AliasSymbol aliasOpt;
            TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt);
            if (isVar)
            {
                declType = operandType;
            }

            if (declType == (object)null)
            {
                Debug.Assert(hasErrors);
                declType = this.CreateErrorType("var");
            }

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);
            if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics))
            {
                hasErrors = true;
            }
            else
            {
                hasErrors |= CheckValidPatternType(typeSyntax, operand, operandType, declType,
                                                   isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
            }

            switch (node.Designation.Kind())
            {
                case SyntaxKind.SingleVariableDesignation:
                    break;
                case SyntaxKind.DiscardedDesignation:
                    return new BoundDeclarationPattern(node, null, boundDeclType, isVar, hasErrors);
                default:
                    throw ExceptionUtilities.UnexpectedValue(node.Designation.Kind());
            }

            var designation = (SingleVariableDesignationSyntax)node.Designation;
            var identifier = designation.Identifier;
            SourceLocalSymbol localSymbol = this.LookupLocal(identifier);

            if (localSymbol != (object)null)
            {
                if (InConstructorInitializer || InFieldInitializer)
                {
                    Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, node);
                }

                localSymbol.SetType(declType);

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

                if (!hasErrors)
                {
                    hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax);
                }

                return new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors);
            }
            else
            {
                // We should have the right binder in the chain for a script or interactive, so we use the field for the pattern.
                Debug.Assert(node.SyntaxTree.Options.Kind != SourceCodeKind.Regular);
                GlobalExpressionVariable expressionVariableField = LookupDeclaredField(designation);
                DiagnosticBag tempDiagnostics = DiagnosticBag.GetInstance();
                expressionVariableField.SetType(declType, tempDiagnostics);
                tempDiagnostics.Free();
                BoundExpression receiver = SynthesizeReceiver(node, expressionVariableField, diagnostics);
                var variableAccess = new BoundFieldAccess(node, receiver, expressionVariableField, null, hasErrors);
                return new BoundDeclarationPattern(node, expressionVariableField, variableAccess, boundDeclType, isVar, hasErrors);
            }
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        ///
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;

            Debug.Assert(enumeratorInfo != null);

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            BoundExpression rewrittenExpression  = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody        = (BoundStatement)Visit(node.Body);

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType    = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = _factory.SynthesizedLocal(enumeratorType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachEnumerator);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = MakeConversion(
                syntax: forEachSyntax,
                rewrittenOperand: MakeConversion(
                    syntax: forEachSyntax,
                    rewrittenOperand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    rewrittenType: elementType,
                    @checked: node.Checked),
                conversion: node.ElementConversion,
                rewrittenType: iterationVar.Type,
                @checked: node.Checked);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }

            var rewrittenBodyBlock = CreateBlockDeclaringIterationVariable(iterationVar, iterationVarDecl, rewrittenBody, forEachSyntax);

            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: rewrittenBodyBlock,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            MethodSymbol disposeMethod;

            if (enumeratorInfo.NeedsDisposeMethod && Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, forEachSyntax, _diagnostics, out disposeMethod))
            {
                Binder.ReportDiagnosticsIfObsolete(_diagnostics, disposeMethod, forEachSyntax,
                                                   hasBaseReceiver: false,
                                                   containingMember: _factory.CurrentMethod,
                                                   containingType: _factory.CurrentType,
                                                   location: enumeratorInfo.Location);

                BoundBlock finallyBlockOpt;
                var        idisposableTypeSymbol = disposeMethod.ContainingType;
                var        conversions           = new TypeConversions(_factory.CurrentMethod.ContainingAssembly.CorLibrary);

                HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                var isImplicit = conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol, ref useSiteDiagnostics).IsImplicit;
                _diagnostics.Add(forEachSyntax, useSiteDiagnostics);

                if (isImplicit)
                {
                    Debug.Assert(enumeratorInfo.NeedsDisposeMethod);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                                                    Conversion.Boxing :
                                                    Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                                                                              expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, disposeMethod, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose();
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                        operatorKind: BinaryOperatorKind.NotEqual,
                                                                        left: MakeConversion(
                                                                            syntax: forEachSyntax,
                                                                            rewrittenOperand: boundEnumeratorVar,
                                                                            conversion: enumeratorInfo.EnumeratorConversion,
                                                                            rewrittenType: _compilation.GetSpecialType(SpecialType.System_Object),
                                                                            @checked: false),
                                                                        right: MakeLiteral(forEachSyntax,
                                                                                           constantValue: ConstantValue.Null,
                                                                                           type: null),
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray <LocalSymbol> .Empty,
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = _factory.SynthesizedLocal(idisposableTypeSymbol);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                                                                                           aliasOpt: null,
                                                                                           type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                                                                                 operand: boundEnumeratorVar,
                                                                                 targetType: boundIDisposableTypeExpr,
                                                                                 conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                                                                                 type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                    operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                                                                    left: boundDisposableVar,
                                                                    right: MakeLiteral(forEachSyntax,
                                                                                       constantValue: ConstantValue.Null,
                                                                                       type: null),
                                                                    constantValueOpt: null,
                                                                    methodOpt: null,
                                                                    resultKind: LookupResultKind.Viable,
                                                                    type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                                                                           expression: BoundCall.Synthesized(
                                                                               syntax: forEachSyntax,
                                                                               receiverOpt: boundDisposableVar,
                                                                               method: disposeMethod)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray.Create <LocalSymbol>(disposableVar),
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                                                                  tryBlock: new BoundBlock(forEachSyntax,
                                                                                           locals: ImmutableArray <LocalSymbol> .Empty,
                                                                                           localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                                                           statements: ImmutableArray.Create <BoundStatement>(whileLoop)),
                                                                  catchBlocks: ImmutableArray <BoundCatchBlock> .Empty,
                                                                  finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
Example #12
0
        public BoundExpression VisitDynamicInvocation(BoundDynamicInvocation node, bool resultDiscarded)
        {
            var loweredArguments = VisitList(node.Arguments);

            bool hasImplicitReceiver;
            BoundExpression loweredReceiver;
            ImmutableArray<TypeSymbol> typeArguments;
            string name;
            switch (node.Expression.Kind)
            {
                case BoundKind.MethodGroup:
                    // method invocation
                    BoundMethodGroup methodGroup = (BoundMethodGroup)node.Expression;
                    typeArguments = methodGroup.TypeArgumentsOpt;
                    name = methodGroup.Name;
                    hasImplicitReceiver = (methodGroup.Flags & BoundMethodGroupFlags.HasImplicitReceiver) != 0;

                    // Should have been eliminated during binding of dynamic invocation:
                    Debug.Assert(methodGroup.ReceiverOpt == null || methodGroup.ReceiverOpt.Kind != BoundKind.TypeOrValueExpression);

                    if (methodGroup.ReceiverOpt == null)
                    {
                        // Calling a static method defined on an outer class via its simple name.
                        NamedTypeSymbol firstContainer = node.ApplicableMethods.First().ContainingType;
                        Debug.Assert(node.ApplicableMethods.All(m => m.IsStatic && m.ContainingType == firstContainer));

                        loweredReceiver = new BoundTypeExpression(node.Syntax, null, firstContainer);
                    }
                    else if (hasImplicitReceiver && _factory.TopLevelMethod.IsStatic)
                    {
                        // Calling a static method defined on the current class via its simple name.
                        loweredReceiver = new BoundTypeExpression(node.Syntax, null, _factory.CurrentType);
                    }
                    else
                    {
                        loweredReceiver = VisitExpression(methodGroup.ReceiverOpt);
                    }

                    // If we are calling a method on a NoPIA type, we need to embed all methods/properties
                    // with the matching name of this dynamic invocation.
                    EmbedIfNeedTo(loweredReceiver, methodGroup.Methods, node.Syntax);

                    break;

                case BoundKind.DynamicMemberAccess:
                    // method invocation
                    var memberAccess = (BoundDynamicMemberAccess)node.Expression;
                    name = memberAccess.Name;
                    typeArguments = memberAccess.TypeArgumentsOpt;
                    loweredReceiver = VisitExpression(memberAccess.Receiver);
                    hasImplicitReceiver = false;
                    break;

                default:
                    // delegate invocation
                    var loweredExpression = VisitExpression(node.Expression);
                    return _dynamicFactory.MakeDynamicInvocation(loweredExpression, loweredArguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, resultDiscarded).ToExpression();
            }

            Debug.Assert(loweredReceiver != null);
            return _dynamicFactory.MakeDynamicMemberInvocation(
                name,
                loweredReceiver,
                typeArguments,
                loweredArguments,
                node.ArgumentNamesOpt,
                node.ArgumentRefKindsOpt,
                hasImplicitReceiver,
                resultDiscarded).ToExpression();
        }
Example #13
0
        private BoundPattern BindDeclarationPattern(
            DeclarationPatternSyntax node,
            TypeSymbol operandType,
            bool hasErrors,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(operandType != (object)null);

            var typeSyntax = node.Type;

            bool        isVar;
            AliasSymbol aliasOpt;
            TypeSymbol  declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar, out aliasOpt);

            if (isVar)
            {
                declType = operandType;
            }

            if (declType == (object)null)
            {
                Debug.Assert(hasErrors);
                declType = this.CreateErrorType("var");
            }

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);

            if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics))
            {
                hasErrors = true;
            }
            else
            {
                hasErrors |= CheckValidPatternType(typeSyntax, operandType, declType,
                                                   isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
            }

            switch (node.Designation.Kind())
            {
            case SyntaxKind.SingleVariableDesignation:
                break;

            case SyntaxKind.DiscardDesignation:
                return(new BoundDeclarationPattern(node, null, boundDeclType, isVar, hasErrors));

            default:
                throw ExceptionUtilities.UnexpectedValue(node.Designation.Kind());
            }

            var designation = (SingleVariableDesignationSyntax)node.Designation;
            var identifier  = designation.Identifier;
            SourceLocalSymbol localSymbol = this.LookupLocal(identifier);

            if (localSymbol != (object)null)
            {
                if ((InConstructorInitializer || InFieldInitializer) && ContainingMemberOrLambda.ContainingSymbol.Kind == SymbolKind.NamedType)
                {
                    CheckFeatureAvailability(node, MessageID.IDS_FeatureExpressionVariablesInQueriesAndInitializers, diagnostics);
                }

                localSymbol.SetType(declType);

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

                if (!hasErrors)
                {
                    hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax);
                }

                return(new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors));
            }
            else
            {
                // We should have the right binder in the chain for a script or interactive, so we use the field for the pattern.
                Debug.Assert(node.SyntaxTree.Options.Kind != SourceCodeKind.Regular);
                GlobalExpressionVariable expressionVariableField = LookupDeclaredField(designation);
                DiagnosticBag            tempDiagnostics         = DiagnosticBag.GetInstance();
                expressionVariableField.SetType(declType, tempDiagnostics);
                tempDiagnostics.Free();
                BoundExpression receiver       = SynthesizeReceiver(node, expressionVariableField, diagnostics);
                var             variableAccess = new BoundFieldAccess(node, receiver, expressionVariableField, null, hasErrors);
                return(new BoundDeclarationPattern(node, expressionVariableField, variableAccess, boundDeclType, isVar, hasErrors));
            }
        }
Example #14
0
        public override BoundNode VisitTypeExpression(BoundTypeExpression node)
        {
            var result = base.VisitTypeExpression(node);

            Debug.Assert(result is { });
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        /// 
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;
            Debug.Assert(enumeratorInfo != null);

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = _factory.SynthesizedLocal(enumeratorType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachEnumerator);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = MakeConversion(
                syntax: forEachSyntax,
                rewrittenOperand: MakeConversion(
                    syntax: forEachSyntax,
                    rewrittenOperand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    rewrittenType: elementType,
                    @checked: node.Checked),
                conversion: node.ElementConversion,
                rewrittenType: iterationVar.Type,
                @checked: node.Checked);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }

            var rewrittenBodyBlock = CreateBlockDeclaringIterationVariable(iterationVar, iterationVarDecl, rewrittenBody, forEachSyntax);

            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: rewrittenBodyBlock,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            MethodSymbol disposeMethod;
            if (enumeratorInfo.NeedsDisposeMethod && Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, forEachSyntax, _diagnostics, out disposeMethod))
            {
                Binder.ReportDiagnosticsIfObsolete(_diagnostics, disposeMethod, forEachSyntax,
                                                   hasBaseReceiver: false,
                                                   containingMember: _factory.CurrentMethod,
                                                   containingType: _factory.CurrentType,
                                                   location: enumeratorInfo.Location);

                BoundBlock finallyBlockOpt;
                var idisposableTypeSymbol = disposeMethod.ContainingType;
                var conversions = new TypeConversions(_factory.CurrentMethod.ContainingAssembly.CorLibrary);

                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                var isImplicit = conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol, ref useSiteDiagnostics).IsImplicit;
                _diagnostics.Add(forEachSyntax, useSiteDiagnostics);

                if (isImplicit)
                {
                    Debug.Assert(enumeratorInfo.NeedsDisposeMethod);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                        Conversion.Boxing :
                        Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                        expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, disposeMethod, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose(); 
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                operatorKind: BinaryOperatorKind.NotEqual,
                                left: MakeConversion(
                                    syntax: forEachSyntax,
                                    rewrittenOperand: boundEnumeratorVar,
                                    conversion: enumeratorInfo.EnumeratorConversion,
                                    rewrittenType: _compilation.GetSpecialType(SpecialType.System_Object),
                                    @checked: false),
                                right: MakeLiteral(forEachSyntax,
                                    constantValue: ConstantValue.Null,
                                    type: null),
                                constantValueOpt: null,
                                methodOpt: null,
                                resultKind: LookupResultKind.Viable,
                                type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                        locals: ImmutableArray<LocalSymbol>.Empty,
                        localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
                        statements: ImmutableArray.Create<BoundStatement>(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = _factory.SynthesizedLocal(idisposableTypeSymbol);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                        aliasOpt: null,
                        type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                        operand: boundEnumeratorVar,
                        targetType: boundIDisposableTypeExpr,
                        conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                        type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                            operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                            left: boundDisposableVar,
                            right: MakeLiteral(forEachSyntax,
                                constantValue: ConstantValue.Null,
                                type: null),
                            constantValueOpt: null,
                            methodOpt: null,
                            resultKind: LookupResultKind.Viable,
                            type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                            expression: BoundCall.Synthesized(
                                syntax: forEachSyntax,
                                receiverOpt: boundDisposableVar,
                                method: disposeMethod)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                        locals: ImmutableArray.Create<LocalSymbol>(disposableVar),
                        localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
                        statements: ImmutableArray.Create<BoundStatement>(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                    tryBlock: new BoundBlock(forEachSyntax,
                        locals: ImmutableArray<LocalSymbol>.Empty,
                        localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
                        statements: ImmutableArray.Create<BoundStatement>(whileLoop)),
                    catchBlocks: ImmutableArray<BoundCatchBlock>.Empty,
                    finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
                    statements: ImmutableArray.Create<BoundStatement>(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
                    statements: ImmutableArray.Create<BoundStatement>(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return result;
        }
Example #16
0
 public BoundDeclarationPattern(SyntaxNode syntax, LocalSymbol localSymbol, BoundTypeExpression declaredType, bool isVar, bool hasErrors = false)
     : this(syntax, localSymbol, localSymbol == null ? new BoundDiscardExpression(syntax, declaredType.Type) : (BoundExpression) new BoundLocal(syntax, localSymbol, null, declaredType.Type), declaredType, isVar, hasErrors)
 {
 }
Example #17
0
 public BoundTypeExpression(SyntaxNode syntax, AliasSymbol aliasOpt, BoundTypeExpression boundContainingTypeOpt, ImmutableArray <BoundExpression> boundDimensionsOpt, TypeWithAnnotations typeWithAnnotations, bool hasErrors = false)
     : this(syntax, aliasOpt, boundContainingTypeOpt, boundDimensionsOpt, typeWithAnnotations, typeWithAnnotations.Type, hasErrors)
 {
     Debug.Assert((object)typeWithAnnotations.Type != null, "Field 'type' cannot be null");
 }
Example #18
0
        private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics)
        {
            BoundExpression collectionExpr = this.Next.BindValue(syntax.Expression, diagnostics, BindValueKind.RValue); //bind with next to avoid seeing iteration variable

            ForEachEnumeratorInfo.Builder builder = new ForEachEnumeratorInfo.Builder();
            TypeSymbol inferredType;
            bool       hasErrors = !GetEnumeratorInfoAndInferCollectionElementType(ref builder, ref collectionExpr, diagnostics, out inferredType);

            // These should only occur when special types are missing or malformed.
            hasErrors = hasErrors ||
                        (object)builder.GetEnumeratorMethod == null ||
                        (object)builder.MoveNextMethod == null ||
                        (object)builder.CurrentPropertyGetter == null;

            // Check for local variable conflicts in the *enclosing* binder; obviously the *current*
            // binder has a local that matches!
            hasErrors |= this.ValidateDeclarationNameConflictsInScope(IterationVariable, diagnostics);

            // If the type in syntax is "var", then the type should be set explicitly so that the
            // Type property doesn't fail.

            TypeSyntax typeSyntax = this.syntax.Type;

            bool        isVar;
            AliasSymbol alias;
            TypeSymbol  declType = BindType(typeSyntax, diagnostics, out isVar, out alias);

            TypeSymbol iterationVariableType;

            if (isVar)
            {
                iterationVariableType = inferredType ?? CreateErrorType("var");
            }
            else
            {
                Debug.Assert((object)declType != null);
                iterationVariableType = declType;
            }


            BoundTypeExpression boundIterationVariableType = new BoundTypeExpression(typeSyntax, alias, iterationVariableType);

            this.IterationVariable.SetTypeSymbol(iterationVariableType);

            BoundStatement body = BindPossibleEmbeddedStatement(syntax.Statement, diagnostics);

            hasErrors = hasErrors || iterationVariableType.IsErrorType();

            // Skip the conversion checks and array/enumerator differentiation if we know we have an error.
            if (hasErrors)
            {
                return(new BoundForEachStatement(
                           syntax,
                           ImmutableArray <LocalSymbol> .Empty,
                           null, // can't be sure that it's complete
                           default(Conversion),
                           boundIterationVariableType,
                           this.IterationVariable,
                           collectionExpr,
                           body,
                           CheckOverflowAtRuntime,
                           this.BreakLabel,
                           this.ContinueLabel,
                           hasErrors));
            }

            var foreachKeyword = syntax.ForEachKeyword;

            ReportDiagnosticsIfObsolete(diagnostics, builder.GetEnumeratorMethod, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.MoveNextMethod, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter.AssociatedSymbol, foreachKeyword, hasBaseReceiver: false);

            // We want to convert from inferredType in the array/string case and builder.ElementType in the enumerator case,
            // but it turns out that these are equivalent (when both are available).

            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            Conversion elementConversion = this.Conversions.ClassifyConversionForCast(inferredType, iterationVariableType, ref useSiteDiagnostics);

            if (!elementConversion.IsValid)
            {
                ImmutableArray <MethodSymbol> originalUserDefinedConversions = elementConversion.OriginalUserDefinedConversions;
                if (originalUserDefinedConversions.Length > 1)
                {
                    diagnostics.Add(ErrorCode.ERR_AmbigUDConv, syntax.ForEachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
                }
                else
                {
                    SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, inferredType, iterationVariableType);
                    diagnostics.Add(ErrorCode.ERR_NoExplicitConv, syntax.ForEachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
                }
                hasErrors = true;
            }
            else
            {
                ReportDiagnosticsIfObsolete(diagnostics, elementConversion, syntax.ForEachKeyword, hasBaseReceiver: false);
            }

            // Spec (§8.8.4):
            // If the type X of expression is dynamic then there is an implicit conversion from >>expression<< (not the type of the expression)
            // to the System.Collections.IEnumerable interface (§6.1.8).
            builder.CollectionConversion = this.Conversions.ClassifyConversionFromExpression(collectionExpr, builder.CollectionType, ref useSiteDiagnostics);
            builder.CurrentConversion    = this.Conversions.ClassifyConversion(builder.CurrentPropertyGetter.ReturnType, builder.ElementType, ref useSiteDiagnostics);

            builder.EnumeratorConversion = this.Conversions.ClassifyConversion(builder.GetEnumeratorMethod.ReturnType, GetSpecialType(SpecialType.System_Object, diagnostics, this.syntax), ref useSiteDiagnostics);

            diagnostics.Add(syntax.ForEachKeyword.GetLocation(), useSiteDiagnostics);

            // Due to the way we extracted the various types, these conversions should always be possible.
            // CAVEAT: if we're iterating over an array of pointers, the current conversion will fail since we
            // can't convert from object to a pointer type.  Similarly, if we're iterating over an array of
            // Nullable<Error>, the current conversion will fail because we don't know if an ErrorType is a
            // value type.  This doesn't matter in practice, since we won't actually use the enumerator pattern
            // when we lower the loop.
            Debug.Assert(builder.CollectionConversion.IsValid);
            Debug.Assert(builder.CurrentConversion.IsValid ||
                         (builder.ElementType.IsPointerType() && collectionExpr.Type.IsArray()) ||
                         (builder.ElementType.IsNullableType() && builder.ElementType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single().IsErrorType() && collectionExpr.Type.IsArray()));
            Debug.Assert(builder.EnumeratorConversion.IsValid ||
                         this.Compilation.GetSpecialType(SpecialType.System_Object).TypeKind == TypeKind.Error,
                         "Conversions to object succeed unless there's a problem with the object type");

            // If user-defined conversions could occur here, we would need to check for ObsoleteAttribute.
            Debug.Assert((object)builder.CollectionConversion.Method == null,
                         "Conversion from collection expression to collection type should not be user-defined");
            Debug.Assert((object)builder.CurrentConversion.Method == null,
                         "Conversion from Current property type to element type should not be user-defined");
            Debug.Assert((object)builder.EnumeratorConversion.Method == null,
                         "Conversion from GetEnumerator return type to System.Object should not be user-defined");

            // We're wrapping the collection expression in a (non-synthesized) conversion so that its converted
            // type (i.e. builder.CollectionType) will be available in the binding API.
            BoundConversion convertedCollectionExpression = new BoundConversion(
                collectionExpr.Syntax,
                collectionExpr,
                builder.CollectionConversion,
                CheckOverflowAtRuntime,
                false,
                ConstantValue.NotAvailable,
                builder.CollectionType);

            return(new BoundForEachStatement(
                       syntax,
                       ImmutableArray <LocalSymbol> .Empty,
                       builder.Build(this.Flags),
                       elementConversion,
                       boundIterationVariableType,
                       this.IterationVariable,
                       convertedCollectionExpression,
                       body,
                       CheckOverflowAtRuntime,
                       this.BreakLabel,
                       this.ContinueLabel,
                       hasErrors));
        }
Example #19
0
        private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var resultType = (TypeSymbol)GetSpecialType(SpecialType.System_Boolean, diagnostics, node);
            var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
            AliasSymbol alias;
            TypeSymbol targetType;
            {
                // try binding as a type, but back off to binding as an expression if that does not work.
                var tempBag = DiagnosticBag.GetInstance();
                targetType = BindType(node.Right, tempBag, out alias);
                if (targetType?.IsErrorType() == true && tempBag.HasAnyResolvedErrors() &&
                    ((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching))
                {
                    // it did not bind as a type; try binding as a constant expression pattern
                    bool wasExpression;
                    var tempBag2 = DiagnosticBag.GetInstance();
                    var boundConstantPattern = BindConstantPattern(
                        node, operand, operand.Type, node.Right, node.Right.HasErrors, tempBag2, out wasExpression, wasSwitchCase: false);
                    if (wasExpression)
                    {
                        tempBag.Free();
                        diagnostics.AddRangeAndFree(tempBag2);
                        return new BoundIsPatternExpression(node, operand, boundConstantPattern, resultType);
                    }

                    tempBag2.Free();
                }

                diagnostics.AddRangeAndFree(tempBag);
            }

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

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

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;

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

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

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

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

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

            Conversion conversion = Conversions.ClassifyConversion(operandType, targetType, ref useSiteDiagnostics);
            diagnostics.Add(node, useSiteDiagnostics);
            ReportIsOperatorConstantWarnings(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValue);
            return new BoundIsOperator(node, operand, typeExpression, conversion, resultType);
        }
Example #20
0
        private BoundPattern BindDeclarationPattern(
            DeclarationPatternSyntax node,
            BoundExpression operand,
            TypeSymbol operandType,
            bool hasErrors,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(operand != null || operandType != (object)null);
            var typeSyntax = node.Type;
            var identifier = node.Identifier;

            bool isVar;
            AliasSymbol aliasOpt;
            TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt);
            if (isVar && operandType != (object)null)
            {
                declType = operandType;
            }

            if (declType == (object)null)
            {
                Debug.Assert(hasErrors);
                declType = this.CreateErrorType();
            }

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);
            if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics))
            {
                hasErrors = true;
            }
            else
            {
                hasErrors |= CheckValidPatternType(typeSyntax, operand, operandType, declType,
                                                  isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
            }

            SourceLocalSymbol localSymbol = this.LookupLocal(identifier);

            // In error scenarios with misplaced code, it is possible we can't bind the local declaration.
            // This occurs through the semantic model.  In that case concoct a plausible result.
            if (localSymbol == (object)null)
            {
                localSymbol = SourceLocalSymbol.MakeLocal(
                    ContainingMemberOrLambda,
                    this,
                    RefKind.None,
                    typeSyntax,
                    identifier,
                    LocalDeclarationKind.PatternVariable);
            }

            if (isVar)
            {
                localSymbol.SetTypeSymbol(operandType);
            }

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

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

            DeclareLocalVariable(localSymbol, identifier, declType);
            return new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors);
        }
Example #21
0
 public BoundTypeExpression(SyntaxNode syntax, AliasSymbol aliasOpt, BoundTypeExpression boundContainingTypeOpt, TypeWithAnnotations typeWithAnnotations, bool hasErrors = false)
     : this(syntax, aliasOpt, boundContainingTypeOpt, ImmutableArray <BoundExpression> .Empty, typeWithAnnotations, hasErrors)
 {
 }
Example #22
0
        protected BoundLocalDeclaration BindVariableDeclaration(
            LocalDeclarationKind kind,
            bool isVar,
            VariableDeclaratorSyntax declarator,
            TypeSyntax typeSyntax,
            TypeSymbol declTypeOpt,
            AliasSymbol aliasOpt,
            DiagnosticBag diagnostics,
            CSharpSyntaxNode associatedSyntaxNode = null)
        {
            Debug.Assert(declarator != null);
            Debug.Assert((object)declTypeOpt != null || isVar);
            Debug.Assert(typeSyntax != null);

            // if we are not given desired syntax, we use declarator
            associatedSyntaxNode = associatedSyntaxNode ?? declarator;

            bool hasErrors = false;

            BoundExpression initializerOpt;

            SourceLocalSymbol localSymbol = this.LookupLocal(declarator.Identifier);

            // In error scenarios with misplaced code, it is possible we can't bind the local declaration.
            // This occurs through the semantic model.  In that case concoct a plausible result.
            if ((object)localSymbol == null)
            {
                localSymbol = SourceLocalSymbol.MakeLocal(
                    ContainingMemberOrLambda as MethodSymbol, this, typeSyntax,
                    declarator.Identifier, declarator.Initializer, LocalDeclarationKind.Variable);
            }

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

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

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

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

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

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

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

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

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

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

            DeclareLocalVariable(
                localSymbol,
                declarator.Identifier,
                declTypeOpt);

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

            // It is possible that we have a bracketed argument list, like "int x[];" or "int x[123];" 
            // in a non-fixed-size-array declaration . This is a common error made by C++ programmers. 
            // We have already given a good error at parse time telling the user to either make it "fixed"
            // or to move the brackets to the type. However, we should still do semantic analysis of
            // the arguments, so that errors in them are discovered, hovering over them in the IDE
            // gives good results, and so on.

            var arguments = default(ImmutableArray<BoundExpression>);

            if (declarator.ArgumentList != null)
            {
                var builder = ArrayBuilder<BoundExpression>.GetInstance();
                foreach (var argument in declarator.ArgumentList.Arguments)
                {
                    var boundArgument = BindValue(argument.Expression, diagnostics, BindValueKind.RValue);
                    builder.Add(boundArgument);
                }
                arguments = builder.ToImmutableAndFree();
            }

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

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

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt);
            return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors);
        }
Example #23
0
        private BoundPattern BindDeclarationPattern(
            DeclarationPatternSyntax node,
            BoundExpression operand,
            TypeSymbol operandType,
            bool hasErrors,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(operand != null && operandType != (object)null);

            var typeSyntax = node.Type;
            var identifier = node.Identifier;

            bool        isVar;
            AliasSymbol aliasOpt;
            TypeSymbol  declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt);

            if (isVar)
            {
                declType = operandType;
            }

            if (declType == (object)null)
            {
                Debug.Assert(hasErrors);
                declType = this.CreateErrorType("var");
            }

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);

            if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics))
            {
                hasErrors = true;
            }
            else
            {
                hasErrors |= CheckValidPatternType(typeSyntax, operand, operandType, declType,
                                                   isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
            }

            SourceLocalSymbol localSymbol = this.LookupLocal(identifier);

            if (localSymbol != (object)null)
            {
                if (InConstructorInitializer || InFieldInitializer)
                {
                    Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, node);
                }

                localSymbol.SetType(declType);

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

                if (!hasErrors)
                {
                    hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax);
                }

                return(new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors));
            }
            else
            {
                // We should have the right binder in the chain for a script or interactive, so we use the field for the pattern.
                Debug.Assert(node.SyntaxTree.Options.Kind != SourceCodeKind.Regular);
                GlobalExpressionVariable expressionVariableField = LookupDeclaredField(node);
                DiagnosticBag            tempDiagnostics         = DiagnosticBag.GetInstance();
                expressionVariableField.SetType(declType, tempDiagnostics);
                tempDiagnostics.Free();
                BoundExpression receiver       = SynthesizeReceiver(node, expressionVariableField, diagnostics);
                var             variableAccess = new BoundFieldAccess(node, receiver, expressionVariableField, null, hasErrors);
                return(new BoundDeclarationPattern(node, expressionVariableField, variableAccess, boundDeclType, isVar, hasErrors));
            }
        }
Example #24
0
        private BoundPattern BindDeclarationPattern(
            DeclarationPatternSyntax node,
            BoundExpression operand,
            TypeSymbol operandType,
            bool hasErrors,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(operand != null || operandType != (object)null);

            if (InConstructorInitializer || InFieldInitializer)
            {
                Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, node);
            }

            var typeSyntax = node.Type;
            var identifier = node.Identifier;

            bool        isVar;
            AliasSymbol aliasOpt;
            TypeSymbol  declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt);

            if (isVar && operandType != (object)null)
            {
                declType = operandType;
            }

            if (declType == (object)null)
            {
                Debug.Assert(hasErrors);
                declType = this.CreateErrorType("var");
            }

            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);

            if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics))
            {
                hasErrors = true;
            }
            else
            {
                hasErrors |= CheckValidPatternType(typeSyntax, operand, operandType, declType,
                                                   isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
            }

            SourceLocalSymbol localSymbol = this.LookupLocal(identifier);

            // In error scenarios with misplaced code, it is possible we can't bind the local declaration.
            // This occurs through the semantic model.  In that case concoct a plausible result.
            if (localSymbol == (object)null)
            {
                localSymbol = SourceLocalSymbol.MakeLocal(
                    ContainingMemberOrLambda,
                    this,
                    false, // do not allow ref
                    typeSyntax,
                    identifier,
                    LocalDeclarationKind.PatternVariable);
            }

            localSymbol.SetType(declType);

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

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

            return(new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors));
        }
Example #25
0
        protected BoundLocalDeclaration BindVariableDeclaration(
            SourceLocalSymbol localSymbol,
            LocalDeclarationKind kind,
            bool isVar,
            VariableDeclaratorSyntax declarator,
            TypeSyntax typeSyntax,
            TypeSymbol declTypeOpt,
            AliasSymbol aliasOpt,
            DiagnosticBag diagnostics,
            CSharpSyntaxNode associatedSyntaxNode = null)
        {
            Debug.Assert(declarator != null);
            Debug.Assert((object)declTypeOpt != null || isVar);
            Debug.Assert(typeSyntax != null);

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

            bool hasErrors = false;

            BoundExpression initializerOpt;

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

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

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

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

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

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

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

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

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

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

            DeclareLocalVariable(
                localSymbol,
                declarator.Identifier,
                declTypeOpt);

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

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

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

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

            diagnostics.AddRangeAndFree(localDiagnostics);
            var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt);
            return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors);
        }
Example #26
0
        private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics, Binder originalBinder)
        {
            // Use the right binder to avoid seeing iteration variable
            BoundExpression collectionExpr = originalBinder.GetBinder(_syntax.Expression).BindValue(_syntax.Expression, diagnostics, BindValueKind.RValue); 

            ForEachEnumeratorInfo.Builder builder = new ForEachEnumeratorInfo.Builder();
            TypeSymbol inferredType;
            bool hasErrors = !GetEnumeratorInfoAndInferCollectionElementType(ref builder, ref collectionExpr, diagnostics, out inferredType);

            // These should only occur when special types are missing or malformed.
            hasErrors = hasErrors ||
                (object)builder.GetEnumeratorMethod == null ||
                (object)builder.MoveNextMethod == null ||
                (object)builder.CurrentPropertyGetter == null;

            // Check for local variable conflicts in the *enclosing* binder; obviously the *current*
            // binder has a local that matches!
            var hasNameConflicts = originalBinder.ValidateDeclarationNameConflictsInScope(IterationVariable, diagnostics);

            // If the type in syntax is "var", then the type should be set explicitly so that the
            // Type property doesn't fail.

            TypeSyntax typeSyntax = _syntax.Type;

            bool isVar;
            AliasSymbol alias;
            TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out alias);

            TypeSymbol iterationVariableType;
            if (isVar)
            {
                iterationVariableType = inferredType ?? CreateErrorType("var");
            }
            else
            {
                Debug.Assert((object)declType != null);
                iterationVariableType = declType;
            }


            BoundTypeExpression boundIterationVariableType = new BoundTypeExpression(typeSyntax, alias, iterationVariableType);
            this.IterationVariable.SetTypeSymbol(iterationVariableType);

            BoundStatement body = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics);

            hasErrors = hasErrors || iterationVariableType.IsErrorType();

            // Skip the conversion checks and array/enumerator differentiation if we know we have an error (except local name conflicts).
            if (hasErrors)
            {
                return new BoundForEachStatement(
                    _syntax,
                    null, // can't be sure that it's complete
                    default(Conversion),
                    boundIterationVariableType,
                    this.IterationVariable,
                    collectionExpr,
                    body,
                    CheckOverflowAtRuntime,
                    this.BreakLabel,
                    this.ContinueLabel,
                    hasErrors);
            }

            hasErrors |= hasNameConflicts;

            var foreachKeyword = _syntax.ForEachKeyword;
            ReportDiagnosticsIfObsolete(diagnostics, builder.GetEnumeratorMethod, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.MoveNextMethod, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter, foreachKeyword, hasBaseReceiver: false);
            ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter.AssociatedSymbol, foreachKeyword, hasBaseReceiver: false);

            // We want to convert from inferredType in the array/string case and builder.ElementType in the enumerator case,
            // but it turns out that these are equivalent (when both are available).

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            Conversion elementConversion = this.Conversions.ClassifyConversionForCast(inferredType, iterationVariableType, ref useSiteDiagnostics);

            if (!elementConversion.IsValid)
            {
                ImmutableArray<MethodSymbol> originalUserDefinedConversions = elementConversion.OriginalUserDefinedConversions;
                if (originalUserDefinedConversions.Length > 1)
                {
                    diagnostics.Add(ErrorCode.ERR_AmbigUDConv, _syntax.ForEachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
                }
                else
                {
                    SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, inferredType, iterationVariableType);
                    diagnostics.Add(ErrorCode.ERR_NoExplicitConv, _syntax.ForEachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
                }
                hasErrors = true;
            }
            else
            {
                ReportDiagnosticsIfObsolete(diagnostics, elementConversion, _syntax.ForEachKeyword, hasBaseReceiver: false);
            }

            // Spec (§8.8.4):
            // If the type X of expression is dynamic then there is an implicit conversion from >>expression<< (not the type of the expression) 
            // to the System.Collections.IEnumerable interface (§6.1.8). 
            builder.CollectionConversion = this.Conversions.ClassifyConversionFromExpression(collectionExpr, builder.CollectionType, ref useSiteDiagnostics);
            builder.CurrentConversion = this.Conversions.ClassifyConversion(builder.CurrentPropertyGetter.ReturnType, builder.ElementType, ref useSiteDiagnostics);

            builder.EnumeratorConversion = this.Conversions.ClassifyConversion(builder.GetEnumeratorMethod.ReturnType, GetSpecialType(SpecialType.System_Object, diagnostics, _syntax), ref useSiteDiagnostics);

            diagnostics.Add(_syntax.ForEachKeyword.GetLocation(), useSiteDiagnostics);

            // Due to the way we extracted the various types, these conversions should always be possible.
            // CAVEAT: if we're iterating over an array of pointers, the current conversion will fail since we
            // can't convert from object to a pointer type.  Similarly, if we're iterating over an array of
            // Nullable<Error>, the current conversion will fail because we don't know if an ErrorType is a
            // value type.  This doesn't matter in practice, since we won't actually use the enumerator pattern 
            // when we lower the loop.
            Debug.Assert(builder.CollectionConversion.IsValid);
            Debug.Assert(builder.CurrentConversion.IsValid ||
                (builder.ElementType.IsPointerType() && collectionExpr.Type.IsArray()) ||
                (builder.ElementType.IsNullableType() && builder.ElementType.GetMemberTypeArgumentsNoUseSiteDiagnostics().Single().IsErrorType() && collectionExpr.Type.IsArray()));
            Debug.Assert(builder.EnumeratorConversion.IsValid ||
                this.Compilation.GetSpecialType(SpecialType.System_Object).TypeKind == TypeKind.Error ||
                !useSiteDiagnostics.IsNullOrEmpty(),
                "Conversions to object succeed unless there's a problem with the object type or the source type");

            // If user-defined conversions could occur here, we would need to check for ObsoleteAttribute.
            Debug.Assert((object)builder.CollectionConversion.Method == null,
                "Conversion from collection expression to collection type should not be user-defined");
            Debug.Assert((object)builder.CurrentConversion.Method == null,
                "Conversion from Current property type to element type should not be user-defined");
            Debug.Assert((object)builder.EnumeratorConversion.Method == null,
                "Conversion from GetEnumerator return type to System.Object should not be user-defined");

            // We're wrapping the collection expression in a (non-synthesized) conversion so that its converted
            // type (i.e. builder.CollectionType) will be available in the binding API.
            BoundConversion convertedCollectionExpression = new BoundConversion(
                collectionExpr.Syntax,
                collectionExpr,
                builder.CollectionConversion,
                CheckOverflowAtRuntime,
                false,
                ConstantValue.NotAvailable,
                builder.CollectionType);

            return new BoundForEachStatement(
                _syntax,
                builder.Build(this.Flags),
                elementConversion,
                boundIterationVariableType,
                this.IterationVariable,
                convertedCollectionExpression,
                body,
                CheckOverflowAtRuntime,
                this.BreakLabel,
                this.ContinueLabel,
                hasErrors);
        }
Example #27
0
        private bool IsOperatorErrors(CSharpSyntaxNode node, TypeSymbol operandType, BoundTypeExpression typeExpression, DiagnosticBag diagnostics)
        {
            var targetType = typeExpression.Type;
            var targetTypeKind = targetType.TypeKind;

            // The native compiler allows "x is C" where C is a static class. This
            // is strictly illegal according to the specification (see the section
            // called "Referencing Static Class Types".) To retain compatibility we
            // allow it, but when /feature:strict is enabled we break with the native
            // compiler and turn this into an error, as it should be.
            if (targetType.IsStatic && Compilation.FeatureStrictEnabled)
            {
                Error(diagnostics, ErrorCode.ERR_StaticInAsOrIs, node, targetType);
                return true;
            }

            if ((object)operandType != null && operandType.TypeKind == TypeKind.Pointer || targetTypeKind == TypeKind.Pointer)
            {
                // operand for an is or as expression cannot be of pointer type
                Error(diagnostics, ErrorCode.ERR_PointerInAsOrIs, node);
                return true;
            }

            return targetTypeKind == TypeKind.Error;
        }
Example #28
0
        private BoundExpression MakeIsOperator(
            BoundIsOperator oldNode,
            SyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            if (rewrittenOperand.Kind == BoundKind.MethodGroup)
            {
                var             methodGroup = (BoundMethodGroup)rewrittenOperand;
                BoundExpression receiver    = methodGroup.ReceiverOpt;
                if (receiver != null && receiver.Kind != BoundKind.ThisReference)
                {
                    // possible side-effect
                    return(RewriteConstantIsOperator(receiver.Syntax, receiver, ConstantValue.False, rewrittenType));
                }
                else
                {
                    return(MakeLiteral(syntax, ConstantValue.False, rewrittenType));
                }
            }

            var operandType = rewrittenOperand.Type;
            var targetType  = rewrittenTargetType.Type;

            Debug.Assert((object)operandType != null || rewrittenOperand.ConstantValue.IsNull);
            Debug.Assert((object)targetType != null);

            // TODO: Handle dynamic operand type and target type

            if (!_inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetIsOperatorConstantResult(operandType, targetType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    return(RewriteConstantIsOperator(syntax, rewrittenOperand, constantValue, rewrittenType));
                }
                else if (conversion.IsImplicit)
                {
                    // operand is a reference type with bound identity or implicit conversion
                    // We can replace the "is" instruction with a null check

                    Debug.Assert((object)operandType != null);
                    if (operandType.TypeKind == TypeKind.TypeParameter)
                    {
                        // We need to box the type parameter even if it is a known
                        // reference type to ensure there are no verifier errors
                        rewrittenOperand = MakeConversionNode(
                            syntax: rewrittenOperand.Syntax,
                            rewrittenOperand: rewrittenOperand,
                            conversion: Conversion.Boxing,
                            rewrittenType: _compilation.GetSpecialType(SpecialType.System_Object),
                            @checked: false);
                    }

                    return(MakeNullCheck(syntax, rewrittenOperand, BinaryOperatorKind.NotEqual));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
Example #29
0
        private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
            AliasSymbol alias;
            var targetType = BindType(node.Right, diagnostics, out alias);
            var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
            var targetTypeKind = targetType.TypeKind;
            var resultType = targetType;

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

            switch (operand.Kind)
            {
                case BoundKind.UnboundLambda:
                case BoundKind.Lambda:
                case BoundKind.MethodGroup:  // New in Roslyn - see DevDiv #864740.
                    // operand for an is or as expression cannot be a lambda expression or method group
                    if (!operand.HasAnyErrors)
                    {
                        Error(diagnostics, ErrorCode.ERR_LambdaInIsAs, node);
                    }

                    return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            if (operand.HasAnyErrors || targetTypeKind == TypeKind.Error)
            {
                // If either operand is bad or target type has errors, bail out preventing more cascading errors.
                return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            // SPEC:    In an operation of the form E as T, E must be an expression and T must be a
            // SPEC:    reference type, a type parameter known to be a reference type, or a nullable type.

            if (!targetType.IsReferenceType && !targetType.IsNullableType())
            {
                // target type for an as expression cannot be a non-nullable value type.
                // generate appropriate error
                if (targetTypeKind == TypeKind.TypeParameter)
                {
                    Error(diagnostics, ErrorCode.ERR_AsWithTypeVar, node, targetType);
                }
                else if (targetTypeKind == TypeKind.Pointer)
                {
                    Error(diagnostics, ErrorCode.ERR_PointerInAsOrIs, node);
                }
                else
                {
                    Error(diagnostics, ErrorCode.ERR_AsMustHaveReferenceType, node, targetType);
                }

                return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            // The C# specification states in the section called 
            // "Referencing Static Class Types" that it is always
            // illegal to use "as" with a static type. The
            // native compiler actually allows "null as C" for
            // a static type C to be an expression of type C.
            // It also allows "someObject as C" if "someObject"
            // is of type object. To retain compatibility we
            // allow it, but when /feature:strict is enabled we break with the native
            // compiler and turn this into an error, as it should be.
            if (targetType.IsStatic && Compilation.FeatureStrictEnabled)
            {
                Error(diagnostics, ErrorCode.ERR_StaticInAsOrIs, node, targetType);
                return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            if (operand.IsLiteralNull())
            {
                // We do not want to warn for the case "null as TYPE" where the null
                // is a literal, because the user might be saying it to cause overload resolution
                // to pick a particular method
                return new BoundAsOperator(node, operand, typeExpression, Conversion.NullLiteral, resultType);
            }

            if (operand.Kind == BoundKind.MethodGroup)
            {
                Error(diagnostics, ErrorCode.ERR_NoExplicitBuiltinConv, node, MessageID.IDS_MethodGroup.Localize(), targetType);
                return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            var operandType = operand.Type;
            Debug.Assert((object)operandType != null);
            var operandTypeKind = operandType.TypeKind;

            Debug.Assert(targetTypeKind != TypeKind.Pointer, "Should have been caught above");
            if (operandTypeKind == TypeKind.Pointer)
            {
                // operand for an is or as expression cannot be of pointer type
                Error(diagnostics, ErrorCode.ERR_PointerInAsOrIs, node);
                return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

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

            if (targetTypeKind == TypeKind.Dynamic)
            {
                // for "as dynamic", we do the same thing as though it were an "as object"
                targetType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
                targetTypeKind = targetType.TypeKind;
            }

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            Conversion conversion = Conversions.ClassifyConversion(operandType, targetType, ref useSiteDiagnostics, builtinOnly: true);
            diagnostics.Add(node, useSiteDiagnostics);
            bool hasErrors = ReportAsOperatorConversionDiagnostics(node, diagnostics, this.Compilation, operandType, targetType, conversion.Kind, operand.ConstantValue);

            return new BoundAsOperator(node, operand, typeExpression, conversion, resultType, hasErrors);
        }
Example #30
0
        private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
            AliasSymbol alias;
            TypeSymbol targetType = BindType(node.Right, diagnostics, out alias);
            var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
            var targetTypeKind = targetType.TypeKind;
            var resultType = (TypeSymbol)GetSpecialType(SpecialType.System_Boolean, diagnostics, node);

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

            switch (operand.Kind)
            {
                case BoundKind.UnboundLambda:
                case BoundKind.Lambda:
                case BoundKind.MethodGroup:  // New in Roslyn - see DevDiv #864740.
                    // operand for an is or as expression cannot be a lambda expression or method group
                    Error(diagnostics, ErrorCode.ERR_LambdaInIsAs, node);
                    return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            if (operand.HasAnyErrors || targetTypeKind == TypeKind.Error)
            {
                // If either operand is bad or target type has errors, bail out preventing more cascading errors.
                return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            // The native compiler allows "x is C" where C is a static class. This
            // is strictly illegal according to the specification (see the section
            // called "Referencing Static Class Types".) To retain compatibility we
            // allow it, but when /feature:strict is enabled we break with the native
            // compiler and turn this into an error, as it should be.
            if (targetType.IsStatic && Compilation.FeatureStrictEnabled)
            {
                Error(diagnostics, ErrorCode.ERR_StaticInAsOrIs, node, targetType);
                return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            var operandType = operand.Type;
            if ((object)operandType != null && operandType.TypeKind == TypeKind.Pointer || targetTypeKind == TypeKind.Pointer)
            {
                // operand for an is or as expression cannot be of pointer type
                Error(diagnostics, ErrorCode.ERR_PointerInAsOrIs, node);
                return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
            }

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;

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

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

                Error(diagnostics, ErrorCode.WRN_IsAlwaysFalse, node, targetType);

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


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

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

            Conversion conversion = Conversions.ClassifyConversion(operandType, targetType, ref useSiteDiagnostics);
            diagnostics.Add(node, useSiteDiagnostics);
            ReportIsOperatorConstantWarnings(node, diagnostics, operandType, targetType, conversion.Kind, operand.ConstantValue);

            return new BoundIsOperator(node, operand, typeExpression, conversion, resultType);
        }
Example #31
0
 public BoundForEachStatement(SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfoOpt, Conversion elementConversion, BoundTypeExpression iterationVariableType, ImmutableArray <LocalSymbol> iterationVariables, BoundExpression expression, BoundForEachDeconstructStep deconstructionOpt, BoundStatement body, bool @checked, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors = false) :
     this(syntax, enumeratorInfoOpt, elementConversion, iterationVariableType, iterationVariables, iterationErrorExpressionOpt : null, expression, deconstructionOpt, body, @checked, breakLabel, continueLabel, hasErrors)
 {
 }
Example #32
0
        public BoundExpression VisitDynamicInvocation(BoundDynamicInvocation node, bool resultDiscarded)
        {
            var loweredArguments = VisitList(node.Arguments);

            bool                        hasImplicitReceiver;
            BoundExpression             loweredReceiver;
            ImmutableArray <TypeSymbol> typeArguments;
            string                      name;

            switch (node.Expression.Kind)
            {
            case BoundKind.MethodGroup:
                // method invocation
                BoundMethodGroup methodGroup = (BoundMethodGroup)node.Expression;
                typeArguments       = methodGroup.TypeArgumentsOpt;
                name                = methodGroup.Name;
                hasImplicitReceiver = (methodGroup.Flags & BoundMethodGroupFlags.HasImplicitReceiver) != 0;

                // Should have been eliminated during binding of dynamic invocation:
                Debug.Assert(methodGroup.ReceiverOpt == null || methodGroup.ReceiverOpt.Kind != BoundKind.TypeOrValueExpression);

                if (methodGroup.ReceiverOpt == null)
                {
                    // Calling a static method defined on an outer class via its simple name.
                    NamedTypeSymbol firstContainer = node.ApplicableMethods.First().ContainingType;
                    Debug.Assert(node.ApplicableMethods.All(m => m.IsStatic && m.ContainingType == firstContainer));

                    loweredReceiver = new BoundTypeExpression(node.Syntax, null, firstContainer);
                }
                else if (hasImplicitReceiver && factory.TopLevelMethod.IsStatic)
                {
                    // Calling a static method defined on the current class via its simple name.
                    loweredReceiver = new BoundTypeExpression(node.Syntax, null, factory.CurrentClass);
                }
                else
                {
                    loweredReceiver = VisitExpression(methodGroup.ReceiverOpt);
                }

                // If we are calling a method on a NoPIA type, we need to embed all methods/properties
                // with the matching name of this dynamic invocation.
                EmbedIfNeedTo(loweredReceiver, methodGroup.Methods, node.Syntax);

                break;

            case BoundKind.DynamicMemberAccess:
                // method invocation
                var memberAccess = (BoundDynamicMemberAccess)node.Expression;
                name                = memberAccess.Name;
                typeArguments       = memberAccess.TypeArgumentsOpt;
                loweredReceiver     = VisitExpression(memberAccess.Receiver);
                hasImplicitReceiver = false;
                break;

            default:
                // delegate invocation
                var loweredExpression = VisitExpression(node.Expression);
                return(dynamicFactory.MakeDynamicInvocation(loweredExpression, loweredArguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, resultDiscarded).ToExpression());
            }

            Debug.Assert(loweredReceiver != null);
            return(dynamicFactory.MakeDynamicMemberInvocation(
                       name,
                       loweredReceiver,
                       typeArguments,
                       loweredArguments,
                       node.ArgumentNamesOpt,
                       node.ArgumentRefKindsOpt,
                       hasImplicitReceiver,
                       resultDiscarded).ToExpression());
        }