ReadAccess = 1 << 3,
EmptyArguments = 1 << 4,
IgnoreArity = 1 << 5,
- IgnoreAmbiguity = 1 << 6
+ IgnoreAmbiguity = 1 << 6,
+ NameOfExcluded = 1 << 7,
}
//
if (members == null)
return null;
- MemberSpec non_method = null;
- MemberSpec ambig_non_method = null;
+ Expression expr;
do {
- for (int i = 0; i < members.Count; ++i) {
- var member = members[i];
+ expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
+ if (expr != null)
+ return expr;
- // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
- if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
- continue;
+ if (members [0].DeclaringType.BaseType == null)
+ members = null;
+ else
+ members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
+ } while (members != null);
- if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
- continue;
+ return expr;
+ }
- if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
- continue;
+ public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
+ {
+ MemberSpec non_method = null;
+ MemberSpec ambig_non_method = null;
- if (!errorMode) {
- if (!member.IsAccessible (rc))
- continue;
+ for (int i = 0; i < members.Count; ++i) {
+ var member = members [i];
- //
- // With runtime binder we can have a situation where queried type is inaccessible
- // because it came via dynamic object, the check about inconsisted accessibility
- // had no effect as the type was unknown during compilation
- //
- // class A {
- // private class N { }
- //
- // public dynamic Foo ()
- // {
- // return new N ();
- // }
- // }
- //
- if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
- continue;
- }
+ // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
+ if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
+ continue;
- 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);
+ if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
+ continue;
- return new MethodGroupExpr (members, queried_type, loc);
- }
+ if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
+ continue;
- if (!Invocation.IsMemberInvocable (member))
- continue;
- }
+ if (!errorMode) {
+ if (!member.IsAccessible (rc))
+ continue;
- if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
- non_method = member;
- } else if (!errorMode && !member.IsNotCSharpCompatible) {
- //
- // Interface members that are hidden by class members are removed from the set when T is a type parameter and
- // T has both an effective base class other than object and a non-empty effective interface set.
+ //
+ // With runtime binder we can have a situation where queried type is inaccessible
+ // because it came via dynamic object, the check about inconsisted accessibility
+ // had no effect as the type was unknown during compilation
+ //
+ // class A {
+ // private class N { }
+ //
+ // public dynamic Foo ()
+ // {
+ // return new N ();
+ // }
+ // }
+ //
+ if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
+ continue;
+ }
+
+ if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
+ if (member is MethodSpec) {
//
- // The spec has more complex rules but we simply remove all members declared in an interface declaration.
+ // 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) {
- if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
- continue;
+ if (tps != null && tps.HasTypeConstraint)
+ members = RemoveHiddenTypeParameterMethods (members);
- if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
- non_method = member;
- continue;
- }
- }
-
- ambig_non_method = member;
+ return new MethodGroupExpr (members, queried_type, loc);
}
+
+ if (!Invocation.IsMemberInvocable (member))
+ continue;
}
- if (non_method != null) {
- if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
- var report = rc.Module.Compiler.Report;
- report.SymbolRelatedToPreviousError (non_method);
- report.SymbolRelatedToPreviousError (ambig_non_method);
- report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
- non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
+ if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
+ non_method = member;
+ } else if (!errorMode && !member.IsNotCSharpCompatible) {
+ //
+ // Interface members that are hidden by class members are removed from the set when T is a type parameter and
+ // T has both an effective base class other than object and a non-empty effective interface set.
+ //
+ // The spec has more complex rules but we simply remove all members declared in an interface declaration.
+ //
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null && tps.HasTypeConstraint) {
+ if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
+ continue;
+
+ if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
+ non_method = member;
+ continue;
+ }
}
- if (non_method is MethodSpec)
- return new MethodGroupExpr (members, queried_type, loc);
+ ambig_non_method = member;
+ }
+ }
- return ExprClassFromMemberInfo (non_method, loc);
+ if (non_method != null) {
+ if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
+ var report = rc.Module.Compiler.Report;
+ report.SymbolRelatedToPreviousError (non_method);
+ report.SymbolRelatedToPreviousError (ambig_non_method);
+ report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
+ non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
}
- if (members[0].DeclaringType.BaseType == null)
- members = null;
- else
- members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
+ if (non_method is MethodSpec)
+ return new MethodGroupExpr (members, queried_type, loc);
- } while (members != null);
+ return ExprClassFromMemberInfo (non_method, loc);
+ }
return null;
}
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);
return members;
}
+ protected static void Error_NamedArgument (NamedArgument na, Report Report)
+ {
+ Report.Error (1742, na.Location, "An element access expression cannot use named argument");
+ }
+
protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
{
throw new NotImplementedException ();
rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
}
+ protected void Error_NullPropagatingLValue (ResolveContext rc)
+ {
+ rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
+ }
+
public virtual void FlowAnalysis (FlowAnalysisContext fc)
{
}
if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
Arguments args = new Arguments (1);
args.Add (new Argument (source));
- return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
+ return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
}
Expression converted;
return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
}
+ public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
+ {
+ if (args.Count != 1){
+ rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
+ return null;
+ }
+
+ var arg = args [0];
+ if (arg is NamedArgument)
+ Error_NamedArgument ((NamedArgument) arg, rc.Report);
+
+ var index = arg.Expr.Resolve (rc);
+ if (index == null)
+ return null;
+
+ index = ConvertExpressionToArrayIndex (rc, index, true);
+
+ Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
+ return new Indirection (p, loc);
+ }
+
//
// Derived classes implement this method by cloning the fields that
// could become altered during the Resolve stage
return null;
ExpressionStatement es = e as ExpressionStatement;
- if (es == null || e is AnonymousMethodBody)
+ if (es == null || e is AnonymousMethodBody) {
+ var reduced = e as IReducedExpressionStatement;
+ if (reduced != null) {
+ return EmptyExpressionStatement.Instance;
+ }
+
Error_InvalidExpressionStatement (ec);
+ }
//
// This is quite expensive warning, try to limit the damage
}
}
+ interface IReducedExpressionStatement
+ {
+ }
+
/// <summary>
/// This kind of cast is used to encapsulate the child
/// whose type is child.Type into an expression that is
//
public class ReducedExpression : Expression
{
- public sealed class ReducedConstantExpression : EmptyConstantCast
+ public class ReducedConstantExpression : EmptyConstantCast
{
readonly Expression orig_expr;
}
}
+ sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
+ {
+ public ReducedConstantStatement (Constant expr, Expression origExpr)
+ : base (expr, origExpr)
+ {
+ }
+ }
+
sealed class ReducedExpressionStatement : ExpressionStatement
{
readonly Expression orig_expr;
//
// Creates fully resolved expression switcher
//
- public static Constant Create (Constant expr, Expression original_expr)
+ public static Constant Create (Constant expr, Expression originalExpr)
{
if (expr.eclass == ExprClass.Unresolved)
throw new ArgumentException ("Unresolved expression");
- return new ReducedConstantExpression (expr, original_expr);
+ if (originalExpr is ExpressionStatement)
+ return new ReducedConstantStatement (expr, originalExpr);
+
+ return new ReducedConstantExpression (expr, originalExpr);
}
public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
}
protected ATypeNameExpression (string name, int arity, Location l)
- : this (name, new UnboundTypeArguments (arity), l)
+ : this (name, new UnboundTypeArguments (arity, l), l)
{
}
(targs == null || targs.Equals (atne.targs));
}
- protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
- {
- mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
- }
-
public override int GetHashCode ()
{
return Name.GetHashCode ();
return ct;
}
- if (!allowUnboundTypeArguments)
- Error_OpenGenericTypeIsNotAllowed (mc);
+ targs.Resolve (mc, allowUnboundTypeArguments);
return new GenericOpenTypeExpr (fne.Type, loc);
}
return fne;
}
- if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
+ if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
mc.Module.Compiler.Report.Error (1980, Location,
"Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
}
+ public bool IsPossibleType (IMemberContext mc)
+ {
+ return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
+ }
+
public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
{
int lookup_arity = Arity;
ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
}
} else {
- // LAMESPEC: again, ignores InvocableOnly
- if (variable != null) {
- rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
- rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
- }
-
//
// MemberLookup does not check accessors availability, this is actually needed for properties only
//
pe.Getter = pe.PropertyInfo.Get;
} else {
- if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
+ if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
+ pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
+ var p = (Property) pe.PropertyInfo.MemberDefinition;
+ return new FieldExpr (p.BackingField, loc);
+ }
+
+ if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc)) {
+ variable_found = true;
break;
+ }
pe.Setter = pe.PropertyInfo.Set;
}
me = me.ResolveMemberAccess (rc, null, null);
if (Arity > 0) {
- targs.Resolve (rc);
+ targs.Resolve (rc, false);
me.SetTypeArguments (rc, targs);
}
//
if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
if (IsPossibleTypeOrNamespace (rc)) {
- if (variable != null) {
- rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
- rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
- }
-
return ResolveAsTypeOrNamespace (rc, false);
}
}
- var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
- if (mg != null) {
+ var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
+ if (expr != null) {
if (Arity > 0) {
- targs.Resolve (rc);
- mg.SetTypeArguments (rc, targs);
+ targs.Resolve (rc, false);
+
+ var me = expr as MemberExpr;
+ if (me != null)
+ me.SetTypeArguments (rc, targs);
}
- return mg;
+ return expr;
}
- if (Name == "nameof")
+ if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
return new NameOf (this);
if (errorMode) {
// Obsolete checks cannot be done when resolving base context as they
// require type dependencies to be set but we are in process of resolving them
//
- if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
- ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
- if (obsolete_attr != null && !mc.IsObsolete) {
- AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
- }
+ if (mc is ResolveContext) {
+ var oa = type.GetAttributeObsolete ();
+ if (oa != null && !mc.IsObsolete)
+ AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
}
return type;
return this;
}
- public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
+ public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
{
var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
if (retval != null) {
ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
}
- if (!rc.IsObsolete) {
- ObsoleteAttribute oa = member.GetAttributeObsolete ();
- if (oa != null)
- AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
- }
+ member.CheckObsoleteness (rc, loc);
if (!(member is FieldSpec))
member.MemberDefinition.SetIsUsed ();
if (InstanceExpression is TypeExpr) {
var t = InstanceExpression.Type;
do {
- ObsoleteAttribute oa = t.GetAttributeObsolete ();
- if (oa != null && !rc.IsObsolete) {
- AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
- }
+ t.CheckObsoleteness (rc, loc);
t = t.DeclaringType;
} while (t != null);
int arity = type_arguments == null ? 0 : type_arguments.Count;
- candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
+ candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
if (candidates == null)
return null;
public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
{
+ 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;
// TODO: Scan full hierarchy
ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
+ */
return false;
}
bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
{
rc.Report.SymbolRelatedToPreviousError (best);
- rc.Report.Error (1928, loc,
- "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
- queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
if (index == 0) {
rc.Report.Error (1929, loc,
- "Extension method instance type `{0}' cannot be converted to `{1}'",
- arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
+ "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
+ queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
+ } else {
+ rc.Report.Error (1928, loc,
+ "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
+ queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
}
return true;
Name, target.GetSignatureForError ());
}
+ public bool HasAccessibleCandidate (ResolveContext rc)
+ {
+ foreach (var candidate in Candidates) {
+ if (candidate.IsAccessible (rc))
+ return true;
+ }
+
+ return false;
+ }
+
public static bool IsExtensionMethodArgument (Expression expr)
{
//
return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
- var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
+ var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
if (methods == null)
return null;
var cand_param = candidate_pd.FixedParameters [j];
var best_param = best_pd.FixedParameters [j];
+ if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
+ return cand_param.HasDefaultValue;
+
if (candidate_pd.Count == best_pd.Count) {
//
// LAMESPEC:
// void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
// void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
//
- if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
- return cand_param.HasDefaultValue;
if (cand_param.HasDefaultValue) {
++j;
// void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
// void Foo (string s, params int[]) <-> Foo (string s, params byte[])
//
- if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
- return false;
+ return false;
}
break;
//
// 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) {
+ 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) {
Arguments candidate_args = args;
bool error_mode = false;
MemberSpec invocable_member = null;
+ int applicable_candidates = 0;
while (true) {
best_candidate = null;
if (candidate_rate < 0)
return null;
+ applicable_candidates = 1;
if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
// Only parameterless methods are considered
} else {
continue;
}
+ ++applicable_candidates;
bool is_better;
if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
//
//
// Check type constraints only when explicit type arguments are used
//
- if (best_candidate.IsGeneric && type_arguments != null) {
+ if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
MethodSpec bc = best_candidate as MethodSpec;
if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
ConstraintChecker cc = new ConstraintChecker (rc);
//
// 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);
+ best_candidate.CheckObsoleteness (rc, loc);
best_candidate.MemberDefinition.SetIsUsed ();
}
continue;
if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
- custom_errors.NoArgumentMatch (ec, member);
+ if (a.IsExtensionType) {
+ // TODO: Should report better message type, something similar to CS1928/1929 instead of
+ // CS1061 but that still better than confusing CS0123
+ var ma = new MemberAccess (a.Expr, member.Name, loc);
+ ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
+ } else {
+ custom_errors.NoArgumentMatch (ec, member);
+ }
return false;
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
- if (ConditionalAccess)
- throw new NotSupportedException ("null propagating operator assignment");
+ if (HasConditionalAccess ())
+ Error_NullPropagatingLValue (ec);
if (spec is FixedFieldSpec) {
// It could be much better error message but we want to be error compatible
return;
}
- if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
+ if (TypeSpec.IsValueType (InstanceExpression.Type)) {
+ var le = SkipLeftValueTypeAccess (InstanceExpression);
+ if (le != null)
+ le.FlowAnalysis (fc);
+
return;
+ }
}
base.FlowAnalysis (fc);
fc.ConditionalAccessEnd ();
}
+ static Expression SkipLeftValueTypeAccess (Expression expr)
+ {
+ if (!TypeSpec.IsValueType (expr.Type))
+ return expr;
+
+ if (expr is VariableReference)
+ return null;
+
+ var fe = expr as FieldExpr;
+ if (fe == null)
+ return expr;
+
+ if (fe.InstanceExpression == null)
+ return expr;
+
+ return SkipLeftValueTypeAccess (fe.InstanceExpression);
+ }
+
public override int GetHashCode ()
{
return spec.GetHashCode ();
if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
return false;
+ if (prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
+ var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (prop.ShortName, prop.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
+ if (ps == null)
+ return false;
+
+ prop = (Property) ps.MemberDefinition;
+ }
+
var spec = prop.BackingField;
if (spec == null)
return false;
public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
{
- if (ConditionalAccess)
- throw new NotSupportedException ("null propagating operator assignment");
+ if (HasConditionalAccess ())
+ Error_NullPropagatingLValue (rc);
if (right_side == EmptyExpression.OutAccess) {
// TODO: best_candidate can be null at this point
spec.MemberDefinition.SetIsUsed ();
- if (!ec.IsObsolete) {
- ObsoleteAttribute oa = spec.GetAttributeObsolete ();
- if (oa != null)
- AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
- }
+ spec.CheckObsoleteness (ec, loc);
if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
Error_AssignmentEventOnly (ec);
return null;
}
+ if (HasConditionalAccess ())
+ Error_NullPropagatingLValue (ec);
+
op = CandidateToBaseOverride (ec, op);
return this;
}
}
}
- public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
+ public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
{
- var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
+ var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
return new TemporaryVariableReference (li, loc);
}
ec.Report.Error (815, loc,
"An implicitly typed local variable declaration cannot be initialized with `{0}'",
type.GetSignatureForError ());
+ type = InternalType.ErrorType;
return false;
}