// Returns a method group.
MethodGroup = 4,
- // Allows SimpleNames to be returned.
- // This is used by MemberAccess to construct long names that can not be
- // partially resolved (namespace-qualified names for example).
- SimpleName = 8,
-
// Mask of all the expression class flags.
- MaskExprClass = 15,
+ MaskExprClass = 7,
// Disable control flow analysis while resolving the expression.
// This is used when resolving the instance expression of a field expression.
- DisableFlowAnalysis = 16,
+ DisableFlowAnalysis = 8,
// Set if this is resolving the first part of a MemberAccess.
- Intermediate = 32
+ Intermediate = 16
}
//
}
/// <summary>
- /// This interface is implemented by variables
+ /// We are either a namespace or a type.
+ /// If we're a type, `IsType' is true and we may use `Type' to get
+ /// a TypeExpr representing that type.
/// </summary>
- public interface IVariable {
- VariableInfo VariableInfo {
+ public interface IAlias {
+ bool IsType {
get;
}
- bool VerifyFixed (bool is_expression);
- }
-
- /// <summary>
- /// This interface denotes an expression which evaluates to a member
- /// of a struct or a class.
- /// </summary>
- public interface IMemberExpr
- {
- /// <summary>
- /// The name of this member.
- /// </summary>
string Name {
get;
}
- /// <summary>
- /// Whether this is an instance member.
- /// </summary>
- bool IsInstance {
- get;
- }
-
- /// <summary>
- /// Whether this is a static member.
- /// </summary>
- bool IsStatic {
- get;
- }
+ TypeExpr ResolveAsType (EmitContext ec);
+ }
- /// <summary>
- /// The type which declares this member.
- /// </summary>
- Type DeclaringType {
+ /// <summary>
+ /// This interface is implemented by variables
+ /// </summary>
+ public interface IVariable {
+ VariableInfo VariableInfo {
get;
}
- /// <summary>
- /// The instance expression associated with this member, if it's a
- /// non-static member.
- /// </summary>
- Expression InstanceExpression {
- get; set;
- }
+ bool VerifyFixed (bool is_expression);
}
/// <remarks>
/// <summary>
/// Utility wrapper routine for Warning, just to beautify the code
/// </summary>
- public void Warning (int warning, string s)
+ public void Warning (int code, string format, params object[] args)
{
- if (!Location.IsNull (loc))
- Report.Warning (warning, loc, s);
- else
- Report.Warning (warning, s);
+ Report.Warning (code, loc, format, args);
}
- /// <summary>
- /// Utility wrapper routine for Warning, only prints the warning if
- /// warnings of level `level' are enabled.
- /// </summary>
- public void Warning (int warning, int level, string s)
- {
- if (level <= RootContext.WarningLevel)
- Warning (warning, s);
- }
+ // Not nice but we have broken hierarchy
+ public virtual void CheckMarshallByRefAccess (Type container) {}
/// <summary>
/// Tests presence of ObsoleteAttribute and report proper error
AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, loc);
}
+ public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
+ {
+ MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ must_do_cs1540_check = false; // by default we do not check for this
+
+ //
+ // If only accessible to the current class or children
+ //
+ if (ma == MethodAttributes.Private)
+ return invocation_type == mi.DeclaringType ||
+ TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
+
+ if (mi.DeclaringType.Assembly == invocation_type.Assembly) {
+ if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
+ return true;
+ } else {
+ if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
+ return false;
+ }
+
+ // Family and FamANDAssem require that we derive.
+ // FamORAssem requires that we derive if in different assemblies.
+ if (ma == MethodAttributes.Family ||
+ ma == MethodAttributes.FamANDAssem ||
+ ma == MethodAttributes.FamORAssem) {
+ if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
+ return false;
+
+ if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
+ must_do_cs1540_check = true;
+
+ return true;
+ }
+
+ return true;
+ }
+
/// <summary>
/// Performs semantic analysis on the Expression
/// </summary>
public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
- return DoResolve (ec);
+ return null;
}
//
- // 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.
+ // This is used if the expression should be resolved as a type or namespace name.
+ // the default implementation fails.
//
- public virtual Expression ResolveAsTypeStep (EmitContext ec)
+ public virtual FullNamedExpression ResolveAsTypeStep (EmitContext ec)
{
return null;
}
// value will be returned if the expression is not a type
// reference
//
- public TypeExpr ResolveAsTypeTerminal (EmitContext ec)
+ public TypeExpr ResolveAsTypeTerminal (EmitContext ec, bool silent)
{
- return ResolveAsTypeStep (ec) as TypeExpr;
+ int errors = Report.Errors;
+
+ FullNamedExpression fne = ResolveAsTypeStep (ec);
+
+ if (fne == null) {
+ if (!silent && errors == Report.Errors)
+ Report.Error (246, Location, "Cannot find type '{0}'", ToString ());
+ return null;
+ }
+
+ if (fne.eclass != ExprClass.Type) {
+ if (!silent && errors == Report.Errors)
+ Report.Error (118, Location, "'{0}' denotes a '{1}', where a type was expected",
+ fne.FullName, fne.ExprClassName ());
+ return null;
+ }
+
+ TypeExpr te = fne as TypeExpr;
+
+ if (!te.CheckAccessLevel (ec.DeclSpace)) {
+ Report.Error (122, Location, "'{0}' is inaccessible due to its protection level", te.Name);
+ return null;
+ }
+
+ return te;
}
/// <summary>
Expression e;
bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
if (this is SimpleName)
- e = ((SimpleName) this).DoResolveAllowStatic (ec, intermediate);
+ e = ((SimpleName) this).DoResolve (ec, intermediate);
else
e = DoResolve (ec);
if (e == null)
return null;
- if (e is SimpleName){
- SimpleName s = (SimpleName) e;
-
- if ((flags & ResolveFlags.SimpleName) == 0) {
- MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
- ec.DeclSpace.Name, loc);
- return null;
- }
-
- return s;
- }
-
- if ((e is TypeExpr) || (e is ComposedCast)) {
+ if ((e is TypeExpr) || (e is ComposedCast) || (e is Namespace)) {
if ((flags & ResolveFlags.Type) == 0) {
- e.Error_UnexpectedKind (flags);
+ e.Error_UnexpectedKind (flags, loc);
return null;
}
switch (e.eclass) {
case ExprClass.Type:
+ case ExprClass.Namespace:
if ((flags & ResolveFlags.VariableOrValue) == 0) {
- e.Error_UnexpectedKind (flags);
+ e.Error_UnexpectedKind (flags, loc);
return null;
}
break;
case ExprClass.MethodGroup:
- if (!RootContext.V2){
+ if (RootContext.Version == LanguageVersion.ISO_1){
if ((flags & ResolveFlags.MethodGroup) == 0) {
((MethodGroupExpr) e).ReportUsageError ();
return null;
FieldInfo fi = ((FieldExpr) e).FieldInfo;
Console.WriteLine ("{0} and {1}", fi.DeclaringType, fi.Name);
- e.Error_UnexpectedKind (flags);
+ e.Error_UnexpectedKind (flags, loc);
return null;
}
break;
" ExprClass is Invalid after resolve");
}
- if (e.type == null)
+ if (e.type == null && !(e is Namespace)) {
throw new Exception (
"Expression " + e.GetType () +
" did not set its type after Resolve\n" +
"called from: " + this.GetType ());
+ }
return e;
}
/// Currently ResolveLValue wraps DoResolveLValue to perform sanity
/// checking and assertion checking on what we expect from Resolve
/// </remarks>
- public Expression ResolveLValue (EmitContext ec, Expression right_side)
+ public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
{
+ int errors = Report.Errors;
Expression e = DoResolveLValue (ec, right_side);
- if (e != null){
- if (e is SimpleName){
- SimpleName s = (SimpleName) e;
- MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
- ec.DeclSpace.Name, loc);
- return null;
- }
+ if (e == null) {
+ if (errors == Report.Errors)
+ Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
+ return null;
+ }
+ if (e != null){
if (e.eclass == ExprClass.Invalid)
throw new Exception ("Expression " + e +
" ExprClass is Invalid after resolve");
return new CharConstant ((char)v);
else if (t == TypeManager.bool_type)
return new BoolConstant ((bool) v);
+ else if (t == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
else if (TypeManager.IsEnumType (t)){
Type real_type = TypeManager.TypeToCoreType (v.GetType ());
if (real_type == t)
- real_type = real_type.UnderlyingSystemType;
+ real_type = System.Enum.GetUnderlyingType (real_type);
Constant e = Constantify (v, real_type);
return new EnumConstant (e, t);
- } else
+ } else if (v == null && !TypeManager.IsValueType (t))
+ return NullLiteral.Null;
+ else
throw new Exception ("Unknown type for constant (" + t +
"), details: " + v);
}
return null;
}
-
- private static ArrayList almostMatchedMembers = new ArrayList (4);
+ protected static ArrayList almostMatchedMembers = new ArrayList (4);
//
// FIXME: Probably implement a cache for (t,name,current_access_set)?
if (e == null && errors == Report.Errors)
// No errors were reported by MemberLookup, but there was an error.
- MemberLookupFailed (ec, qualifier_type, queried_type, name, null, loc);
+ MemberLookupFailed (ec, qualifier_type, queried_type, name, null, true, loc);
return e;
}
public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
Type queried_type, string name,
- string class_name, Location loc)
+ string class_name, bool complain_if_none_found,
+ Location loc)
{
if (almostMatchedMembers.Count != 0) {
- if (qualifier_type == null) {
- foreach (MemberInfo m in almostMatchedMembers)
+ for (int i = 0; i < almostMatchedMembers.Count; ++i) {
+ MemberInfo m = (MemberInfo) almostMatchedMembers [i];
+ for (int j = 0; j < i; ++j) {
+ if (m == almostMatchedMembers [j]) {
+ m = null;
+ break;
+ }
+ }
+ if (m == null)
+ continue;
+
+ Type declaring_type = m.DeclaringType;
+
+ Report.SymbolRelatedToPreviousError (m);
+ if (qualifier_type == null) {
Report.Error (38, loc,
"Cannot access non-static member `{0}' via nested type `{1}'",
TypeManager.GetFullNameSignature (m),
TypeManager.CSharpName (ec.ContainerType));
- return;
- }
-
- if (qualifier_type != ec.ContainerType) {
- // 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.
- foreach (MemberInfo m in almostMatchedMembers)
+
+ } else if (qualifier_type != ec.ContainerType &&
+ TypeManager.IsNestedFamilyAccessible (ec.ContainerType, declaring_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 base of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
Report.Error (1540, loc,
"Cannot access protected member `{0}' via a qualifier of type `{1}';"
+ " the qualifier must be of type `{2}' (or derived from it)",
TypeManager.GetFullNameSignature (m),
TypeManager.CSharpName (qualifier_type),
TypeManager.CSharpName (ec.ContainerType));
- return;
+ } else {
+ Report.Error (122, loc,
+ "'{0}' is inaccessible due to its protection level",
+ TypeManager.GetFullNameSignature (m));
+ }
}
almostMatchedMembers.Clear ();
+ return;
}
object lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
BindingFlags.NonPublic, name, null);
if (lookup == null) {
+ if (!complain_if_none_found)
+ return;
+
if (class_name != null)
Report.Error (103, loc, "The name `" + name + "' could not be " +
"found in `" + class_name + "'");
return;
}
- if (qualifier_type != null)
- Report.Error_T (122, loc, TypeManager.CSharpName (qualifier_type) + "." + name);
- else if (name == ".ctor") {
- Report.Error (143, loc, String.Format ("The type {0} has no constructors defined",
- TypeManager.CSharpName (queried_type)));
+ if (name == ".ctor" && TypeManager.FindMembers (qualifier_type, MemberTypes.Constructor,
+ BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null).Count == 0)
+ {
+ Report.Error (143, loc, String.Format ("The type '{0}' has no constructors defined", TypeManager.CSharpName (queried_type)));
+ return;
+ }
+
+ if (qualifier_type != null) {
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", TypeManager.CSharpName (qualifier_type) + "." + name);
} else {
- Report.Error_T (122, loc, name);
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", name);
}
}
- static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
- {
- EventInfo ei = event_expr.EventInfo;
-
- return TypeManager.GetPrivateFieldOfEvent (ei);
- }
-
/// <summary>
/// Returns an expression that can be used to invoke operator true
/// on the expression if it exists.
ArrayList arguments = new ArrayList ();
arguments.Add (new Argument (e, Argument.AType.Expression));
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) operator_group, arguments, loc);
+ method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) operator_group, arguments, false, loc);
if (method == null)
return null;
if (e == null)
return null;
- Expression converted = e;
- if (e.Type != TypeManager.bool_type)
- converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, new Location (-1));
+ if (e.Type == TypeManager.bool_type)
+ return e;
+
+ Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
+
+ if (converted != null)
+ return converted;
//
// 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;
+ 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;
+ }
+ return operator_true;
}
- static string ExprClassName (ExprClass c)
+ public string ExprClassName ()
{
- switch (c){
+ switch (eclass){
case ExprClass.Invalid:
return "Invalid";
case ExprClass.Value:
/// <summary>
/// Reports that we were expecting `expr' to be of class `expected'
/// </summary>
- public void Error_UnexpectedKind (string expected)
+ public void Error_UnexpectedKind (string expected, Location loc)
{
- string kind = "Unknown";
-
- kind = ExprClassName (eclass);
-
- Error (118, "Expression denotes a `" + kind +
+ Report.Error (118, loc, "Expression denotes a `" + ExprClassName () +
"' where a `" + expected + "' was expected");
}
- public void Error_UnexpectedKind (ResolveFlags flags)
+ public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
{
ArrayList valid = new ArrayList (10);
if ((flags & ResolveFlags.MethodGroup) != 0)
valid.Add ("method group");
- if ((flags & ResolveFlags.SimpleName) != 0)
- valid.Add ("simple name");
-
if (valid.Count == 0)
valid.Add ("unknown");
sb.Append (valid [i]);
}
- string kind = ExprClassName (eclass);
-
- Error (119, "Expression denotes a `" + kind + "' where " +
+ Report.Error (119, loc, "Expression denotes a `" + ExprClassName () + "' where " +
"a `" + sb.ToString () + "' was expected");
}
/// </summary>
public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
{
- if (!Convert.ImplicitStandardConversionExists (c, target_type)){
+ if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, c, target_type)){
Convert.Error_CannotImplicitConversion (loc, c.Type, target_type);
return null;
}
}
s = v.ToString ();
- } else if (c is UIntConstant){
+ } else if (c is UIntConstant){
uint v = ((UIntConstant) c).Value;
if (target_type == TypeManager.int32_type){
else if (target_type == TypeManager.uint64_type)
return (ulong) v;
s = v.ToString ();
- } else if (c is LongConstant){
+ } else if (c is LongConstant){
long v = ((LongConstant) c).Value;
if (target_type == TypeManager.int32_type){
return (ulong) v;
}
s = v.ToString ();
- } else if (c is ULongConstant){
+ } else if (c is ULongConstant){
ulong v = ((ULongConstant) c).Value;
if (target_type == TypeManager.int32_type){
return 0;
}
- static void Error_NegativeArrayIndex (Location loc)
+ public static void Error_NegativeArrayIndex (Location loc)
{
- Report.Error (284, loc, "Can not create array with a negative size");
+ Report.Error (248, loc, "Cannot create an array with a negative size");
}
//
public EmptyCast (Expression child, Type return_type)
{
eclass = child.eclass;
+ loc = child.Location;
type = return_type;
this.child = child;
}
child.Emit (ec);
}
}
+ /// <summary>
+ /// This is a numeric cast to a Decimal
+ /// </summary>
+ public class CastToDecimal : EmptyCast {
+
+ MethodInfo conversion_operator;
+
+ public CastToDecimal (EmitContext ec, Expression child)
+ : this (ec, child, false)
+ {
+ }
+
+ public CastToDecimal (EmitContext ec, Expression child, bool find_explicit)
+ : base (child, TypeManager.decimal_type)
+ {
+ conversion_operator = GetConversionOperator (ec, find_explicit);
+
+ if (conversion_operator == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+ }
+
+ // Returns the implicit operator that converts from
+ // 'child.Type' to System.Decimal.
+ MethodInfo GetConversionOperator (EmitContext ec, bool find_explicit)
+ {
+ string operator_name = "op_Implicit";
+
+ if (find_explicit)
+ operator_name = "op_Explicit";
+
+ MethodGroupExpr opers = Expression.MethodLookup (
+ ec, type, operator_name, loc) as MethodGroupExpr;
+
+ if (opers == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+
+ foreach (MethodInfo oper in opers.Methods) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+ }
+ /// <summary>
+ /// This is an explicit numeric cast from a Decimal
+ /// </summary>
+ public class CastFromDecimal : EmptyCast
+ {
+ MethodInfo conversion_operator;
+ public CastFromDecimal (EmitContext ec, Expression child, Type return_type)
+ : base (child, return_type)
+ {
+ if (child.Type != TypeManager.decimal_type)
+ throw new InternalErrorException (
+ "The expected type is Decimal, instead it is " + child.Type.FullName);
+
+ conversion_operator = GetConversionOperator (ec);
+ if (conversion_operator == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+ }
+
+ // Returns the explicit operator that converts from an
+ // express of type System.Decimal to 'type'.
+ MethodInfo GetConversionOperator (EmitContext ec)
+ {
+ MethodGroupExpr opers = Expression.MethodLookup (
+ ec, child.Type, "op_Explicit", loc) as MethodGroupExpr;
+
+ if (opers == null)
+ Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+
+ foreach (MethodInfo oper in opers.Methods) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+ }
//
// We need to special case this since an empty cast of
{
child.Emit (ec);
}
+
+ public override bool IsDefaultValue {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public override bool IsNegative {
+ get {
+ return false;
+ }
+ }
}
return Child.GetValue ();
}
+ public object GetValueAsEnumType ()
+ {
+ return System.Enum.ToObject (type, Child.GetValue ());
+ }
+
//
// Converts from one of the valid underlying types for an enumeration
// (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
{
return Child.ConvertToInt ();
}
-
+
+ public override bool IsDefaultValue {
+ get {
+ return Child.IsDefaultValue;
+ }
+ }
+
public override bool IsZeroInteger {
get { return Child.IsZeroInteger; }
}
+
+ public override bool IsNegative {
+ get {
+ return Child.IsNegative;
+ }
+ }
}
/// <summary>
}
/// <summary>
- /// SimpleName expressions are initially formed of a single
- /// word and it only happens at the beginning of the expression.
+ /// SimpleName expressions are formed of a single word and only happen at the beginning
+ /// of a dotted-name.
/// </summary>
- ///
- /// <remarks>
- /// The expression will try to be bound to a Field, a Method
- /// group or a Property. If those fail we pass the name to our
- /// caller and the SimpleName is compounded to perform a type
- /// lookup. The idea behind this process is that we want to avoid
- /// creating a namespace map from the assemblies, as that requires
- /// the GetExportedTypes function to be called and a hashtable to
- /// be constructed which reduces startup time. If later we find
- /// that this is slower, we should create a `NamespaceExpr' expression
- /// that fully participates in the resolution process.
- ///
- /// For example `System.Console.WriteLine' is decomposed into
- /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
- ///
- /// The first SimpleName wont produce a match on its own, so it will
- /// be turned into:
- /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
- ///
- /// System.Console will produce a TypeExpr match.
- ///
- /// The downside of this is that we might be hitting `LookupType' too many
- /// times with this scheme.
- /// </remarks>
public class SimpleName : Expression {
public string Name;
+ bool in_transit;
- //
- // 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)
"An object reference is required " +
"for the non-static field `"+name+"'");
}
-
- //
- // Checks whether we are trying to access an instance
- // property, method or field from a static body.
- //
- Expression MemberStaticCheck (EmitContext ec, Expression e)
- {
- if (e is IMemberExpr){
- IMemberExpr member = (IMemberExpr) e;
-
- if (!member.IsStatic){
- Error_ObjectRefRequired (ec, loc, Name);
- return null;
- }
- }
- return e;
+ public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
+ {
+ return resolved_to != null && resolved_to.Type != null &&
+ resolved_to.Type.Name == Name &&
+ (ec.DeclSpace.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
}
-
+
public override Expression DoResolve (EmitContext ec)
{
- return SimpleNameResolve (ec, null, false, false);
+ return SimpleNameResolve (ec, null, false);
}
public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
- return SimpleNameResolve (ec, right_side, false, false);
+ return SimpleNameResolve (ec, right_side, false);
}
- public Expression DoResolveAllowStatic (EmitContext ec, bool intermediate)
+ public Expression DoResolve (EmitContext ec, bool intermediate)
{
- return SimpleNameResolve (ec, null, true, intermediate);
+ return SimpleNameResolve (ec, null, intermediate);
}
- public override Expression ResolveAsTypeStep (EmitContext ec)
+ public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
{
- DeclSpace ds = ec.DeclSpace;
- NamespaceEntry ns = ds.NamespaceEntry;
- Type t;
- string alias_value;
-
- //
- // 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;
-
- if (ec.ResolvingTypeTree){
- int errors = Report.Errors;
- Type dt = ds.FindType (loc, Name);
-
- if (Report.Errors != errors)
- return null;
-
- if (dt != null)
- return new TypeExpression (dt, loc);
-
- if (alias_value != null){
- if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
- return new TypeExpression (t, loc);
- }
- }
-
- //
- // First, the using aliases
- //
- if (alias_value != null){
- if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
- return new TypeExpression (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.
- //
+ int errors = Report.Errors;
+ FullNamedExpression dt = ec.DeclSpace.LookupType (Name, loc, /*ignore_cs0104=*/ false);
+ if (Report.Errors != errors)
+ return null;
- if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
- return new TypeExpression (t, loc);
-
- // No match, maybe our parent can compose us
- // into something meaningful.
- return this;
+ return dt;
}
- Expression SimpleNameResolve (EmitContext ec, Expression right_side,
- bool allow_static, bool intermediate)
+ Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
{
- Expression e = DoSimpleNameResolve (ec, right_side, allow_static, intermediate);
+ if (in_transit)
+ return null;
+ in_transit = true;
+
+ Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
if (e == null)
return null;
- Block current_block = ec.CurrentBlock;
- if (current_block != null){
- LocalInfo vi = current_block.GetLocalInfo (Name);
- if (is_base &&
- current_block.IsVariableNameUsedInChildBlock(Name)) {
- Report.Error (135, Location,
- "'{0}' has a different meaning in a " +
- "child block", Name);
- return null;
- }
- }
+ if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
+ return e;
- return e;
+ return null;
}
/// <remarks>
/// Local Variables and Parameters are handled at
/// parse time, so they never occur as SimpleNames.
///
- /// The `allow_static' flag is used by MemberAccess only
+ /// The `intermediate' flag is used by MemberAccess only
/// and it is used to inform us that it is ok for us to
/// avoid the static check, because MemberAccess might end
/// up resolving the Name as a Type name and the access as
/// Type is both an instance variable and a Type; Type.GetType
/// is the static method not an instance method of type.
/// </remarks>
- Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static, bool intermediate)
+ Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
{
Expression e = null;
var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
if (right_side != null)
- return var.ResolveLValue (ec, right_side);
+ return var.ResolveLValue (ec, right_side, loc);
else
return var.Resolve (ec);
}
- int idx = -1;
- Parameter par = null;
- Parameters pars = current_block.Parameters;
- if (pars != null)
- par = pars.GetParameterByName (Name, out idx);
-
- if (par != null) {
- ParameterReference param;
-
- param = new ParameterReference (pars, current_block, idx, Name, loc);
-
+ ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
+ if (pref != null) {
if (right_side != null)
- return param.ResolveLValue (ec, right_side);
+ return pref.ResolveLValue (ec, right_side, loc);
else
- return param.Resolve (ec);
+ return pref.Resolve (ec);
}
}
//
DeclSpace lookup_ds = ec.DeclSpace;
+ Type almost_matched_type = null;
+ ArrayList almost_matched = null;
do {
if (lookup_ds.TypeBuilder == null)
break;
if (e != null)
break;
+ if (almost_matched == null && almostMatchedMembers.Count > 0) {
+ almost_matched_type = lookup_ds.TypeBuilder;
+ almost_matched = (ArrayList) almostMatchedMembers.Clone ();
+ }
+
lookup_ds =lookup_ds.Parent;
} while (lookup_ds != null);
e = MemberLookup (ec, ec.ContainerType, Name, loc);
if (e == null) {
- //
- // Since we are cheating (is_base is our hint
- // that we are the beginning of the name): we
- // only do the Alias lookup for namespaces if
- // the name does not include any dots in it
- //
- NamespaceEntry ns = ec.DeclSpace.NamespaceEntry;
- if (is_base && ns != null){
- string alias_value = ns.LookupAlias (Name);
- if (alias_value != null){
- Name = alias_value;
- Type t;
-
- if ((t = TypeManager.LookupType (Name)) != null)
- return new TypeExpression (t, loc);
-
- // No match, maybe our parent can compose us
- // into something meaningful.
- return this;
- }
+ if (almost_matched == null && almostMatchedMembers.Count > 0) {
+ almost_matched_type = ec.ContainerType;
+ almost_matched = (ArrayList) almostMatchedMembers.Clone ();
}
+ e = ResolveAsTypeStep (ec);
+ }
- return ResolveAsTypeStep (ec);
+ if (e == null) {
+ if (almost_matched != null)
+ almostMatchedMembers = almost_matched;
+ if (almost_matched_type == null)
+ almost_matched_type = ec.ContainerType;
+ MemberLookupFailed (ec, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclSpace.Name, true, loc);
+ return null;
}
if (e is TypeExpr)
return e;
- if (e is IMemberExpr) {
- e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
+ if (e is MemberExpr) {
+ MemberExpr me = (MemberExpr) e;
+
+ Expression left;
+ if (me.IsInstance) {
+ if (ec.IsStatic || ec.IsFieldInitializer) {
+ //
+ // Note that an MemberExpr can be both IsInstance and IsStatic.
+ // An unresolved MethodGroupExpr can contain both kinds of methods
+ // and each predicate is true if the MethodGroupExpr contains
+ // at least one of that kind of method.
+ //
+
+ if (!me.IsStatic &&
+ (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
+ Error_ObjectRefRequired (ec, loc, Name);
+ return null;
+ }
+
+ //
+ // Pass the buck to MemberAccess and Invocation.
+ //
+ left = EmptyExpression.Null;
+ } else {
+ left = ec.GetThis (loc);
+ }
+ } else {
+ left = new TypeExpression (ec.ContainerType, loc);
+ }
+
+ e = me.ResolveMemberAccess (ec, left, loc, null);
if (e == null)
return null;
- IMemberExpr me = e as IMemberExpr;
+ me = e as MemberExpr;
if (me == null)
return e;
- // This fails if ResolveMemberAccess() was unable to decide whether
- // it's a field or a type of the same name.
-
- if (!me.IsStatic && (me.InstanceExpression == null))
- return e;
-
if (!me.IsStatic &&
- TypeManager.IsSubclassOrNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
+ TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
me.InstanceExpression.Type != me.DeclaringType &&
!me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType) &&
- (!intermediate || !MemberAccess.IdenticalNameAndTypeName (ec, this, e, loc))) {
+ (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
"outer type `" + me.DeclaringType + "' via nested type `" +
me.InstanceExpression.Type + "'");
}
return (right_side != null)
- ? e.DoResolveLValue (ec, right_side)
- : e.DoResolve (ec);
+ ? me.DoResolveLValue (ec, right_side)
+ : me.DoResolve (ec);
}
- if (ec.IsStatic || ec.IsFieldInitializer){
- if (allow_static)
- return e;
-
- return MemberStaticCheck (ec, e);
- } else
- return e;
+ return e;
}
public override void Emit (EmitContext ec)
return Name;
}
}
+
+ /// <summary>
+ /// Represents a namespace or a type. The name of the class was inspired by
+ /// section 10.8.1 (Fully Qualified Names).
+ /// </summary>
+ public abstract class FullNamedExpression : Expression {
+ public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
+ {
+ return this;
+ }
+
+ public abstract string FullName {
+ get;
+ }
+ }
/// <summary>
/// Fully resolved expression that evaluates to a type
/// </summary>
- public abstract class TypeExpr : Expression {
- override public Expression ResolveAsTypeStep (EmitContext ec)
+ public abstract class TypeExpr : FullNamedExpression {
+ override public FullNamedExpression ResolveAsTypeStep (EmitContext ec)
{
TypeExpr t = DoResolveAsTypeStep (ec);
if (t == null)
override public Expression DoResolve (EmitContext ec)
{
- return ResolveAsTypeTerminal (ec);
+ return ResolveAsTypeTerminal (ec, false);
}
override public void Emit (EmitContext ec)
return true;
}
- public virtual bool IsAttribute {
- get {
- return Type == TypeManager.attribute_type ||
- Type.IsSubclassOf (TypeManager.attribute_type);
- }
- }
-
- public virtual TypeExpr[] GetInterfaces ()
- {
- return TypeManager.GetInterfaces (Type);
- }
-
public abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
public virtual Type ResolveType (EmitContext ec)
{
- TypeExpr t = ResolveAsTypeTerminal (ec);
+ TypeExpr t = ResolveAsTypeTerminal (ec, false);
if (t == null)
return null;
return Type.ToString ();
}
}
+
+ public override string FullName {
+ get {
+ return Type.FullName;
+ }
+ }
}
/// <summary>
public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
{
- if (type == null)
- type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
+ if (type == null) {
+ FullNamedExpression t = ec.DeclSpace.LookupType (name, Location.Null, /*ignore_cs0104=*/ false);
+ if (t == null) {
+ Report.Error (246, loc, "Cannot find type `" + name + "'");
+ return null;
+ }
+ if (!(t is TypeExpr)) {
+ Report.Error (118, Location, "'{0}' denotes a '{1}', where a type was expected",
+ t.FullName, t.ExprClassName ());
+
+ return null;
+ }
+ type = ((TypeExpr) t).ResolveType (ec);
+ }
+
return this;
}
return name;
}
}
+
+ public override string FullName {
+ get {
+ return name;
+ }
+ }
+ }
+
+ public class TypeAliasExpression : TypeExpr {
+ TypeExpr texpr;
+
+ public TypeAliasExpression (TypeExpr texpr, Location l)
+ {
+ this.texpr = texpr;
+ loc = texpr.Location;
+
+ eclass = ExprClass.Type;
+ }
+
+ public override string Name {
+ get { return texpr.Name; }
+ }
+
+ public override string FullName {
+ get { return texpr.FullName; }
+ }
+
+ public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ {
+ Type type = texpr.ResolveType (ec);
+ if (type == null)
+ return null;
+
+ return new TypeExpression (type, loc);
+ }
+
+ public override bool CheckAccessLevel (DeclSpace ds)
+ {
+ return texpr.CheckAccessLevel (ds);
+ }
+
+ public override bool AsAccessible (DeclSpace ds, int flags)
+ {
+ return texpr.AsAccessible (ds, flags);
+ }
+
+ public override bool IsClass {
+ get { return texpr.IsClass; }
+ }
+
+ public override bool IsValueType {
+ get { return texpr.IsValueType; }
+ }
+
+ public override bool IsInterface {
+ get { return texpr.IsInterface; }
+ }
+
+ public override bool IsSealed {
+ get { return texpr.IsSealed; }
+ }
+ }
+
+ /// <summary>
+ /// This class denotes an expression which evaluates to a member
+ /// of a struct or a class.
+ /// </summary>
+ public abstract class MemberExpr : Expression
+ {
+ /// <summary>
+ /// The name of this member.
+ /// </summary>
+ public abstract string Name {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is an instance member.
+ /// </summary>
+ public abstract bool IsInstance {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is a static member.
+ /// </summary>
+ public abstract bool IsStatic {
+ get;
+ }
+
+ /// <summary>
+ /// The type which declares this member.
+ /// </summary>
+ public abstract Type DeclaringType {
+ get;
+ }
+
+ /// <summary>
+ /// The instance expression associated with this member, if it's a
+ /// non-static member.
+ /// </summary>
+ public Expression InstanceExpression;
+
+ public static void error176 (Location loc, string name)
+ {
+ Report.Error (176, loc, "Static member `" + name + "' cannot be accessed " +
+ "with an instance reference, qualify with a type name instead");
+ }
+
+
+ // TODO: possible optimalization
+ // Cache resolved constant result in FieldBuilder <-> expression map
+ public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ //
+ // Precondition:
+ // original == null || original.Resolve (...) ==> left
+ //
+
+ if (left is TypeExpr) {
+ if (!IsStatic) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, Name);
+ return null;
+ }
+
+ return this;
+ }
+
+ if (!IsInstance) {
+ if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
+ return this;
+
+ error176 (loc, Name);
+ return null;
+ }
+
+ InstanceExpression = left;
+
+ return this;
+ }
}
/// <summary>
///
/// This is a fully resolved expression that evaluates to a type
/// </summary>
- public class MethodGroupExpr : Expression, IMemberExpr {
+ public class MethodGroupExpr : MemberExpr {
public MethodBase [] Methods;
- Expression instance_expression = null;
- bool is_explicit_impl = false;
bool identical_type_name = false;
bool is_base;
type = TypeManager.object_type;
}
- public Type DeclaringType {
+ public override Type DeclaringType {
get {
//
// The methods are arranged in this order:
return Methods [0].DeclaringType;
}
}
-
- //
- // `A method group may have associated an instance expression'
- //
- public Expression InstanceExpression {
- get {
- return instance_expression;
- }
-
- set {
- instance_expression = value;
- }
- }
-
- public bool IsExplicitImpl {
- get {
- return is_explicit_impl;
- }
-
- set {
- is_explicit_impl = value;
- }
- }
public bool IdenticalTypeName {
get {
}
}
- public string Name {
+ public override string Name {
get {
return Methods [0].Name;
}
}
- public bool IsInstance {
+ public override bool IsInstance {
get {
foreach (MethodBase mb in Methods)
if (!mb.IsStatic)
}
}
- public bool IsStatic {
+ public override bool IsStatic {
get {
foreach (MethodBase mb in Methods)
if (mb.IsStatic)
return false;
}
}
+
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ if (!(left is TypeExpr) &&
+ original != null && original.IdenticalNameAndTypeName (ec, left, loc))
+ IdenticalTypeName = true;
+
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
override public Expression DoResolve (EmitContext ec)
{
if (!IsInstance)
- instance_expression = null;
+ InstanceExpression = null;
- if (instance_expression != null) {
- instance_expression = instance_expression.DoResolve (ec);
- if (instance_expression == null)
+ if (InstanceExpression != null) {
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
return null;
}
/// <summary>
/// Fully resolved expression that evaluates to a Field
/// </summary>
- public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr, IVariable {
+ public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
public readonly FieldInfo FieldInfo;
- Expression instance_expr;
VariableInfo variable_info;
LocalTemporary temp;
bool prepared;
+ bool in_initializer;
+
+ public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
+ this (fi, l)
+ {
+ this.in_initializer = in_initializer;
+ }
public FieldExpr (FieldInfo fi, Location l)
{
loc = l;
}
- public string Name {
+ public override string Name {
get {
return FieldInfo.Name;
}
}
- public bool IsInstance {
+ public override bool IsInstance {
get {
return !FieldInfo.IsStatic;
}
}
- public bool IsStatic {
+ public override bool IsStatic {
get {
return FieldInfo.IsStatic;
}
}
- public Type DeclaringType {
+ public override Type DeclaringType {
get {
return FieldInfo.DeclaringType;
}
}
- public Expression InstanceExpression {
+ public VariableInfo VariableInfo {
get {
- return instance_expr;
+ return variable_info;
}
+ }
- set {
- instance_expr = value;
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ bool left_is_type = left is TypeExpr;
+
+ Type decl_type = FieldInfo.DeclaringType;
+
+ bool is_emitted = FieldInfo is FieldBuilder;
+ Type t = FieldInfo.FieldType;
+
+ if (is_emitted) {
+ Const c = TypeManager.LookupConstant ((FieldBuilder) FieldInfo);
+
+ if (c != null) {
+ object o;
+ if (!c.LookupConstantValue (out o))
+ return null;
+
+ c.SetMemberIsUsed ();
+ object real_value = ((Constant) c.Expr).GetValue ();
+
+ Expression exp = Constantify (real_value, t);
+
+ if (!left_is_type &&
+ (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
+ Report.SymbolRelatedToPreviousError (c);
+ error176 (loc, c.GetSignatureForError ());
+ return null;
+ }
+
+ return exp;
+ }
}
- }
- public VariableInfo VariableInfo {
- get {
- return variable_info;
+ //
+ // Decimal constants cannot be encoded in the constant blob, and thus are marked
+ // as IsInitOnly ('readonly' in C# parlance). We get its value from the
+ // DecimalConstantAttribute metadata.
+ //
+ if (FieldInfo.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
+ object[] attrs = FieldInfo.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
+ if (attrs.Length == 1)
+ return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
+ }
+
+ if (FieldInfo.IsLiteral) {
+ object o;
+
+ if (is_emitted)
+ o = TypeManager.GetValue ((FieldBuilder) FieldInfo);
+ else
+ o = FieldInfo.GetValue (FieldInfo);
+
+ if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
+ if (!left_is_type &&
+ (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
+ error176 (loc, FieldInfo.Name);
+ return null;
+ }
+
+ Expression enum_member = MemberLookup (
+ ec, decl_type, "value__", MemberTypes.Field,
+ AllBindingFlags | BindingFlags.NonPublic, loc);
+
+ Enum en = TypeManager.LookupEnum (decl_type);
+
+ Constant c;
+ if (en != null)
+ c = Constantify (o, en.UnderlyingType);
+ else
+ c = Constantify (o, enum_member.Type);
+
+ return new EnumConstant (c, decl_type);
+ }
+
+ Expression exp = Constantify (o, t);
+
+ if (!left_is_type) {
+ error176 (loc, FieldInfo.Name);
+ return null;
+ }
+
+ return exp;
}
+
+ if (t.IsPointer && !ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
+ }
+
+ return base.ResolveMemberAccess (ec, left, loc, original);
}
override public Expression DoResolve (EmitContext ec)
{
+ if (ec.InRefOutArgumentResolving && FieldInfo.IsInitOnly && !ec.IsConstructor && FieldInfo.FieldType.IsValueType) {
+ if (FieldInfo.FieldType is TypeBuilder) {
+ if (FieldInfo.IsStatic)
+ Report.Error (1651, loc, "Members of readonly static field '{0}.{1}' cannot be passed ref or out (except in a constructor)",
+ TypeManager.CSharpName (DeclaringType), Name);
+ else
+ Report.Error (1649, loc, "Members of readonly field '{0}.{1}' cannot be passed ref or out (except in a constructor)",
+ TypeManager.CSharpName (DeclaringType), Name);
+ } else {
+ if (FieldInfo.IsStatic)
+ Report.Error (199, loc, "A static readonly field '{0}' cannot be passed ref or out (except in a static constructor)",
+ Name);
+ else
+ Report.Error (192, loc, "A readonly field '{0}' cannot be passed ref or out (except in a constructor)",
+ Name);
+ }
+ return null;
+ }
+
if (!FieldInfo.IsStatic){
- if (instance_expr == null){
+ if (InstanceExpression == null){
//
// This can happen when referencing an instance field using
// a fully qualified type expression: TypeName.InstanceField = xxx
// Resolve the field's instance expression while flow analysis is turned
// off: when accessing a field "a.b", we must check whether the field
// "a.b" is initialized, not whether the whole struct "a" is initialized.
- instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
+ InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue |
ResolveFlags.DisableFlowAnalysis);
- if (instance_expr == null)
+ if (InstanceExpression == null)
return null;
}
- ObsoleteAttribute oa;
- FieldBase f = TypeManager.GetField (FieldInfo);
- if (f != null) {
- oa = f.GetObsoleteAttribute (ec.DeclSpace);
- if (oa != null)
- AttributeTester.Report_ObsoleteMessage (oa, f.GetSignatureForError (), loc);
+ if (!in_initializer) {
+ ObsoleteAttribute oa;
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if (f != null) {
+ oa = f.GetObsoleteAttribute (f.Parent);
+ if (oa != null)
+ AttributeTester.Report_ObsoleteMessage (oa, f.GetSignatureForError (), loc);
- // To be sure that type is external because we do not register generated fields
- } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
- oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
- if (oa != null)
- AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
+ // To be sure that type is external because we do not register generated fields
+ } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
+ oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
+ if (oa != null)
+ AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
+ }
}
+ if (ec.CurrentAnonymousMethod != null){
+ if (!FieldInfo.IsStatic){
+ if (ec.TypeContainer is Struct){
+ Report.Error (1673, loc, "Can not reference instance variables in anonymous methods hosted in structs");
+ return null;
+ }
+ ec.CaptureField (this);
+ }
+ }
+
// If the instance expression is a local variable or parameter.
- IVariable var = instance_expr as IVariable;
+ IVariable var = InstanceExpression as IVariable;
if ((var == null) || (var.VariableInfo == null))
return this;
override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
- IVariable var = instance_expr as IVariable;
+ IVariable var = InstanceExpression as IVariable;
if ((var != null) && (var.VariableInfo != null))
var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
if (e == null)
return null;
- if (!FieldInfo.IsStatic && (instance_expr.Type.IsValueType && !(instance_expr is IMemoryLocation))) {
+ if (!FieldInfo.IsStatic && (InstanceExpression.Type.IsValueType && !(InstanceExpression is IMemoryLocation))) {
// FIXME: Provide better error reporting.
Error (1612, "Cannot modify expression because it is not a variable.");
return null;
}
- if (!FieldInfo.IsInitOnly)
- return this;
-
FieldBase fb = TypeManager.GetField (FieldInfo);
if (fb != null)
fb.SetAssigned ();
+ if (!FieldInfo.IsInitOnly)
+ return this;
+
//
// InitOnly fields can only be assigned in constructors
//
return this;
}
- Report_AssignToReadonly (true);
+ Report_AssignToReadonly (!IsStatic);
return null;
}
+ public override void CheckMarshallByRefAccess (Type container)
+ {
+ if (!IsStatic && Type.IsValueType && !container.IsSubclassOf (TypeManager.mbr_type) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
+ Report.SymbolRelatedToPreviousError (DeclaringType);
+ Report.Error (1690, loc, "Cannot call '{0}' method, property, or indexer because it is a value type member of a marshal-by-reference class", Name);
+ }
+ }
+
public bool VerifyFixed (bool is_expression)
{
- IVariable variable = instance_expr as IVariable;
+ IVariable variable = InstanceExpression as IVariable;
if ((variable == null) || !variable.VerifyFixed (true))
return false;
return true;
}
+
+ public override int GetHashCode()
+ {
+ return FieldInfo.GetHashCode ();
+ }
+
+ public override bool Equals (object obj)
+ {
+ FieldExpr fe = obj as FieldExpr;
+ if (fe == null)
+ return false;
+
+ if (FieldInfo != fe.FieldInfo)
+ return false;
+
+ if (InstanceExpression == null || fe.InstanceExpression == null)
+ return true;
+
+ return InstanceExpression.Equals (fe.InstanceExpression);
+ }
public void Emit (EmitContext ec, bool leave_copy)
{
if ((f.ModFlags & Modifiers.VOLATILE) != 0)
is_volatile = true;
- f.status |= Field.Status.USED;
+ f.SetMemberIsUsed ();
}
}
if (is_volatile)
ig.Emit (OpCodes.Volatile);
-
- ig.Emit (OpCodes.Ldfld, FieldInfo);
+
+ IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
+ if (ff != null)
+ {
+ ig.Emit (OpCodes.Ldflda, FieldInfo);
+ ig.Emit (OpCodes.Ldflda, ff.Element);
+ }
+ else {
+ ig.Emit (OpCodes.Ldfld, FieldInfo);
+ }
}
-
+
if (leave_copy) {
ec.ig.Emit (OpCodes.Dup);
if (!FieldInfo.IsStatic) {
void EmitInstance (EmitContext ec)
{
- if (instance_expr.Type.IsValueType) {
- if (instance_expr is IMemoryLocation) {
- ((IMemoryLocation) instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ if (InstanceExpression.Type.IsValueType) {
+ if (InstanceExpression is IMemoryLocation) {
+ ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
} else {
- LocalTemporary t = new LocalTemporary (ec, instance_expr.Type);
- instance_expr.Emit (ec);
+ LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
+ InstanceExpression.Emit (ec);
t.Store (ec);
t.AddressOf (ec, AddressOp.Store);
}
} else
- instance_expr.Emit (ec);
+ InstanceExpression.Emit (ec);
}
public override void Emit (EmitContext ec)
{
Emit (ec, false);
}
-
+
public void AddressOf (EmitContext ec, AddressOp mode)
{
ILGenerator ig = ec.ig;
if ((mode & AddressOp.Store) != 0)
f.status |= Field.Status.ASSIGNED;
if ((mode & AddressOp.Load) != 0)
- f.status |= Field.Status.USED;
+ f.SetMemberIsUsed ();
}
}
/// This is not an LValue because we need to re-write the expression, we
/// can not take data from the stack and store it.
/// </summary>
- public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
+ public class PropertyExpr : MemberExpr, IAssignMethod {
public readonly PropertyInfo PropertyInfo;
//
public bool IsBase;
MethodInfo getter, setter;
bool is_static;
- bool must_do_cs1540_check;
+
+ bool resolved;
- Expression instance_expr;
LocalTemporary temp;
bool prepared;
+ internal static PtrHashtable AccessorTable = new PtrHashtable ();
+
public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
{
PropertyInfo = pi;
ResolveAccessors (ec);
}
- public string Name {
+ public override string Name {
get {
return PropertyInfo.Name;
}
}
- public bool IsInstance {
+ public override bool IsInstance {
get {
return !is_static;
}
}
- public bool IsStatic {
+ public override bool IsStatic {
get {
return is_static;
}
}
- public Type DeclaringType {
+ public override Type DeclaringType {
get {
return PropertyInfo.DeclaringType;
}
}
- //
- // The instance expression associated with this expression
- //
- public Expression InstanceExpression {
- set {
- instance_expr = value;
- }
-
- get {
- return instance_expr;
- }
- }
-
public bool VerifyAssignable ()
{
if (setter == null) {
return true;
}
- MethodInfo FindAccessor (Type invocation_type, bool is_set)
+ void FindAccessors (Type invocation_type)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance |
if (group.Length != 1)
// Oooops, can this ever happen ?
- return null;
+ return;
PropertyInfo pi = (PropertyInfo) group [0];
- MethodInfo get = pi.GetGetMethod (true);
- MethodInfo set = pi.GetSetMethod (true);
-
- if (is_set) {
- if (set != null)
- return set;
- } else {
- if (get != null)
- return get;
- }
-
- MethodInfo accessor = get != null ? get : set;
- if (accessor == null)
- continue;
- if ((accessor.Attributes & MethodAttributes.NewSlot) != 0)
- break;
- }
-
- return null;
- }
-
- MethodInfo GetAccessor (Type invocation_type, bool is_set)
- {
- MethodInfo mi = FindAccessor (invocation_type, is_set);
- if (mi == null)
- return null;
-
- 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
- return null;
- } 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)
- return null;
- 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)
- return mi;
- }
+ if (getter == null)
+ getter = pi.GetGetMethod (true);
- // We already know that we aren't in the same assembly.
- if (ma == MethodAttributes.Assembly)
- return null;
+ if (setter == null)
+ setter = pi.GetSetMethod (true);
- // Family and FamANDAssem require that we derive.
- if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem) || (ma == MethodAttributes.FamORAssem)){
- if (!TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType))
- return null;
- else {
- if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
- must_do_cs1540_check = true;
+ MethodInfo accessor = getter != null ? getter : setter;
- return mi;
- }
+ if (!accessor.IsVirtual)
+ return;
}
-
- return mi;
}
//
//
void ResolveAccessors (EmitContext ec)
{
- getter = GetAccessor (ec.ContainerType, false);
- if ((getter != null) && getter.IsStatic)
- is_static = true;
+ FindAccessors (ec.ContainerType);
- setter = GetAccessor (ec.ContainerType, true);
- if ((setter != null) && setter.IsStatic)
- is_static = true;
+ if (getter != null) {
+ IMethodData md = TypeManager.GetMethod (getter);
+ if (md != null)
+ md.SetMemberIsUsed ();
+
+ AccessorTable [getter] = PropertyInfo;
+ is_static = getter.IsStatic;
+ }
+
+ if (setter != null) {
+ IMethodData md = TypeManager.GetMethod (setter);
+ if (md != null)
+ md.SetMemberIsUsed ();
- if (setter == null && getter == null){
- Report.Error_T (122, loc, PropertyInfo.Name);
+ AccessorTable [setter] = PropertyInfo;
+ is_static = setter.IsStatic;
}
}
- bool InstanceResolve (EmitContext ec)
+ bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
{
- if ((instance_expr == null) && ec.IsStatic && !is_static) {
+ if ((InstanceExpression == null) && ec.IsStatic && !is_static) {
SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
return false;
}
- if (instance_expr != null) {
- instance_expr = instance_expr.DoResolve (ec);
- if (instance_expr == null)
+ if (!IsInstance || InstanceExpression == EmptyExpression.Null)
+ InstanceExpression = null;
+
+ if (InstanceExpression != null) {
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
return false;
+
+ InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
}
- if (must_do_cs1540_check && (instance_expr != null)) {
- if ((instance_expr.Type != ec.ContainerType) &&
- ec.ContainerType.IsSubclassOf (instance_expr.Type)) {
+ if (must_do_cs1540_check && (InstanceExpression != null)) {
+ if ((InstanceExpression.Type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
Report.Error (1540, loc, "Cannot access protected member `" +
PropertyInfo.DeclaringType + "." + PropertyInfo.Name +
"' via a qualifier of type `" +
- TypeManager.CSharpName (instance_expr.Type) +
+ TypeManager.CSharpName (InstanceExpression.Type) +
"'; the qualifier must be of type `" +
TypeManager.CSharpName (ec.ContainerType) +
"' (or derived from it)");
override public Expression DoResolve (EmitContext ec)
{
+ if (resolved) {
+ Report.Debug ("Double resolve of " + Name);
+ return this;
+ }
+
if (getter != null){
if (TypeManager.GetArgumentTypes (getter).Length != 0){
Report.Error (
//
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 (InstanceExpression != EmptyExpression.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))
+ bool must_do_cs1540_check = false;
+ if (getter != null &&
+ !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
+ PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
+ if (pm != null && pm.HasCustomAccessModifier) {
+ Report.SymbolRelatedToPreviousError (pm);
+ Report.Error (271, loc, "The property or indexer '{0}' cannot be used in this context because the get accessor is inaccessible",
+ TypeManager.CSharpSignature (getter));
+ }
+ else
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level",
+ TypeManager.CSharpSignature (getter));
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
return null;
//
return null;
}
+ if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ resolved = true;
+
return this;
}
if (getter == null)
return null;
- Report.Error (154, loc,
- "The property `" + PropertyInfo.Name +
- "' can not be used in " +
- "this context because it lacks a set accessor");
+ // TODO: Print better property name
+ Report.Error (200, loc, "Property or indexer '{0}' cannot be assigned to -- it is read only",
+ PropertyInfo.Name);
return null;
}
return null;
}
- if (!InstanceResolve (ec))
+ bool must_do_cs1540_check;
+ if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
+ PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
+ if (pm != null && pm.HasCustomAccessModifier) {
+ Report.SymbolRelatedToPreviousError (pm);
+ Report.Error (272, loc, "The property or indexer '{0}' cannot be used in this context because the set accessor is inaccessible",
+ TypeManager.CSharpSignature (setter));
+ }
+ else
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level",
+ TypeManager.CSharpSignature (setter));
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
return null;
//
//
// Check that we are not making changes to a temporary memory location
//
- if (instance_expr != null && instance_expr.Type.IsValueType && !(instance_expr is IMemoryLocation)) {
+ if (InstanceExpression != null && InstanceExpression.Type.IsValueType && !(InstanceExpression is IMemoryLocation)) {
// FIXME: Provide better error reporting.
Error (1612, "Cannot modify expression because it is not a variable.");
return null;
if (is_static)
return;
- if (instance_expr.Type.IsValueType) {
- if (instance_expr is IMemoryLocation) {
- ((IMemoryLocation) instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ if (InstanceExpression.Type.IsValueType) {
+ if (InstanceExpression is IMemoryLocation) {
+ ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
} else {
- LocalTemporary t = new LocalTemporary (ec, instance_expr.Type);
- instance_expr.Emit (ec);
+ LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
+ InstanceExpression.Emit (ec);
t.Store (ec);
t.AddressOf (ec, AddressOp.Store);
}
} else
- instance_expr.Emit (ec);
+ InstanceExpression.Emit (ec);
if (prepared)
ec.ig.Emit (OpCodes.Dup);
//
if ((getter == TypeManager.system_int_array_get_length) ||
(getter == TypeManager.int_array_get_length)){
- Type iet = instance_expr.Type;
+ Type iet = InstanceExpression.Type;
//
// System.Array.Length can be called, but the Type does not
if (temp != null)
temp.Emit (ec);
}
-
- override public void EmitStatement (EmitContext ec)
- {
- Emit (ec);
- ec.ig.Emit (OpCodes.Pop);
- }
}
/// <summary>
/// Fully resolved expression that evaluates to an Event
/// </summary>
- public class EventExpr : Expression, IMemberExpr {
+ public class EventExpr : MemberExpr {
public readonly EventInfo EventInfo;
- Expression instance_expr;
bool is_static;
MethodInfo add_accessor, remove_accessor;
type = EventInfo.EventHandlerType;
}
- public string Name {
+ public override string Name {
get {
return EventInfo.Name;
}
}
- public bool IsInstance {
+ public override bool IsInstance {
get {
return !is_static;
}
}
- public bool IsStatic {
+ public override bool IsStatic {
get {
return is_static;
}
}
- public Type DeclaringType {
+ public override Type DeclaringType {
get {
return EventInfo.DeclaringType;
}
}
- public Expression InstanceExpression {
- get {
- return instance_expr;
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ //
+ // If the event is local to this class, we transform ourselves into a FieldExpr
+ //
+
+ if (EventInfo.DeclaringType == ec.ContainerType ||
+ TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
+ MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
+
+ if (mi != null) {
+ MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return null;
+ }
+
+ InstanceExpression = null;
+
+ return ml.ResolveMemberAccess (ec, left, loc, original);
+ }
}
- set {
- instance_expr = value;
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
+
+
+ bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
+ {
+ if ((InstanceExpression == null) && ec.IsStatic && !is_static) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
+ return false;
+ }
+
+ if (!IsInstance || InstanceExpression == EmptyExpression.Null)
+ InstanceExpression = null;
+
+ if (InstanceExpression != null) {
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
+ return false;
}
+
+ //
+ // This is using the same mechanism as the CS1540 check in PropertyExpr.
+ // However, in the Event case, we reported a CS0122 instead.
+ //
+ if (must_do_cs1540_check && (InstanceExpression != null)) {
+ if ((InstanceExpression.Type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level",
+ DeclaringType.Name + "." + EventInfo.Name);
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return DoResolve (ec);
}
public override Expression DoResolve (EmitContext ec)
{
- if (instance_expr != null) {
- instance_expr = instance_expr.DoResolve (ec);
- if (instance_expr == null)
+ if (!IsInstance)
+ InstanceExpression = null;
+
+ if (InstanceExpression != null) {
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
return null;
}
+ bool must_do_cs1540_check;
+ if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
+ IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
+
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level",
+ DeclaringType.Name + "." + EventInfo.Name);
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
+ return null;
return this;
- }
+ }
public override void Emit (EmitContext ec)
{
- Report.Error (70, loc, "The event `" + Name + "' can only appear on the left hand side of += or -= (except on the defining type)");
+ if (InstanceExpression is This)
+ Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=, try calling the actual delegate", Name);
+ else
+ Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
+ "(except on the defining type)", Name);
}
public void EmitAddOrRemove (EmitContext ec, Expression source)
if (source_del.IsAddition)
Invocation.EmitCall (
- ec, false, IsStatic, instance_expr, add_accessor, args, loc);
+ ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
else
Invocation.EmitCall (
- ec, false, IsStatic, instance_expr, remove_accessor, args, loc);
+ ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
}
}
}