/// 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;
}
int errors = Report.Errors;
- FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec);
+ FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec, false);
if (fn == null) {
if (errors != Report.Errors)
expr = cexpr;
} else
- expr = fn.ResolveAsTypeTerminal (ec);
+ expr = fn.ResolveAsTypeTerminal (ec, false);
if ((expr == null) || (expr.Type == null))
return false;
/// <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 (EmitContext ec)
+ public void EmitAttributes ()
{
if (OptAttributes != null)
- OptAttributes.Emit (ec, this);
+ OptAttributes.Emit ();
}
public override string DocCommentHeader {
return null;
if (t.IsGenericParameter)
return dargs [t.GenericParameterPosition];
- if (t.IsGenericInstance) {
+ 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;
atypes = new Type [count];
for (int i = 0; i < count; i++){
- TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
+ TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec, false);
if (te == null) {
ok = false;
continue;
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)) {
}
TypeExpr ct = new ConstructedType (ctype, new_args, loc);
- if (ct.ResolveAsTypeStep (ec) == null)
+ if (ct.ResolveAsTypeStep (ec, false) == null)
return false;
ctype = ct.Type;
} else if (ctype.IsGenericParameter) {
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)
{
- if (atype is TypeBuilder) {
- if (atype.IsAbstract)
- return false;
+ if (atype.IsAbstract)
+ return false;
+ again:
+ atype = TypeManager.DropGenericTypeArguments (atype);
+ if (atype is TypeBuilder) {
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, 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;
}
if (!p.Resolve (ec))
ok = false;
}
- if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec) == null))
+ if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null))
ok = false;
return ok;
}
- public void EmitAttributes (EmitContext ec)
+ public void EmitAttributes ()
{
for (int i = 0; i < TypeParameters.Length; i++)
- TypeParameters [i].EmitAttributes (ec);
+ TypeParameters [i].EmitAttributes ();
if (OptAttributes != null)
- OptAttributes.Emit (ec, this);
+ OptAttributes.Emit ();
}
public override bool DefineMembers ()
public override Expression DoResolve (EmitContext ec)
{
- TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
+ TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
if (texpr == null)
return null;
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);
ConstructedType ctype = new ConstructedType (TypeManager.generic_nullable_type, args, loc);
- return ctype.ResolveAsTypeTerminal (ec);
+ return ctype.ResolveAsTypeTerminal (ec, false);
}
}
if (m.IsGenericMethodDefinition)
return m;
if (m.IsGenericMethod)
- return m.GetGenericMethodDefinition ();
+ return ((MethodInfo) m).GetGenericMethodDefinition ();
if (!m.DeclaringType.IsGenericType)
return m;
return m;
}
+ public static FieldInfo GetGenericFieldDefinition (FieldInfo fi)
+ {
+ if (fi.DeclaringType.IsGenericTypeDefinition ||
+ !fi.DeclaringType.IsGenericType)
+ return fi;
+
+ Type t = fi.DeclaringType.GetGenericTypeDefinition ();
+ BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+ foreach (FieldInfo f in t.GetFields (bf))
+ if (f.MetadataToken == fi.MetadataToken)
+ return f;
+
+ return fi;
+ }
+
//
// Whether `array' is an array of T and `enumerator' is `IEnumerable<T>'.
// For instance "string[]" -> "IEnumerable<string>".
//
public static bool IsIEnumerable (Type array, Type enumerator)
{
- if (!array.IsArray || !enumerator.IsGenericInstance)
+ if (!array.IsArray || !enumerator.IsGenericType)
return false;
if (enumerator.GetGenericTypeDefinition () != generic_ienumerable_type)
// class X<T,U> : I<T>, I<U>
// class X<T> : I<T>, I<float>
//
- if (b.IsGenericParameter || !b.IsGenericInstance) {
+ if (b.IsGenericParameter || !b.IsGenericType) {
int pos = a.GenericParameterPosition;
Type[] args = a.DeclaringMethod != null ? method_infered : class_infered;
if (args [pos] == null) {
// become equal).
//
- if (a.IsGenericInstance || b.IsGenericInstance)
+ if (a.IsGenericType || b.IsGenericType)
return MayBecomeEqualGenericInstances (a, b, class_infered, method_infered);
//
Type[] class_infered,
Type[] method_infered)
{
- if (!a.IsGenericInstance || !b.IsGenericInstance)
+ if (!a.IsGenericType || !b.IsGenericType)
return false;
if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
return false;
static bool InferType (Type pt, Type at, Type[] infered)
{
- if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) {
+ if (pt.IsGenericParameter) {
+ if (pt.DeclaringMethod == null)
+ 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;
}
}
if (at.IsArray) {
- if (!pt.IsArray ||
- (at.GetArrayRank () != pt.GetArrayRank ()))
- return false;
+ if (pt.IsArray) {
+ if (at.GetArrayRank () != pt.GetArrayRank ())
+ return false;
- return InferType (pt.GetElementType (), at.GetElementType (), infered);
+ return InferType (pt.GetElementType (), at.GetElementType (), infered);
+ }
+
+ if (!pt.IsGenericType ||
+ (pt.GetGenericTypeDefinition () != generic_ienumerable_type))
+ return false;
+
+ Type[] args = GetTypeArguments (pt);
+ return InferType (args [0], at.GetElementType (), infered);
}
if (pt.IsArray) {
if (pt.IsByRef && at.IsByRef)
return InferType (pt.GetElementType (), at.GetElementType (), infered);
ArrayList list = new ArrayList ();
- if (at.IsGenericInstance)
+ if (at.IsGenericType)
list.Add (at);
for (Type bt = at.BaseType; bt != null; bt = bt.BaseType)
list.Add (bt);
bool found_one = false;
foreach (Type type in list) {
- if (!type.IsGenericInstance)
+ if (!type.IsGenericType)
continue;
Type[] infered_types = new Type [infered.Length];
/// 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;
- if (!(expr is IMemoryLocation))
- temp = new LocalTemporary (ec, expr.Type);
+ temp = new LocalTemporary (expr.Type);
info = new NullableInfo (expr.Type);
type = info.UnderlyingType;
ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
}
+ public void Store (EmitContext ec)
+ {
+ create_temp (ec);
+ }
+
void create_temp (EmitContext ec)
{
if ((temp != null) && !has_temp) {
public void EmitAssign (EmitContext ec, Expression source,
bool leave_copy, bool prepare_for_load)
{
- source.Emit (ec);
- ec.ig.Emit (OpCodes.Newobj, info.Constructor);
+ InternalWrap wrap = new InternalWrap (source, info, loc);
+ ((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false);
+ }
+
+ protected class InternalWrap : Expression
+ {
+ public Expression expr;
+ public NullableInfo info;
+
+ public InternalWrap (Expression expr, NullableInfo info, Location loc)
+ {
+ this.expr = expr;
+ this.info = info;
+ this.loc = loc;
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
+ type = info.Type;
+ eclass = ExprClass.Value;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
- Expression empty = new EmptyExpression (expr.Type);
- ((IAssignMethod) expr).EmitAssign (ec, empty, false, prepare_for_load);
+ public override void Emit (EmitContext ec)
+ {
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Newobj, info.Constructor);
+ }
}
}
- 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)
return null;
TypeExpr target_type = new NullableType (expr.Type, loc);
- target_type = target_type.ResolveAsTypeTerminal (ec);
+ target_type = target_type.ResolveAsTypeTerminal (ec, false);
if (target_type == null)
return null;
}
}
- 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 readonly Binary.Operator Oper;
- Expression left, right, underlying, null_value, bool_wrap;
+ Expression left, right, original_left, original_right;
+ Expression underlying, null_value, bool_wrap;
Unwrap left_unwrap, right_unwrap;
bool is_equality, is_comparision, is_boolean;
Location loc)
{
this.Oper = op;
- this.left = left;
- this.right = right;
+ this.left = original_left = left;
+ this.right = original_right = right;
this.loc = loc;
}
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) ||
- (Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr)) &&
+ if ((Oper == Binary.Operator.LogicalAnd) ||
+ (Oper == Binary.Operator.LogicalOr)) {
+ Binary.Error_OperatorCannotBeApplied (
+ loc, Binary.OperName (Oper),
+ original_left.GetSignatureForError (),
+ original_right.GetSignatureForError ());
+ 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 void Emit (EmitContext ec)
{
+ if (left_unwrap != null)
+ left_unwrap.Store (ec);
+ if (right_unwrap != null)
+ right_unwrap.Store (ec);
+
if (is_boolean) {
EmitBoolean (ec);
return;
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;