}
}
- /// <summary>
- /// Expression which resolves to a type.
- /// </summary>
- public interface ITypeExpression
- {
- /// <summary>
- /// Resolve the expression, but only lookup types.
- /// </summary>
- Expression DoResolveType (EmitContext ec);
- }
-
/// <remarks>
/// Base class for expressions
/// </remarks>
{
return DoResolve (ec);
}
-
+
+ //
+ // This is used if the expression should be resolved as a type.
+ // the default implementation fails. Use this method in
+ // those participants in the SimpleName chain system.
+ //
+ public virtual Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ return null;
+ }
+
+ //
+ // This is used to resolve the expression as a type, a null
+ // value will be returned if the expression is not a type
+ // reference
+ //
+ public Expression ResolveAsTypeTerminal (EmitContext ec)
+ {
+ Expression e = ResolveAsTypeStep (ec);
+
+ if (e == null)
+ return null;
+ if (e is SimpleName)
+ return null;
+ return e;
+ }
+
/// <summary>
/// Resolves an expression and performs semantic analysis on it.
/// </summary>
/// </remarks>
public Expression Resolve (EmitContext ec, ResolveFlags flags)
{
- // Are we doing a types-only search ?
- if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) {
- ITypeExpression type_expr = this as ITypeExpression;
-
- if (type_expr == null)
- return null;
-
- return type_expr.DoResolveType (ec);
- }
+ if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return ResolveAsTypeStep (ec);
bool old_do_flow_analysis = ec.DoFlowAnalysis;
if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
SimpleName s = (SimpleName) e;
if ((flags & ResolveFlags.SimpleName) == 0) {
-
- object lookup = TypeManager.MemberLookup (
- ec.ContainerType, ec.ContainerType, AllMemberTypes,
- AllBindingFlags | BindingFlags.NonPublic, s.Name);
- if (lookup != null)
- Error (122, "`" + s.Name + "' " +
- "is inaccessible because of its protection level");
- else
- Error (103, "The name `" + s.Name + "' could not be " +
- "found in `" + ec.DeclSpace.Name + "'");
+ MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
+ ec.DeclSpace.Name, loc);
return null;
}
if ((e is TypeExpr) || (e is ComposedCast)) {
if ((flags & ResolveFlags.Type) == 0) {
- e.Error118 (flags);
+ e.Error_UnexpectedKind (flags);
return null;
}
switch (e.eclass) {
case ExprClass.Type:
if ((flags & ResolveFlags.VariableOrValue) == 0) {
- e.Error118 (flags);
+ e.Error_UnexpectedKind (flags);
return null;
}
break;
case ExprClass.EventAccess:
case ExprClass.IndexerAccess:
if ((flags & ResolveFlags.VariableOrValue) == 0) {
- e.Error118 (flags);
+ Console.WriteLine ("I got: {0} and {1}", e.GetType (), e);
+ Console.WriteLine ("I am {0} and {1}", this.GetType (), this);
+ FieldInfo fi = ((FieldExpr) e).FieldInfo;
+
+ Console.WriteLine ("{0} and {1}", fi.DeclaringType, fi.Name);
+ e.Error_UnexpectedKind (flags);
return null;
}
break;
if (e != null){
if (e is SimpleName){
SimpleName s = (SimpleName) e;
-
- Report.Error (
- 103, loc,
- "The name `" + s.Name + "' could not be found in `" +
- ec.DeclSpace.Name + "'");
+ MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
+ ec.DeclSpace.Name, loc);
return null;
}
else if (mi is FieldInfo)
return new FieldExpr ((FieldInfo) mi, loc);
else if (mi is PropertyInfo)
- return new PropertyExpr ((PropertyInfo) mi, loc);
+ return new PropertyExpr (ec, (PropertyInfo) mi, loc);
else if (mi is Type){
return new TypeExpr ((System.Type) mi, loc);
}
// FIXME: Potential optimization, have a static ArrayList
//
- public static Expression MemberLookup (EmitContext ec, Type t, string name,
+ public static Expression MemberLookup (EmitContext ec, Type queried_type, string name,
MemberTypes mt, BindingFlags bf, Location loc)
{
- return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
+ return MemberLookup (ec, ec.ContainerType, null, queried_type, name, mt, bf, loc);
}
//
- // Lookup type `t' for code in class `invocation_type'. Note that it's important
- // to set `invocation_type' correctly since this method also checks whether the
- // invoking class is allowed to access the member in class `t'. When you want to
- // explicitly do a lookup in the base class, you must set both `t' and `invocation_type'
- // to the base class (although a derived class can access protected members of its base
- // class it cannot do so through an instance of the base class (error CS1540)).
- //
+ // Lookup type `queried_type' for code in class `container_type' with a qualifier of
+ // `qualifier_type' or null to lookup members in the current class.
+ //
- public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
- string name, MemberTypes mt, BindingFlags bf,
- Location loc)
+ public static Expression MemberLookup (EmitContext ec, Type container_type,
+ Type qualifier_type, Type queried_type,
+ string name, MemberTypes mt,
+ BindingFlags bf, Location loc)
{
- MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
+ MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
+ queried_type, mt, bf, name);
if (mi == null)
return null;
int count = mi.Length;
- if (count > 1)
- return new MethodGroupExpr (mi, loc);
-
if (mi [0] is MethodBase)
return new MethodGroupExpr (mi, loc);
+ if (count > 1)
+ return null;
+
return ExprClassFromMemberInfo (ec, mi [0], loc);
}
BindingFlags.Static |
BindingFlags.Instance;
- public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc)
+ public static Expression MemberLookup (EmitContext ec, Type queried_type,
+ string name, Location loc)
{
- return MemberLookup (ec, ec.ContainerType, t, name,
+ return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
AllMemberTypes, AllBindingFlags, loc);
}
- public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
+ public static Expression MemberLookup (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name, Location loc)
{
- return MemberLookup (ec, ec.ContainerType, t, name,
+ return MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
+ name, AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MethodLookup (EmitContext ec, Type queried_type,
+ string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
MemberTypes.Method, AllBindingFlags, loc);
}
/// look for private members and display a useful debugging message if we
/// find it.
/// </summary>
- public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
- Location loc)
+ public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name, Location loc)
{
- return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
+ return MemberLookupFinal (ec, qualifier_type, queried_type, name,
+ AllMemberTypes, AllBindingFlags, loc);
}
- public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
- MemberTypes mt, BindingFlags bf, Location loc)
+ public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name,
+ MemberTypes mt, BindingFlags bf,
+ Location loc)
{
Expression e;
int errors = Report.Errors;
- e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
+ e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
+ name, mt, bf, loc);
if (e != null)
return e;
// Error has already been reported.
if (errors < Report.Errors)
return null;
-
- e = MemberLookup (ec, t, name, AllMemberTypes,
- AllBindingFlags | BindingFlags.NonPublic, loc);
- if (e == null){
+
+ MemberLookupFailed (ec, qualifier_type, queried_type, name, null, loc);
+ return null;
+ }
+
+ public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name,
+ string class_name, Location loc)
+ {
+ object lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
+ AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, name);
+
+ if (lookup == null) {
+ if (class_name != null)
+ Report.Error (103, loc, "The name `" + name + "' could not be " +
+ "found in `" + class_name + "'");
+ else
+ Report.Error (
+ 117, loc, "`" + queried_type + "' does not contain a " +
+ "definition for `" + name + "'");
+ return;
+ }
+
+ if ((qualifier_type != null) && (qualifier_type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (qualifier_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 parent of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
+
+ lookup = TypeManager.MemberLookup (
+ ec.ContainerType, ec.ContainerType, ec.ContainerType,
+ AllMemberTypes, AllBindingFlags, name);
+
+ if (lookup != null) {
+ Report.Error (
+ 1540, loc, "Cannot access protected member `" +
+ TypeManager.CSharpName (qualifier_type) + "." +
+ name + "' " + "via a qualifier of type `" +
+ TypeManager.CSharpName (qualifier_type) + "'; the " +
+ "qualifier must be of type `" +
+ TypeManager.CSharpName (ec.ContainerType) + "' " +
+ "(or derived from it)");
+ return;
+ }
+ }
+
+ if (qualifier_type != null)
Report.Error (
- 117, loc, "`" + t + "' does not contain a definition " +
- "for `" + name + "'");
- } else {
+ 122, loc, "`" + TypeManager.CSharpName (qualifier_type) + "." +
+ name + "' is inaccessible due to its protection level");
+ else
Report.Error (
- 122, loc, "`" + t + "." + name +
- "' is inaccessible due to its protection level");
- }
-
- return null;
+ 122, loc, "`" + name + "' is inaccessible due to its " +
+ "protection level");
}
static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
expr.Emit (null);
}
-
+
+ //
+ // notice that it is possible to write "ValueType v = 1", the ValueType here
+ // is an abstract class, and not really a value type, so we apply the same rules.
+ //
if (target_type == TypeManager.object_type) {
//
// A pointer type cannot be converted to object
if (expr_type.IsValueType)
return new BoxedCast (expr);
- if (expr_type.IsClass || expr_type.IsInterface)
+ if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type)
return new EmptyCast (expr, target_type);
+ } else if (target_type == TypeManager.value_type) {
+ if (expr_type.IsValueType)
+ return new BoxedCast (expr);
+ if (expr is NullLiteral)
+ return new BoxedCast (expr);
} else if (expr_type.IsSubclassOf (target_type)) {
+ //
+ // Special case: enumeration to System.Enum.
+ // System.Enum is not a value type, it is a class, so we need
+ // a boxing conversion
+ //
+ if (expr_type.IsEnum)
+ return new BoxedCast (expr);
+
return new EmptyCast (expr, target_type);
} else {
// from the null type to any reference-type.
if (expr is NullLiteral && !target_type.IsValueType)
- return new EmptyCast (expr, target_type);
+ return new NullLiteralTyped (target_type);
// from any class-type S to any interface-type T.
- if (expr_type.IsClass && target_type.IsInterface) {
- if (TypeManager.ImplementsInterface (expr_type, target_type))
- return new EmptyCast (expr, target_type);
- else
- return null;
+ if (target_type.IsInterface) {
+ if (TypeManager.ImplementsInterface (expr_type, target_type)){
+ if (expr_type.IsClass)
+ return new EmptyCast (expr, target_type);
+ else if (expr_type.IsValueType)
+ return new BoxedCast (expr);
+ }
}
// from any interface type S to interface-type T.
if (expr_type.IsInterface && target_type.IsInterface) {
-
if (TypeManager.ImplementsInterface (expr_type, target_type))
return new EmptyCast (expr, target_type);
else
return new EmptyCast (expr, target_type);
// from any delegate type to System.Delegate
- if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
+ if ((expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type)) &&
target_type == TypeManager.delegate_type)
return new EmptyCast (expr, target_type);
// from any array-type or delegate type into System.ICloneable.
- if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
+ if (expr_type.IsArray ||
+ expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type))
if (target_type == TypeManager.icloneable_type)
return new EmptyCast (expr, target_type);
return null;
}
- /// <summary>
- /// Handles expressions like this: decimal d; d = 1;
- /// and changes them into: decimal d; d = new System.Decimal (1);
- /// </summary>
- static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target)
- {
- ArrayList args = new ArrayList ();
-
- args.Add (new Argument (expr, Argument.AType.Expression));
-
- Expression ne = new New (new TypeExpr (target, Location.Null), args, Location.Null);
-
- return ne.Resolve (ec);
- }
-
/// <summary>
/// Implicit Numeric Conversions.
///
//
// Attempt to do the implicit constant expression conversions
- if (expr is IntConstant){
- Expression e;
+ if (expr is Constant){
- e = TryImplicitIntConversion (target_type, (IntConstant) expr);
-
- if (e != null)
- return e;
- } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
- //
- // Try the implicit constant expression conversion
- // from long to ulong, instead of a nice routine,
- // we just inline it
- //
- long v = ((LongConstant) expr).Value;
- if (v > 0)
- return new ULongConstant ((ulong) v);
+ if (expr is IntConstant){
+ Expression e;
+
+ e = TryImplicitIntConversion (target_type, (IntConstant) expr);
+
+ if (e != null)
+ return e;
+ } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
+ //
+ // Try the implicit constant expression conversion
+ // from long to ulong, instead of a nice routine,
+ // we just inline it
+ //
+ long v = ((LongConstant) expr).Value;
+ if (v > 0)
+ return new ULongConstant ((ulong) v);
+ }
}
-
+
Type real_target_type = target_type;
if (expr_type == TypeManager.sbyte_type){
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
if (real_target_type == TypeManager.short_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.byte_type){
//
// From byte to short, ushort, int, uint, long, ulong, float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
if (real_target_type == TypeManager.double_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.short_type){
//
// From short to int, long, float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.ushort_type){
//
// From ushort to int, uint, long, ulong, float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.int32_type){
//
// From int to long, float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.uint32_type){
//
// From uint to long, ulong, float, double
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.int64_type){
//
// From long/ulong to float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.uint64_type){
//
// From ulong to float, double
if (real_target_type == TypeManager.float_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
OpCodes.Conv_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.char_type){
//
// From char to ushort, int, uint, long, ulong, float, double
return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
if (real_target_type == TypeManager.double_type)
return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.float_type){
//
// float to double
// This is the boxed case.
//
if (target_type == TypeManager.object_type) {
- if ((expr_type.IsClass) ||
- (expr_type.IsValueType) ||
- (expr_type.IsInterface))
+ if (expr_type.IsClass || expr_type.IsValueType ||
+ expr_type.IsInterface || expr_type == TypeManager.enum_type)
return true;
-
} else if (expr_type.IsSubclassOf (target_type)) {
return true;
-
} else {
// Please remember that all code below actually comes
// from ImplicitReferenceConversion so make sure code remains in sync
// from any class-type S to any interface-type T.
- if (expr_type.IsClass && target_type.IsInterface) {
+ if (target_type.IsInterface) {
if (TypeManager.ImplementsInterface (expr_type, target_type))
return true;
}
return true;
// from any delegate type to System.Delegate
- if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
+ if ((expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type)) &&
target_type == TypeManager.delegate_type)
if (target_type.IsAssignableFrom (expr_type))
return true;
// from any array-type or delegate type into System.ICloneable.
- if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
+ if (expr_type.IsArray ||
+ expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type))
if (target_type == TypeManager.icloneable_type)
return true;
return false;
}
+ public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
+ {
+ Expression dummy = ImplicitUserConversion (
+ ec, new EmptyExpression (source), target, Location.Null);
+ return dummy != null;
+ }
+
/// <summary>
/// Determines if a standard implicit conversion exists from
/// expr_type to target_type
return true;
}
- if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
+ if ((target_type == TypeManager.enum_type ||
+ target_type.IsSubclassOf (TypeManager.enum_type)) &&
+ expr is IntLiteral){
IntLiteral i = (IntLiteral) expr;
if (i.Value == 0)
return UserDefinedConversion (ec, source, target, loc, true);
}
+ /// <summary>
+ /// Returns an expression that can be used to invoke operator true
+ /// on the expression if it exists.
+ /// </summary>
+ static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
+ {
+ MethodBase method;
+ Expression operator_group;
+
+ operator_group = MethodLookup (ec, e.Type, "op_True", loc);
+ if (operator_group == null)
+ return null;
+
+ ArrayList arguments = new ArrayList ();
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) operator_group, arguments, loc);
+
+ if (method == null)
+ return null;
+
+ return new StaticCallExpr ((MethodInfo) method, arguments, loc);
+ }
+
+ /// <summary>
+ /// Resolves the expression `e' into a boolean expression: either through
+ /// an implicit conversion, or through an `operator true' invocation
+ /// </summary>
+ public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
+ {
+ e = e.Resolve (ec);
+ if (e == null)
+ return null;
+
+ Expression converted = e;
+ if (e.Type != TypeManager.bool_type)
+ converted = Expression.ConvertImplicit (ec, e, TypeManager.bool_type, new Location (-1));
+
+ //
+ // If no implicit conversion to bool exists, try using `operator true'
+ //
+ if (converted == null){
+ Expression operator_true = Expression.GetOperatorTrue (ec, e, loc);
+ if (operator_true == null){
+ Report.Error (
+ 31, loc, "Can not convert the expression to a boolean");
+ return null;
+ }
+ e = operator_true;
+ } else
+ e = converted;
+
+ return e;
+ }
+
/// <summary>
/// Computes the MethodGroup for the user-defined conversion
/// operators from source_type to target_type. `look_for_explicit'
Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
string op_name;
- //
- // FIXME : How does the False operator come into the picture ?
- // This doesn't look complete and very correct !
- //
- if (target_type == TypeManager.bool_type && !look_for_explicit)
- op_name = "op_True";
- else
- op_name = "op_Implicit";
+ op_name = "op_Implicit";
MethodGroupExpr union3;
-
+
mg1 = MethodLookup (ec, source_type, op_name, loc);
if (source_type.BaseType != null)
mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
MethodGroupExpr union;
Type source_type = source.Type;
MethodBase method = null;
-
+
union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
if (union == null)
return null;
Type most_specific_source, most_specific_target;
-
#if BLAH
foreach (MethodBase m in union.Methods){
Console.WriteLine ("Name: " + m.Name);
int count = 0;
+
foreach (MethodBase mb in union.Methods){
ParameterData pd = Invocation.GetParameterData (mb);
MethodInfo mi = (MethodInfo) mb;
}
}
- if (method == null || count > 1) {
- Report.Error (-11, loc, "Ambiguous user defined conversion");
+ if (method == null || count > 1)
return null;
- }
+
//
// This will do the conversion to the best match that we
e = ConvertImplicitStandard (ec, e, target, loc);
else
e = ConvertExplicitStandard (ec, e, target, loc);
- }
+ }
+
return e;
}
e = ImplicitReferenceConversion (expr, target_type);
if (e != null)
return e;
-
- if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
+
+ if ((target_type == TypeManager.enum_type ||
+ target_type.IsSubclassOf (TypeManager.enum_type)) &&
+ expr is IntLiteral){
IntLiteral i = (IntLiteral) expr;
if (i.Value == 0)
- return new EmptyCast (expr, target_type);
+ return new EnumConstant ((Constant) expr, target_type);
}
if (ec.InUnsafe) {
// t1 == t2, we have to compare their element types.
//
if (target_type.IsPointer){
- if (target_type.GetElementType()==expr_type.GetElementType())
+ if (target_type.GetElementType() == expr_type.GetElementType())
return expr;
}
}
- if (target_type.IsPointer){
+ if (target_type.IsPointer) {
if (expr is NullLiteral)
return new EmptyCast (expr, target_type);
+
+ if (expr_type == TypeManager.void_ptr_type)
+ return new EmptyCast (expr, target_type);
}
}
{
int value = ic.Value;
- //
- // FIXME: This could return constants instead of EmptyCasts
- //
if (target_type == TypeManager.sbyte_type){
if (value >= SByte.MinValue && value <= SByte.MaxValue)
return new SByteConstant ((sbyte) value);
//
if (value >= 0)
return new ULongConstant ((ulong) value);
- }
+ } else if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) value);
+ else if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) value);
- if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type))
- return new EnumConstant (ic, target_type);
-
+ if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
+ Type underlying = TypeManager.EnumToUnderlying (target_type);
+ Constant e = (Constant) ic;
+
+ //
+ // Possibly, we need to create a different 0 literal before passing
+ // to EnumConstant
+ //n
+ if (underlying == TypeManager.int64_type)
+ e = new LongLiteral (0);
+ else if (underlying == TypeManager.uint64_type)
+ e = new ULongLiteral (0);
+
+ return new EnumConstant (e, target_type);
+ }
return null;
}
"Double literal cannot be implicitly converted to " +
"float type, use F suffix to create a float literal");
}
-
+
Error_CannotConvertImplicit (loc, source.Type, target_type);
return null;
/// <summary>
/// Performs the explicit numeric conversions
/// </summary>
- static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type)
+ static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc)
{
Type expr_type = expr.Type;
if (TypeManager.IsEnumType (real_target_type))
real_target_type = TypeManager.EnumToUnderlying (real_target_type);
- if (StandardConversionExists (expr, real_target_type))
- return new EmptyCast (expr, target_type);
+ if (StandardConversionExists (expr, real_target_type)){
+ Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc);
+
+ if (real_target_type != target_type)
+ return new EmptyCast (ce, target_type);
+ return ce;
+ }
if (expr_type == TypeManager.sbyte_type){
//
return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
if (real_target_type == TypeManager.char_type)
return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
} else if (expr_type == TypeManager.double_type){
//
// From double to byte, byte, short,
return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
if (real_target_type == TypeManager.float_type)
return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
- if (real_target_type == TypeManager.decimal_type)
- return InternalTypeConstructor (ec, expr, target_type);
}
// decimal is taken care of by the op_Explicit methods.
Type target_type, Location loc)
{
Type expr_type = expr.Type;
+ Type original_expr_type = expr_type;
+
+ if (expr_type.IsSubclassOf (TypeManager.enum_type)){
+ if (target_type == TypeManager.enum_type ||
+ target_type == TypeManager.object_type) {
+ if (expr is EnumConstant)
+ expr = ((EnumConstant) expr).Child;
+ // We really need all these casts here .... :-(
+ expr = new BoxedCast (new EmptyCast (expr, expr_type));
+ return new EmptyCast (expr, target_type);
+ } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
+ target_type.IsSubclassOf (TypeManager.enum_type))
+ return new UnboxCast (expr, target_type);
+
+ //
+ // Notice that we have kept the expr_type unmodified, which is only
+ // used later on to
+ if (expr is EnumConstant)
+ expr = ((EnumConstant) expr).Child;
+ else
+ expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
+ expr_type = expr.Type;
+ }
+
Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
if (ne != null)
return ne;
- ne = ConvertNumericExplicit (ec, expr, target_type);
+ ne = ConvertNumericExplicit (ec, expr, target_type, loc);
if (ne != null)
return ne;
//
// Unboxing conversion.
//
- if (expr_type == TypeManager.object_type && target_type.IsValueType)
- return new UnboxCast (expr, target_type);
-
- //
- // Enum types
- //
- if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
- Expression e;
-
- //
- // FIXME: Is there any reason we should have EnumConstant
- // dealt with here instead of just using always the
- // UnderlyingSystemType to wrap the type?
- //
- if (expr is EnumConstant)
- e = ((EnumConstant) expr).Child;
- else {
- e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
+ if (expr_type == TypeManager.object_type && target_type.IsValueType){
+ if (expr is NullLiteral){
+ Report.Error (37, "Cannot convert null to value type `" + TypeManager.CSharpName (expr_type) + "'");
+ return null;
}
-
- Expression t = ConvertImplicit (ec, e, target_type, loc);
- if (t != null)
- return t;
-
- return ConvertNumericExplicit (ec, e, target_type);
+ return new UnboxCast (expr, target_type);
}
+
ne = ConvertReferenceExplicit (expr, target_type);
if (ne != null)
if (ci != null)
return ci;
- ce = ConvertNumericExplicit (ec, e, target_type);
+ ce = ConvertNumericExplicit (ec, e, target_type, loc);
if (ce != null)
return ce;
//
if (ne != null)
return ne;
- Error_CannotConvertType (loc, expr_type, target_type);
+ Error_CannotConvertType (loc, original_expr_type, target_type);
return null;
}
if (ne != null)
return ne;
- ne = ConvertNumericExplicit (ec, expr, target_type);
+ ne = ConvertNumericExplicit (ec, expr, target_type, l);
if (ne != null)
return ne;
/// <summary>
/// Reports that we were expecting `expr' to be of class `expected'
/// </summary>
- public void Error118 (string expected)
+ public void Error_UnexpectedKind (string expected)
{
string kind = "Unknown";
"' where a `" + expected + "' was expected");
}
- public void Error118 (ResolveFlags flags)
+ public void Error_UnexpectedKind (ResolveFlags flags)
{
ArrayList valid = new ArrayList (10);
//
public static void StoreFromPtr (ILGenerator ig, Type type)
{
- if (type.IsEnum)
+ if (TypeManager.IsEnumType (type))
type = TypeManager.EnumToUnderlying (type);
if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
ig.Emit (OpCodes.Stind_I4);
/// </summary>
public class EmptyCast : Expression {
protected Expression child;
-
+
public EmptyCast (Expression child, Type return_type)
{
eclass = child.eclass;
public class BoxedCast : EmptyCast {
public BoxedCast (Expression expr)
- : base (expr, TypeManager.object_type)
+ : base (expr, TypeManager.object_type)
{
}
-
+
public override Expression DoResolve (EmitContext ec)
{
// This should never be invoked, we are born in fully
return this;
}
+ public override string ToString ()
+ {
+ return String.Format ("ConvCast ({0}, {1})", mode, child);
+ }
+
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
/// The downside of this is that we might be hitting `LookupType' too many
/// times with this scheme.
/// </remarks>
- public class SimpleName : Expression, ITypeExpression {
+ public class SimpleName : Expression {
public readonly string Name;
+
+ //
+ // If true, then we are a simple name, not composed with a ".
+ //
+ bool is_base;
+
+ public SimpleName (string a, string b, Location l)
+ {
+ Name = String.Concat (a, ".", b);
+ loc = l;
+ is_base = false;
+ }
public SimpleName (string name, Location l)
{
Name = name;
loc = l;
+ is_base = true;
}
public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
return SimpleNameResolve (ec, null, true);
}
- public Expression DoResolveType (EmitContext ec)
+ public override Expression ResolveAsTypeStep (EmitContext ec)
{
- //
- // Stage 3: Lookup symbol in the various namespaces.
- //
DeclSpace ds = ec.DeclSpace;
+ Namespace ns = ds.Namespace;
Type t;
string alias_value;
- if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
- return new TypeExpr (t, loc);
-
- //
- // Stage 2 part b: Lookup up if we are an alias to a type
- // or a namespace.
//
// Since we are cheating: we only do the Alias lookup for
// namespaces if the name does not include any dots in it
//
+ if (ns != null && is_base)
+ alias_value = ns.LookupAlias (Name);
+ else
+ alias_value = null;
- alias_value = ec.DeclSpace.LookupAlias (Name);
+ if (ec.ResolvingTypeTree){
+ if (alias_value != null){
+ if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
+ return new TypeExpr (t, loc);
+ }
+
+ int errors = Report.Errors;
+ Type dt = ec.DeclSpace.FindType (loc, Name);
+ if (Report.Errors != errors)
+ return null;
- if (Name.IndexOf ('.') == -1 && alias_value != null) {
+ if (dt != null)
+ return new TypeExpr (dt, loc);
+ }
+
+ //
+ // First, the using aliases
+ //
+ if (alias_value != null){
if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
return new TypeExpr (t, loc);
-
+
// we have alias value, but it isn't Type, so try if it's namespace
return new SimpleName (alias_value, loc);
}
+
+ //
+ // Stage 2: Lookup up if we are an alias to a type
+ // or a namespace.
+ //
+
+ if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
+ return new TypeExpr (t, loc);
- if (ec.ResolvingTypeTree){
- Type dt = ec.DeclSpace.FindType (Name);
- if (dt != null)
- return new TypeExpr (dt, loc);
- }
-
// No match, maybe our parent can compose us
// into something meaningful.
return this;
// Stage 1: Performed by the parser (binding to locals or parameters).
//
Block current_block = ec.CurrentBlock;
- if (current_block != null && current_block.IsVariableDefined (Name)){
+ if (current_block != null && current_block.GetVariableInfo (Name) != null){
LocalVariableReference var;
var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
// Stage 2: Lookup members
//
- //
- // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
- // Hence we have two different cases
- //
-
DeclSpace lookup_ds = ec.DeclSpace;
do {
if (lookup_ds.TypeBuilder == null)
if (e != null)
break;
- //
- // Classes/structs keep looking, enums break
- //
- if (lookup_ds is TypeContainer)
- lookup_ds = ((TypeContainer) lookup_ds).Parent;
- else
- break;
+ lookup_ds =lookup_ds.Parent;
} while (lookup_ds != null);
if (e == null && ec.ContainerType != null)
e = MemberLookup (ec, ec.ContainerType, Name, loc);
if (e == null)
- return DoResolveType (ec);
+ return ResolveAsTypeStep (ec);
if (e is TypeExpr)
return e;
return e;
if (!me.IsStatic &&
- TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
+ TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
+ !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType)) {
Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
"outer type `" + me.DeclaringType + "' via nested type `" +
me.InstanceExpression.Type + "'");
/// <summary>
/// Fully resolved expression that evaluates to a type
/// </summary>
- public class TypeExpr : Expression, ITypeExpression {
+ public class TypeExpr : Expression {
public TypeExpr (Type t, Location l)
{
Type = t;
loc = l;
}
- public virtual Expression DoResolveType (EmitContext ec)
+ public override Expression ResolveAsTypeStep (EmitContext ec)
{
return this;
}
this.name = name;
}
- public override Expression DoResolveType (EmitContext ec)
+ public override Expression ResolveAsTypeStep (EmitContext ec)
{
if (type == null)
type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
public override Expression DoResolve (EmitContext ec)
{
- return DoResolveType (ec);
+ return ResolveAsTypeStep (ec);
}
public override void Emit (EmitContext ec)
{
if (!FieldInfo.IsStatic){
if (instance_expr == null){
- throw new Exception ("non-static FieldExpr without instance var\n" +
- "You have to assign the Instance variable\n" +
- "Of the FieldExpr to set this\n");
+ //
+ // This can happen when referencing an instance field using
+ // a fully qualified type expression: TypeName.InstanceField = xxx
+ //
+ SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
+ return null;
}
// Resolve the field's instance expression while flow analysis is turned
// InitOnly fields can only be assigned in constructors
//
- if (ec.IsConstructor)
- return this;
+ if (ec.IsConstructor){
+ if (ec.ContainerType == FieldInfo.DeclaringType)
+ return this;
+ }
Report_AssignToReadonly (true);
if (instance_expr.Type.IsValueType){
IMemoryLocation ml;
LocalTemporary tempo = null;
-
+
if (!(instance_expr is IMemoryLocation)){
tempo = new LocalTemporary (
ec, instance_expr.Type);
// Handle initonly fields specially: make a copy and then
// get the address of the copy.
//
- if (FieldInfo.IsInitOnly){
- if (ec.IsConstructor) {
- ig.Emit (OpCodes.Ldsflda, FieldInfo);
- } else {
- LocalBuilder local;
+ if (FieldInfo.IsInitOnly && !ec.IsConstructor){
+ LocalBuilder local;
- Emit (ec);
- local = ig.DeclareLocal (type);
- ig.Emit (OpCodes.Stloc, local);
- ig.Emit (OpCodes.Ldloca, local);
- }
+ Emit (ec);
+ local = ig.DeclareLocal (type);
+ ig.Emit (OpCodes.Stloc, local);
+ ig.Emit (OpCodes.Ldloca, local);
return;
}
if (FieldInfo.IsStatic)
ig.Emit (OpCodes.Ldsflda, FieldInfo);
else {
- if (instance_expr is IMemoryLocation)
- ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
- else
+ //
+ // In the case of `This', we call the AddressOf method, which will
+ // only load the pointer, and not perform an Ldobj immediately after
+ // the value has been loaded into the stack.
+ //
+ if (instance_expr is This)
+ ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ else if (instance_expr.Type.IsValueType && instance_expr is IMemoryLocation){
+ IMemoryLocation ml = (IMemoryLocation) instance_expr;
+
+ ml.AddressOf (ec, AddressOp.LoadStore);
+ } else
instance_expr.Emit (ec);
ig.Emit (OpCodes.Ldflda, FieldInfo);
}
/// </summary>
public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
public readonly PropertyInfo PropertyInfo;
+
+ //
+ // This is set externally by the `BaseAccess' class
+ //
public bool IsBase;
- MethodInfo [] Accessors;
+ MethodInfo getter, setter;
bool is_static;
+ bool must_do_cs1540_check;
Expression instance_expr;
- public PropertyExpr (PropertyInfo pi, Location l)
+ public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
{
PropertyInfo = pi;
eclass = ExprClass.PropertyAccess;
is_static = false;
loc = l;
- Accessors = TypeManager.GetAccessors (pi);
- if (Accessors != null)
- foreach (MethodInfo mi in Accessors){
- if (mi != null)
- if (mi.IsStatic)
- is_static = true;
- }
- else
- Accessors = new MethodInfo [2];
-
type = TypeManager.TypeToCoreType (pi.PropertyType);
+
+ ResolveAccessors (ec);
}
public string Name {
public bool VerifyAssignable ()
{
- if (!PropertyInfo.CanWrite){
+ if (setter == null) {
Report.Error (200, loc,
"The property `" + PropertyInfo.Name +
"' can not be assigned to, as it has not set accessor");
return true;
}
- override public Expression DoResolve (EmitContext ec)
+ MethodInfo GetAccessor (Type invocation_type, string accessor_name)
{
- if (!PropertyInfo.CanRead){
- Report.Error (154, loc,
- "The property `" + PropertyInfo.Name +
- "' can not be used in " +
- "this context because it lacks a get accessor");
+ BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance;
+ MemberInfo[] group;
+
+ group = TypeManager.MemberLookup (
+ invocation_type, invocation_type, PropertyInfo.DeclaringType,
+ MemberTypes.Method, flags, accessor_name + "_" + PropertyInfo.Name);
+
+ //
+ // The first method is the closest to us
+ //
+ if (group == null)
return null;
+
+ foreach (MethodInfo mi in group) {
+ MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ //
+ // If only accessible to the current class or children
+ //
+ if (ma == MethodAttributes.Private) {
+ Type declaring_type = mi.DeclaringType;
+
+ if (invocation_type != declaring_type){
+ if (TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType))
+ return mi;
+ else
+ continue;
+ } else
+ return mi;
+ }
+ //
+ // FamAndAssem requires that we not only derivate, but we are on the
+ // same assembly.
+ //
+ if (ma == MethodAttributes.FamANDAssem){
+ if (mi.DeclaringType.Assembly != invocation_type.Assembly)
+ continue;
+ else
+ return mi;
+ }
+
+ // Assembly and FamORAssem succeed if we're in the same assembly.
+ if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
+ if (mi.DeclaringType.Assembly != invocation_type.Assembly)
+ continue;
+ else
+ return mi;
+ }
+
+ // We already know that we aren't in the same assembly.
+ if (ma == MethodAttributes.Assembly)
+ continue;
+
+ // Family and FamANDAssem require that we derive.
+ if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
+ if (!TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType))
+ continue;
+ else {
+ must_do_cs1540_check = true;
+
+ return mi;
+ }
+ }
+
+ return mi;
}
+ return null;
+ }
+
+ //
+ // We also perform the permission checking here, as the PropertyInfo does not
+ // hold the information for the accessibility of its setter/getter
+ //
+ void ResolveAccessors (EmitContext ec)
+ {
+ getter = GetAccessor (ec.ContainerType, "get");
+ if ((getter != null) && getter.IsStatic)
+ is_static = true;
+
+ setter = GetAccessor (ec.ContainerType, "set");
+ if ((setter != null) && setter.IsStatic)
+ is_static = true;
+
+ if (setter == null && getter == null){
+ Error (122, "`" + PropertyInfo.Name + "' " +
+ "is inaccessible because of its protection level");
+
+ }
+ }
+
+ bool InstanceResolve (EmitContext ec)
+ {
if ((instance_expr == null) && ec.IsStatic && !is_static) {
SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
- return null;
+ return false;
}
if (instance_expr != null) {
instance_expr = instance_expr.DoResolve (ec);
if (instance_expr == null)
+ return false;
+ }
+
+ if (must_do_cs1540_check && (instance_expr != null)) {
+ if ((instance_expr.Type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (instance_expr.Type)) {
+ Report.Error (1540, loc, "Cannot access protected member `" +
+ PropertyInfo.DeclaringType + "." + PropertyInfo.Name +
+ "' via a qualifier of type `" +
+ TypeManager.CSharpName (instance_expr.Type) +
+ "'; the qualifier must be of type `" +
+ TypeManager.CSharpName (ec.ContainerType) +
+ "' (or derived from it)");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (getter == null){
+ //
+ // The following condition happens if the PropertyExpr was
+ // created, but is invalid (ie, the property is inaccessible),
+ // and we did not want to embed the knowledge about this in
+ // the caller routine. This only avoids double error reporting.
+ //
+ if (setter == null)
return null;
+
+ Report.Error (154, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be used in " +
+ "this context because it lacks a get accessor");
+ return null;
+ }
+
+ if (!InstanceResolve (ec))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && getter.IsAbstract){
+ Report.Error (205, loc, "Cannot call an abstract base property: " +
+ PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
+ return null;
}
return this;
override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
- if (!PropertyInfo.CanWrite){
+ if (setter == null){
+ //
+ // The following condition happens if the PropertyExpr was
+ // created, but is invalid (ie, the property is inaccessible),
+ // and we did not want to embed the knowledge about this in
+ // the caller routine. This only avoids double error reporting.
+ //
+ if (getter == null)
+ return null;
+
Report.Error (154, loc,
"The property `" + PropertyInfo.Name +
"' can not be used in " +
return null;
}
- if (instance_expr != null) {
- instance_expr = instance_expr.DoResolve (ec);
- if (instance_expr == null)
- return null;
+ if (!InstanceResolve (ec))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && setter.IsAbstract){
+ Report.Error (205, loc, "Cannot call an abstract base property: " +
+ PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
+ return null;
}
-
return this;
}
override public void Emit (EmitContext ec)
{
- MethodInfo method = Accessors [0];
-
//
- // Special case: length of single dimension array is turned into ldlen
+ // Special case: length of single dimension array property is turned into ldlen
//
- if ((method == TypeManager.system_int_array_get_length) ||
- (method == TypeManager.int_array_get_length)){
+ if ((getter == TypeManager.system_int_array_get_length) ||
+ (getter == TypeManager.int_array_get_length)){
Type iet = instance_expr.Type;
//
}
}
- Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, method, null, loc);
+ Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, loc);
}
ArrayList args = new ArrayList ();
args.Add (arg);
- Invocation.EmitCall (ec, false, IsStatic, instance_expr, Accessors [1], args, loc);
+ Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, loc);
}
override public void EmitStatement (EmitContext ec)
if (add_accessor.IsStatic || remove_accessor.IsStatic)
is_static = true;
- if (EventInfo is MyEventBuilder)
- type = ((MyEventBuilder) EventInfo).EventType;
- else
+ if (EventInfo is MyEventBuilder){
+ MyEventBuilder eb = (MyEventBuilder) EventInfo;
+ type = eb.EventType;
+ eb.SetUsed ();
+ } else
type = EventInfo.EventHandlerType;
}
return null;
}
+
return this;
}
public override void Emit (EmitContext ec)
{
- throw new Exception ("Should not happen I think");
+ Report.Error (70, loc, "The event `" + Name + "' can only appear on the left hand side of += or -= (except on the defining type)");
}
public void EmitAddOrRemove (EmitContext ec, Expression source)