/// Resolve the constraints - but only resolve things into Expression's, not
/// into actual types.
/// </summary>
- public bool Resolve (EmitContext ec)
+ public bool Resolve (IResolveContext ec)
{
if (resolved)
return true;
/// <summary>
/// Resolve the constraints into actual types.
/// </summary>
- public bool ResolveTypes (EmitContext ec)
+ public bool ResolveTypes (IResolveContext ec)
{
if (resolved_types)
return true;
return false;
}
- foreach (TypeExpr iface_constraint in iface_constraints) {
- if (iface_constraint.ResolveType (ec) == null)
+ for (int i = 0; i < iface_constraints.Count; ++i) {
+ TypeExpr iface_constraint = (TypeExpr) iface_constraints [i];
+ iface_constraint = iface_constraint.ResolveAsTypeTerminal (ec, false);
+ if (iface_constraint == null)
return false;
+ iface_constraints [i] = iface_constraint;
}
if (class_constraint != null) {
- if (class_constraint.ResolveType (ec) == null)
+ class_constraint = class_constraint.ResolveAsTypeTerminal (ec, false);
+ if (class_constraint == null)
return false;
}
/// where T : class
/// where U : T, struct
/// </summary>
- public bool CheckDependencies (EmitContext ec)
+ public bool CheckDependencies ()
{
foreach (TypeParameterExpr expr in type_param_constraints) {
- if (!CheckDependencies (expr.TypeParameter, ec))
+ if (!CheckDependencies (expr.TypeParameter))
return false;
}
return true;
}
- bool CheckDependencies (TypeParameter tparam, EmitContext ec)
+ bool CheckDependencies (TypeParameter tparam)
{
Constraints constraints = tparam.Constraints;
if (constraints == null)
Type t2 = constraints.ClassConstraint;
TypeExpr e2 = constraints.class_constraint;
- if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
- !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
+ if (!Convert.ImplicitReferenceConversionExists (e1, t2) &&
+ !Convert.ImplicitReferenceConversionExists (e2, t1)) {
Report.Error (455, loc,
"Type parameter `{0}' inherits " +
"conflicting constraints `{1}' and `{2}'",
return true;
foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
- if (!CheckDependencies (expr.TypeParameter, ec))
+ if (!CheckDependencies (expr.TypeParameter))
return false;
}
/// method. To do that, we're called on each of the implementing method's
/// type parameters.
/// </summary>
- public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc)
+ public bool CheckInterfaceMethod (GenericConstraints gc)
{
if (gc.Attributes != attrs)
return false;
}
}
+ // FIXME: This should be removed once we fix the handling of RootContext.Tree.Types
+ public override DeclSpace DeclContainer {
+ get { return DeclSpace; }
+ }
+
/// <summary>
/// This is the first method which is called during the resolving
/// process; we're called immediately after creating the type parameters
public bool Resolve (DeclSpace ds)
{
if (constraints != null) {
- if (!constraints.Resolve (ds.EmitContext)) {
+ if (!constraints.Resolve (ds)) {
constraints = null;
return false;
}
/// Note that we may have circular dependencies on type parameters - this
/// is why Resolve() and ResolveType() are separate.
/// </summary>
- public bool ResolveType (EmitContext ec)
+ public bool ResolveType (IResolveContext ec)
{
if (constraints != null) {
if (!constraints.ResolveTypes (ec)) {
/// process. We're called after everything is fully resolved and actually
/// register the constraints with SRE and the TypeManager.
/// </summary>
- public bool DefineType (EmitContext ec)
+ public bool DefineType (IResolveContext ec)
{
return DefineType (ec, null, null, false);
}
/// The `builder', `implementing' and `is_override' arguments are only
/// applicable to method type parameters.
/// </summary>
- public bool DefineType (EmitContext ec, MethodBuilder builder,
+ public bool DefineType (IResolveContext ec, MethodBuilder builder,
MethodInfo implementing, bool is_override)
{
if (!ResolveType (ec))
if (constraints != null) {
if (temp_gc == null)
ok = false;
- else if (!constraints.CheckInterfaceMethod (ec, gc))
+ else if (!constraints.CheckInterfaceMethod (gc))
ok = false;
} else {
if (!is_override && (temp_gc != null))
/// where T : class
/// where U : T, struct
/// </summary>
- public bool CheckDependencies (EmitContext ec)
+ public bool CheckDependencies ()
{
if (constraints != null)
- return constraints.CheckDependencies (ec);
+ return constraints.CheckDependencies ();
return true;
}
/// check that they're the same.
/// con
/// </summary>
- public bool UpdateConstraints (EmitContext ec, Constraints new_constraints)
+ public bool UpdateConstraints (IResolveContext ec, Constraints new_constraints)
{
if (type == null)
throw new InvalidOperationException ();
- if (constraints == null) {
- new_constraints = constraints;
- return true;
- } else if (new_constraints == null)
+ if (new_constraints == null)
return true;
if (!new_constraints.Resolve (ec))
if (!new_constraints.ResolveTypes (ec))
return false;
- return constraints.CheckInterfaceMethod (ec, new_constraints);
+ if (constraints != null)
+ return constraints.CheckInterfaceMethod (new_constraints);
+
+ constraints = new_constraints;
+ return true;
}
public void EmitAttributes ()
if (t.IsGenericParameter)
return dargs [t.GenericParameterPosition];
if (t.IsGenericType) {
+ Type[] args = t.GetGenericArguments ();
+ Type[] inflated = new Type [args.Length];
+
+ for (int i = 0; i < args.Length; i++)
+ inflated [i] = inflate (args [i]);
+
t = t.GetGenericTypeDefinition ();
- t = t.MakeGenericType (dargs);
+ t = t.MakeGenericType (inflated);
}
return t;
this.loc = loc;
}
- protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
type = type_parameter.Type;
/// <summary>
/// Resolve the type arguments.
/// </summary>
- public bool Resolve (EmitContext ec)
+ public bool Resolve (IResolveContext ec)
{
int count = args.Count;
bool ok = true;
return TypeManager.CSharpName (gt);
}
- protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
if (!ResolveConstructedType (ec))
return null;
/// Check the constraints; we're called from ResolveAsTypeTerminal()
/// after fully resolving the constructed type.
/// </summary>
- public bool CheckConstraints (EmitContext ec)
+ public bool CheckConstraints (IResolveContext ec)
{
return ConstraintChecker.CheckConstraints (ec, gt, gen_params, atypes, loc);
}
/// <summary>
/// Resolve the constructed type, but don't check the constraints.
/// </summary>
- public bool ResolveConstructedType (EmitContext ec)
+ public bool ResolveConstructedType (IResolveContext ec)
{
if (type != null)
return true;
return DoResolveType (ec);
}
- bool DoResolveType (EmitContext ec)
+ bool DoResolveType (IResolveContext ec)
{
//
// Resolve the arguments.
/// Check the constraints; we're called from ResolveAsTypeTerminal()
/// after fully resolving the constructed type.
/// </summary>
- public bool CheckConstraints (EmitContext ec)
+ public bool CheckConstraints (IResolveContext ec)
{
for (int i = 0; i < gen_params.Length; i++) {
if (!CheckConstraints (ec, i))
return true;
}
- protected bool CheckConstraints (EmitContext ec, int index)
+ protected bool CheckConstraints (IResolveContext ec, int index)
{
Type atype = atypes [index];
Type ptype = gen_params [index];
if (atype.IsGenericParameter) {
GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
if (agc != null) {
+ if (agc is Constraints)
+ ((Constraints) agc).Resolve (ec);
is_class = agc.HasReferenceTypeConstraint;
is_struct = agc.HasValueTypeConstraint;
} else {
is_class = is_struct = false;
}
} else {
+#if MS_COMPATIBLE
+ is_class = false;
+ if (!atype.IsGenericType)
+#endif
is_class = atype.IsClass || atype.IsInterface;
is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype);
}
//
// Now, check the interface constraints.
//
- foreach (Type it in gc.InterfaceConstraints) {
- if (!CheckConstraint (ec, ptype, aexpr, it))
- return false;
+ if (gc.InterfaceConstraints != null) {
+ foreach (Type it in gc.InterfaceConstraints) {
+ if (!CheckConstraint (ec, ptype, aexpr, it))
+ return false;
+ }
}
//
if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
return true;
- if (HasDefaultConstructor (ec, atype))
+ if (HasDefaultConstructor (ec.DeclContainer.TypeBuilder, atype))
return true;
Report_SymbolRelatedToPreviousError ();
return false;
}
- protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr,
+ protected bool CheckConstraint (IResolveContext ec, Type ptype, Expression expr,
Type ctype)
{
if (TypeManager.HasGenericArguments (ctype)) {
ctype = atypes [pos];
}
- if (Convert.ImplicitStandardConversionExists (ec, expr, ctype))
+ if (Convert.ImplicitStandardConversionExists (expr, ctype))
return true;
Error_TypeMustBeConvertible (expr.Type, ctype, ptype);
return false;
}
- bool HasDefaultConstructor (EmitContext ec, Type atype)
+ bool HasDefaultConstructor (Type containerType, Type atype)
{
- atype = TypeManager.DropGenericTypeArguments (atype);
+ if (atype.IsAbstract)
+ return false;
+ again:
+ atype = TypeManager.DropGenericTypeArguments (atype);
if (atype is TypeBuilder) {
- if (atype.IsAbstract)
- return false;
-
TypeContainer tc = TypeManager.LookupTypeContainer (atype);
+ if (tc.InstanceConstructors == null) {
+ atype = atype.BaseType;
+ goto again;
+ }
+
foreach (Constructor c in tc.InstanceConstructors) {
if ((c.ModFlags & Modifiers.PUBLIC) == 0)
continue;
}
}
- MethodGroupExpr mg = Expression.MemberLookup (
- ec.ContainerType, atype, ".ctor", MemberTypes.Constructor,
+ TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
+ if (tparam != null)
+ return tparam.HasConstructorConstraint;
+
+ MemberList list = TypeManager.FindMembers (
+ atype, MemberTypes.Constructor,
BindingFlags.Public | BindingFlags.Instance |
- BindingFlags.DeclaredOnly, loc)
- as MethodGroupExpr;
+ BindingFlags.DeclaredOnly, null, null);
- if (!atype.IsAbstract && (mg != null) && mg.IsInstance) {
- foreach (MethodBase mb in mg.Methods) {
- ParameterData pd = TypeManager.GetParameterData (mb);
- if (pd.Count == 0)
- return true;
- }
+ if (atype.IsAbstract || (list == null))
+ return false;
+
+ foreach (MethodBase mb in list) {
+ ParameterData pd = TypeManager.GetParameterData (mb);
+ if ((pd.Count == 0) && mb.IsPublic && !mb.IsStatic)
+ return true;
}
return false;
return checker.CheckConstraints (ec);
}
- public static bool CheckConstraints (EmitContext ec, Type gt, Type[] gen_params,
+ public static bool CheckConstraints (IResolveContext ec, Type gt, Type[] gen_params,
Type[] atypes, Location loc)
{
TypeConstraintChecker checker = new TypeConstraintChecker (
Expression return_type;
Parameters parameters;
- public GenericMethod (NamespaceEntry ns, TypeContainer parent, MemberName name,
+ public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
Expression return_type, Parameters parameters)
: base (ns, parent, name, null)
{
public override bool Define ()
{
- ec = new EmitContext (this, this, Location, null, null, ModFlags, false);
-
for (int i = 0; i < TypeParameters.Length; i++)
if (!TypeParameters [i].Resolve (this))
return false;
return false;
for (int i = 0; i < TypeParameters.Length; i++) {
- if (!TypeParameters [i].ResolveType (ec))
+ if (!TypeParameters [i].ResolveType (this))
return false;
}
public override void Emit (EmitContext ec)
{
if (type.IsGenericParameter || TypeManager.IsValueType (type)) {
- LocalTemporary temp_storage = new LocalTemporary (ec, type);
+ LocalTemporary temp_storage = new LocalTemporary (type);
temp_storage.AddressOf (ec, AddressOp.LoadStore);
ec.ig.Emit (OpCodes.Initobj, type);
get { return underlying.ToString () + "?"; }
}
- protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
TypeArguments args = new TypeArguments (loc);
args.Add (underlying);
static bool InferType (Type pt, Type at, Type[] infered)
{
- if (pt == at)
- return true;
-
if (pt.IsGenericParameter) {
if (pt.DeclaringMethod == null)
- return false;
+ return pt == at;
int pos = pt.GenericParameterPosition;
if (infered [pos] == null) {
- Type check = at;
- while (check.IsArray)
- check = check.GetElementType ();
-
- if (pt == check)
- return false;
-
infered [pos] = at;
return true;
}
/// when resolving an Invocation or a DelegateInvocation and the user
/// did not explicitly specify type arguments.
/// </summary>
- public static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
+ public static bool InferTypeArguments (ArrayList arguments,
ref MethodBase method)
{
if (!TypeManager.IsGenericMethod (method))
break;
}
}
+
+ // If none of the method parameters mention a generic parameter, we can't infer the generic parameters
if (!is_open)
- return true;
+ return !TypeManager.IsGenericMethodDefinition (method);
Type[] infered_types = new Type [method_args.Length];
/// <summary>
/// Type inference.
/// </summary>
- public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
+ public static bool InferTypeArguments (ParameterData apd,
ref MethodBase method)
{
if (!TypeManager.IsGenericMethod (method))
{
return generic_nullable_type == DropGenericTypeArguments (t);
}
+
+ public static bool IsNullableTypeOf (Type t, Type nullable)
+ {
+ if (!IsNullableType (t))
+ return false;
+
+ return GetTypeArguments (t) [0] == nullable;
+ }
+
+ public static bool IsNullableValueType (Type t)
+ {
+ if (!IsNullableType (t))
+ return false;
+
+ return GetTypeArguments (t) [0].IsValueType;
+ }
}
public abstract class Nullable
{
- protected sealed class NullableInfo
+ public sealed class NullableInfo
{
public readonly Type Type;
public readonly Type UnderlyingType;
}
}
- protected class Unwrap : Expression, IMemoryLocation, IAssignMethod
+ public class Unwrap : Expression, IMemoryLocation, IAssignMethod
{
Expression expr;
NullableInfo info;
LocalTemporary temp;
bool has_temp;
- public Unwrap (Expression expr, Location loc)
+ protected Unwrap (Expression expr)
{
this.expr = expr;
- this.loc = loc;
+ this.loc = expr.Location;
+ }
+
+ public static Unwrap Create (Expression expr, EmitContext ec)
+ {
+ return new Unwrap (expr).Resolve (ec) as Unwrap;
}
public override Expression DoResolve (EmitContext ec)
if (expr == null)
return null;
- temp = new LocalTemporary (ec, expr.Type);
+ temp = new LocalTemporary (expr.Type);
info = new NullableInfo (expr.Type);
type = info.UnderlyingType;
}
}
- protected class Wrap : Expression
+ public class Wrap : Expression
{
Expression expr;
NullableInfo info;
- public Wrap (Expression expr, Location loc)
+ protected Wrap (Expression expr)
{
this.expr = expr;
- this.loc = loc;
+ this.loc = expr.Location;
+ }
+
+ public static Wrap Create (Expression expr, EmitContext ec)
+ {
+ return new Wrap (expr).Resolve (ec) as Wrap;
}
public override Expression DoResolve (EmitContext ec)
}
}
- public class NullableLiteral : Expression, IMemoryLocation {
+ public class NullableLiteral : NullLiteral, IMemoryLocation {
public NullableLiteral (Type target_type, Location loc)
+ : base (loc)
{
this.type = target_type;
- this.loc = loc;
eclass = ExprClass.Value;
}
public override void Emit (EmitContext ec)
{
- LocalTemporary value_target = new LocalTemporary (ec, type);
+ LocalTemporary value_target = new LocalTemporary (type);
value_target.AddressOf (ec, AddressOp.Store);
ec.ig.Emit (OpCodes.Initobj, type);
public void AddressOf (EmitContext ec, AddressOp Mode)
{
- LocalTemporary value_target = new LocalTemporary (ec, type);
+ LocalTemporary value_target = new LocalTemporary (type);
value_target.AddressOf (ec, AddressOp.Store);
ec.ig.Emit (OpCodes.Initobj, type);
if (expr == null)
return null;
- unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec);
+ unwrap = Unwrap.Create (expr, ec);
if (unwrap == null)
return null;
if (underlying == null)
return null;
- wrap = new Wrap (underlying, loc).Resolve (ec);
+ wrap = Wrap.Create (underlying, ec);
if (wrap == null)
return null;
public override Expression DoResolve (EmitContext ec)
{
if (TypeManager.IsNullableType (left.Type)) {
- left_unwrap = new Unwrap (left, loc);
- left = left_unwrap.Resolve (ec);
+ left = left_unwrap = Unwrap.Create (left, ec);
if (left == null)
return null;
}
if (TypeManager.IsNullableType (right.Type)) {
- right_unwrap = new Unwrap (right, loc);
- right = right_unwrap.Resolve (ec);
+ right = right_unwrap = Unwrap.Create (right, ec);
if (right == null)
return null;
}
if (((Oper == Binary.Operator.BitwiseAnd) || (Oper == Binary.Operator.BitwiseOr)) &&
((left.Type == TypeManager.bool_type) && (right.Type == TypeManager.bool_type))) {
Expression empty = new EmptyExpression (TypeManager.bool_type);
- bool_wrap = new Wrap (empty, loc).Resolve (ec);
+ bool_wrap = Wrap.Create (empty, ec);
null_value = new NullableLiteral (bool_wrap.Type, loc).Resolve (ec);
type = bool_wrap.Type;
if (underlying == null)
return null;
- underlying = new Wrap (underlying, loc).Resolve (ec);
+ underlying = Wrap.Create (underlying, ec);
if (underlying == null)
return null;
{
ILGenerator ig = ec.ig;
- Label left_not_null_label = ig.DefineLabel ();
- Label false_label = ig.DefineLabel ();
- Label true_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- bool false_label_used = false;
- bool true_label_used = false;
+ // Given 'X? x;' for any value type X: 'x != null' is the same as 'x.HasValue'
+ if (left is NullLiteral) {
+ if (right_unwrap == null)
+ throw new InternalErrorException ();
+ right_unwrap.EmitCheck (ec);
+ if (Oper == Binary.Operator.Equality) {
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
+ }
+ return;
+ }
- if (left_unwrap != null) {
+ if (right is NullLiteral) {
+ if (left_unwrap == null)
+ throw new InternalErrorException ();
left_unwrap.EmitCheck (ec);
- if (right is NullLiteral) {
- if (Oper == Binary.Operator.Equality) {
- true_label_used = true;
- ig.Emit (OpCodes.Brfalse, true_label);
- } else {
- false_label_used = true;
- ig.Emit (OpCodes.Brfalse, false_label);
- }
- } else if (right_unwrap != null) {
- ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Brtrue, left_not_null_label);
- right_unwrap.EmitCheck (ec);
+ if (Oper == Binary.Operator.Equality) {
+ ig.Emit (OpCodes.Ldc_I4_0);
ig.Emit (OpCodes.Ceq);
- if (Oper == Binary.Operator.Inequality) {
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ceq);
- }
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (left_not_null_label);
- ig.Emit (OpCodes.Pop);
- } else {
- if (Oper == Binary.Operator.Equality) {
- false_label_used = true;
- ig.Emit (OpCodes.Brfalse, false_label);
- } else {
- true_label_used = true;
- ig.Emit (OpCodes.Brfalse, true_label);
- }
}
+ return;
}
- if (right_unwrap != null) {
+ Label both_have_value_label = ig.DefineLabel ();
+ Label end_label = ig.DefineLabel ();
+
+ if (left_unwrap != null && right_unwrap != null) {
+ Label dissimilar_label = ig.DefineLabel ();
+
+ left_unwrap.EmitCheck (ec);
+ ig.Emit (OpCodes.Dup);
right_unwrap.EmitCheck (ec);
- if (left is NullLiteral) {
- if (Oper == Binary.Operator.Equality) {
- true_label_used = true;
- ig.Emit (OpCodes.Brfalse, true_label);
- } else {
- false_label_used = true;
- ig.Emit (OpCodes.Brfalse, false_label);
- }
- } else {
- if (Oper == Binary.Operator.Equality) {
- false_label_used = true;
- ig.Emit (OpCodes.Brfalse, false_label);
- } else {
- true_label_used = true;
- ig.Emit (OpCodes.Brfalse, true_label);
- }
- }
- }
+ ig.Emit (OpCodes.Bne_Un, dissimilar_label);
- bool left_is_null = left is NullLiteral;
- bool right_is_null = right is NullLiteral;
- if (left_is_null || right_is_null) {
- if (((Oper == Binary.Operator.Equality) && (left_is_null == right_is_null)) ||
- ((Oper == Binary.Operator.Inequality) && (left_is_null != right_is_null))) {
- true_label_used = true;
- ig.Emit (OpCodes.Br, true_label);
- } else {
- false_label_used = true;
- ig.Emit (OpCodes.Br, false_label);
- }
- } else {
- underlying.Emit (ec);
+ ig.Emit (OpCodes.Brtrue, both_have_value_label);
+
+ // both are null
+ if (Oper == Binary.Operator.Equality)
+ ig.Emit (OpCodes.Ldc_I4_1);
+ else
+ ig.Emit (OpCodes.Ldc_I4_0);
ig.Emit (OpCodes.Br, end_label);
- }
- ig.MarkLabel (false_label);
- if (false_label_used) {
- ig.Emit (OpCodes.Ldc_I4_0);
- if (true_label_used)
- ig.Emit (OpCodes.Br, end_label);
+ ig.MarkLabel (dissimilar_label);
+ ig.Emit (OpCodes.Pop);
+ } else if (left_unwrap != null) {
+ left_unwrap.EmitCheck (ec);
+ ig.Emit (OpCodes.Brtrue, both_have_value_label);
+ } else if (right_unwrap != null) {
+ right_unwrap.EmitCheck (ec);
+ ig.Emit (OpCodes.Brtrue, both_have_value_label);
+ } else {
+ throw new InternalErrorException ("shouldn't get here");
}
- ig.MarkLabel (true_label);
- if (true_label_used)
+ // one is null while the other isn't
+ if (Oper == Binary.Operator.Equality)
+ ig.Emit (OpCodes.Ldc_I4_0);
+ else
ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Br, end_label);
+
+ ig.MarkLabel (both_have_value_label);
+ underlying.Emit (ec);
ig.MarkLabel (end_label);
}
public override Expression DoResolve (EmitContext ec)
{
- unwrap = new Unwrap (expr, loc);
- expr = unwrap.Resolve (ec);
- if (expr == null)
+ unwrap = Unwrap.Create (expr, ec);
+ if (unwrap == null)
return null;
if (unwrap.Type != TypeManager.bool_type)
if (TypeManager.IsNullableType (ltype)) {
NullableInfo info = new NullableInfo (ltype);
- unwrap = (Unwrap) new Unwrap (left, loc).Resolve (ec);
+ unwrap = Unwrap.Create (left, ec);
if (unwrap == null)
return null;
if (expr == null)
return null;
- unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec);
+ unwrap = Unwrap.Create (expr, ec);
if (unwrap == null)
return null;