//
// Author:
// Miguel de Icaza (miguel@ximian.com)
-// Marek Safar (marek.safar@seznam.cz)
+// Marek Safar (marek.safar@gmail.com)
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
-// Copyright 2011 Xamarin Inc.
+// Copyright 2011-2012 Xamarin Inc.
//
//
public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
{
if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
- rc.Report.SymbolRelatedToPreviousError (type);
- if (rc.CurrentInitializerVariable != null) {
- rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
- type.GetSignatureForError (), GetSignatureForError ());
- } else {
- rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
- GetSignatureForError ());
- }
+ // Already reported as CS1612
} else {
rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
}
}
}
+ //
+ // Implements identical simple name and type-name resolution
+ //
+ public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
+ {
+ var t = left.Type;
+ if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
+ return left;
+
+ // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
+ // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
+
+ if (left is MemberExpr || left is VariableReference) {
+ var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
+ if (identical_type != null && identical_type.Type == left.Type)
+ return identical_type;
+ }
+
+ return left;
+ }
+
public virtual string GetSignatureForError ()
{
return type.GetDefinition ().GetSignatureForError ();
if (es == null)
Error_InvalidExpressionStatement (ec);
- if (ec.CurrentAnonymousMethod is AsyncInitializer && !(e is Assign) &&
- (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
- ec.Report.Warning (4014, 1, e.Location,
- "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
+ if (!(e is Assign) && (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
+ WarningAsyncWithoutWait (ec, e);
}
return es;
}
+ static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
+ {
+ if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+ bc.Report.Warning (4014, 1, e.Location,
+ "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
+ return;
+ }
+
+ var inv = e as Invocation;
+ if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
+ // The warning won't be reported for imported methods to maintain warning compatiblity with csc
+ bc.Report.Warning (4014, 1, e.Location,
+ "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
+ return;
+ }
+ }
+
/// <summary>
/// Requests the expression to be emitted in a `statement'
/// context. This means that no new value is left on the
}
}
+ var report = ctx.Module.Compiler.Report;
+
var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
if (retval != null) {
- ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
+ report.SymbolRelatedToPreviousError (retval.Type);
ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
return;
}
return;
}
- NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
+ var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
+ if (ns_candidates != null) {
+ string usings = string.Join ("' or `", ns_candidates.ToArray ());
+ report.Error (246, loc,
+ "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
+ Name, usings);
+ } else {
+ report.Error (246, loc,
+ "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
+ Name);
+ }
}
public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
} else {
break;
}
- } else if (me is MethodGroupExpr) {
+ } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
// Leave it to overload resolution to report correct error
} else {
// TODO: rc.Report.SymbolRelatedToPreviousError ()
//
TypeSpec[] targs = null;
if (method.DeclaringType != InstanceExpression.Type) {
- var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
+ var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
if (base_override.IsGeneric)
targs = method.TypeArguments;
member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
}
- //
- // Implements identicial simple name and type-name
- //
- public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
+ public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
{
- var t = left.Type;
- if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
- return left;
+ if (!ResolveInstanceExpressionCore (rc, rhs))
+ return false;
- // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
- // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
+ //
+ // Check intermediate value modification which won't have any effect
+ //
+ if (rhs != null && InstanceExpression.Type.IsStruct &&
+ (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
- if (left is MemberExpr || left is VariableReference) {
- var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
- if (identical_type != null && identical_type.Type == left.Type)
- return identical_type;
+ if (rc.CurrentInitializerVariable != null) {
+ rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
+ InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
+ } else {
+ rc.Report.Error (1612, loc,
+ "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
+ InstanceExpression.GetSignatureForError ());
+ }
}
- return left;
+ return true;
}
- public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
+ bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
{
if (IsStatic) {
if (InstanceExpression != null) {
"An object reference is required to access non-static member `{0}'",
GetSignatureForError ());
- InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
+ InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
return false;
}
var me = InstanceExpression as MemberExpr;
if (me != null) {
- me.ResolveInstanceExpression (rc, rhs);
-
- var fe = me as FieldExpr;
- if (fe != null && fe.IsMarshalByRefAccess (rc)) {
- rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
- rc.Report.Warning (1690, 1, loc,
- "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
- me.GetSignatureForError ());
+ me.ResolveInstanceExpressionCore (rc, rhs);
+
+ // Using this check to detect probing instance expression resolve
+ if (!rc.OmitStructFlowAnalysis) {
+ var fe = me as FieldExpr;
+ if (fe != null && fe.IsMarshalByRefAccess (rc)) {
+ rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
+ rc.Report.Warning (1690, 1, loc,
+ "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
+ me.GetSignatureForError ());
+ }
}
return true;
}
var me = ExtensionExpression as MemberExpr;
- if (me != null)
+ if (me != null) {
me.ResolveInstanceExpression (ec, null);
+ var fe = me as FieldExpr;
+ if (fe != null)
+ fe.Spec.MemberDefinition.SetIsUsed ();
+ }
InstanceExpression = null;
return this;
best_candidate_return = best_candidate.ReturnType;
}
+ if (best_candidate.IsGeneric && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
+ ConstraintChecker cc = new ConstraintChecker (ec);
+ cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
+ }
+
+ //
+ // Additional check for possible imported base override method which
+ // could not be done during IsOverrideMethodBaseTypeAccessible
+ //
+ if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
+ best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
+ ec.Report.SymbolRelatedToPreviousError (best_candidate);
+ ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
+ }
+
return this;
}
public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
{
+ var fe = left as FieldExpr;
+ if (fe != null) {
+ //
+ // Using method-group on struct fields makes the struct assigned. I am not sure
+ // why but that's what .net does
+ //
+ fe.Spec.MemberDefinition.SetIsAssigned ();
+ }
+
simple_name = original;
return base.ResolveMemberAccess (ec, left, original);
}
TypeSpec best_candidate_return_type;
SessionReportPrinter lambda_conv_msgs;
- ReportPrinter prev_recorder;
public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
: this (members, null, restrictions, loc)
if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
return 0;
+ var orig_p = p;
p = p_m.ReturnType;
+ var orig_q = q;
q = q_m.ReturnType;
//
return p.Kind != MemberKind.Void ? 1: 0;
}
+ var am = (AnonymousMethodExpression) a.Expr;
+
//
// When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
// better conversion is performed between underlying types Y1 and Y2
//
if (p.IsGenericTask || q.IsGenericTask) {
- var async_am = a.Expr as AnonymousMethodExpression;
- if (async_am != null && async_am.Block.IsAsync) {
-
- if (p.IsGenericTask != q.IsGenericTask) {
- return 0;
- }
-
+ if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
q = q.TypeArguments[0];
p = p.TypeArguments[0];
}
+ } else if (q != p) {
+ //
+ // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
+ //
+ if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
+ var am_rt = am.InferReturnType (ec, null, orig_q);
+ if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
+ return 2;
+ } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
+ var am_rt = am.InferReturnType (ec, null, orig_p);
+ if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
+ return 1;
+ }
}
//
//
// Foo (int i) is better than Foo (int i, long l = 0)
// Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
+ // Foo (string s, params string[] args) is better than Foo (params string[] args)
//
// Prefer non-optional version
//
// LAMESPEC: Specification claims this should be done at last but the opposite is true
//
if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
- if (candidate_pd.Count >= best_pd.Count)
- return false;
-
if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
return false;
- return true;
+ if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
+ return true;
+
+ return candidate_pd.Count >= best_pd.Count;
}
//
return false;
}
+ static bool CheckInflatedArguments (MethodSpec ms)
+ {
+ if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
+ return true;
+
+ // Setup constraint checker for probing only
+ ConstraintChecker cc = new ConstraintChecker (null);
+
+ var mp = ms.Parameters.Types;
+ for (int i = 0; i < mp.Length; ++i) {
+ var type = mp[i] as InflatedTypeSpec;
+ if (type == null)
+ continue;
+
+ var targs = type.TypeArguments;
+ if (targs.Length == 0)
+ continue;
+
+ // TODO: Checking inflated MVAR arguments should be enough
+ if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
+ return false;
+ }
+
+ return true;
+ }
+
public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
{
rc.Report.Error (1729, loc,
//
// A return value rates candidate method compatibility,
// 0 = the best, int.MaxValue = the worst
+ // -1 = fatal error
//
int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
{
} else if (arg_count > param_count) {
int args_gap = System.Math.Abs (arg_count - param_count);
return int.MaxValue - 10000 + args_gap;
+ } else if (arg_count < param_count - optional_count) {
+ int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
+ return int.MaxValue - 10000 + args_gap;
}
} else if (arg_count != param_count) {
int args_gap = System.Math.Abs (arg_count - param_count);
arg_count = arguments.Count;
}
+ //
+ // Don't do any expensive checks when the candidate cannot succeed
+ //
+ if (arg_count != param_count && !cpd.HasParams)
+ return (param_count - arg_count) * 2 + 1;
+
+ var dep = candidate.GetMissingDependencies ();
+ if (dep != null) {
+ ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
+ return -1;
+ }
+
//
// 1. Handle generic method using type arguments when specified or type inference
//
TypeSpec[] ptypes;
var ms = candidate as MethodSpec;
if (ms != null && ms.IsGeneric) {
- // Setup constraint checker for probing only
- ConstraintChecker cc = new ConstraintChecker (null);
-
if (type_arguments != null) {
var g_args_count = ms.Arity;
if (g_args_count != type_arguments.Count)
ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
} else {
- // TODO: It should not be here (we don't know yet whether any argument is lambda) but
- // for now it simplifies things. I should probably add a callback to ResolveContext
+ //
+ // Deploy custom error reporting for infered anonymous expression or lambda methods. When
+ // probing lambda methods keep all errors reported in separate set and once we are done and no best
+ // candidate was found use the set to report more details about what was wrong with lambda body.
+ // The general idea is to distinguish between code errors and errors caused by
+ // trial-and-error type inference
+ //
if (lambda_conv_msgs == null) {
- lambda_conv_msgs = new SessionReportPrinter ();
- prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
+ for (int i = 0; i < arg_count; i++) {
+ Argument a = arguments[i];
+ if (a == null)
+ continue;
+
+ var am = a.Expr as AnonymousMethodExpression;
+ if (am != null) {
+ if (lambda_conv_msgs == null)
+ lambda_conv_msgs = new SessionReportPrinter ();
+
+ am.TypeInferenceReportPrinter = lambda_conv_msgs;
+ }
+ }
}
var ti = new TypeInference (arguments);
TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
- lambda_conv_msgs.EndSession ();
if (i_args == null)
return ti.InferenceScore - 20000;
+ //
+ // Clear any error messages when the result was success
+ //
+ if (lambda_conv_msgs != null)
+ lambda_conv_msgs.ClearSession ();
+
if (i_args.Length != 0) {
ms = ms.MakeGenericMethod (ec, i_args);
}
-
- cc.IgnoreInferredDynamic = true;
}
//
// Type arguments constraints have to match for the method to be applicable
//
- if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
+ if (!CheckInflatedArguments (ms)) {
candidate = ms;
return int.MaxValue - 25000;
}
// if the type matches
//
Expression e = fp.DefaultValue;
- if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
- //
- // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
- //
- if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
- e = new MemberAccess (new MemberAccess (new MemberAccess (
- new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
- } else {
- e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
- }
-
- e = e.Resolve (ec);
+ if (e != null) {
+ e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
}
if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
return 0;
}
+ public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
+ {
+ if (e is Constant && e.Type == ptype)
+ return e;
+
+ //
+ // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
+ //
+ if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
+ e = new MemberAccess (new MemberAccess (new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
+ } else if (e is Constant) {
+ //
+ // Handles int to int? conversions
+ //
+ e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
+
+ //
+ // When constant type paramter contains type argument
+ //
+ // Foo (T[] arg = null)
+ //
+ if (e == null) {
+ e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
+ }
+ } else {
+ e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
+ }
+
+
+ return e.Resolve (ec);
+ }
+
//
// Tests argument compatibility with the parameter
// The possible return values are
if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
return -1;
- //
- // Deploy custom error reporting for lambda methods. When probing lambda methods
- // keep all errors reported in separate set and once we are done and no best
- // candidate was found, this set is used to report more details about what was wrong
- // with lambda body
- //
- if (argument.Expr.Type == InternalType.AnonymousMethod) {
- if (lambda_conv_msgs == null) {
- lambda_conv_msgs = new SessionReportPrinter ();
- prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
- }
- }
-
//
// Use implicit conversion in all modes to return same candidates when the expression
// is used as argument or delegate conversion
//
if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
- if (lambda_conv_msgs != null) {
- lambda_conv_msgs.EndSession ();
- }
-
return 2;
}
}
return p;
if (specific == ac_q.Element)
return q;
- } else if (TypeManager.IsGenericType (p)) {
+ } else if (p.IsGeneric && q.IsGeneric) {
var pargs = TypeManager.GetTypeArguments (p);
var qargs = TypeManager.GetTypeArguments (q);
bool error_mode = false;
MemberSpec invocable_member = null;
- // Be careful, cannot return until error reporter is restored
while (true) {
best_candidate = null;
best_candidate_rate = int.MaxValue;
var type_members = members;
- try {
+ do {
+ for (int i = 0; i < type_members.Count; ++i) {
+ var member = type_members[i];
- do {
- for (int i = 0; i < type_members.Count; ++i) {
- var member = type_members[i];
+ //
+ // Methods in a base class are not candidates if any method in a derived
+ // class is applicable
+ //
+ if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
+ continue;
+ if (!error_mode) {
+ if (!member.IsAccessible (rc))
+ continue;
+
+ if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
+ continue;
+
+ if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
+ instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
+ continue;
+ }
+ }
+
+ IParametersMember pm = member as IParametersMember;
+ if (pm == null) {
//
- // Methods in a base class are not candidates if any method in a derived
- // class is applicable
+ // Will use it later to report ambiguity between best method and invocable member
//
- if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
- continue;
+ if (Invocation.IsMemberInvocable (member))
+ invocable_member = member;
- if (!error_mode) {
- if (!member.IsAccessible (rc))
- continue;
+ continue;
+ }
- if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
- continue;
+ //
+ // Overload resolution is looking for base member but using parameter names
+ // and default values from the closest member. That means to do expensive lookup
+ // for the closest override for virtual or abstract members
+ //
+ if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
+ var override_params = base_provider.GetOverrideMemberParameters (member);
+ if (override_params != null)
+ pm = override_params;
+ }
- if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
- instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
+ //
+ // Check if the member candidate is applicable
+ //
+ bool params_expanded_form = false;
+ bool dynamic_argument = false;
+ TypeSpec rt = pm.MemberType;
+ int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
+
+ if (lambda_conv_msgs != null)
+ lambda_conv_msgs.EndSession ();
+
+ //
+ // How does it score compare to others
+ //
+ if (candidate_rate < best_candidate_rate) {
+
+ // Fatal error (missing dependency), cannot continue
+ if (candidate_rate < 0)
+ return null;
+
+ best_candidate_rate = candidate_rate;
+ best_candidate = member;
+ best_candidate_args = candidate_args;
+ best_candidate_params = params_expanded_form;
+ best_candidate_dynamic = dynamic_argument;
+ best_parameter_member = pm;
+ best_candidate_return_type = rt;
+ } else if (candidate_rate == 0) {
+ //
+ // The member look is done per type for most operations but sometimes
+ // it's not possible like for binary operators overload because they
+ // are unioned between 2 sides
+ //
+ if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
+ if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
continue;
- }
}
- IParametersMember pm = member as IParametersMember;
- if (pm == null) {
+ bool is_better;
+ if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
+ //
+ // We pack all interface members into top level type which makes the overload resolution
+ // more complicated for interfaces. We compensate it by removing methods with same
+ // signature when building the cache hence this path should not really be hit often
//
- // Will use it later to report ambiguity between best method and invocable member
+ // Example:
+ // interface IA { void Foo (int arg); }
+ // interface IB : IA { void Foo (params int[] args); }
//
- if (Invocation.IsMemberInvocable (member))
- invocable_member = member;
+ // IB::Foo is the best overload when calling IB.Foo (1)
+ //
+ is_better = true;
+ if (ambiguous_candidates != null) {
+ foreach (var amb_cand in ambiguous_candidates) {
+ if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
+ continue;
+ }
- continue;
- }
+ is_better = false;
+ break;
+ }
- //
- // Overload resolution is looking for base member but using parameter names
- // and default values from the closest member. That means to do expensive lookup
- // for the closest override for virtual or abstract members
- //
- if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
- var override_params = base_provider.GetOverrideMemberParameters (member);
- if (override_params != null)
- pm = override_params;
+ if (is_better)
+ ambiguous_candidates = null;
+ }
+ } else {
+ // Is the new candidate better
+ is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
}
- //
- // Check if the member candidate is applicable
- //
- bool params_expanded_form = false;
- bool dynamic_argument = false;
- TypeSpec rt = pm.MemberType;
- int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
-
- //
- // How does it score compare to others
- //
- if (candidate_rate < best_candidate_rate) {
- best_candidate_rate = candidate_rate;
+ if (is_better) {
best_candidate = member;
best_candidate_args = candidate_args;
best_candidate_params = params_expanded_form;
best_candidate_dynamic = dynamic_argument;
best_parameter_member = pm;
best_candidate_return_type = rt;
- } else if (candidate_rate == 0) {
- //
- // The member look is done per type for most operations but sometimes
- // it's not possible like for binary operators overload because they
- // are unioned between 2 sides
- //
- if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
- if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
- continue;
- }
-
- bool is_better;
- if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
- //
- // We pack all interface members into top level type which makes the overload resolution
- // more complicated for interfaces. We compensate it by removing methods with same
- // signature when building the cache hence this path should not really be hit often
- //
- // Example:
- // interface IA { void Foo (int arg); }
- // interface IB : IA { void Foo (params int[] args); }
- //
- // IB::Foo is the best overload when calling IB.Foo (1)
- //
- is_better = true;
- if (ambiguous_candidates != null) {
- foreach (var amb_cand in ambiguous_candidates) {
- if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
- continue;
- }
-
- is_better = false;
- break;
- }
-
- if (is_better)
- ambiguous_candidates = null;
- }
- } else {
- // Is the new candidate better
- is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
- }
+ } else {
+ // It's not better but any other found later could be but we are not sure yet
+ if (ambiguous_candidates == null)
+ ambiguous_candidates = new List<AmbiguousCandidate> ();
- if (is_better) {
- best_candidate = member;
- best_candidate_args = candidate_args;
- best_candidate_params = params_expanded_form;
- best_candidate_dynamic = dynamic_argument;
- best_parameter_member = pm;
- best_candidate_return_type = rt;
- } else {
- // It's not better but any other found later could be but we are not sure yet
- if (ambiguous_candidates == null)
- ambiguous_candidates = new List<AmbiguousCandidate> ();
-
- ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
- }
+ ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
}
-
- // Restore expanded arguments
- if (candidate_args != args)
- candidate_args = args;
}
- } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
- } finally {
- if (prev_recorder != null)
- rc.Report.SetPrinter (prev_recorder);
- }
+
+ // Restore expanded arguments
+ if (candidate_args != args)
+ candidate_args = args;
+ }
+ } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
//
// We've found exact match
args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
}
+ //
+ // Check type constraints only when explicit type arguments are used
+ //
+ if (best_candidate.IsGeneric && type_arguments != null) {
+ MethodSpec bc = best_candidate as MethodSpec;
+ if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
+ ConstraintChecker cc = new ConstraintChecker (rc);
+ cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
+ }
+ }
+
BestCandidateIsDynamic = true;
return null;
}
return null;
//
- // Check ObsoleteAttribute on the best method
+ // Don't run possibly expensive checks in probing mode
//
- ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
- if (oa != null && !rc.IsObsolete)
- AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
+ if (!rc.IsInProbingMode) {
+ //
+ // Check ObsoleteAttribute on the best method
+ //
+ ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
+ if (oa != null && !rc.IsObsolete)
+ AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
- var dep = best_candidate.GetMissingDependencies ();
- if (dep != null) {
- ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
+ best_candidate.MemberDefinition.SetIsUsed ();
}
- best_candidate.MemberDefinition.SetIsUsed ();
-
args = best_candidate_args;
return (T) best_candidate;
}
if (a is CollectionElementInitializer.ElementInitializerArgument) {
ec.Report.SymbolRelatedToPreviousError (method);
if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
- ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
+ ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
TypeManager.CSharpSignature (method));
return;
}
p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
}
- ec.Report.Error (1503, loc,
+ if ((mod & Parameter.Modifier.RefOutMask) != 0) {
+ p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
+ p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
+ }
+
+ ec.Report.Error (1503, a.Expr.Location,
"Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
}
}
return;
}
- if (lambda_conv_msgs != null) {
- if (lambda_conv_msgs.Merge (rc.Report.Printer))
- return;
+ if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
+ return;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
+ return CreateExpressionTree (ec, true);
+ }
+
+ public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
+ {
+ Arguments args;
Expression instance;
+
if (InstanceExpression == null) {
instance = new NullLiteral (loc);
- } else {
+ } else if (convertInstance) {
instance = InstanceExpression.CreateExpressionTree (ec);
+ } else {
+ args = new Arguments (1);
+ args.Add (new Argument (InstanceExpression));
+ instance = CreateExpressionFactoryCall (ec, "Constant", args);
}
- Arguments args = Arguments.CreateForExpressionTree (ec, null,
+ args = Arguments.CreateForExpressionTree (ec, null,
instance,
CreateTypeOfExpression ());
protected override Expression DoResolve (ResolveContext ec)
{
+ spec.MemberDefinition.SetIsUsed ();
+
return DoResolve (ec, null);
}
if (lvalue_instance && var != null && var.VariableInfo != null) {
var.VariableInfo.SetStructFieldAssigned (ec, Name);
}
-
+
if (fb != null) {
IFixedExpression fe = InstanceExpression as IFixedExpression;
if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
{
bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
- spec.MemberDefinition.SetIsUsed ();
-
if (IsStatic){
if (is_volatile)
ec.Emit (OpCodes.Volatile);
//
sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
{
+ Arguments arguments;
+
public PropertyExpr (PropertySpec spec, Location l)
: base (l)
{
protected override Arguments Arguments {
get {
- return null;
+ return arguments;
}
set {
+ arguments = value;
}
}
}
}
} else {
- args = new Arguments (1);
+ args = arguments == null ? new Arguments (1) : arguments;
if (leave_copy) {
source.Emit (ec);
}
DoBestMemberChecks (rc, best_candidate);
+
+ // Handling of com-imported properties with any number of default property parameters
+ if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
+ var p = best_candidate.Get.Parameters;
+ arguments = new Arguments (p.Count);
+ for (int i = 0; i < p.Count; ++i) {
+ arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
+ }
+ } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
+ var p = best_candidate.Set.Parameters;
+ arguments = new Arguments (p.Count - 1);
+ for (int i = 0; i < p.Count - 1; ++i) {
+ arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
+ }
+ }
+
return this;
}
return null;
}
- // if the property/indexer returns a value type, and we try to set a field in it
- if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
- Error_ValueAssignment (ec, right_side);
- }
-
if (eclass == ExprClass.Unresolved) {
var expr = OverloadResolve (ec, right_side);
if (expr == null)
GetSignatureForError ());
} else {
rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
- ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
+ ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
}
}