// // Returns AnonymousMethod container if this anonymous method // expression can be implicitly converted to the delegate type `delegate_type' // public Expression Compatible (ResolveContext ec, TypeSpec type) { Expression am; if (compatibles.TryGetValue (type, out am)) return am; TypeSpec delegate_type = CompatibleChecks (ec, type); if (delegate_type == null) return null; // // At this point its the first time we know the return type that is // needed for the anonymous method. We create the method here. // var invoke_mb = Delegate.GetInvokeMethod (delegate_type); TypeSpec return_type = invoke_mb.ReturnType; // // Second: the return type of the delegate must be compatible with // the anonymous type. Instead of doing a pass to examine the block // we satisfy the rule by setting the return type on the EmitContext // to be the delegate type return type. // var body = CompatibleMethodBody (ec, null, return_type, delegate_type); if (body == null) return null; bool etree_conversion = delegate_type != type; try { if (etree_conversion) { if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) { // // Nested expression tree lambda use same scope as parent // lambda, this also means no variable capturing between this // and parent scope // am = body.Compatible (ec, ec.CurrentAnonymousMethod); // // Quote nested expression tree // if (am != null) am = new Quote (am); } else { int errors = ec.Report.Errors; if (Block.IsAsync) { ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees"); } using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) { am = body.Compatible (ec); } // // Rewrite expressions into expression tree when targeting Expression<T> // if (am != null && errors == ec.Report.Errors) am = CreateExpressionTree (ec, delegate_type); } } else { am = body.Compatible (ec); if (body.DirectMethodGroupConversion != null) { var errors_printer = new SessionReportPrinter (); var old = ec.Report.SetPrinter (errors_printer); var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) { AllowSpecialMethodsInvocation = true }.Resolve (ec); ec.Report.SetPrinter (old); if (expr != null && errors_printer.ErrorsCount == 0) am = expr; } } } catch (CompletionResult) { throw; } catch (FatalException) { throw; } catch (Exception e) { throw new InternalErrorException (e, loc); } if (!ec.IsInProbingMode) { compatibles.Add (type, am ?? EmptyExpression.Null); } return am; }
public override bool Resolve(BlockContext bc) { if (bc.CurrentBlock is Linq.QueryBlock) { bc.Report.Error(1995, loc, "The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause"); return(false); } if (!base.Resolve(bc)) { return(false); } type = expr.Type; Arguments args = new Arguments(0); // // The await expression is of dynamic type // if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { result_type = type; expr = new Invocation(new MemberAccess(expr, "GetAwaiter"), args).Resolve(bc); return(true); } // // Check whether the expression is awaitable // Expression ama = new AwaitableMemberAccess(expr).Resolve(bc); if (ama == null) { return(false); } var errors_printer = new SessionReportPrinter(); var old = bc.Report.SetPrinter(errors_printer); ama = new Invocation(ama, args).Resolve(bc); bc.Report.SetPrinter(old); if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type)) { bc.Report.Error(1986, expr.Location, "The `await' operand type `{0}' must have suitable GetAwaiter method", expr.Type.GetSignatureForError()); return(false); } var awaiter_type = ama.Type; awaiter_definition = bc.Module.GetAwaiter(awaiter_type); if (!awaiter_definition.IsValidPattern) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } if (!awaiter_definition.INotifyCompletion) { bc.Report.Error(4027, loc, "The awaiter type `{0}' must implement interface `{1}'", awaiter_type.GetSignatureForError(), bc.Module.PredefinedTypes.INotifyCompletion.GetSignatureForError()); return(false); } expr = ama; result_type = awaiter_definition.GetResult.ReturnType; return(true); }
public override bool Resolve(BlockContext bc) { if (bc.CurrentBlock is Linq.QueryBlock) { bc.Report.Error(1995, loc, "The `await' operator may only be used in a query expression within the first collection expression of the initial `from' clause or within the collection expression of a `join' clause"); return(false); } if (!base.Resolve(bc)) { return(false); } Arguments args = new Arguments(0); type = expr.Type; // // The await expression is of dynamic type // if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { result_type = type; expr = new Invocation(new MemberAccess(expr, "GetAwaiter"), args).Resolve(bc); return(true); } // // Check whether the expression is awaitable // Expression ama = new AwaitableMemberAccess(expr).Resolve(bc); if (ama == null) { return(false); } var errors_printer = new SessionReportPrinter(); var old = bc.Report.SetPrinter(errors_printer); ama = new Invocation(ama, args).Resolve(bc); bc.Report.SetPrinter(old); if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type)) { bc.Report.Error(1986, expr.Location, "The `await' operand type `{0}' must have suitable GetAwaiter method", expr.Type.GetSignatureForError()); return(false); } var awaiter_type = ama.Type; expr = ama; // // Predefined: bool IsCompleted { get; } // is_completed = MemberCache.FindMember(awaiter_type, MemberFilter.Property("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool), BindingRestriction.InstanceOnly) as PropertySpec; if (is_completed == null || !is_completed.HasGet) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } // // Predefined: GetResult () // // The method return type is also result type of await expression // get_result = MemberCache.FindMember(awaiter_type, MemberFilter.Method("GetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.InstanceOnly) as MethodSpec; if (get_result == null) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } // // Predefined: INotifyCompletion.OnCompleted (System.Action) // var nc = bc.Module.PredefinedTypes.INotifyCompletion; if (nc.Define() && !awaiter_type.ImplementsInterface(nc.TypeSpec, false)) { bc.Report.Error(4027, loc, "The awaiter type `{0}' must implement interface `{1}'", awaiter_type.GetSignatureForError(), nc.GetSignatureForError()); return(false); } result_type = get_result.ReturnType; return(true); }
/// <summary> /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true. /// </summary> void ResolveAttributeType () { SessionReportPrinter resolve_printer = new SessionReportPrinter (); ReportPrinter prev_recorder = context.Compiler.Report.SetPrinter (resolve_printer); bool t1_is_attr = false; bool t2_is_attr = false; TypeSpec t1, t2; ATypeNameExpression expanded = null; try { t1 = ResolvePossibleAttributeType (expression, ref t1_is_attr); if (nameEscaped) { t2 = null; } else { expanded = (ATypeNameExpression) expression.Clone (null); expanded.Name += "Attribute"; t2 = ResolvePossibleAttributeType (expanded, ref t2_is_attr); } resolve_printer.EndSession (); } finally { context.Compiler.Report.SetPrinter (prev_recorder); } if (t1_is_attr && t2_is_attr) { Report.Error (1614, Location, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'", GetSignatureForError (), expression.GetSignatureForError (), expanded.GetSignatureForError ()); resolve_error = true; return; } if (t1_is_attr) { Type = t1; return; } if (t2_is_attr) { Type = t2; return; } resolve_printer.Merge (prev_recorder); resolve_error = true; }
/// <summary> /// Find the Applicable Function Members (7.4.2.1) /// /// me: Method Group expression with the members to select. /// it might contain constructors or methods (or anything /// that maps to a method). /// /// Arguments: ArrayList containing resolved Argument objects. /// /// loc: The location if we want an error to be reported, or a Null /// location for "probing" purposes. /// /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo) /// that is the best match of me on Arguments. /// /// </summary> public virtual MethodGroupExpr OverloadResolve(ResolveContext ec, ref Arguments Arguments, bool may_fail, Location loc) { var candidates = new List<MethodSpec> (2); List<MethodSpec> params_candidates = null; int arg_count = Arguments != null ? Arguments.Count : 0; Dictionary<MethodSpec, Arguments> candidates_expanded = null; Arguments candidate_args = Arguments; if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) { if (!may_fail) ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate"); return null; } // // Enable message recording, it's used mainly by lambda expressions // var msg_recorder = new SessionReportPrinter (); var prev_recorder = ec.Report.SetPrinter (msg_recorder); do { // // Methods in a base class are not candidates if any method in a derived // class is applicable // int best_candidate_rate = int.MaxValue; foreach (var member in Methods) { var m = member as MethodSpec; if (m == null) { // TODO: It's wrong when non-member is before applicable method // TODO: Should report only when at least 1 from the batch is applicable if (candidates.Count != 0) { ec.Report.SymbolRelatedToPreviousError (candidates [0]); ec.Report.SymbolRelatedToPreviousError (member); ec.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'", candidates[0].GetSignatureForError (), member.GetSignatureForError ()); } continue; } // // Check if candidate is applicable (section 14.4.2.1) // bool params_expanded_form = false; int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref m, ref params_expanded_form); if (candidate_rate < best_candidate_rate) { best_candidate_rate = candidate_rate; best_candidate = m; } if (params_expanded_form) { if (params_candidates == null) params_candidates = new List<MethodSpec> (2); params_candidates.Add (m); } if (candidate_args != Arguments) { if (candidates_expanded == null) candidates_expanded = new Dictionary<MethodSpec, Arguments> (2); candidates_expanded.Add (m, candidate_args); candidate_args = Arguments; } if (candidate_rate != 0 || has_inaccessible_candidates_only) { if (msg_recorder != null) msg_recorder.EndSession (); continue; } msg_recorder = null; candidates.Add (m); } } while (candidates.Count == 0 && GetBaseTypeMethods (ec)); ec.Report.SetPrinter (prev_recorder); if (msg_recorder != null && !msg_recorder.IsEmpty) { if (!may_fail) msg_recorder.Merge (prev_recorder); return null; } int candidate_top = candidates.Count; if (candidate_top == 0) { // // When we found a top level method which does not match and it's // not an extension method. We start extension methods lookup from here // if (InstanceExpression != null) { var first = Methods.First (); var arity = type_arguments == null ? -1 : type_arguments.Count; ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, first.Name, arity, loc); if (ex_method_lookup != null) { ex_method_lookup.ExtensionExpression = InstanceExpression; ex_method_lookup.SetTypeArguments (ec, type_arguments); return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc); } } if (may_fail) return null; // // Okay so we have failed to find exact match so we // return error info about the closest match // if (best_candidate != null) { if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate)) return null; bool params_expanded = params_candidates != null && params_candidates.Contains (best_candidate); if (NoExactMatch (ec, ref Arguments, params_expanded)) return null; } // // We failed to find any method with correct argument count // if (Methods.First ().Kind == MemberKind.Constructor) { ec.Report.SymbolRelatedToPreviousError (queried_type); ec.Report.Error (1729, loc, "The type `{0}' does not contain a constructor that takes `{1}' arguments", TypeManager.CSharpName (queried_type), arg_count.ToString ()); } else { Error_ArgumentCountWrong (ec, arg_count); } return null; } if (arg_count != 0 && Arguments.HasDynamic) { best_candidate = null; return this; } // // Now we actually find the best method // best_candidate = candidates [0]; bool method_params = params_candidates != null && params_candidates.Contains (best_candidate); for (int ix = 1; ix < candidate_top; ix++) { var candidate = candidates [ix]; if (candidate == best_candidate) continue; bool cand_params = params_candidates != null && params_candidates.Contains (candidate); if (candidates_expanded != null && candidates_expanded.ContainsKey (candidate)) { candidate_args = candidates_expanded[candidate]; arg_count = candidate_args.Count; } if (BetterFunction (ec, candidate_args, arg_count, candidate, cand_params, best_candidate, method_params)) { best_candidate = candidate; method_params = cand_params; } if (candidate_args != Arguments) { candidate_args = Arguments; arg_count = candidate_args != null ? candidate_args.Count : 0; } } if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) { candidate_args = candidates_expanded[best_candidate]; arg_count = candidate_args.Count; } // // Now check that there are no ambiguities i.e the selected method // should be better than all the others // MethodSpec ambiguous = null; for (int ix = 1; ix < candidate_top; ix++) { var candidate = candidates [ix]; if (candidate == best_candidate) continue; bool cand_params = params_candidates != null && params_candidates.Contains (candidate); if (!BetterFunction (ec, candidate_args, arg_count, best_candidate, method_params, candidate, cand_params)) { if (!may_fail) ec.Report.SymbolRelatedToPreviousError (candidate); ambiguous = candidate; } } if (ambiguous != null) { Error_AmbiguousCall (ec, ambiguous); return this; } // // And now check if the arguments are all // compatible, perform conversions if // necessary etc. and return if everything is // all right // if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate, method_params, may_fail, loc)) return null; if (best_candidate == null) return null; if (best_candidate.IsGeneric) { ConstraintChecker.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc, ec.Report); } // // Check ObsoleteAttribute on the best method // ObsoleteAttribute oa = best_candidate.GetAttributeObsolete (); if (oa != null && !ec.IsObsolete) AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report); best_candidate.MemberDefinition.SetIsUsed (); Arguments = candidate_args; return this; }
public override bool Resolve(BlockContext bc) { if (!base.Resolve(bc)) { return(false); } Arguments args = new Arguments(0); type = expr.Type; // // The await expression is of dynamic type // if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { result_type = type; awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(type, loc); expr = new Invocation(new MemberAccess(expr, "GetAwaiter"), args).Resolve(bc); return(true); } // // Check whether the expression is awaitable // Expression ama = new AwaitableMemberAccess(expr).Resolve(bc); if (ama == null) { return(false); } var errors_printer = new SessionReportPrinter(); var old = bc.Report.SetPrinter(errors_printer); ama = new Invocation(ama, args).Resolve(bc); bc.Report.SetPrinter(old); if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type)) { bc.Report.Error(1986, expr.Location, "The `await' operand type `{0}' must have suitable GetAwaiter method", expr.Type.GetSignatureForError()); return(false); } var awaiter_type = ama.Type; awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(awaiter_type, loc); expr = ama; // // Predefined: bool IsCompleted { get; } // is_completed = MemberCache.FindMember(awaiter_type, MemberFilter.Property("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool), BindingRestriction.InstanceOnly) as PropertySpec; if (is_completed == null || !is_completed.HasGet) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } // // Predefined: OnCompleted (Action) // if (bc.Module.PredefinedTypes.Action.Define()) { on_completed = MemberCache.FindMember(awaiter_type, MemberFilter.Method("OnCompleted", 0, ParametersCompiled.CreateFullyResolved(bc.Module.PredefinedTypes.Action.TypeSpec), bc.Module.Compiler.BuiltinTypes.Void), BindingRestriction.InstanceOnly) as MethodSpec; if (on_completed == null) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } } // // Predefined: GetResult () // // The method return type is also result type of await expression // get_result = MemberCache.FindMember(awaiter_type, MemberFilter.Method("GetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.InstanceOnly) as MethodSpec; if (get_result == null) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } result_type = get_result.ReturnType; return(true); }
/// <summary> /// User-defined conversions /// </summary> public static Expression UserDefinedConversion(ResolveContext ec, Expression source, TypeSpec target, Location loc, bool look_for_explicit, bool return_convert) { TypeSpec source_type = source.Type; MethodSpec method = null; Expression expr = null; object o; DoubleHash hash; if (look_for_explicit) { hash = explicit_conv; } else { // Implicit user operators cannot convert to interfaces if (target.IsInterface) return null; hash = implicit_conv; } if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { method = (MethodSpec) o; } else { if (source_type == InternalType.Dynamic) return null; method = GetConversionOperator (ec.Compiler, null, source, target, look_for_explicit); } if (method != null) { TypeSpec most_specific_source = method.Parameters.Types[0]; // // This will do the conversion to the best match that we // found. Now we need to perform an implict standard conversion // if the best match was not the type that we were requested // by target. // if (look_for_explicit) { ReportPrinter temp = new SessionReportPrinter (); ReportPrinter prev = ec.Report.SetPrinter (temp); expr = ExplicitConversionStandard (ec, source, most_specific_source, loc); ec.Report.SetPrinter (prev); if (temp.ErrorsCount != 0) expr = null; } else { if (ImplicitStandardConversionExists (source, most_specific_source)) expr = ImplicitConversionStandard (ec, source, most_specific_source, loc); else expr = null; } } if (expr == null) { bool nullable = false; if (TypeManager.IsNullableType (source_type)) { source = Nullable.Unwrap.Create (source); nullable = true; } TypeSpec target_underlying; if (TypeManager.IsNullableType (target)) { target_underlying = TypeManager.GetTypeArguments (target)[0]; nullable = true; } else { // No implicit conversion S? -> T for non-reference type T if (!look_for_explicit && !TypeManager.IsReferenceType (target)) nullable = false; target_underlying = target; } if (nullable) { expr = UserDefinedConversion (ec, source, target_underlying, loc, look_for_explicit, return_convert); // Do result expression lifting only when it's needed if (expr != null && (!look_for_explicit || TypeManager.IsReferenceType (target))) expr = new Nullable.Lifted (expr, source, target).Resolve (ec); return expr; } } else { expr = new UserCast (method, expr, loc).Resolve (ec); if (return_convert && !TypeManager.IsEqual (expr.Type, target)) { if (look_for_explicit) { expr = ExplicitConversionStandard (ec, expr, target, loc); } else { expr = ImplicitConversionStandard (ec, expr, target, loc); } } } if (!(source is Constant)) hash.Insert (source_type, target, method); return expr; }
public override bool Resolve(BlockContext bc) { if (!base.Resolve(bc)) { return(false); } type = expr.Type; // // The task result is of dynamic type // if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { throw new NotImplementedException("dynamic await"); } // // Check whether the expression is awaitable // Expression ama = new AwaitableMemberAccess(expr).Resolve(bc); if (ama == null) { return(false); } Arguments args = new Arguments(0); var errors_printer = new SessionReportPrinter(); var old = bc.Report.SetPrinter(errors_printer); ama = new Invocation(ama, args).Resolve(bc); if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression(ama.Type)) { bc.Report.SetPrinter(old); Error_WrongGetAwaiter(bc, loc, expr.Type); return(false); } var awaiter_type = ama.Type; awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(awaiter_type, loc); expr = ama; // // Predefined: bool IsCompleted { get; } // var is_completed_ma = new MemberAccess(expr, "IsCompleted").Resolve(bc); if (is_completed_ma != null) { is_completed = is_completed_ma as PropertyExpr; if (is_completed != null && is_completed.Type.BuiltinType == BuiltinTypeSpec.Type.Bool && is_completed.IsInstance && is_completed.Getter != null) { // valid } else { bc.Report.SetPrinter(old); Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } } bc.Report.SetPrinter(old); if (errors_printer.ErrorsCount > 0) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } // // Predefined: OnCompleted (Action) // if (bc.Module.PredefinedTypes.Action.Define()) { on_completed = MemberCache.FindMember(awaiter_type, MemberFilter.Method("OnCompleted", 0, ParametersCompiled.CreateFullyResolved(bc.Module.PredefinedTypes.Action.TypeSpec), bc.Module.Compiler.BuiltinTypes.Void), BindingRestriction.InstanceOnly) as MethodSpec; if (on_completed == null) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } } // // Predefined: GetResult () // // The method return type is also result type of await expression // get_result = MemberCache.FindMember(awaiter_type, MemberFilter.Method("GetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.InstanceOnly) as MethodSpec; if (get_result == null) { Error_WrongAwaiterPattern(bc, awaiter_type); return(false); } return(true); }
/// <summary> /// Find the Applicable Function Members (7.4.2.1) /// /// me: Method Group expression with the members to select. /// it might contain constructors or methods (or anything /// that maps to a method). /// /// Arguments: ArrayList containing resolved Argument objects. /// /// loc: The location if we want an error to be reported, or a Null /// location for "probing" purposes. /// /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo) /// that is the best match of me on Arguments. /// /// </summary> public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments, bool may_fail, Location loc) { bool method_params = false; Type applicable_type = null; ArrayList candidates = new ArrayList (2); ArrayList candidate_overrides = null; // // Used to keep a map between the candidate // and whether it is being considered in its // normal or expanded form // // false is normal form, true is expanded form // Hashtable candidate_to_form = null; Hashtable candidates_expanded = null; Arguments candidate_args = Arguments; int arg_count = Arguments != null ? Arguments.Count : 0; if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) { if (!may_fail) ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate"); return null; } int nmethods = Methods.Length; if (!IsBase) { // // Methods marked 'override' don't take part in 'applicable_type' // computation, nor in the actual overload resolution. // However, they still need to be emitted instead of a base virtual method. // So, we salt them away into the 'candidate_overrides' array. // // In case of reflected methods, we replace each overriding method with // its corresponding base virtual method. This is to improve compatibility // with non-C# libraries which change the visibility of overrides (#75636) // int j = 0; for (int i = 0; i < Methods.Length; ++i) { MethodBase m = Methods [i]; if (TypeManager.IsOverride (m)) { if (candidate_overrides == null) candidate_overrides = new ArrayList (); candidate_overrides.Add (m); m = TypeManager.TryGetBaseDefinition (m); } if (m != null) Methods [j++] = m; } nmethods = j; } // // Enable message recording, it's used mainly by lambda expressions // SessionReportPrinter msg_recorder = new SessionReportPrinter (); ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder); // // First we construct the set of applicable methods // bool is_sorted = true; int best_candidate_rate = int.MaxValue; for (int i = 0; i < nmethods; i++) { Type decl_type = Methods [i].DeclaringType; // // If we have already found an applicable method // we eliminate all base types (Section 14.5.5.1) // if (applicable_type != null && IsAncestralType (decl_type, applicable_type)) continue; // // Check if candidate is applicable (section 14.4.2.1) // bool params_expanded_form = false; int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form); if (candidate_rate < best_candidate_rate) { best_candidate_rate = candidate_rate; best_candidate = Methods [i]; } if (params_expanded_form) { if (candidate_to_form == null) candidate_to_form = new PtrHashtable (); MethodBase candidate = Methods [i]; candidate_to_form [candidate] = candidate; } if (candidate_args != Arguments) { if (candidates_expanded == null) candidates_expanded = new Hashtable (2); candidates_expanded.Add (Methods [i], candidate_args); candidate_args = Arguments; } if (candidate_rate != 0 || has_inaccessible_candidates_only) { if (msg_recorder != null) msg_recorder.EndSession (); continue; } msg_recorder = null; candidates.Add (Methods [i]); if (applicable_type == null) applicable_type = decl_type; else if (applicable_type != decl_type) { is_sorted = false; if (IsAncestralType (applicable_type, decl_type)) applicable_type = decl_type; } } ec.Report.SetPrinter (prev_recorder); if (msg_recorder != null && !msg_recorder.IsEmpty) { if (!may_fail) msg_recorder.Merge (prev_recorder); return null; } int candidate_top = candidates.Count; if (applicable_type == null) { // // When we found a top level method which does not match and it's // not an extension method. We start extension methods lookup from here // if (InstanceExpression != null) { ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc); if (ex_method_lookup != null) { ex_method_lookup.ExtensionExpression = InstanceExpression; ex_method_lookup.SetTypeArguments (ec, type_arguments); return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc); } } if (may_fail) return null; // // Okay so we have failed to find exact match so we // return error info about the closest match // if (best_candidate != null) { if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate)) return null; AParametersCollection pd = TypeManager.GetParameterData (best_candidate); bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); if (arg_count == pd.Count || pd.HasParams) { if (TypeManager.IsGenericMethodDefinition (best_candidate)) { if (type_arguments == null) { ec.Report.Error (411, loc, "The type arguments for method `{0}' cannot be inferred from " + "the usage. Try specifying the type arguments explicitly", TypeManager.CSharpSignature (best_candidate)); return null; } Type[] g_args = TypeManager.GetGenericArguments (best_candidate); if (type_arguments.Count != g_args.Length) { ec.Report.SymbolRelatedToPreviousError (best_candidate); ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)", TypeManager.CSharpSignature (best_candidate), g_args.Length.ToString ()); return null; } } else { if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) { Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc); return null; } } if (has_inaccessible_candidates_only) { if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) { // Although a derived class can access protected members of // its base class it cannot do so through an instance of the // base class (CS1540). If the qualifier_type is a base of the // ec.CurrentType and the lookup succeeds with the latter one, // then we are in this situation. Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType); } else { ec.Report.SymbolRelatedToPreviousError (best_candidate); ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report); } } if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc)) return null; if (has_inaccessible_candidates_only) return null; throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate); } } // // We failed to find any method with correct argument count // if (Name == ConstructorInfo.ConstructorName) { ec.Report.SymbolRelatedToPreviousError (queried_type); ec.Report.Error (1729, loc, "The type `{0}' does not contain a constructor that takes `{1}' arguments", TypeManager.CSharpName (queried_type), arg_count); } else { Error_ArgumentCountWrong (ec, arg_count); } return null; } if (!is_sorted) { // // At this point, applicable_type is _one_ of the most derived types // in the set of types containing the methods in this MethodGroup. // Filter the candidates so that they only contain methods from the // most derived types. // int finalized = 0; // Number of finalized candidates do { // Invariant: applicable_type is a most derived type // We'll try to complete Section 14.5.5.1 for 'applicable_type' by // eliminating all it's base types. At the same time, we'll also move // every unrelated type to the end of the array, and pick the next // 'applicable_type'. Type next_applicable_type = null; int j = finalized; // where to put the next finalized candidate int k = finalized; // where to put the next undiscarded candidate for (int i = finalized; i < candidate_top; ++i) { MethodBase candidate = (MethodBase) candidates [i]; Type decl_type = candidate.DeclaringType; if (decl_type == applicable_type) { candidates [k++] = candidates [j]; candidates [j++] = candidates [i]; continue; } if (IsAncestralType (decl_type, applicable_type)) continue; if (next_applicable_type != null && IsAncestralType (decl_type, next_applicable_type)) continue; candidates [k++] = candidates [i]; if (next_applicable_type == null || IsAncestralType (next_applicable_type, decl_type)) next_applicable_type = decl_type; } applicable_type = next_applicable_type; finalized = j; candidate_top = k; } while (applicable_type != null); } // // Now we actually find the best method // best_candidate = (MethodBase) candidates [0]; method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); // // TODO: Broken inverse order of candidates logic does not work with optional // parameters used for method overrides and I am not going to fix it for SRE // if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) { candidate_args = (Arguments) candidates_expanded [best_candidate]; arg_count = candidate_args.Count; } for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; if (candidate == best_candidate) continue; bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate); if (BetterFunction (ec, candidate_args, arg_count, candidate, cand_params, best_candidate, method_params)) { best_candidate = candidate; method_params = cand_params; } } // // Now check that there are no ambiguities i.e the selected method // should be better than all the others // MethodBase ambiguous = null; for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; if (candidate == best_candidate) continue; bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate); if (!BetterFunction (ec, candidate_args, arg_count, best_candidate, method_params, candidate, cand_params)) { if (!may_fail) ec.Report.SymbolRelatedToPreviousError (candidate); ambiguous = candidate; } } if (ambiguous != null) { Error_AmbiguousCall (ec, ambiguous); return this; } // // If the method is a virtual function, pick an override closer to the LHS type. // if (!IsBase && best_candidate.IsVirtual) { if (TypeManager.IsOverride (best_candidate)) throw new InternalErrorException ( "Should not happen. An 'override' method took part in overload resolution: " + best_candidate); if (candidate_overrides != null) { Type[] gen_args = null; bool gen_override = false; if (TypeManager.IsGenericMethod (best_candidate)) gen_args = TypeManager.GetGenericArguments (best_candidate); foreach (MethodBase candidate in candidate_overrides) { if (TypeManager.IsGenericMethod (candidate)) { if (gen_args == null) continue; if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length) continue; } else { if (gen_args != null) continue; } if (IsOverride (candidate, best_candidate)) { gen_override = true; best_candidate = candidate; } } if (gen_override && gen_args != null) { #if GMCS_SOURCE best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args); #endif } } } // // And now check if the arguments are all // compatible, perform conversions if // necessary etc. and return if everything is // all right // if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate, method_params, may_fail, loc)) return null; if (best_candidate == null) return null; MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate); if (TypeManager.IsGenericMethodDefinition (the_method) && !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc)) return null; // // Check ObsoleteAttribute on the best method // ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method); if (oa != null && !ec.IsObsolete) AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report); IMethodData data = TypeManager.GetMethod (the_method); if (data != null) data.SetMemberIsUsed (); Arguments = candidate_args; return this; }
protected override Expression DoResolve (ResolveContext rc) { var sn = expr as SimpleName; const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type; if (sn != null) { var errors_printer = new SessionReportPrinter (); var old = rc.Report.SetPrinter (errors_printer); try { expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity); } finally { rc.Report.SetPrinter (old); } if (errors_printer.ErrorsCount != 0) return null; // // Resolve expression which does have type set as we need expression type // with disable flow analysis as we don't know whether left side expression // is used as variable or type // if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) { expr = expr.Resolve (rc); } else if (expr is TypeParameterExpr) { expr.Error_UnexpectedKind (rc, flags, sn.Location); expr = null; } } else { expr = expr.Resolve (rc, flags); } if (expr == null) return null; TypeSpec expr_type = expr.Type; if (expr_type.IsPointer || expr_type.Kind == MemberKind.Void || expr_type == InternalType.NullLiteral || expr_type == InternalType.AnonymousMethod) { expr.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type); return null; } if (targs != null) { if (!targs.Resolve (rc, true)) return null; } var results = new List<string> (); var nexpr = expr as NamespaceExpression; if (nexpr != null) { string namespaced_partial; if (partial_name == null) namespaced_partial = nexpr.Namespace.Name; else namespaced_partial = nexpr.Namespace.Name + "." + partial_name; rc.CurrentMemberDefinition.GetCompletionStartingWith (namespaced_partial, results); if (partial_name != null) results = results.Select (l => l.Substring (partial_name.Length)).ToList (); } else { var r = MemberCache.GetCompletitionMembers (rc, expr_type, partial_name).Select (l => l.Name); AppendResults (results, partial_name, r); } throw new CompletionResult (partial_name == null ? "" : partial_name, results.Distinct ().ToArray ()); }
protected override Expression DoResolve(ResolveContext rc) { var sn = expr as SimpleName; const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type; if (sn != null) { var errors_printer = new SessionReportPrinter(); var old = rc.Report.SetPrinter(errors_printer); try { expr = sn.LookupNameExpression(rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity); } finally { rc.Report.SetPrinter(old); } if (errors_printer.ErrorsCount != 0) { return(null); } // // Resolve expression which does have type set as we need expression type // with disable flow analysis as we don't know whether left side expression // is used as variable or type // if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) { expr = expr.Resolve(rc); } else if (expr is TypeParameterExpr) { expr.Error_UnexpectedKind(rc, flags, sn.Location); expr = null; } } else { expr = expr.Resolve(rc, flags); } if (expr == null) { return(null); } TypeSpec expr_type = expr.Type; if (expr_type.IsPointer || expr_type.Kind == MemberKind.Void || expr_type == InternalType.NullLiteral || expr_type == InternalType.AnonymousMethod) { expr.Error_OperatorCannotBeApplied(rc, loc, ".", expr_type); return(null); } if (targs != null) { if (!targs.Resolve(rc, true)) { return(null); } } var results = new List <string> (); var nexpr = expr as NamespaceExpression; if (nexpr != null) { string namespaced_partial; if (partial_name == null) { namespaced_partial = nexpr.Namespace.Name; } else { namespaced_partial = nexpr.Namespace.Name + "." + partial_name; } rc.CurrentMemberDefinition.GetCompletionStartingWith(namespaced_partial, results); if (partial_name != null) { results = results.Select(l => l.Substring(partial_name.Length)).ToList(); } } else { var r = MemberCache.GetCompletitionMembers(rc, expr_type, partial_name).Select(l => l.Name); AppendResults(results, partial_name, r); } throw new CompletionResult(partial_name == null ? "" : partial_name, results.Distinct().ToArray()); }