/// <summary>
        /// We've found a possible violation of the single-definition rule.  Check that it is an actual conflict, and if
        /// so report it.
        /// </summary>
        /// <param name="oldMeaning">Previously recorded single meaning for this local scope</param>
        /// <param name="newMeaning">New single meaning found for this local scope</param>
        /// <param name="diagnostics">Where to place any diagnostics</param>
        /// <param name="done">Set to true if the caller should stop checking enclosing scope</param>
        /// <returns>true if an error was reported</returns>
        /// <remarks>
        /// Diagnostics produce by this method should not satisfy ErrorFacts.PreventsSuccessfulDelegateConversion because
        /// name conflicts are independent of the delegate type to which an anonymous function is converted.
        /// </remarks>
        private bool ResolveConflict(SingleMeaning oldMeaning, SingleMeaning newMeaning, DiagnosticBag diagnostics, ref bool done)
        {
            if ((object)oldMeaning.Symbol != null && oldMeaning.Symbol == newMeaning.Symbol)
            {
                // reference to same symbol, by far the most common case.
                done = !newMeaning.IsDefinition;
                return(false);
            }

            return(ResolveConflictComplex(oldMeaning, newMeaning, diagnostics, ref done));
        }
        private static TypeSymbol GetTypeSymbol(SingleMeaning meaning)
        {
            Symbol     symbol = meaning.Symbol;
            TypeSymbol type   = symbol as TypeSymbol;

            if ((object)type != null)
            {
                return(type);
            }

            AliasSymbol alias = symbol as AliasSymbol;

            return((object)alias == null ? null : alias.Target as TypeSymbol);
        }
        /// <summary>
        /// Given a meaning, ensure that it is the only meaning within this scope (or report a diagnostic that it isn't).
        /// Returns true if a diagnostic was reported.  Sets done=true if there is no need to check further enclosing
        /// scopes (for example, when this meaning is the same as a previous meaning, or it can be determined that a
        /// diagnostic had previously been reported).
        /// </summary>
        private bool EnsureSingleDefinition(SingleMeaning newMeaning, DiagnosticBag diagnostics, ref bool done)
        {
            if (singleMeaningTable == null)
            {
                Interlocked.CompareExchange(ref singleMeaningTable, new SmallDictionary <string, SingleMeaning>(), null);
            }

            lock (singleMeaningTable)
            {
                SingleMeaning oldMeaning;
                if (singleMeaningTable.TryGetValue(newMeaning.Name, out oldMeaning))
                {
                    if (oldMeaning.Direct)
                    {
                        return(ResolveConflict(oldMeaning, newMeaning, diagnostics, ref done));
                    }
                    else
                    {
                        if (newMeaning.Direct)
                        {
                            singleMeaningTable[newMeaning.Name] = newMeaning;
                            return(ResolveConflict(oldMeaning, newMeaning, diagnostics, ref done));
                        }
                        else
                        {
                            // both indirect
                            if ((object)oldMeaning.Symbol != null &&
                                newMeaning.Symbol == oldMeaning.Symbol &&
                                !newMeaning.IsDefinition)
                            {
                                done = true; // optimization
                            }
                            return(false);
                        }
                    }
                }
                else
                {
                    singleMeaningTable.Add(newMeaning.Name, newMeaning);
                    return(false);
                }
            }
        }
 private static bool IsTypeMeaning(SingleMeaning meaning, out TypeSymbol type)
 {
     type = GetTypeSymbol(meaning);
     return((object)type != null);
 }
 private static object GetMeaningDiagnosticArgument(SingleMeaning meaning)
 {
     return((object)meaning.Symbol ?? meaning.Name);
 }
        private bool ResolveConflictComplex(SingleMeaning oldMeaning, SingleMeaning newMeaning, DiagnosticBag diagnostics, ref bool done)
        {
            done = true;
            if ((object)oldMeaning.Symbol != null && (object)newMeaning.Symbol != null && oldMeaning.IsDefinition && newMeaning.Symbol.Locations.Any() && oldMeaning.Symbol.Locations[0] == newMeaning.Symbol.Locations[0])
            {
                // a query variable and its corresponding lambda parameter, for example
                return(false);
            }

            Debug.Assert(oldMeaning.Location != newMeaning.Location || oldMeaning.Location == Location.None, "same nonempty location refers to different symbols?");

            // Allow the color-color cases
            TypeSymbol    typeMeaningType;
            SingleMeaning typeMeaning;
            SingleMeaning otherMeaning;

            if (IsTypeMeaning(oldMeaning, out typeMeaningType))
            {
                typeMeaning  = oldMeaning;
                otherMeaning = newMeaning;
            }
            else
            {
                typeMeaning  = newMeaning;
                otherMeaning = oldMeaning;
            }

            // Check for Color-Color conflicts (which are not errors)
            if (((object)typeMeaningType != null || IsTypeMeaning(typeMeaning, out typeMeaningType)) &&
                (object)typeMeaning.ColorColorVariable != null && typeMeaning.ColorColorVariable == otherMeaning.Symbol && // type reference must be contained within scope of the variable
                (!(typeMeaningType is TypeParameterSymbol) || typeMeaningType.ContainingSymbol.Kind != SymbolKind.Method)) // can't reuse a method type parameter name
            {
                done = false;
                return(false);
            }

            if (oldMeaning.Direct == newMeaning.Direct)
            {
                int           oldPosition = oldMeaning.Position;
                int           newPosition = newMeaning.Position;
                SingleMeaning earlier     = (oldPosition > newPosition) ? newMeaning : oldMeaning;
                SingleMeaning later       = (oldPosition > newPosition) ? oldMeaning : newMeaning;

                Debug.Assert(earlier.Direct && later.Direct);
                if (earlier.Reported || later.Reported)
                {
                    return(true);
                }
                later.Reported = earlier.Reported = true;

                Symbol earlierSymbol = earlier.Symbol;
                Symbol laterSymbol   = later.Symbol;

                // Quirk of the way we represent lambda parameters.
                SymbolKind earlierSymbolKind = (object)earlierSymbol == null ? SymbolKind.Parameter : earlierSymbol.Kind;
                SymbolKind laterSymbolKind   = (object)laterSymbol == null ? SymbolKind.Parameter : laterSymbol.Kind;

                if (laterSymbolKind == SymbolKind.ErrorType)
                {
                    return(true);
                }

                if (earlierSymbolKind == SymbolKind.Local && laterSymbolKind == SymbolKind.Local && earlier.IsDefinition && later.IsDefinition)
                {
                    // A local variable named '{0}' is already defined in this scope
                    diagnostics.Add(ErrorCode.ERR_LocalDuplicate, later.Location, later.Name);
                }
                else if (earlierSymbolKind == SymbolKind.TypeParameter && (laterSymbolKind == SymbolKind.Parameter || laterSymbolKind == SymbolKind.Local))
                {
                    // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter
                    diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, later.Location, later.Name);
                }
                else if (earlierSymbolKind == SymbolKind.Parameter && laterSymbolKind == SymbolKind.Parameter)
                {
                    // The parameter name '{0}' is a duplicate
                    diagnostics.Add(ErrorCode.ERR_DuplicateParamName, later.Location, later.Name);
                }
                else if (earlierSymbolKind == SymbolKind.TypeParameter && laterSymbolKind == SymbolKind.TypeParameter)
                {
                    // Type parameter declaration name conflicts are detected elsewhere
                    return(false);
                }
                else
                {
                    diagnostics.Add(ErrorCode.ERR_NameIllegallyOverrides2, later.Location, laterSymbolKind.Localize(), GetMeaningDiagnosticArgument(later), earlierSymbolKind.Localize(), GetMeaningDiagnosticArgument(earlier));
                }

                return(true);
            }

            SingleMeaning direct   = oldMeaning.Direct ? oldMeaning : newMeaning;
            SingleMeaning indirect = oldMeaning.Direct ? newMeaning : oldMeaning;

            Symbol indirectSymbol = indirect.Symbol;
            Symbol directSymbol   = direct.Symbol;

            // Quirk of the way we represent lambda parameters.
            SymbolKind indirectSymbolKind = (object)indirectSymbol == null ? SymbolKind.Parameter : indirectSymbol.Kind;
            SymbolKind directSymbolKind   = (object)directSymbol == null ? SymbolKind.Parameter : directSymbol.Kind;

            if ((object)indirectSymbol == null || indirectSymbol.Locations.Any() && indirect.Location == indirectSymbol.Locations[0])
            {
                // indirect was a definition point.
                if (indirect.Reported)
                {
                    return(true);
                }
                indirect.Reported = true;

                if (directSymbolKind == SymbolKind.TypeParameter && (object)directSymbol != null && directSymbol.ContainingSymbol == ContainingMemberOrLambda)
                {
                    ErrorCode code = indirectSymbolKind == SymbolKind.RangeVariable
                                     // The range variable '{0}' cannot have the same name as a method type parameter
                        ? ErrorCode.ERR_QueryRangeVariableSameAsTypeParam
                                     // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter
                        : ErrorCode.ERR_LocalSameNameAsTypeParam;

                    diagnostics.Add(code, indirect.Location, indirect.Name);
                }
                else if (directSymbolKind == SymbolKind.Local || directSymbolKind == SymbolKind.Parameter)
                {
                    ErrorCode code = indirectSymbolKind == SymbolKind.RangeVariable
                                     // The range variable '{0}' conflicts with a previous declaration of '{0}'
                        ? ErrorCode.ERR_QueryRangeVariableOverrides
                                     // A local or parameter named '{0}' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
                        : ErrorCode.ERR_LocalIllegallyOverrides;

                    diagnostics.Add(code, indirect.Location, indirect.Name);
                }
                else
                {
                    diagnostics.Add(ErrorCode.ERR_NameIllegallyOverrides, indirect.Location, GetMeaningDiagnosticArgument(direct), GetMeaningDiagnosticArgument(indirect), directSymbolKind.Localize());
                }
            }
            else if (indirectSymbolKind == SymbolKind.Local && indirect.Location.SourceSpan.Start < indirectSymbol.Locations[0].SourceSpan.Start)
            {
                // this will be reported elsewhere as a use before definition
                return(false);
            }
            else if (indirectSymbolKind == SymbolKind.ErrorType || directSymbolKind == SymbolKind.ErrorType)
            {
                // avoid cascaded errors
                return(false);
            }
            else
            {
                diagnostics.Add(ErrorCode.ERR_NameIllegallyOverrides3, indirect.Location, indirectSymbolKind.Localize(), GetMeaningDiagnosticArgument(indirect), directSymbolKind.Localize(), GetMeaningDiagnosticArgument(direct));
            }

            return(true);
        }