ResolveResult CreateResult(ResolveResult targetResolveResult, List <LookupGroup> lookupGroups, string name, IList <IType> typeArguments) { // Remove all hidden groups lookupGroups.RemoveAll(g => g.AllHidden); if (lookupGroups.Count == 0) { // No members found return(new UnknownMemberResolveResult(targetResolveResult.Type, name, typeArguments)); } if (lookupGroups.Any(g => !g.MethodsAreHidden && g.Methods.Count > 0)) { // If there are methods, make a MethodGroupResolveResult. // Note that a conflict between a member and a method (possible with multiple interface inheritance) // is only a warning, not an error, and the C# compiler will prefer the method group. List <MethodListWithDeclaringType> methodLists = new List <MethodListWithDeclaringType>(); foreach (var lookupGroup in lookupGroups) { if (!lookupGroup.MethodsAreHidden && lookupGroup.Methods.Count > 0) { var methodListWithDeclType = new MethodListWithDeclaringType(lookupGroup.DeclaringType); foreach (var method in lookupGroup.Methods) { methodListWithDeclType.Add((IMethod)method); } methodLists.Add(methodListWithDeclType); } } return(new MethodGroupResolveResult(targetResolveResult, name, methodLists, typeArguments)); } // If there are ambiguities, report the most-derived result (last group) LookupGroup resultGroup = lookupGroups[lookupGroups.Count - 1]; if (resultGroup.NestedTypes != null && resultGroup.NestedTypes.Count > 0) { if (resultGroup.NestedTypes.Count > 1 || !resultGroup.NonMethodIsHidden || lookupGroups.Count > 1) { return(new AmbiguousTypeResolveResult(resultGroup.NestedTypes[0])); } else { return(new TypeResolveResult(resultGroup.NestedTypes[0])); } } if (lookupGroups.Count > 1) { return(new AmbiguousMemberResolveResult(targetResolveResult, resultGroup.NonMethod, resultGroup.NonMethod.ReturnType.Resolve(context))); } else { return(new MemberResolveResult(targetResolveResult, resultGroup.NonMethod, context)); } }
/// <summary> /// Adds all candidates from the method lists. /// /// This method implements the logic that causes applicable methods in derived types to hide /// all methods in base types. /// </summary> /// <param name="methodLists">The methods, grouped by declaring type. Base types must come first in the list.</param> public void AddMethodLists(IList <MethodListWithDeclaringType> methodLists) { if (methodLists == null) { throw new ArgumentNullException("methodLists"); } // Base types come first, so go through the list backwards (derived types first) bool[] isHiddenByDerivedType; if (methodLists.Count > 1) { isHiddenByDerivedType = new bool[methodLists.Count]; } else { isHiddenByDerivedType = null; } for (int i = methodLists.Count - 1; i >= 0; i--) { if (isHiddenByDerivedType != null && isHiddenByDerivedType[i]) { Log.WriteLine(" Skipping methods in {0} because they are hidden by an applicable method in a derived type", methodLists[i].DeclaringType); continue; } MethodListWithDeclaringType methodList = methodLists[i]; bool foundApplicableCandidateInCurrentList = false; for (int j = 0; j < methodList.Count; j++) { IParameterizedMember method = methodList[j]; Log.Indent(); OverloadResolutionErrors errors = AddCandidate(method); Log.Unindent(); LogCandidateAddingResult(" Candidate", method, errors); foundApplicableCandidateInCurrentList |= IsApplicable(errors); } if (foundApplicableCandidateInCurrentList && i > 0) { foreach (IType baseType in methodList.DeclaringType.GetAllBaseTypes()) { for (int j = 0; j < i; j++) { if (!isHiddenByDerivedType[j] && baseType.Equals(methodLists[j].DeclaringType)) { isHiddenByDerivedType[j] = true; } } } } } }
/// <summary> /// Looks up the indexers on the target type. /// </summary> public IList <MethodListWithDeclaringType> LookupIndexers(IType targetType) { if (targetType == null) { throw new ArgumentNullException("targetType"); } bool allowProtectedAccess = IsProtectedAccessAllowed(targetType); Predicate <IProperty> filter = delegate(IProperty property) { return(property.IsIndexer && IsAccessible(property, allowProtectedAccess)); }; List <LookupGroup> lookupGroups = new List <LookupGroup>(); foreach (IType type in targetType.GetNonInterfaceBaseTypes(context)) { List <IParameterizedMember> newMethods = null; IMember newNonMethod = null; IEnumerable <IType> typeBaseTypes = null; var members = type.GetProperties(context, filter, GetMemberOptions.IgnoreInheritedMembers); AddMembers(type, members, lookupGroups, true, ref typeBaseTypes, ref newMethods, ref newNonMethod); if (newMethods != null || newNonMethod != null) { lookupGroups.Add(new LookupGroup(type, null, newMethods, newNonMethod)); } } // Remove interface members hidden by class members. if (targetType.Kind == TypeKind.TypeParameter) { // This can happen only with type parameters. RemoveInterfaceMembersHiddenByClassMembers(lookupGroups); } // Remove all hidden groups lookupGroups.RemoveAll(g => g.MethodsAreHidden || g.Methods.Count == 0); MethodListWithDeclaringType[] methodLists = new MethodListWithDeclaringType[lookupGroups.Count]; for (int i = 0; i < methodLists.Length; i++) { methodLists[i] = new MethodListWithDeclaringType(lookupGroups[i].DeclaringType, lookupGroups[i].Methods); } return(methodLists); }
public void CannotInferFromMethodParameterTypes() { // static void M<A, B>(Func<A, B> f) {} // M(int.Parse); // type inference fails var A = new DefaultTypeParameter(compilation, EntityType.Method, 0, "A"); var B = new DefaultTypeParameter(compilation, EntityType.Method, 1, "B"); IType declType = compilation.FindType(typeof(int)); var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "Parse")); var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "Parse", new[] { methods }, new IType[0]); bool success; ti.InferTypeArguments(new [] { A, B }, new [] { argument }, new [] { new ParameterizedType(compilation.FindType(typeof(Func <,>)).GetDefinition(), new[] { A, B }) }, out success); Assert.IsFalse(success); }
public void InferFromMethodReturnType() { // static void M<T>(Func<T> f) {} // M(Console.ReadKey); // type inference produces ConsoleKeyInfo var T = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T"); IType declType = compilation.FindType(typeof(Console)); var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "ReadKey")); var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "ReadKey", new[] { methods }, new IType[0]); bool success; Assert.AreEqual( new [] { compilation.FindType(typeof(ConsoleKeyInfo)) }, ti.InferTypeArguments(new [] { T }, new [] { argument }, new [] { new ParameterizedType(compilation.FindType(typeof(Func <>)).GetDefinition(), new[] { T }) }, out success)); Assert.IsTrue(success); }