/// <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); }