internal ImmutableArray <TypeParameterConstraintClause> BindTypeParameterConstraintClauses( Symbol containingSymbol, ImmutableArray <TypeParameterSymbol> typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList <TypeParameterConstraintClauseSyntax> clauses, ref IReadOnlyDictionary <TypeParameterSymbol, bool> isValueTypeOverride, DiagnosticBag diagnostics, bool isForOverride = false) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); RoslynDebug.Assert((object)containingSymbol != null); Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method)); Debug.Assert(typeParameters.Length > 0); Debug.Assert(clauses.Count > 0); int n = typeParameters.Length; // Create a map from type parameter name to ordinal. // No need to report duplicate names since duplicates // are reported when the type parameters are bound. var names = new Dictionary <string, int>(n, StringOrdinalComparer.Instance); foreach (var typeParameter in typeParameters) { var name = typeParameter.Name; if (!names.ContainsKey(name)) { names.Add(name, names.Count); } } // An array of constraint clauses, one for each type parameter, indexed by ordinal. var results = ArrayBuilder <TypeParameterConstraintClause?> .GetInstance(n, fillWithValue : null); var syntaxNodes = ArrayBuilder <ArrayBuilder <TypeConstraintSyntax>?> .GetInstance(n, fillWithValue : null); // Bind each clause and add to the results. foreach (var clause in clauses) { var name = clause.Name.Identifier.ValueText; RoslynDebug.Assert(name is object); int ordinal; if (names.TryGetValue(name, out ordinal)) { Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); (TypeParameterConstraintClause constraintClause, ArrayBuilder <TypeConstraintSyntax>?typeConstraintNodes) = this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; syntaxNodes[ordinal] = typeConstraintNodes; } else { // "A constraint clause has already been specified for type parameter '{0}'. ..." diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name); typeConstraintNodes?.Free(); } } else { // Unrecognized type parameter. Don't bother binding the constraints // (the ": I<U>" in "where U : I<U>") since that will lead to additional // errors ("type or namespace 'U' could not be found") if the type // parameter is referenced in the constraints. // "'{1}' does not define type parameter '{0}'" diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom()); } } // Add default values for type parameters without constraint clauses. for (int i = 0; i < n; i++) { if (results[i] == null) { results[i] = GetDefaultTypeParameterConstraintClause(typeParameterList.Parameters[i], isForOverride); } } TypeParameterConstraintClause.AdjustConstraintTypes(containingSymbol, typeParameters, results, ref isValueTypeOverride); RemoveInvalidConstraints(typeParameters, results !, syntaxNodes, diagnostics); foreach (var typeConstraintsSyntaxes in syntaxNodes) { typeConstraintsSyntaxes?.Free(); } syntaxNodes.Free(); return(results.ToImmutableAndFree() !); }
/// <summary> /// Return a collection of bound constraint clauses indexed by type parameter /// ordinal. All constraint clauses are bound, even if there are multiple constraints /// for the same type parameter, or constraints for unrecognized type parameters. /// Extra constraints are not included in the returned collection however. /// </summary> internal ImmutableArray <TypeParameterConstraintClause> BindTypeParameterConstraintClauses( Symbol containingSymbol, ImmutableArray <TypeParameterSymbol> typeParameters, SyntaxList <TypeParameterConstraintClauseSyntax> clauses, DiagnosticBag diagnostics) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); Debug.Assert((object)containingSymbol != null); Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method)); Debug.Assert(typeParameters.Length > 0); Debug.Assert(clauses.Count > 0); int n = typeParameters.Length; // Create a map from type parameter name to ordinal. // No need to report duplicate names since duplicates // are reported when the type parameters are bound. var names = new Dictionary <string, int>(n); foreach (var typeParameter in typeParameters) { var name = typeParameter.Name; if (!names.ContainsKey(name)) { names.Add(name, names.Count); } } // An array of constraint clauses, one for each type parameter, indexed by ordinal. var results = new TypeParameterConstraintClause[n]; // Bind each clause and add to the results. foreach (var clause in clauses) { var name = clause.Name.Identifier.ValueText; int ordinal; if (names.TryGetValue(name, out ordinal)) { Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); var constraintClause = this.BindTypeParameterConstraints(name, clause.Constraints, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; } else { // "A constraint clause has already been specified for type parameter '{0}'. ..." diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name); } } else { // Unrecognized type parameter. Don't bother binding the constraints // (the ": I<U>" in "where U : I<U>") since that will lead to additional // errors ("type or namespace 'U' could not be found") if the type // parameter is referenced in the constraints. // "'{1}' does not define type parameter '{0}'" diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom()); } } return(results.AsImmutableOrNull()); }
/// <summary> /// Return a collection of bound constraint clauses indexed by type parameter /// ordinal. All constraint clauses are bound, even if there are multiple constraints /// for the same type parameter, or constraints for unrecognized type parameters. /// Extra constraints are not included in the returned collection however. /// </summary> internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstraintClauses( Symbol containingSymbol, ImmutableArray<TypeParameterSymbol> typeParameters, SyntaxList<TypeParameterConstraintClauseSyntax> clauses, DiagnosticBag diagnostics) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); Debug.Assert((object)containingSymbol != null); Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method)); Debug.Assert(typeParameters.Length > 0); Debug.Assert(clauses.Count > 0); int n = typeParameters.Length; // Create a map from type parameter name to ordinal. // No need to report duplicate names since duplicates // are reported when the type parameters are bound. var names = new Dictionary<string, int>(n); foreach (var typeParameter in typeParameters) { var name = typeParameter.Name; if (!names.ContainsKey(name)) { names.Add(name, names.Count); } } // An array of constraint clauses, one for each type parameter, indexed by ordinal. var results = new TypeParameterConstraintClause[n]; // Bind each clause and add to the results. foreach (var clause in clauses) { var name = clause.Name.Identifier.ValueText; int ordinal; if (names.TryGetValue(name, out ordinal)) { Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); var constraintClause = this.BindTypeParameterConstraints(name, clause.Constraints, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; } else { // "A constraint clause has already been specified for type parameter '{0}'. ..." diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name); } } else { // Unrecognized type parameter. Don't bother binding the constraints // (the ": I<U>" in "where U : I<U>") since that will lead to additional // errors ("type or namespace 'U' could not be found") if the type // parameter is referenced in the constraints. // "'{1}' does not define type parameter '{0}'" diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom()); } } return results.AsImmutableOrNull(); }