if ((t != TypeManager.exception_type) &&
!TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
- !(expr is NullLiteral)) {
+ t != TypeManager.null_type) {
Error (155, "The type caught or thrown must be derived from System.Exception");
return false;
}
// The information about a user-perceived local variable
//
public class LocalInfo : IKnownVariable, ILocalVariable {
- public readonly Expression Type;
+ public readonly FullNamedExpression Type;
public Type VariableType;
public readonly string Name;
Flags flags;
ReadOnlyContext ro_context;
LocalBuilder builder;
-
- public LocalInfo (Expression type, string name, Block block, Location l)
+
+ public LocalInfo (FullNamedExpression type, string name, Block block, Location l)
{
Type = type;
Name = name;
// Variables in anonymous block are not resolved yet
//
if (VariableType == null)
- return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+ return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
//
// Variables in method block are resolved
return null;
}
- LocalInfo vi = new LocalInfo (type, name, this, l);
+ LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
AddVariable (vi);
if ((flags & Flags.VariablesInitialized) != 0)
{
Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
name, conflict);
- }
+ }
public bool AddConstant (Expression type, string name, Expression value, Location l)
{
//
if (am_storey != null) {
if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+ //
+ // Creates parent storey reference when hoisted this is accessible
+ //
if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
ExplicitBlock parent = Toplevel.Parent.Explicit;
- while (parent.am_storey == null)
+
+ //
+ // Hoisted this exists in top-level parent storey only
+ //
+ while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
parent = parent.Parent.Explicit;
am_storey.AddParentStoreyReference (parent.am_storey);
public static void Reset ()
{
unique_counter = 0;
+ allowed_types = null;
}
public override bool Resolve (EmitContext ec)
#if GMCS_SOURCE
if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
- unwrap = Nullable.Unwrap.Create (Expr, ec);
+ unwrap = Nullable.Unwrap.Create (Expr, false);
if (unwrap == null)
return false;
}
}
- class StringEmitter : Emitter {
- class StringPtr : Expression
- {
- LocalBuilder b;
-
- public StringPtr (LocalBuilder b, Location l)
- {
- this.b = b;
- eclass = ExprClass.Value;
- type = TypeManager.char_ptr_type;
- loc = l;
- }
-
- public override Expression CreateExpressionTree (EmitContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- // This should never be invoked, we are born in fully
- // initialized state.
-
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- if (TypeManager.int_get_offset_to_string_data == null) {
- // TODO: Move to resolve !!
- TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
- TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
- }
-
- ILGenerator ig = ec.ig;
-
- ig.Emit (OpCodes.Ldloc, b);
- ig.Emit (OpCodes.Conv_I);
- ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
- ig.Emit (OpCodes.Add);
- }
- }
-
- LocalBuilder pinned_string;
- Location loc;
+ class StringEmitter : Emitter
+ {
+ LocalInfo pinned_string;
public StringEmitter (Expression expr, LocalInfo li, Location loc):
base (expr, li)
{
- this.loc = loc;
+ pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
+ pinned_string.Pinned = true;
}
public override void Emit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
-
+ pinned_string.Resolve (ec);
+ pinned_string.ResolveVariable (ec);
+
converted.Emit (ec);
- ig.Emit (OpCodes.Stloc, pinned_string);
+ pinned_string.EmitAssign (ec);
- Expression sptr = new StringPtr (pinned_string, loc);
- converted = Convert.ImplicitConversionRequired (
- ec, sptr, vi.VariableType, loc);
-
- if (converted == null)
- return;
+ PropertyInfo p = TypeManager.int_get_offset_to_string_data;
+ if (p == null) {
+ // TODO: Move to resolve
+ p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
+ TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
- converted.Emit (ec);
+ if (p == null)
+ return;
+ }
+
+ // TODO: Should use Binary::Add
+ pinned_string.Emit (ec);
+ ec.ig.Emit (OpCodes.Conv_I);
+
+ PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location);
+ //pe.InstanceExpression = pinned_string;
+ pe.Resolve (ec).Emit (ec);
+
+ ec.ig.Emit (OpCodes.Add);
vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Ldnull);
- ec.ig.Emit (OpCodes.Stloc, pinned_string);
+ pinned_string.EmitAssign (ec);
}
}
}
}
+ // FIXME: Why is it almost exact copy of Using ??
public class UsingTemporary : ExceptionStatement {
TemporaryVariable local_copy;
public Statement Statement;
Expression var;
Expression init;
- Expression converted_var;
ExpressionStatement assign;
public Using (Expression var, Expression init, Statement stmt, Location l)
loc = l;
}
- bool ResolveVariable (EmitContext ec)
- {
- ExpressionStatement a = new SimpleAssign (var, init, loc);
- a = a.ResolveStatement (ec);
- if (a == null)
- return false;
-
- assign = a;
-
- if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
- converted_var = var;
- return true;
- }
-
- Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
- if (e == null) {
- Error_IsNotConvertibleToIDisposable (var);
- return false;
- }
-
- converted_var = e;
-
- return true;
- }
-
static public void Error_IsNotConvertibleToIDisposable (Expression expr)
{
Report.SymbolRelatedToPreviousError (expr.Type);
protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
+ Label skip = ig.DefineLabel ();
- if (!TypeManager.IsStruct (var.Type)) {
- Label skip = ig.DefineLabel ();
+ bool emit_null_check = !TypeManager.IsValueType (var.Type);
+ if (emit_null_check) {
var.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
- converted_var.Emit (ec);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- ig.MarkLabel (skip);
- } else {
- Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
-
- if (!(ml is MethodGroupExpr)) {
- var.Emit (ec);
- ig.Emit (OpCodes.Box, var.Type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- } else {
- MethodInfo mi = null;
-
- foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
- if (TypeManager.GetParameterData (mk).Count == 0) {
- mi = mk;
- break;
- }
- }
-
- if (mi == null) {
- Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
- return;
- }
+ }
- IMemoryLocation mloc = (IMemoryLocation) var;
+ Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, new ArrayList (0), loc);
- mloc.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- }
- }
+ if (emit_null_check)
+ ig.MarkLabel (skip);
}
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
return ok;
}
+ bool ResolveVariable (EmitContext ec)
+ {
+ assign = new SimpleAssign (var, init, loc);
+ assign = assign.ResolveStatement (ec);
+ if (assign == null)
+ return false;
+
+ if (assign.Type == TypeManager.idisposable_type ||
+ TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) {
+ return true;
+ }
+
+ Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
+ if (e == null) {
+ Error_IsNotConvertibleToIDisposable (var);
+ return false;
+ }
+
+ throw new NotImplementedException ("covariance?");
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Using target = (Using) t;
return true;
}
- //
- // Retrieves a `public void Dispose ()' method from the Type `t'
- //
- static MethodInfo FetchMethodDispose (Type t)
- {
- MemberInfo[] dispose_list = TypeManager.MemberLookup (null, null, t,
- MemberTypes.Method,
- BindingFlags.Public | BindingFlags.Instance,
- "Dispose", null);
-
- foreach (MemberInfo m in dispose_list){
- MethodInfo mi = (MethodInfo) m;
-
- if (TypeManager.GetParameterData (mi).Count == 0){
- if (mi.ReturnType == TypeManager.void_type)
- return mi;
- }
- }
- return null;
- }
-
void Error_Enumerator ()
{
if (enumerator_found) {
return false;
}
- bool is_disposable = !enumerator_type.IsSealed ||
- TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
-
VarExpr ve = var_type as VarExpr;
if (ve != null) {
// Infer implicitly typed local variable from foreach enumerable type
loop = new While (move_next_expr, block, loc);
- wrapper = is_disposable ?
- (Statement) new DisposableWrapper (this) :
- (Statement) new NonDisposableWrapper (this);
+
+ bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
+ if (implements_idisposable || !enumerator_type.IsSealed) {
+ wrapper = new DisposableWrapper (this, implements_idisposable);
+ } else {
+ wrapper = new NonDisposableWrapper (this);
+ }
+
return wrapper.Resolve (ec);
}
}
}
- class DisposableWrapper : ExceptionStatement {
+ sealed class DisposableWrapper : ExceptionStatement
+ {
CollectionForeach parent;
+ bool implements_idisposable;
- internal DisposableWrapper (CollectionForeach parent)
+ internal DisposableWrapper (CollectionForeach parent, bool implements)
{
this.parent = parent;
+ this.implements_idisposable = implements;
}
protected override void CloneTo (CloneContext clonectx, Statement target)
protected override void EmitFinallyBody (EmitContext ec)
{
- parent.EmitFinallyBody (ec);
+ Expression instance = parent.enumerator;
+ if (!TypeManager.IsValueType (parent.enumerator_type)) {
+ ILGenerator ig = ec.ig;
+
+ parent.enumerator.Emit (ec);
+
+ Label call_dispose = ig.DefineLabel ();
+
+ if (!implements_idisposable) {
+ ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+ LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
+ temp.Store (ec);
+ temp.Emit (ec);
+ instance = temp;
+ }
+
+ ig.Emit (OpCodes.Brtrue_S, call_dispose);
+
+ // using 'endfinally' to empty the evaluation stack
+ ig.Emit (OpCodes.Endfinally);
+ ig.MarkLabel (call_dispose);
+ }
+
+ Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, new ArrayList (0), loc);
}
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
loop.Emit (ec);
}
- void EmitFinallyBody (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- if (TypeManager.IsStruct (enumerator_type)) {
- MethodInfo mi = FetchMethodDispose (enumerator_type);
- if (mi != null) {
- enumerator.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- } else {
- enumerator.Emit (ec);
- ig.Emit (OpCodes.Box, enumerator_type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- }
- } else {
- Label call_dispose = ig.DefineLabel ();
-
- enumerator.Emit (ec);
- ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
- ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Brtrue_S, call_dispose);
-
- // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
- // (Partition III, Section 3.35)
- ig.Emit (OpCodes.Endfinally);
-
- ig.MarkLabel (call_dispose);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- }
- }
-
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
enumerator_type = storey.MutateType (enumerator_type);