private ImmutableArray <TypeParameterSymbol> MakeTypeParameters(MethodDeclarationSyntax syntax, DiagnosticBag diagnostics) { Debug.Assert(syntax.TypeParameterList != null); OverriddenMethodTypeParameterMapBase typeMap = null; if (this.IsOverride) { typeMap = new OverriddenMethodTypeParameterMap(this); } else if (this.IsExplicitInterfaceImplementation) { typeMap = new ExplicitInterfaceMethodTypeParameterMap(this); } var typeParameters = syntax.TypeParameterList.Parameters; var result = ArrayBuilder <TypeParameterSymbol> .GetInstance(); for (int ordinal = 0; ordinal < typeParameters.Count; ordinal++) { var parameter = typeParameters[ordinal]; var identifier = parameter.Identifier; var location = identifier.GetLocation(); var name = identifier.ValueText; // Note: It is not an error to have a type parameter named the same as its enclosing method: void M<M>() {} for (int i = 0; i < result.Count; i++) { if (name == result[i].Name) { diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); break; } } var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); if ((object)tpEnclosing != null) { // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); } var syntaxRefs = ImmutableArray.Create(parameter.GetReference()); var locations = ImmutableArray.Create(location); var typeParameter = (typeMap != null) ? (TypeParameterSymbol) new SourceOverridingMethodTypeParameterSymbol( typeMap, name, ordinal, locations, syntaxRefs) : new SourceMethodTypeParameterSymbol( this, name, ordinal, locations, syntaxRefs); result.Add(typeParameter); } return(result.ToImmutableAndFree()); }
private ImmutableArray <TypeParameterSymbol> MakeTypeParameters(DiagnosticBag diagnostics) { if (declaration.Arity == 0) { return(ImmutableArray <TypeParameterSymbol> .Empty); } var typeParameterMismatchReported = false; var typeParameterNames = new string[declaration.Arity]; var typeParameterVarianceKeywords = new string[declaration.Arity]; var parameterBuilders1 = new List <List <TypeParameterBuilder> >(); foreach (var syntaxRef in this.SyntaxReferences) { var typeDecl = (CSharpSyntaxNode)syntaxRef.GetSyntax(); var syntaxTree = syntaxRef.SyntaxTree; TypeParameterListSyntax tpl; switch (typeDecl.Kind()) { case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.InterfaceDeclaration: tpl = ((TypeDeclarationSyntax)typeDecl).TypeParameterList; break; case SyntaxKind.DelegateDeclaration: tpl = ((DelegateDeclarationSyntax)typeDecl).TypeParameterList; break; case SyntaxKind.EnumDeclaration: default: // there is no such thing as a generic enum, so code should never reach here. throw ExceptionUtilities.UnexpectedValue(typeDecl.Kind()); } var parameterBuilder = new List <TypeParameterBuilder>(); parameterBuilders1.Add(parameterBuilder); int i = 0; foreach (var tp in tpl.Parameters) { var name = typeParameterNames[i]; var location = new SourceLocation(tp.Identifier); var varianceKind = typeParameterVarianceKeywords[i]; if (name == null) { name = typeParameterNames[i] = tp.Identifier.ValueText; varianceKind = typeParameterVarianceKeywords[i] = tp.VarianceKeyword.ValueText; for (int j = 0; j < i; j++) { if (name == typeParameterNames[j]) { typeParameterMismatchReported = true; diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); goto next; } } if (!ReferenceEquals(ContainingType, null)) { var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); if ((object)tpEnclosing != null) { // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); } } next :; } else if (!typeParameterMismatchReported) { // Note: the "this", below, refers to the name of the current class, which includes its type // parameter names. But the type parameter names have not been computed yet. Therefore, we // take advantage of the fact that "this" won't undergo "ToString()" until later, when the // diagnostic is printed, by which time the type parameters field will have been filled in. if (varianceKind != tp.VarianceKeyword.ValueText) { // Dev10 reports CS1067, even if names also don't match typeParameterMismatchReported = true; diagnostics.Add( ErrorCode.ERR_PartialWrongTypeParamsVariance, declaration.NameLocations.First(), this); // see comment above } else if (name != tp.Identifier.ValueText) { typeParameterMismatchReported = true; diagnostics.Add( ErrorCode.ERR_PartialWrongTypeParams, declaration.NameLocations.First(), this); // see comment above } } parameterBuilder.Add(new TypeParameterBuilder(syntaxTree.GetReference(tp), this, location)); i++; } } var parameterBuilders2 = parameterBuilders1.Transpose(); // type arguments are positional var parameters = parameterBuilders2.Select((builders, i) => builders[0].MakeSymbol(i, builders, diagnostics)); return(parameters.AsImmutable()); }