示例#1
0
        /// <summary>
        /// Force a variable to have a slot.  Returns -1 if the variable has an empty struct type.
        /// </summary>
        protected virtual int GetOrCreateSlot(
            Symbol symbol,
            int containingSlot        = 0,
            bool forceSlotEvenIfEmpty = false,
            bool createIfMissing      = true
            )
        {
            Debug.Assert(containingSlot >= 0);
            Debug.Assert(symbol != null);

            if (symbol.Kind == SymbolKind.RangeVariable)
            {
                return(-1);
            }

            containingSlot = DescendThroughTupleRestFields(
                ref symbol,
                containingSlot,
                forceContainingSlotsToExist: true
                );

            if (containingSlot < 0)
            {
                // Error case. Diagnostics should already have been produced.
                return(-1);
            }

            VariableIdentifier identifier = new VariableIdentifier(symbol, containingSlot);
            int slot;

            // Since analysis may proceed in multiple passes, it is possible the slot is already assigned.
            if (!TryGetVariable(identifier, out slot))
            {
                if (!createIfMissing)
                {
                    return(-1);
                }

                var variableType = symbol.GetTypeOrReturnType().Type;
                if (!forceSlotEvenIfEmpty && IsEmptyStructType(variableType))
                {
                    return(-1);
                }

                slot = AddVariable(identifier);
            }

            if (IsConditionalState)
            {
                Normalize(ref this.StateWhenTrue);
                Normalize(ref this.StateWhenFalse);
            }
            else
            {
                Normalize(ref this.State);
            }

            return(slot);
        }
示例#2
0
        /// <summary>
        /// Force a variable to have a slot.  Returns -1 if the variable has an empty struct type.
        /// </summary>
        protected int GetOrCreateSlot(Symbol symbol, int containingSlot = 0, bool forceSlotEvenIfEmpty = false)
        {
            Debug.Assert(containingSlot >= 0);

            if (symbol.Kind == SymbolKind.RangeVariable)
            {
                return(-1);
            }

            containingSlot = DescendThroughTupleRestFields(ref symbol, containingSlot, forceContainingSlotsToExist: true);

            if (containingSlot < 0)
            {
                // Error case. Diagnostics should already have been produced.
                return(-1);
            }

            VariableIdentifier identifier = new VariableIdentifier(symbol, containingSlot);
            int slot;

            // Since analysis may proceed in multiple passes, it is possible the slot is already assigned.
            if (!_variableSlot.TryGetValue(identifier, out slot))
            {
                var variableType = symbol.GetTypeOrReturnType().Type;
                if (!forceSlotEvenIfEmpty && IsEmptyStructType(variableType))
                {
                    return(-1);
                }

                if (_maxSlotDepth > 0 && GetSlotDepth(containingSlot) >= _maxSlotDepth)
                {
                    return(-1);
                }

                slot = nextVariableSlot++;
                _variableSlot.Add(identifier, slot);
                if (slot >= variableBySlot.Length)
                {
                    Array.Resize(ref this.variableBySlot, slot * 2);
                }

                variableBySlot[slot] = identifier;
            }

            if (IsConditionalState)
            {
                Normalize(ref this.StateWhenTrue);
                Normalize(ref this.StateWhenFalse);
            }
            else
            {
                Normalize(ref this.State);
            }

            return(slot);
        }
