}
}
- /// <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)
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;
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);
}
// 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 || target_type == TypeManager.value_type) {
+ if (target_type == TypeManager.object_type) {
//
// A pointer type cannot be converted to object
//
if (expr_type.IsPointer)
return null;
- if (TypeManager.IsValueType (expr_type))
+ if (expr_type.IsValueType)
return new BoxedCast (expr);
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.
//
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 (target_type.IsInterface) {
//
// 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){
// This is the boxed case.
//
if (target_type == TypeManager.object_type) {
- if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
+ 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 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);
return null;
Type most_specific_source, most_specific_target;
-
#if BLAH
foreach (MethodBase m in union.Methods){
Console.WriteLine ("Name: " + m.Name);
e = ImplicitReferenceConversion (expr, target_type);
if (e != null)
return e;
-
+
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) {
{
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);
/// <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);
this.child = child;
}
- public Expression Peel ()
- {
- if (child is EmptyCast)
- return ((EmptyCast) child).Peel ();
- return child;
- }
-
public override Expression DoResolve (EmitContext ec)
{
// This should never be invoked, we are born in fully
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;
//
return SimpleNameResolve (ec, null, true);
}
- public Expression DoResolveType (EmitContext ec)
+ public override Expression ResolveAsTypeStep (EmitContext ec)
{
DeclSpace ds = ec.DeclSpace;
Namespace ns = ds.Namespace;
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)
// 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);
if (FieldInfo.IsStatic)
ig.Emit (OpCodes.Ldsflda, FieldInfo);
else {
-#if false
- if (instance_expr is IMemoryLocation)
- ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
- else
-#endif
+ //
+ // 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);
}