PropertyAccess,
EventAccess,
IndexerAccess,
- Nothing,
+ Nothing,
}
/// <remarks>
/// <remarks>
/// Base class for expressions
/// </remarks>
- public abstract class Expression {
+ public abstract class Expression
+ {
public ExprClass eclass;
protected TypeSpec type;
protected Location loc;
-
+
public TypeSpec Type {
get { return type; }
set { type = value; }
return null;
}
+ protected void CheckExpressionVariable (ResolveContext rc)
+ {
+ if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
+ rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
+ } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
+ rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
+ }
+ }
+
public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
{
rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
{
report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
}
-
+
public void Error_InvalidExpressionStatement (BlockContext bc)
{
Error_InvalidExpressionStatement (bc.Report, loc);
if (type == InternalType.ErrorType || target == InternalType.ErrorType)
return;
+ if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
+ target.MemberDefinition.DeclaringAssembly.IsMissing)
+ return;
+
string from_type = type.GetSignatureForError ();
+ if (type.Kind == MemberKind.ByRef)
+ from_type = "ref " + from_type;
string to_type = target.GetSignatureForError ();
+ if (target.Kind == MemberKind.ByRef)
+ to_type = "ref " + to_type;
+
if (from_type == to_type) {
from_type = type.GetSignatureForErrorIncludingAssemblyName ();
to_type = target.GetSignatureForErrorIncludingAssemblyName ();
return false;
}
- protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
+ protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
{
+ var tps = type as TypeParameterSpec;
+ if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
+ Error_OperatorCannotBeApplied (rc, loc, "?", type);
+ }
+
return TypeSpec.IsValueType (type) && !type.IsNullableType ?
Nullable.NullableInfo.MakeType (rc.Module, type) :
type;
public Expression ResolveLValue (ResolveContext ec, Expression right_side)
{
int errors = ec.Report.Errors;
- bool out_access = right_side == EmptyExpression.OutAccess;
+ //bool out_access = right_side == EmptyExpression.OutAccess;
Expression e = DoResolveLValue (ec, right_side);
- if (e != null && out_access && !(e is IMemoryLocation)) {
+ //if (e != null && out_access && !(e is IMemoryLocation)) {
// FIXME: There's no problem with correctness, the 'Expr = null' handles that.
// Enabling this 'throw' will "only" result in deleting useless code elsewhere,
//throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
// e.GetType () + " " + e.GetSignatureForError ());
- e = null;
- }
+ // e = null;
+ //}
if (e == null) {
if (errors == ec.Report.Errors) {
ec.Emit (OpCodes.Pop);
}
+ public virtual void EmitPrepare (EmitContext ec)
+ {
+ }
+
//
// Emits the expression into temporary field variable. The method
// should be used for await expressions only
public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
{
var members = MemberCache.FindMembers (queried_type, name, false);
- if (members == null)
- return null;
-
- Expression expr;
- do {
- expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
- if (expr != null)
- return expr;
- if (members [0].DeclaringType.BaseType == null)
- members = null;
- else
- members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
- } while (members != null);
+ if (members != null) {
+ Expression expr;
+ do {
+ expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
+ if (expr != null)
+ return expr;
+
+ if (members [0].DeclaringType.BaseType == null)
+ members = null;
+ else
+ members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
+ } while (members != null);
+ }
+
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null) {
+ members = MemberCache.FindInterfaceMembers (tps, name);
+ if (members != null)
+ return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
+ }
+
+ if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
+ var ntuple = queried_type as NamedTupleSpec;
+ if (ntuple != null) {
+ var ms = ntuple.FindElement (rc, name, loc);
+ if (ms != null)
+ return ExprClassFromMemberInfo (ms, loc);
+ }
+ }
- return expr;
+ return null;
}
public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
if (member is MethodSpec) {
- //
- // Interface members that are hidden by class members are removed from the set. This
- // step only has an effect if T is a type parameter and T has both an effective base
- // class other than object and a non-empty effective interface set
- //
- var tps = queried_type as TypeParameterSpec;
- if (tps != null && tps.HasTypeConstraint)
- members = RemoveHiddenTypeParameterMethods (members);
-
return new MethodGroupExpr (members, queried_type, loc);
}
return null;
}
- static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
- {
- if (members.Count < 2)
- return members;
-
- //
- // If M is a method, then all non-method members declared in an interface declaration
- // are removed from the set, and all methods with the same signature as M declared in
- // an interface declaration are removed from the set
- //
-
- bool copied = false;
- for (int i = 0; i < members.Count; ++i) {
- var method = members[i] as MethodSpec;
- if (method == null) {
- if (!copied) {
- copied = true;
- members = new List<MemberSpec> (members);
- }
-
- members.RemoveAt (i--);
- continue;
- }
-
- if (!method.DeclaringType.IsInterface)
- continue;
-
- for (int ii = 0; ii < members.Count; ++ii) {
- var candidate = members[ii] as MethodSpec;
- if (candidate == null || !candidate.DeclaringType.IsClass)
- continue;
-
- if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
- continue;
-
- if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
- continue;
-
- if (!copied) {
- copied = true;
- members = new List<MemberSpec> (members);
- }
-
- members.RemoveAt (i--);
- break;
- }
- }
-
- return members;
- }
-
protected static void Error_NamedArgument (NamedArgument na, Report Report)
{
Report.Error (1742, na.Location, "An element access expression cannot use named argument");
{
}
+ public virtual Reachability MarkReachable (Reachability rc)
+ {
+ return rc;
+ }
+
//
// Special version of flow analysis for expressions which can return different
// on-true and on-false result. Used by &&, ||, ?: expressions
Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
}
+ public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
+ {
+ UnsafeInsideIteratorError (rc.Report, loc);
+ }
+
+ public static void UnsafeInsideIteratorError (Report report, Location loc)
+ {
+ report.Error (1629, loc, "Unsafe code may not appear in iterators");
+ }
+
//
// Converts `source' to an int, uint, long or ulong.
//
/// </summary>
public abstract class ExpressionStatement : Expression
{
- public virtual void MarkReachable (Reachability rc)
- {
- }
-
- public ExpressionStatement ResolveStatement (BlockContext ec)
+ public virtual ExpressionStatement ResolveStatement (BlockContext ec)
{
Expression e = Resolve (ec);
if (e == null)
#endif
}
+ public override Reachability MarkReachable (Reachability rc)
+ {
+ return child.MarkReachable (rc);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
// Nothing to clone
public override void FlowAnalysis (FlowAnalysisContext fc)
{
- expr.FlowAnalysis (fc);
+ orig_expr.FlowAnalysis (fc);
+ }
+
+ public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+ {
+ orig_expr.FlowAnalysisConditional (fc);
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
return orig_expr.MakeExpression (ctx);
}
+
+ public override Reachability MarkReachable (Reachability rc)
+ {
+ return expr.MarkReachable (rc);
+ }
}
//
return null;
}
- public bool IsPossibleTypeOrNamespace (IMemberContext mc)
+ bool IsPossibleTypeOrNamespace (IMemberContext mc)
{
- return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
+ //
+ // Has to ignore static usings because we are looking for any member not just type
+ // in this context
+ //
+ return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
}
public bool IsPossibleType (IMemberContext mc)
// introduce redundant storey but with `this' only but it's tricky to avoid
// at this stage as we don't know what expressions follow base
//
+ // TODO: It's needed only when the method with base call is moved to a storey
+ //
if (rc.CurrentAnonymousMethod != null) {
if (targs == null && method.IsGeneric) {
targs = method.TypeArguments;
CheckProtectedMemberAccess (rc, member);
}
- if (member.MemberType.IsPointer && !rc.IsUnsafe) {
- UnsafeError (rc, loc);
+ if (member.MemberType.IsPointer) {
+ if (rc.CurrentIterator != null) {
+ UnsafeInsideIteratorError (rc, loc);
+ } else if (!rc.IsUnsafe) {
+ UnsafeError (rc, loc);
+ }
}
var dep = member.GetMissingDependencies ();
return this;
}
+ public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+
+ }
+
protected void EmitInstance (EmitContext ec, bool prepare_for_load)
{
var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
// For extension methodgroup we are not looking for base members but parent
// namespace extension methods
//
- public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
+ public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
{
// TODO: candidates are null only when doing error reporting, that's
// incorrect. We have to discover same extension methods in error mode
Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
}
- public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
{
- rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
-
- // Not included in C#6
- /*
- ExtensionExpression = ExtensionExpression.Resolve (rc);
- if (ExtensionExpression == null)
- return false;
-
- var argType = ExtensionExpression.Type;
- foreach (MethodSpec candidate in Candidates) {
- if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
- return true;
- }
-
- // TODO: Scan full hierarchy
-
- ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
- */
- return false;
+ rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
}
public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
throw new NotSupportedException ();
}
+ public override void EmitPrepare (EmitContext ec)
+ {
+ InstanceExpression?.EmitPrepare (ec);
+ }
+
public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
{
var call = new CallEmitter ();
return base.ResolveMemberAccess (ec, left, original);
}
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+ if (!HasAccessibleCandidate (rc)) {
+ ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
+ }
+
+ if (expr.HasTypeArguments) {
+ rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
+ }
+ }
+
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
type_arguments = ta;
#region IBaseMembersProvider Members
- public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
+ public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
{
- return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
+ var baseType = type.BaseType;
+
+ IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
+
+ if (members == null && !type.IsInterface) {
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null)
+ members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
+ }
+
+ return members;
}
public IParametersMember GetOverrideMemberParameters (MemberSpec member)
{
TypeSpec argument_type = a.Type;
+ //
+ // Exactly matching Expression phase
+ //
+
//
// If argument is an anonymous function
//
//
// Uwrap delegate from Expression<T>
//
- q = TypeManager.GetTypeArguments (q)[0];
- p = TypeManager.GetTypeArguments (p)[0];
+ q = TypeManager.GetTypeArguments (q) [0];
+ p = TypeManager.GetTypeArguments (p) [0];
}
var p_m = Delegate.GetInvokeMethod (p);
// if p has a return type Y, and q is void returning, then C1 is the better conversion.
//
if (q.Kind == MemberKind.Void) {
- return p.Kind != MemberKind.Void ? 1: 0;
+ return p.Kind != MemberKind.Void ? 1 : 0;
}
- var am = (AnonymousMethodExpression) a.Expr;
+ 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>
//
if (p.IsGenericTask || q.IsGenericTask) {
if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
- q = q.TypeArguments[0];
- p = p.TypeArguments[0];
+ q = q.TypeArguments [0];
+ p = p.TypeArguments [0];
}
}
if (q != p) {
//
- // An inferred return type X exists for E in the context of that parameter list, and
- // the conversion from X to Y1 is better than the conversion from X to Y2
+ // An inferred return type X exists for E in the context of the parameter list, and
+ // an identity conversion exists from X to the return type of D
//
- argument_type = am.InferReturnType (ec, null, orig_q);
- if (argument_type == null) {
- // TODO: Can this be hit?
- return 1;
- }
+ var inferred_type = am.InferReturnType (ec, null, orig_q);
+ if (inferred_type != null) {
+ if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
+ inferred_type = ec.BuiltinTypes.Object;
- if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
- argument_type = ec.BuiltinTypes.Object;
+ if (inferred_type == p)
+ return 1;
+
+ if (inferred_type == q)
+ return 2;
+ }
}
}
if (argument_type == q)
return 2;
- //
- // The parameters are identicial and return type is not void, use better type conversion
- // on return type to determine better one
- //
- return BetterTypeConversion (ec, p, q);
+ return IsBetterConversionTarget (ec, p, q);
+ }
+
+ static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
+ {
+ if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
+
+ if (p.Kind != MemberKind.Delegate) {
+ p = TypeManager.GetTypeArguments (p) [0];
+ }
+
+ if (q.Kind != MemberKind.Delegate) {
+ q = TypeManager.GetTypeArguments (q) [0];
+ }
+
+ var p_m = Delegate.GetInvokeMethod (p);
+ var q_m = Delegate.GetInvokeMethod (q);
+
+ p = p_m.ReturnType;
+ q = q_m.ReturnType;
+
+ //
+ // if p is void returning, and q has a return type Y, then C2 is the better conversion.
+ //
+ if (p.Kind == MemberKind.Void) {
+ return q.Kind != MemberKind.Void ? 2 : 0;
+ }
+
+ //
+ // if p has a return type Y, and q is void returning, then C1 is the better conversion.
+ //
+ if (q.Kind == MemberKind.Void) {
+ return p.Kind != MemberKind.Void ? 1 : 0;
+ }
+
+ return IsBetterConversionTarget (rc, p, q);
+ }
+
+ if (p.IsGenericTask && q.IsGenericTask) {
+ q = q.TypeArguments [0];
+ p = p.TypeArguments [0];
+ return IsBetterConversionTarget (rc, p, q);
+ }
+
+ var p_orig = p;
+ if (p.IsNullableType) {
+ p = Nullable.NullableInfo.GetUnderlyingType (p);
+ if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
+ return BetterTypeConversionImplicitConversion (rc, p_orig, q);
+
+ //
+ // Spec expects implicit conversion check between p and q, q and p
+ // to be done before nullable unwrapping but that's expensive operation.
+ //
+ // Extra manual tweak is needed because BetterTypeConversion works on
+ // unwrapped types
+ //
+ if (p == q)
+ return 2;
+ }
+
+ var q_orig = q;
+ if (q.IsNullableType) {
+ q = Nullable.NullableInfo.GetUnderlyingType (q);
+ if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
+ return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
+
+ if (q == p)
+ return 1;
+ }
+
+ return BetterTypeConversion (rc, p, q);
}
//
}
break;
case BuiltinTypeSpec.Type.Dynamic:
- // Dynamic is never better
- return 2;
+ // LAMESPEC: Dynamic conversions is not considered
+ p = ec.Module.Compiler.BuiltinTypes.Object;
+ break;
}
switch (q.BuiltinType) {
}
break;
case BuiltinTypeSpec.Type.Dynamic:
- // Dynamic is never better
- return 1;
+ // LAMESPEC: Dynamic conversions is not considered
+ q = ec.Module.Compiler.BuiltinTypes.Object;
+ break;
}
- // FIXME: handle lifted operators
+ return BetterTypeConversionImplicitConversion (ec, p, q);
+ }
+ static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
+ {
// TODO: this is expensive
Expression p_tmp = new EmptyExpression (p);
Expression q_tmp = new EmptyExpression (q);
- bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
- bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
+ bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
+ bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
if (p_to_q && !q_to_p)
return 1;
/// false if candidate ain't better
/// true if candidate is better than the current best match
/// </remarks>
- static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
+ bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
MemberSpec best, AParametersCollection bparam, bool best_params)
{
AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
AParametersCollection best_pd = ((IParametersMember) best).Parameters;
- bool better_at_least_one = false;
+ int candidate_better_count = 0;
+ int best_better_count = 0;
+
bool are_equivalent = true;
int args_count = args == null ? 0 : args.Count;
int j = 0;
// for each argument, the conversion to 'ct' should be no worse than
// the conversion to 'bt'.
if (result == 2) {
- better_at_least_one = false;
-
- ++j;
- while (j < args_count && !args [j++].IsDefaultArgument) ;
+ //
+ // No optional parameters tie breaking rules for delegates overload resolution
+ //
+ if ((restrictions & Restrictions.CovariantDelegate) != 0)
+ return false;
- break;
+ ++best_better_count;
+ continue;
}
// for at least one argument, the conversion to 'ct' should be better than
// the conversion to 'bt'.
if (result != 0)
- better_at_least_one = true;
+ ++candidate_better_count;
}
- if (better_at_least_one)
+ if (candidate_better_count != 0 && best_better_count == 0)
return true;
+ if (best_better_count > 0 && candidate_better_count == 0)
+ return false;
+
//
// LAMESPEC: Tie-breaking rules for not equivalent parameter types
//
if (!are_equivalent) {
+ while (j < args_count && !args [j++].IsDefaultArgument) ;
+
//
// A candidate with no default parameters is still better when there
- // is no better expression conversion
+ // is no better expression conversion and does not have more parameters
//
if (candidate_pd.Count < best_pd.Count) {
- if (!candidate_params && !candidate_pd.FixedParameters [j - j].HasDefaultValue) {
+ if (candidate_params)
+ return false;
+
+ if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
return true;
- }
+
+ if (best_pd.FixedParameters [j].HasDefaultValue)
+ return true;
+
} else if (candidate_pd.Count == best_pd.Count) {
if (candidate_params)
return false;
// The slot has been taken by positional argument
if (temp != null && !(temp is NamedArgument))
- break;
+ return NamedArgumentsMismatch - i - 1;
}
if (!arg_moved) {
if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
} else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
- e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
+ e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
} else if (ec.MemberContext.CurrentMemberDefinition != null) {
e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
}
if (arg_type == InternalType.VarOutType)
return 0;
+ var ref_arg_type = arg_type as ReferenceContainer;
+ if (ref_arg_type != null) {
+ arg_type = ref_arg_type.Element;
+ }
+
//
// Do full equality check after quick path
//
static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
{
- if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
- return q;
- if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
- return p;
+ if (p.IsGenericParameter != q.IsGenericParameter)
+ return p.IsGenericParameter ? q : p;
var ac_p = p as ArrayContainer;
if (ac_p != null) {
return p;
if (specific == ac_q.Element)
return q;
- } else if (p.IsGeneric && q.IsGeneric) {
- var pargs = TypeManager.GetTypeArguments (p);
- var qargs = TypeManager.GetTypeArguments (q);
+
+ return null;
+ }
+
+ if (p.IsGeneric && q.IsGeneric) {
+ var pargs = p.TypeArguments;
+ var qargs = q.TypeArguments;
bool p_specific_at_least_once = false;
bool q_specific_at_least_once = false;
for (int i = 0; i < pargs.Length; i++) {
- TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
- if (specific == pargs[i])
+ TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
+ if (specific == pargs [i])
p_specific_at_least_once = true;
- if (specific == qargs[i])
+ if (specific == qargs [i])
q_specific_at_least_once = true;
}
// Restore expanded arguments
candidate_args = args;
}
- } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
+ } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
//
// We've found exact match
int arg_count = args == null ? 0 : args.Count;
for (; a_idx < arg_count; a_idx++, ++a_pos) {
- a = args[a_idx];
+ a = args [a_idx];
if (a == null)
continue;
if (p_mod != Parameter.Modifier.PARAMS) {
p_mod = cpd.FixedParameters [a_idx].ModFlags;
- pt = ptypes[a_idx];
+ pt = ptypes [a_idx];
has_unsafe_arg |= pt.IsPointer;
if (p_mod == Parameter.Modifier.PARAMS) {
continue;
}
+ var ref_arg_type = arg_type as ReferenceContainer;
+ if (ref_arg_type != null) {
+ if (ref_arg_type.Element != pt)
+ break;
+
+ return true;
+ }
+
if (!TypeSpecComparer.IsEqual (arg_type, pt))
break;
}
arg_count++;
}
- if (has_unsafe_arg && !ec.IsUnsafe) {
- Expression.UnsafeError (ec, loc);
+ if (has_unsafe_arg) {
+ if (ec.CurrentIterator != null) {
+ Expression.UnsafeInsideIteratorError (ec, loc);
+ } else if (!ec.IsUnsafe) {
+ Expression.UnsafeError (ec, loc);
+ }
}
//
return constant.GetSignatureForError ();
}
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+ constant.CheckObsoleteness (rc, expr.Location);
+ }
+
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
return this;
}
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+ spec.CheckObsoleteness (rc, expr.Location);
+ }
+
public void SetFieldAssigned (FlowAnalysisContext fc)
{
if (!IsInstance)
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
if (right_side == EmptyExpression.LValueMemberAccess) {
// Already reported as CS1648/CS1650
- return null;
+ return ErrorExpression.Instance;
}
if (right_side == EmptyExpression.LValueMemberOutAccess) {
rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
if (IsStatic) {
GetSignatureForError ());
}
- return null;
+ return ErrorExpression.Instance;
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
if (backing_field != null) {
- backing_field.EmitAssign (ec, source, false, false);
+ backing_field.EmitAssign (ec, source, leave_copy, false);
return;
}
return true;
}
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+ if (!best_candidate.IsAccessible (rc))
+ ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
+
+ best_candidate.CheckObsoleteness (rc, expr.Location);
+ }
+
public void SetBackingFieldAssigned (FlowAnalysisContext fc)
{
if (backing_field != null) {
Error_NullPropagatingLValue (rc);
if (right_side == EmptyExpression.OutAccess) {
+ if (best_candidate?.MemberType.Kind == MemberKind.ByRef) {
+ if (Arguments?.ContainsEmitWithAwait () == true) {
+ rc.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+ GetSignatureForError ());
+ }
+
+ return this;
+ }
+
// TODO: best_candidate can be null at this point
INamedBlockVariable variable = null;
if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
if (ResolveAutopropertyAssignment (rc, right_side))
return this;
+ if (best_candidate.MemberType.Kind == MemberKind.ByRef) {
+ getter = CandidateToBaseOverride (rc, best_candidate.Get);
+ return ByRefDereference.Create(this).Resolve(rc);
+ }
+
rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
GetSignatureForError ());
return null;
return TypeManager.CSharpSignature (spec);
}
+ public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
+ {
+ spec.CheckObsoleteness (rc, expr.Location);
+ }
+
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
{
}
- public bool InferType (ResolveContext ec, Expression right_side)
+ public bool InferType (ResolveContext ec, Expression rhs)
{
if (type != null)
throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
- type = right_side.Type;
- if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
+ type = rhs.Type;
+
+ if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || (rhs is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
ec.Report.Error (815, loc,
"An implicitly typed local variable declaration cannot be initialized with `{0}'",
type.GetSignatureForError ());