private static bool MethodSymbolMatchesParamInfo(MethodSymbol candidateMethod, ParamInfo <TypeSymbol>[] targetParamInfo) { int numParams = targetParamInfo.Length - 1; //don't count return type if (candidateMethod.ParameterCount != numParams) { return(false); } // IndexedTypeParameterSymbol is not going to be exposed anywhere, // so we'll cheat and use it here for comparison purposes. TypeMap candidateMethodTypeMap = new TypeMap( nonNullTypesContext: NonNullTypesFalseContext.Instance, // The NonNullType context doesn't really matter here, because nullability of reference types is not considered for the purpose of the method. candidateMethod.TypeParameters, IndexedTypeParameterSymbol.Take(candidateMethod.Arity), true); if (!ReturnTypesMatch(candidateMethod, candidateMethodTypeMap, ref targetParamInfo[0])) { return(false); } for (int i = 0; i < numParams; i++) { if (!ParametersMatch(candidateMethod.Parameters[i], candidateMethodTypeMap, ref targetParamInfo[i + 1 /*for return type*/])) { return(false); } } return(true); }
private static bool MethodSymbolMatchesParamInfo(MethodSymbol candidateMethod, ParamInfo <TypeSymbol>[] targetParamInfo) { int numParams = targetParamInfo.Length - 1; //don't count return type if (candidateMethod.ParameterCount != numParams) { return(false); } // IndexedTypeParameterSymbol is not going to be exposed anywhere, // so we'll cheat and use it here for comparison purposes. TypeMap candidateMethodTypeMap = new TypeMap( candidateMethod.TypeParameters, IndexedTypeParameterSymbol.Take(candidateMethod.Arity), true); if (!ReturnTypesMatch(candidateMethod, candidateMethodTypeMap, ref targetParamInfo[0])) { return(false); } for (int i = 0; i < numParams; i++) { if (!ParametersMatch(candidateMethod.Parameters[i], candidateMethodTypeMap, ref targetParamInfo[i + 1 /*for return type*/])) { return(false); } } return(true); }
public void TestTake() { var zero = IndexedTypeParameterSymbol.TakeSymbols(0); Assert.Equal(0, zero.Length); var five = IndexedTypeParameterSymbol.TakeSymbols(5); Assert.Equal(5, five.Length); Assert.Equal(five[0], IndexedTypeParameterSymbol.GetTypeParameter(0)); Assert.Equal(five[1], IndexedTypeParameterSymbol.GetTypeParameter(1)); Assert.Equal(five[2], IndexedTypeParameterSymbol.GetTypeParameter(2)); Assert.Equal(five[3], IndexedTypeParameterSymbol.GetTypeParameter(3)); Assert.Equal(five[4], IndexedTypeParameterSymbol.GetTypeParameter(4)); var fifty = IndexedTypeParameterSymbol.TakeSymbols(50); Assert.Equal(50, fifty.Length); // prove they are all unique var set = new HashSet <TypeParameterSymbol>(fifty); Assert.Equal(50, set.Count); var fiveHundred = IndexedTypeParameterSymbol.TakeSymbols(500); Assert.Equal(500, fiveHundred.Length); }
private static MethodSymbol SubstituteTypeParameters(MethodSymbol method) { Debug.Assert(method.IsDefinition); var typeParameters = method.TypeParameters; int n = typeParameters.Length; if (n == 0) { return method; } return method.Construct(IndexedTypeParameterSymbol.Take(n).Cast<TypeParameterSymbol, TypeSymbol>()); }
/// <summary> /// Given a list of method and/or property candidates, choose the first one (if any) with a signature /// that matches the parameter list in the cref. Return null if there isn't one. /// </summary> /// <remarks> /// Produces a diagnostic for ambiguous matches, but not for unresolved members - WRN_BadXMLRef is /// handled in BindMemberCref. /// </remarks> private static ImmutableArray <Symbol> PerformCrefOverloadResolution(ArrayBuilder <Symbol> candidates, ImmutableArray <ParameterSymbol> parameterSymbols, int arity, MemberCrefSyntax memberSyntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { ArrayBuilder <Symbol>?viable = null; foreach (Symbol candidate in candidates) { // BREAK: In dev11, any candidate with the type "dynamic" anywhere in its parameter list would be skipped // (see XmlDocCommentBinder::bindXmlReference). Apparently, this was because "the params that the xml doc // comments produce never will." This does not appear to have made sense in dev11 (skipping dropping the // candidate doesn't cause anything to blow up and may cause resolution to start succeeding) and it almost // certainly does not in roslyn (the signature comparer ignores the object-dynamic distinction anyway). Symbol signatureMember; switch (candidate.Kind) { case SymbolKind.Method: { MethodSymbol candidateMethod = (MethodSymbol)candidate; MethodKind candidateMethodKind = candidateMethod.MethodKind; bool candidateMethodIsVararg = candidateMethod.IsVararg; // If the arity from the cref is zero, then we accept methods of any arity. int signatureMemberArity = candidateMethodKind == MethodKind.Constructor ? 0 : (arity == 0 ? candidateMethod.Arity : arity); // CONSIDER: we might want to reuse this method symbol (as long as the MethodKind and Vararg-ness match). signatureMember = new SignatureOnlyMethodSymbol( methodKind: candidateMethodKind, typeParameters: IndexedTypeParameterSymbol.TakeSymbols(signatureMemberArity), parameters: parameterSymbols, // This specific comparer only looks for varargs. callingConvention: candidateMethodIsVararg ? Microsoft.Cci.CallingConvention.ExtraArguments : Microsoft.Cci.CallingConvention.HasThis, // These are ignored by this specific MemberSignatureComparer. containingType: null, name: null, refKind: RefKind.None, isInitOnly: false, isStatic: false, returnType: default, refCustomModifiers: ImmutableArray <CustomModifier> .Empty, explicitInterfaceImplementations: ImmutableArray <MethodSymbol> .Empty); break; }
/// <summary> /// We know that we'll never have a method context because that's what we're /// trying to find. Instead, just return an indexed type parameter that will /// make comparison easier. /// </summary> /// <param name="position"></param> /// <returns></returns> protected override TypeSymbol GetGenericMethodTypeParamSymbol(int position) { // Note: technically this is a source symbol, but we only care about the position return(IndexedTypeParameterSymbol.GetTypeParameter(position)); }
/// <summary> /// Given a list of method and/or property candidates, choose the first one (if any) with a signature /// that matches the parameter list in the cref. Return null if there isn't one. /// </summary> /// <remarks> /// Produces a diagnostic for ambiguous matches, but not for unresolved members - WRN_BadXMLRef is /// handled in BindMemberCref. /// </remarks> private static ImmutableArray <Symbol> PerformCrefOverloadResolution(ArrayBuilder <Symbol> candidates, ImmutableArray <ParameterSymbol> parameterSymbols, int arity, MemberCrefSyntax memberSyntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { ArrayBuilder <Symbol> viable = null; foreach (Symbol candidate in candidates) { // BREAK: In dev11, any candidate with the type "dynamic" anywhere in its parameter list would be skipped // (see XmlDocCommentBinder::bindXmlReference). Apparently, this was because "the params that the xml doc // comments produce never will." This does not appear to have made sense in dev11 (skipping dropping the // candidate doesn't cause anything to blow up and may cause resolution to start succeeding) and it almost // certainly does not in roslyn (the signature comparer ignores the object-dynamic distiction anyway). Symbol signatureMember; switch (candidate.Kind) { case SymbolKind.Method: { MethodSymbol candidateMethod = (MethodSymbol)candidate; MethodKind candidateMethodKind = candidateMethod.MethodKind; bool candidateMethodIsVararg = candidateMethod.IsVararg; // If the arity from the cref is zero, then we accept methods of any arity. int signatureMemberArity = candidateMethodKind == MethodKind.Constructor ? 0 : (arity == 0 ? candidateMethod.Arity : arity); // CONSIDER: we might want to reuse this method symbol (as long as the MethodKind and Vararg-ness match). signatureMember = new SignatureOnlyMethodSymbol( methodKind: candidateMethodKind, typeParameters: IndexedTypeParameterSymbol.Take(signatureMemberArity), parameters: parameterSymbols, // This specific comparer only looks for varargs. callingConvention: candidateMethodIsVararg ? Microsoft.Cci.CallingConvention.ExtraArguments : Microsoft.Cci.CallingConvention.HasThis, // These are ignored by this specific MemberSignatureComparer. containingType: null, name: null, returnType: null, returnTypeCustomModifiers: ImmutableArray <CustomModifier> .Empty, explicitInterfaceImplementations: ImmutableArray <MethodSymbol> .Empty); break; } case SymbolKind.Property: { // CONSIDER: we might want to reuse this property symbol. signatureMember = new SignatureOnlyPropertySymbol( parameters: parameterSymbols, // These are ignored by this specific MemberSignatureComparer. containingType: null, name: null, type: null, typeCustomModifiers: ImmutableArray <CustomModifier> .Empty, isStatic: false, explicitInterfaceImplementations: ImmutableArray <PropertySymbol> .Empty); break; } case SymbolKind.NamedType: // Because we replaced them with constructors when we built the candidate list. throw ExceptionUtilities.UnexpectedValue(candidate.Kind); default: continue; } if (MemberSignatureComparer.CrefComparer.Equals(signatureMember, candidate)) { Debug.Assert(candidate.GetMemberArity() != 0 || candidate.Name == WellKnownMemberNames.InstanceConstructorName || arity == 0, "Can only have a 0-arity, non-constructor candidate if the desired arity is 0."); if (viable == null) { viable = ArrayBuilder <Symbol> .GetInstance(); viable.Add(candidate); } else { bool oldArityIsZero = viable[0].GetMemberArity() == 0; bool newArityIsZero = candidate.GetMemberArity() == 0; // If the cref specified arity 0 and the current candidate has arity 0 but the previous // match did not, then the current candidate is the unambiguous winner (unless there's // another match with arity 0 in a subsequent iteration). if (!oldArityIsZero || newArityIsZero) { if (!oldArityIsZero && newArityIsZero) { viable.Clear(); } viable.Add(candidate); } } } } if (viable == null) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } if (viable.Count > 1) { ambiguityWinner = viable[0]; CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); diagnostics.Add(ErrorCode.WRN_AmbiguousXMLReference, crefSyntax.Location, crefSyntax.ToString(), ambiguityWinner, viable[1]); } else { ambiguityWinner = null; } return(viable.ToImmutableAndFree()); }
private MethodMemberBuilder(NamedTypeSymbol container, Binder enclosing, MemberDeclarationSyntax syntax, DiagnosticBag diagnostics) : base(enclosing.Location(syntax) as SourceLocation, container, enclosing) { Debug.Assert(syntax != null); this.syntax = syntax; // Make a binder context in which each type parameter binds to a corresponding numbered type parameter Binder parametersContext = Enclosing; if (syntax.Kind == SyntaxKind.MethodDeclaration) { var methodSyntax = syntax as MethodDeclarationSyntax; int arity = methodSyntax.Arity; if (arity != 0) { var typeParamMap = new MultiDictionary <string, TypeParameterSymbol>(); var typeParams = methodSyntax.TypeParameterListOpt.Parameters; for (int iParam = 0; iParam < typeParams.Count; iParam++) { var arg = typeParams[iParam]; var symbol = IndexedTypeParameterSymbol.GetTypeParameter(iParam); typeParamMap.Add(arg.Identifier.ValueText, symbol); } parametersContext = new WithDummyTypeParametersBinder(typeParamMap, Enclosing); } if (methodSyntax.ExplicitInterfaceSpecifierOpt != null) { this.explicitInterfaceType = enclosing.BindType(methodSyntax.ExplicitInterfaceSpecifierOpt.Name, diagnostics); } } // TODOngafter 1: recast this code using ReadOnlyArray. IEnumerable <ParameterSyntax> parameters = SyntaxParameters.HasValue ? SyntaxParameters.Value : SpecializedCollections.EmptyEnumerable <ParameterSyntax>(); declaredParameterTypes = parameters.Select(p => { if (p.TypeOpt == null) { return(new CSErrorTypeSymbol(enclosing.Compilation.GlobalNamespace, "ErrorType", 0, diagnostics.Add(ErrorCode.ERR_NotYetImplementedInRoslyn, new SourceLocation(Tree, p)))); } return(parametersContext.BindType(p.TypeOpt, diagnostics)); }).ToList(); var parameterRefs = parameters.Select(p => p.Modifiers.GetRefKind()).ToList(); switch (syntax.Kind) { case SyntaxKind.ConstructorDeclaration: Binder original = parametersContext; // TODOngafter 1: worry about diagnostic reporting and suppression here. declaredReturnType = Enclosing.GetSpecialType(SpecialType.System_Void, diagnostics, syntax); break; default: declaredReturnType = parametersContext.BindType(SyntaxReturnType, diagnostics); break; } TypeSymbol explType = null; var explSyntax = ExplicitInterface; if (explSyntax != null) { explType = parametersContext.BindType(explSyntax, diagnostics); } // TODOngafter 3: map dynamic->object for the signature this.signature = new MethodSignature(Name, SyntaxArity, declaredParameterTypes, parameterRefs, explType); }
internal ReadOnlyArray <TypeSymbol> ArgumentTypes(MethodSymbol method) { return(new TypeMap( IndexedTypeParameterSymbol.Take(SyntaxArity).AsReadOnly <TypeSymbol>(), method.TypeParameters.Cast <TypeParameterSymbol, TypeSymbol>()).SubstituteTypes(declaredParameterTypes)); }
internal TypeSymbol ReturnType(MethodSymbol method) { return(new TypeMap( IndexedTypeParameterSymbol.Take(SyntaxArity).AsReadOnly <TypeSymbol>(), method.TypeParameters.Cast <TypeParameterSymbol, TypeSymbol>()).SubstituteType(declaredReturnType)); }