示例#3
0
        /// <summary>
        /// Force a variable to have a slot.  Returns -1 if the variable has an empty struct type.
        /// </summary>
        protected virtual int GetOrCreateSlot(Symbol symbol, int containingSlot = 0, bool forceSlotEvenIfEmpty = false)
        {
            if (symbol.Kind == SymbolKind.RangeVariable)
            {
                return(-1);
            }

            containingSlot = DescendThroughTupleRestFields(ref symbol, containingSlot, forceContainingSlotsToExist: true);

            VariableIdentifier identifier = new VariableIdentifier(symbol, containingSlot);
            int slot;

            // Since analysis may proceed in multiple passes, it is possible the slot is already assigned.
            if (!_variableSlot.TryGetValue(identifier, out slot))
            {
                var variableType = symbol.GetTypeOrReturnType().Type;
                if (!forceSlotEvenIfEmpty && _emptyStructTypeCache.IsEmptyStructType(variableType))
                {
                    return(-1);
                }

                slot = nextVariableSlot++;
                _variableSlot.Add(identifier, slot);
                if (slot >= variableBySlot.Length)
                {
                    Array.Resize(ref this.variableBySlot, slot * 2);
                }

                variableBySlot[slot] = identifier;
            }

            if (IsConditionalState)
            {
                Normalize(ref this.StateWhenTrue);
                Normalize(ref this.StateWhenFalse);
            }
            else
            {
                Normalize(ref this.State);
            }

            return(slot);
        }
        /// <summary>
        /// Learn from any constant null patterns appearing in the pattern.
        /// </summary>
        /// <param name="inputType">Type type of the input expression (before nullable analysis).
        /// Used to determine which types can contain null.</param>
        /// <returns>true if there is a top-level explicit null check</returns>
        private void LearnFromAnyNullPatterns(
            int inputSlot,
            TypeSymbol inputType,
            BoundPattern pattern)
        {
            if (inputSlot <= 0)
            {
                return;
            }

            // https://github.com/dotnet/roslyn/issues/35041 We only need to do this when we're rewriting, so we
            // can get information for any nodes in the pattern.
            VisitPatternForRewriting(pattern);

            switch (pattern)
            {
            case BoundConstantPattern cp:
                bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null;
                if (isExplicitNullCheck)
                {
                    LearnFromNullTest(inputSlot, inputType, ref this.State);
                }
                break;

            case BoundDeclarationPattern _:
            case BoundDiscardPattern _:
            case BoundITuplePattern _:
                break;     // nothing to learn

            case BoundRecursivePattern rp:
            {
                // for positional part: we only learn from tuples (not Deconstruct)
                if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault)
                {
                    var elements = inputType.TupleElements;
                    for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++)
                    {
                        BoundSubpattern item    = rp.Deconstruction[i];
                        FieldSymbol     element = elements[i];
                        LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern);
                    }
                }

                // for property part
                if (!rp.Properties.IsDefault)
                {
                    for (int i = 0, n = rp.Properties.Length; i < n; i++)
                    {
                        BoundSubpattern item   = rp.Properties[i];
                        Symbol          symbol = item.Symbol;
                        if (symbol?.ContainingType.Equals(inputType, TypeCompareKind.AllIgnoreOptions) == true)
                        {
                            LearnFromAnyNullPatterns(GetOrCreateSlot(symbol, inputSlot), symbol.GetTypeOrReturnType().Type, item.Pattern);
                        }
                    }
                }
            }
            break;

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern);
            }
        }
        /// <summary>
        /// Performs the following checks:
        /// 
        /// Spec 7.6.5: Invocation expressions (definition of Final Validation) 
        ///   The method is validated in the context of the method group: If the best method is a static method, 
        ///   the method group must have resulted from a simple-name or a member-access through a type. If the best 
        ///   method is an instance method, the method group must have resulted from a simple-name, a member-access
        ///   through a variable or value, or a base-access. If neither of these requirements is true, a binding-time
        ///   error occurs.
        ///   (Note that the spec omits to mention, in the case of an instance method invoked through a simple name, that
        ///   the invocation must appear within the body of an instance method)
        ///
        /// Spec 7.5.4: Compile-time checking of dynamic overload resolution 
        ///   If F is a static method, the method group must have resulted from a simple-name, a member-access through a type, 
        ///   or a member-access whose receiver can’t be classified as a type or value until after overload resolution (see §7.6.4.1). 
        ///   If F is an instance method, the method group must have resulted from a simple-name, a member-access through a variable or value,
        ///   or a member-access whose receiver can’t be classified as a type or value until after overload resolution (see §7.6.4.1).
        /// </summary>
        /// <returns>
        /// True if there is any error.
        /// </returns>
        private bool MemberGroupFinalValidationAccessibilityChecks(BoundExpression receiverOpt, Symbol memberSymbol, CSharpSyntaxNode node, DiagnosticBag diagnostics, bool invokedAsExtensionMethod)
        {
            // Perform final validation of the method to be invoked.

            Debug.Assert(memberSymbol.Kind != SymbolKind.Method || memberSymbol.CanBeReferencedByName); //should be true since the caller has LookupOptions.MustBeReferenceableByName set
            //note that the same assert does not hold for all properties. Some properties and (all indexers) are not referenceable by name, yet
            //their binding brings them through here, perhaps needlessly.

            if (receiverOpt != null && receiverOpt.Kind == BoundKind.TypeOrValueExpression)
            {
                // TypeOrValue expression isn't replaced only if the invocation is late bound, in which case it can't be extension method.
                // None of the checks below apply if the receiver can’t be classified as a type or value. 
                Debug.Assert(!invokedAsExtensionMethod);
            }
            else if (memberSymbol.IsStatic)
            {
                Debug.Assert(!invokedAsExtensionMethod || (receiverOpt != null));
                if (!invokedAsExtensionMethod && !WasImplicitReceiver(receiverOpt) && IsMemberAccessedThroughVariableOrValue(receiverOpt))
                {
                    if (this.Flags.Includes(BinderFlags.CollectionInitializerAddMethod))
                    {
                        diagnostics.Add(ErrorCode.ERR_InitializerAddHasWrongSignature, node.Location, memberSymbol);
                    }
                    else if (node.Kind == SyntaxKind.AwaitExpression && memberSymbol.Name == WellKnownMemberNames.GetAwaiter)
                    {
                        diagnostics.Add(ErrorCode.ERR_BadAwaitArg, node.Location, receiverOpt.Type);
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.ERR_ObjectProhibited, node.Location, memberSymbol);
                    }
                    return true;
                }
            }
            else if (IsMemberAccessedThroughType(receiverOpt))
            {
                diagnostics.Add(ErrorCode.ERR_ObjectRequired, node.Location, memberSymbol);
                return true;
            }
            else if (WasImplicitReceiver(receiverOpt))
            {
                if (InFieldInitializer && !ContainingType.IsScriptClass || InConstructorInitializer || InAttributeArgument)
                {
                    CSharpSyntaxNode errorNode = node;
                    if (node.Parent != null && node.Parent.Kind == SyntaxKind.InvocationExpression)
                    {
                        errorNode = node.Parent;
                    }

                    ErrorCode code = InFieldInitializer ? ErrorCode.ERR_FieldInitRefNonstatic : ErrorCode.ERR_ObjectRequired;
                    diagnostics.Add(code, errorNode.Location, memberSymbol);
                    return true;
                }

                // If we could access the member thru implicit "this" the receiver would be a BoundThisReference.
                // If it is null it means that the instance member is inaccessible.
                if (receiverOpt == null || ContainingMember().IsStatic)
                {
                    Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, memberSymbol);
                    return true;
                }
            }

            var containingType = this.ContainingType;
            if ((object)containingType != null)
            {
                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                bool isAccessible = this.IsSymbolAccessibleConditional(memberSymbol.GetTypeOrReturnType(), containingType, ref useSiteDiagnostics);
                diagnostics.Add(node, useSiteDiagnostics);

                if (!isAccessible)
                {
                    // In the presence of non-transitive [InternalsVisibleTo] in source, or obnoxious symbols from metadata, it is possible
                    // to select a method through overload resolution in which the type is not accessible.  In this case a method cannot
                    // be called through normal IL, so we give an error.  Neither [InternalsVisibleTo] nor the need for this diagnostic is
                    // described by the language specification.
                    //
                    // Dev11 perform different access checks. See bug #530360 and tests AccessCheckTests.InaccessibleReturnType.
                    Error(diagnostics, ErrorCode.ERR_BadAccess, node, memberSymbol);
                    return true;
                }
            }

            return false;
        }