/// Currently ResolveLValue wraps DoResolveLValue to perform sanity
/// checking and assertion checking on what we expect from Resolve
/// </remarks>
- public Expression ResolveLValue (EmitContext ec, Expression right_side)
+ public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
{
int errors = Report.Errors;
Expression e = DoResolveLValue (ec, right_side);
if (e == null) {
if (errors == Report.Errors)
- Report.Error (131, Location, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
+ Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
return null;
}
Location loc)
{
if (almostMatchedMembers.Count != 0) {
- if (qualifier_type == null) {
- foreach (MemberInfo m in almostMatchedMembers)
+ for (int i = 0; i < almostMatchedMembers.Count; ++i) {
+ MemberInfo m = (MemberInfo) almostMatchedMembers [i];
+ for (int j = 0; j < i; ++j) {
+ if (m == almostMatchedMembers [j]) {
+ m = null;
+ break;
+ }
+ }
+ if (m == null)
+ continue;
+
+ Type declaring_type = m.DeclaringType;
+
+ Report.SymbolRelatedToPreviousError (m);
+ if (qualifier_type == null) {
Report.Error (38, loc,
"Cannot access non-static member `{0}' via nested type `{1}'",
TypeManager.GetFullNameSignature (m),
TypeManager.CSharpName (ec.ContainerType));
- return;
- }
-
- if (qualifier_type != ec.ContainerType) {
- // 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.ContainerType and the lookup succeeds with the latter one,
- // then we are in this situation.
- for (int i = 0; i < almostMatchedMembers.Count; ++i) {
- MemberInfo m = (MemberInfo) almostMatchedMembers [i];
- for (int j = 0; j < i; ++j) {
- if (m == almostMatchedMembers [j]) {
- m = null;
- break;
- }
- }
- if (m == null)
- continue;
-
- Report.SymbolRelatedToPreviousError (m);
+
+ } else if (qualifier_type != ec.ContainerType &&
+ TypeManager.IsNestedFamilyAccessible (ec.ContainerType, declaring_type)) {
+ // 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.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
Report.Error (1540, loc,
"Cannot access protected member `{0}' via a qualifier of type `{1}';"
+ " the qualifier must be of type `{2}' (or derived from it)",
TypeManager.GetFullNameSignature (m),
TypeManager.CSharpName (qualifier_type),
TypeManager.CSharpName (ec.ContainerType));
+ } else {
+ Report.Error (122, loc,
+ "'{0}' is inaccessible due to its protection level",
+ TypeManager.GetFullNameSignature (m));
}
- return;
}
almostMatchedMembers.Clear ();
+ return;
}
object lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
child.Emit (ec);
}
}
+ /// <summary>
+ /// This is a numeric cast to a Decimal
+ /// </summary>
+ public class CastToDecimal : EmptyCast {
+
+ MethodInfo conversion_operator;
+
+ public CastToDecimal (EmitContext ec, Expression child)
+ : this (ec, child, false)
+ {
+ }
+
+ public CastToDecimal (EmitContext ec, Expression child, bool find_explicit)
+ : base (child, TypeManager.decimal_type)
+ {
+ conversion_operator = GetConversionOperator (ec, find_explicit);
+
+ if (conversion_operator == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+ }
+
+ // Returns the implicit operator that converts from
+ // 'child.Type' to System.Decimal.
+ MethodInfo GetConversionOperator (EmitContext ec, bool find_explicit)
+ {
+ string operator_name = "op_Implicit";
+
+ if (find_explicit)
+ operator_name = "op_Explicit";
+
+ MethodGroupExpr opers = Expression.MethodLookup (
+ ec, type, operator_name, loc) as MethodGroupExpr;
+
+ if (opers == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+
+ foreach (MethodInfo oper in opers.Methods) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+ }
+ /// <summary>
+ /// This is an explicit numeric cast from a Decimal
+ /// </summary>
+ public class CastFromDecimal : EmptyCast
+ {
+ MethodInfo conversion_operator;
+ public CastFromDecimal (EmitContext ec, Expression child, Type return_type)
+ : base (child, return_type)
+ {
+ if (child.Type != TypeManager.decimal_type)
+ throw new InternalErrorException (
+ "The expected type is Decimal, instead it is " + child.Type.FullName);
+
+ conversion_operator = GetConversionOperator (ec);
+ if (conversion_operator == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+ }
+
+ // Returns the explicit operator that converts from an
+ // express of type System.Decimal to 'type'.
+ MethodInfo GetConversionOperator (EmitContext ec)
+ {
+ MethodGroupExpr opers = Expression.MethodLookup (
+ ec, child.Type, "op_Explicit", loc) as MethodGroupExpr;
+
+ if (opers == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+
+ foreach (MethodInfo oper in opers.Methods) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+ }
//
// We need to special case this since an empty cast of
/// </summary>
public class SimpleName : Expression {
public string Name;
+ bool in_transit;
public SimpleName (string name, Location l)
{
Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
{
+ if (in_transit)
+ return null;
+ in_transit = true;
+
Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
if (e == null)
return null;
var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
if (right_side != null)
- return var.ResolveLValue (ec, right_side);
+ return var.ResolveLValue (ec, right_side, loc);
else
return var.Resolve (ec);
}
- ParameterReference pref = current_block.GetParameterReference (Name, loc);
+ ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
if (pref != null) {
if (right_side != null)
- return pref.ResolveLValue (ec, right_side);
+ return pref.ResolveLValue (ec, right_side, loc);
else
return pref.Resolve (ec);
}
return exp;
}
}
-
- // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
+
+ //
+ // Decimal constants cannot be encoded in the constant blob, and thus are marked
+ // as IsInitOnly ('readonly' in C# parlance). We get its value from the
+ // DecimalConstantAttribute metadata.
+ //
if (FieldInfo.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
object[] attrs = FieldInfo.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
if (attrs.Length == 1)