// 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 = 16
}
//
get;
}
- TypeExpr Type {
- get;
- }
+ TypeExpr ResolveAsType (EmitContext ec);
}
/// <summary>
/// <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);
}
+ // Not nice but we have broken hierarchy
+ public virtual void CheckMarshallByRefAccess (Type container) {}
+
/// <summary>
- /// Utility wrapper routine for Warning, only prints the warning if
- /// warnings of level `level' are enabled.
+ /// Tests presence of ObsoleteAttribute and report proper error
/// </summary>
- public void Warning (int warning, int level, string s)
+ protected void CheckObsoleteAttribute (Type type)
{
- if (level <= RootContext.WarningLevel)
- Warning (warning, s);
+ ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type);
+ if (obsolete_attr == null)
+ return;
+
+ 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) {
+ Type declaring_type = mi.DeclaringType;
+
+ if (invocation_type != declaring_type)
+ return TypeManager.IsNestedChildOf (invocation_type, declaring_type);
+
+ return true;
+ }
+ //
+ // FamAndAssem requires that we not only derivate, but we are on the
+ // same assembly.
+ //
+ if (ma == MethodAttributes.FamANDAssem){
+ return (mi.DeclaringType.Assembly != invocation_type.Assembly);
+ }
+
+ // 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 true;
+ }
+
+ // We already know that we aren't in the same assembly.
+ if (ma == MethodAttributes.Assembly)
+ return false;
+
+ // Family and FamANDAssem require that we derive.
+ 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>
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 virtual TypeExpr ResolveAsTypeTerminal (EmitContext ec)
{
- return ResolveAsTypeStep (ec) as TypeExpr;
+ int errors = Report.Errors;
+
+ FullNamedExpression fne = ResolveAsTypeStep (ec);
+
+ if (fne == null) {
+ if (errors == Report.Errors)
+ Report.Error (246, Location, "Cannot find type '{0}'", ToString ());
+ return null;
+ }
+
+ if (fne.eclass != ExprClass.Type) {
+ if (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>
ec.DoFlowAnalysis = false;
Expression e;
+ bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
if (this is SimpleName)
- e = ((SimpleName) this).DoResolveAllowStatic (ec);
+ e = ((SimpleName) this).DoResolveAllowStatic (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 ((flags & ResolveFlags.MethodGroup) == 0) {
- ((MethodGroupExpr) e).ReportUsageError ();
- return null;
- }
+ if (RootContext.Version == LanguageVersion.ISO_1){
+ if ((flags & ResolveFlags.MethodGroup) == 0) {
+ ((MethodGroupExpr) e).ReportUsageError ();
+ return null;
+ }
}
break;
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;
}
/// </remarks>
public Expression ResolveLValue (EmitContext ec, Expression right_side)
{
+ 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, Location, "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)){
- Constant e = Constantify (v, TypeManager.TypeToCoreType (v.GetType ()));
+ Type real_type = TypeManager.TypeToCoreType (v.GetType ());
+ if (real_type == t)
+ 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;
}
+ protected static ArrayList almostMatchedMembers = new ArrayList (4);
+
//
// FIXME: Probably implement a cache for (t,name,current_access_set)?
//
string name, MemberTypes mt,
BindingFlags bf, Location loc)
{
+ almostMatchedMembers.Clear ();
+
MemberInfo [] mi = TypeManager.MemberLookup (
- container_type, qualifier_type,queried_type, mt, bf, name);
+ container_type, qualifier_type,queried_type, mt, bf, name,
+ almostMatchedMembers);
if (mi == null)
return null;
e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
name, mt, bf, loc);
- if (e != null)
- return e;
+ 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);
- // Error has already been reported.
- if (errors < Report.Errors)
- return null;
-
- MemberLookupFailed (ec, qualifier_type, queried_type, name,
- null, loc);
- return null;
+ return e;
}
public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
Type queried_type, string name,
string class_name, Location loc)
{
+ if (almostMatchedMembers.Count != 0) {
+ if (qualifier_type == null) {
+ foreach (MemberInfo m in almostMatchedMembers)
+ 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 base of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
+ 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;
+
+ Report.SymbolRelatedToPreviousError (m);
+ 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;
+ }
+ almostMatchedMembers.Clear ();
+ }
+
MemberInfo[] mi = TypeManager.MemberLookup (queried_type, null, queried_type,
AllMemberTypes, AllBindingFlags |
- BindingFlags.NonPublic, name);
+ BindingFlags.NonPublic, name, null);
if (mi == null) {
if (class_name != null)
if (TypeManager.MemberLookup (queried_type, null, queried_type,
AllMemberTypes, AllBindingFlags |
- BindingFlags.NonPublic, name) == null) {
+ BindingFlags.NonPublic, name, null) == null) {
if ((mi.Length == 1) && (mi [0] is Type)) {
Type t = (Type) mi [0];
}
}
- if ((qualifier_type != null) && (qualifier_type != ec.ContainerType) &&
- ec.ContainerType.IsSubclassOf (qualifier_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 parent of the
- // ec.ContainerType and the lookup succeeds with the latter one,
- // then we are in this situation.
-
- mi = TypeManager.MemberLookup (
- ec.ContainerType, ec.ContainerType, ec.ContainerType,
- AllMemberTypes, AllBindingFlags, name);
-
- if (mi != null) {
- Report.Error (
- 1540, loc, "Cannot access protected member `" +
- TypeManager.CSharpName (qualifier_type) + "." +
- name + "' " + "via a qualifier of type `" +
- TypeManager.CSharpName (qualifier_type) + "'; the " +
- "qualifier must be of type `" +
- TypeManager.CSharpName (ec.ContainerType) + "' " +
- "(or derived from it)");
- return;
- }
+ 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, "`" + TypeManager.CSharpName (qualifier_type) + "." +
- name + "' is inaccessible due to its protection level");
- else if (name == ".ctor") {
- Report.Error (143, loc, String.Format ("The type {0} has no constructors defined",
- TypeManager.CSharpName (queried_type)));
+ if (qualifier_type != null) {
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", TypeManager.CSharpName (qualifier_type) + "." + name);
} else {
- Report.Error (
- 122, loc, "`" + name + "' is inaccessible due to its " +
- "protection level");
+ Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", name);
}
}
/// Returns an expression that can be used to invoke operator true
/// on the expression if it exists.
/// </summary>
- static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
+ static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
{
return GetOperatorTrueOrFalse (ec, e, true, loc);
}
/// Returns an expression that can be used to invoke operator false
/// on the expression if it exists.
/// </summary>
- static public StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
+ static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
{
return GetOperatorTrueOrFalse (ec, e, false, loc);
}
- static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
+ static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
{
MethodBase method;
Expression operator_group;
+ if (TypeManager.IsNullableType (e.Type))
+ return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
+
operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
if (operator_group == 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, new Location (-1));
+
+ 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){
ig.Emit (OpCodes.Ldind_Ref);
else
LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
- } else if (t.IsValueType)
+ } else if (t.IsValueType || t.IsGenericParameter)
ig.Emit (OpCodes.Ldobj, t);
else if (t.IsPointer)
ig.Emit (OpCodes.Ldind_I);
- else
+ else
ig.Emit (OpCodes.Ldind_Ref);
}
ig.Emit (OpCodes.Stind_I1);
else if (type == TypeManager.intptr_type)
ig.Emit (OpCodes.Stind_I);
- else if (type.IsValueType)
+ else if (type.IsValueType || type.IsGenericParameter)
ig.Emit (OpCodes.Stobj, type);
else
ig.Emit (OpCodes.Stind_Ref);
return 0;
}
- //
- // Default implementation of IAssignMethod.CacheTemporaries
- //
- public void CacheTemporaries (EmitContext ec)
- {
- }
-
- 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);
}
+
+ 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;
+ public readonly TypeArguments Arguments;
- //
- // If true, then we are a simple name, not composed with a ".
- //
- bool is_base;
-
- public SimpleName (string a, string b, Location l)
+ public SimpleName (string name, Location l)
{
- Name = String.Concat (a, ".", b);
+ Name = name;
loc = l;
- is_base = false;
}
-
- public SimpleName (string name, Location l)
+
+ public SimpleName (string name, TypeArguments args, Location l)
{
Name = name;
+ Arguments = args;
loc = l;
- is_base = true;
}
public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
public override Expression DoResolve (EmitContext ec)
{
- return SimpleNameResolve (ec, null, false);
+ return SimpleNameResolve (ec, null, false, false);
}
public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
- return SimpleNameResolve (ec, right_side, false);
+ return SimpleNameResolve (ec, right_side, false, false);
}
- public Expression DoResolveAllowStatic (EmitContext ec)
+ public Expression DoResolveAllowStatic (EmitContext ec, bool intermediate)
{
- return SimpleNameResolve (ec, null, true);
+ return SimpleNameResolve (ec, null, true, intermediate);
}
- public override Expression ResolveAsTypeStep (EmitContext ec)
+ public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
{
DeclSpace ds = ec.DeclSpace;
- NamespaceEntry ns = ds.NamespaceEntry;
- TypeExpr t;
- IAlias alias_value;
+ FullNamedExpression dt;
- //
- // 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;
+ dt = ds.LookupGeneric (Name, loc);
+ if (dt != null)
+ return dt.ResolveAsTypeStep (ec);
- TypeParameterExpr generic_type = ds.LookupGeneric (Name, loc);
- if (generic_type != null)
- return generic_type.ResolveAsTypeTerminal (ec);
+ int errors = Report.Errors;
+ dt = ec.ResolvingTypeTree
+ ? ds.FindType (loc, Name)
+ : ds.LookupType (Name, loc, /*silent=*/ true, /*ignore_cs0104=*/ false);
+ if (Report.Errors != errors)
+ return null;
- if (ec.ResolvingTypeTree){
- int errors = Report.Errors;
- Type dt = ds.FindType (loc, Name);
-
- if (Report.Errors != errors)
+ return dt;
+ }
+
+ Expression SimpleNameResolve (EmitContext ec, Expression right_side,
+ bool allow_static, bool intermediate)
+ {
+ Expression e = DoSimpleNameResolve (ec, right_side, allow_static, intermediate);
+ if (e == null)
+ return null;
+
+ Block current_block = ec.CurrentBlock;
+ if (current_block != null){
+ if (current_block.IsVariableNameUsedInChildBlock (Name)) {
+ Report.Error (135, Location,
+ "'{0}' has a different meaning in a child block", Name);
return null;
-
- if (dt != null)
- return new TypeExpression (dt, loc);
-
- if (alias_value != null){
- if (alias_value.IsType)
- return alias_value.Type;
- if ((t = RootContext.LookupType (ds, alias_value.Name, true, loc)) != null)
- return t;
}
}
- //
- // First, the using aliases
- //
- if (alias_value != null){
- if (alias_value.IsType)
- return alias_value.Type;
- if ((t = RootContext.LookupType (ds, alias_value.Name, true, loc)) != null)
- return t;
-
- // we have alias value, but it isn't Type, so try if it's namespace
- return new SimpleName (alias_value.Name, loc);
+ if (e.Type != null && e.Type.IsPointer && !ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
}
- //
- // Stage 2: Lookup up if we are an alias to a type
- // or a namespace.
- //
-
- if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
- return t;
-
- // No match, maybe our parent can compose us
- // into something meaningful.
- return this;
+ return e;
}
/// <remarks>
/// Type is both an instance variable and a Type; Type.GetType
/// is the static method not an instance method of type.
/// </remarks>
- Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
+ Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static, bool intermediate)
{
Expression e = null;
//
Block current_block = ec.CurrentBlock;
if (current_block != null){
- if (is_base && current_block.IsVariableNameUsedInChildBlock(Name)) {
- Report.Error (135, Location, "'" + Name + "' has a different meaning in a child block");
- return null;
- }
-
LocalInfo vi = current_block.GetLocalInfo (Name);
if (vi != null){
Expression var;
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.GetParameterReference (Name, loc);
+ if (pref != null) {
if (right_side != null)
- return param.ResolveLValue (ec, right_side);
+ return pref.ResolveLValue (ec, right_side);
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){
- IAlias alias_value = ns.LookupAlias (Name);
- if (alias_value != null){
- if (alias_value.IsType)
- return alias_value.Type;
-
- Name = alias_value.Name;
- 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, loc);
+ return null;
}
if (e is TypeExpr)
if (me == null)
return e;
+ if (Arguments != null) {
+ MethodGroupExpr mg = me as MethodGroupExpr;
+ if (mg == null)
+ return null;
+
+ return mg.ResolveGeneric (ec, Arguments);
+ }
+
// 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.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
- !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType)) {
+ TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
+ me.InstanceExpression.Type != me.DeclaringType &&
+ !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
+ (!intermediate || !MemberAccess.IdenticalNameAndTypeName (ec, this, e, loc))) {
Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
"outer type `" + me.DeclaringType + "' via nested type `" +
me.InstanceExpression.Type + "'");
return null;
}
- if (right_side != null)
- e = e.DoResolveLValue (ec, right_side);
- else
- e = e.DoResolve (ec);
-
- return e;
+ return (right_side != null)
+ ? e.DoResolveLValue (ec, right_side)
+ : e.DoResolve (ec);
}
if (ec.IsStatic || ec.IsFieldInitializer){
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, IAlias {
- override public Expression ResolveAsTypeStep (EmitContext ec)
+ public abstract class TypeExpr : FullNamedExpression {
+ override public FullNamedExpression ResolveAsTypeStep (EmitContext ec)
{
TypeExpr t = DoResolveAsTypeStep (ec);
if (t == null)
}
}
- public virtual TypeExpr[] GetInterfaces ()
- {
- return TypeManager.GetInterfaces (Type);
- }
-
- public abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
+ protected abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
public virtual Type ResolveType (EmitContext ec)
{
{
return Name;
}
-
- bool IAlias.IsType {
- get { return true; }
- }
-
- TypeExpr IAlias.Type {
- get {
- return this;
- }
- }
}
- public class TypeExpression : TypeExpr, IAlias {
+ public class TypeExpression : TypeExpr {
public TypeExpression (Type t, Location l)
{
Type = t;
loc = l;
}
- public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
{
return this;
}
}
}
- string IAlias.Name {
+ public override string FullName {
get {
return Type.FullName != null ? Type.FullName : Type.Name;
}
this.name = name;
}
- public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
{
if (type == null) {
- TypeExpr texpr = RootContext.LookupType (
- ec.DeclSpace, name, false, Location.Null);
- if (texpr == null)
+ FullNamedExpression t = ec.DeclSpace.LookupType (
+ name, Location.Null, /*silent=*/ false, /*ignore_cs0104=*/ false);
+ if (t == null)
return null;
-
- type = texpr.ResolveType (ec);
- if (type == null)
+ if (!(t is TypeExpr))
return null;
+ type = ((TypeExpr) t).ResolveType (ec);
}
return this;
return name;
}
}
+
+ public override string FullName {
+ get {
+ return name;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Represents an "unbound generic type", ie. typeof (Foo<>).
+ /// See 14.5.11.
+ /// </summary>
+ public class UnboundTypeExpression : TypeLookupExpression {
+ public UnboundTypeExpression (string name)
+ : base (name)
+ { }
}
- public class TypeAliasExpression : TypeExpr, IAlias {
+ public class TypeAliasExpression : TypeExpr {
+ FullNamedExpression alias;
TypeExpr texpr;
TypeArguments args;
string name;
- public TypeAliasExpression (TypeExpr texpr, TypeArguments args, Location l)
+ public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
{
- this.texpr = texpr;
+ this.alias = alias;
this.args = args;
- loc = texpr.Location;
+ loc = l;
eclass = ExprClass.Type;
if (args != null)
- name = texpr.Name + "<" + args.ToString () + ">";
+ name = alias.FullName + "<" + args.ToString () + ">";
else
- name = texpr.Name;
+ name = alias.FullName;
}
public override string Name {
+ get { return alias.FullName; }
+ }
+
+ public override string FullName {
get { return name; }
}
- public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
{
- Type type = texpr.ResolveType (ec);
- if (type == null)
+ texpr = alias.ResolveAsTypeTerminal (ec);
+ if (texpr == null)
return null;
+ Type type = texpr.Type;
int num_args = TypeManager.GetNumberOfTypeArguments (type);
if (args != null) {
return new TypeExpression (type, loc);
}
- public override Type ResolveType (EmitContext ec)
- {
- TypeExpr t = ResolveAsTypeTerminal (ec);
- if (t == null)
- return null;
-
- type = t.ResolveType (ec);
- return type;
- }
-
public override bool CheckAccessLevel (DeclSpace ds)
{
return texpr.CheckAccessLevel (ds);
Expression instance_expression = null;
bool is_explicit_impl = false;
bool has_type_arguments = false;
+ bool identical_type_name = false;
+ bool is_base;
public MethodGroupExpr (MemberInfo [] mi, Location l)
{
}
}
+ public bool IdenticalTypeName {
+ get {
+ return identical_type_name;
+ }
+
+ set {
+ identical_type_name = value;
+ }
+ }
+
+ public bool IsBase {
+ get {
+ return is_base;
+ }
+ set {
+ is_base = value;
+ }
+ }
+
public string Name {
get {
- return TypeManager.CSharpSignature (
- Methods [Methods.Length - 1]);
+ //return Methods [0].Name;
+ return Methods [Methods.Length - 1].Name;
}
}
{
return RemoveMethods (false);
}
+
+ public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
+ {
+ if (args.Resolve (ec) == false)
+ return null;
+
+ Type[] atypes = args.Arguments;
+
+ int first_count = 0;
+ MethodInfo first = null;
+
+ ArrayList list = new ArrayList ();
+ foreach (MethodBase mb in Methods) {
+ MethodInfo mi = mb as MethodInfo;
+ if ((mi == null) || !mi.HasGenericParameters)
+ continue;
+
+ Type[] gen_params = mi.GetGenericArguments ();
+
+ if (first == null) {
+ first = mi;
+ first_count = gen_params.Length;
+ }
+
+ if (gen_params.Length != atypes.Length)
+ continue;
+
+ list.Add (mi.BindGenericParameters (atypes));
+ }
+
+ if (list.Count > 0) {
+ MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
+ new_mg.InstanceExpression = InstanceExpression;
+ new_mg.HasTypeArguments = true;
+ return new_mg;
+ }
+
+ if (first != null)
+ Report.Error (
+ 305, loc, "Using the generic method `{0}' " +
+ "requires {1} type arguments", Name,
+ first_count);
+ else
+ Report.Error (
+ 308, loc, "The non-generic method `{0}' " +
+ "cannot be used with type arguments", Name);
+
+ return null;
+ }
}
/// <summary>
Expression instance_expr;
VariableInfo variable_info;
+ LocalTemporary temp;
+ bool prepared;
+ bool is_field_initializer;
+
public FieldExpr (FieldInfo fi, Location l)
{
FieldInfo = fi;
}
}
+ public bool IsFieldInitializer {
+ get {
+ return is_field_initializer;
+ }
+
+ set {
+ is_field_initializer = value;
+ }
+ }
+
public VariableInfo VariableInfo {
get {
return variable_info;
return null;
}
+ 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);
+ }
+
+ 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;
if ((var == null) || (var.VariableInfo == null))
Report_AssignToReadonly (false);
Type ctype;
- if (ec.TypeContainer.CurrentType != null)
- ctype = ec.TypeContainer.CurrentType.ResolveType (ec);
+ if (!is_field_initializer &&
+ (ec.TypeContainer.CurrentType != null))
+ ctype = ec.TypeContainer.CurrentType;
else
ctype = ec.ContainerType;
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;
return true;
}
-
- override public void Emit (EmitContext ec)
+
+ public void Emit (EmitContext ec, bool leave_copy)
{
ILGenerator ig = ec.ig;
bool is_volatile = false;
ig.Emit (OpCodes.Volatile);
ig.Emit (OpCodes.Ldsfld, FieldInfo);
- return;
- }
-
- if (instance_expr.Type.IsValueType){
- IMemoryLocation ml;
- LocalTemporary tempo = null;
-
- if (!(instance_expr is IMemoryLocation)){
- tempo = new LocalTemporary (ec, instance_expr.Type);
-
- InstanceExpression.Emit (ec);
- tempo.Store (ec);
- ml = tempo;
- } else
- ml = (IMemoryLocation) instance_expr;
-
- ml.AddressOf (ec, AddressOp.Load);
} else {
- instance_expr.Emit (ec);
+ if (!prepared)
+ EmitInstance (ec);
+
+ if (is_volatile)
+ ig.Emit (OpCodes.Volatile);
+
+ 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) {
+ temp = new LocalTemporary (ec, this.Type);
+ temp.Store (ec);
+ }
}
- if (is_volatile)
- ig.Emit (OpCodes.Volatile);
-
- ig.Emit (OpCodes.Ldfld, FieldInfo);
}
- public void EmitAssign (EmitContext ec, Expression source)
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
{
FieldAttributes fa = FieldInfo.Attributes;
bool is_static = (fa & FieldAttributes.Static) != 0;
bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
ILGenerator ig = ec.ig;
+ prepared = prepare_for_load;
if (is_readonly && !ec.IsConstructor){
Report_AssignToReadonly (!is_static);
return;
}
- if (!is_static){
- Expression instance = instance_expr;
-
- if (instance.Type.IsValueType){
- IMemoryLocation ml = (IMemoryLocation) instance;
-
- ml.AddressOf (ec, AddressOp.Store);
- } else {
- instance.Emit (ec);
- }
+ if (!is_static) {
+ EmitInstance (ec);
+ if (prepare_for_load)
+ ig.Emit (OpCodes.Dup);
}
source.Emit (ec);
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!FieldInfo.IsStatic) {
+ temp = new LocalTemporary (ec, this.Type);
+ temp.Store (ec);
+ }
+ }
if (FieldInfo is FieldBuilder){
FieldBase f = TypeManager.GetField (FieldInfo);
ig.Emit (OpCodes.Stsfld, FieldInfo);
else
ig.Emit (OpCodes.Stfld, FieldInfo);
+
+ if (temp != null)
+ temp.Emit (ec);
}
-
+
+ void EmitInstance (EmitContext ec)
+ {
+ if (instance_expr.Type.IsValueType) {
+ if (instance_expr is IMemoryLocation) {
+ ((IMemoryLocation) instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ } else {
+ LocalTemporary t = new LocalTemporary (ec, instance_expr.Type);
+ instance_expr.Emit (ec);
+ t.Store (ec);
+ t.AddressOf (ec, AddressOp.Store);
+ }
+ } else
+ instance_expr.Emit (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
public void AddressOf (EmitContext ec, AddressOp mode)
{
ILGenerator ig = ec.ig;
if (FieldInfo.IsStatic){
ig.Emit (OpCodes.Ldsflda, FieldInfo);
} else {
- //
- // In the case of `This', we call the AddressOf method, which will
- // only load the pointer, and not perform an Ldobj immediately after
- // the value has been loaded into the stack.
- //
- if (instance_expr is This)
- ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore);
- else if (instance_expr.Type.IsValueType && instance_expr is IMemoryLocation){
- IMemoryLocation ml = (IMemoryLocation) instance_expr;
-
- ml.AddressOf (ec, AddressOp.LoadStore);
- } else
- instance_expr.Emit (ec);
+ EmitInstance (ec);
ig.Emit (OpCodes.Ldflda, FieldInfo);
}
}
public bool IsBase;
MethodInfo getter, setter;
bool is_static;
- bool must_do_cs1540_check;
Expression instance_expr;
+ LocalTemporary temp;
+ bool prepared;
+
+ internal static PtrHashtable AccessorTable = new PtrHashtable ();
public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
{
return true;
}
- MethodInfo GetAccessor (Type invocation_type, string accessor_name)
+ void FindAccessors (Type invocation_type)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
- BindingFlags.Static | BindingFlags.Instance;
- MemberInfo[] group;
-
- group = TypeManager.MemberLookup (
- invocation_type, invocation_type, PropertyInfo.DeclaringType,
- MemberTypes.Method, flags, accessor_name + "_" + PropertyInfo.Name);
+ BindingFlags.Static | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly;
- //
- // The first method is the closest to us
- //
- if (group == null)
- return null;
+ Type current = PropertyInfo.DeclaringType;
+ for (; current != null; current = current.BaseType) {
+ MemberInfo[] group = TypeManager.MemberLookup (
+ invocation_type, invocation_type, current,
+ MemberTypes.Property, flags, PropertyInfo.Name, null);
- foreach (MethodInfo mi in group) {
- MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
+ if (group == null)
+ continue;
- //
- // 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
- continue;
- } 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)
- continue;
- else
- return mi;
- }
+ if (group.Length != 1)
+ // Oooops, can this ever happen ?
+ return;
- // 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;
- }
+ PropertyInfo pi = (PropertyInfo) group [0];
- // We already know that we aren't in the same assembly.
- if (ma == MethodAttributes.Assembly)
- continue;
+ if (getter == null)
+ getter = pi.GetGetMethod (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))
- continue;
- else {
- if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
- must_do_cs1540_check = true;
+ if (setter == null)
+ setter = pi.GetSetMethod (true);
- return mi;
- }
- }
+ MethodInfo accessor = getter != null ? getter : setter;
- return mi;
+ if (!accessor.IsVirtual)
+ return;
}
-
- return null;
}
//
//
void ResolveAccessors (EmitContext ec)
{
- getter = GetAccessor (ec.ContainerType, "get");
- if ((getter != null) && getter.IsStatic)
- is_static = true;
+ FindAccessors (ec.ContainerType);
- setter = GetAccessor (ec.ContainerType, "set");
- if ((setter != null) && setter.IsStatic)
- is_static = true;
+ if (getter != null) {
+ AccessorTable [getter] = PropertyInfo;
+ is_static = getter.IsStatic;
+ }
- if (setter == null && getter == null){
- Error (122, "`" + PropertyInfo.Name + "' " +
- "is inaccessible because of its protection level");
-
+ if (setter != null) {
+ 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) {
SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
instance_expr = instance_expr.DoResolve (ec);
if (instance_expr == null)
return false;
+
+ instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
}
if (must_do_cs1540_check && (instance_expr != null)) {
return null;
}
- if (!InstanceResolve (ec))
+ bool must_do_cs1540_check;
+ if (!IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
+ Report.Error (122, loc, "'{0}.get' is inaccessible due to its protection level", PropertyInfo.Name);
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
return null;
//
return null;
}
- if (!InstanceResolve (ec))
+ bool must_do_cs1540_check;
+ if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
+ Report.Error (122, loc, "'{0}.set' is inaccessible due to its protection level", PropertyInfo.Name);
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
return null;
//
PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
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)) {
+ // FIXME: Provide better error reporting.
+ Error (1612, "Cannot modify expression because it is not a variable.");
+ return null;
+ }
+
return this;
}
- override public void Emit (EmitContext ec)
+
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ void EmitInstance (EmitContext ec)
{
+ if (is_static)
+ return;
+
+ if (instance_expr.Type.IsValueType) {
+ if (instance_expr is IMemoryLocation) {
+ ((IMemoryLocation) instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ } else {
+ LocalTemporary t = new LocalTemporary (ec, instance_expr.Type);
+ instance_expr.Emit (ec);
+ t.Store (ec);
+ t.AddressOf (ec, AddressOp.Store);
+ }
+ } else
+ instance_expr.Emit (ec);
+
+ if (prepared)
+ ec.ig.Emit (OpCodes.Dup);
+ }
+
+
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ if (!prepared)
+ EmitInstance (ec);
+
//
// Special case: length of single dimension array property is turned into ldlen
//
// System.Array.Length can be called, but the Type does not
// support invoking GetArrayRank, so test for that case first
//
- if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
- instance_expr.Emit (ec);
+ if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
ec.ig.Emit (OpCodes.Ldlen);
ec.ig.Emit (OpCodes.Conv_I4);
return;
}
}
- Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, loc);
+ Invocation.EmitCall (ec, IsBase, IsStatic, new EmptyAddressOf (), getter, null, loc);
+
+ if (!leave_copy)
+ return;
+ ec.ig.Emit (OpCodes.Dup);
+ if (!is_static) {
+ temp = new LocalTemporary (ec, this.Type);
+ temp.Store (ec);
+ }
}
//
// Implements the IAssignMethod interface for assignments
//
- public void EmitAssign (EmitContext ec, Expression source)
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
{
- Argument arg = new Argument (source, Argument.AType.Expression);
- ArrayList args = new ArrayList ();
+ prepared = prepare_for_load;
+
+ EmitInstance (ec);
- args.Add (arg);
- Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, loc);
+ source.Emit (ec);
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!is_static) {
+ temp = new LocalTemporary (ec, this.Type);
+ temp.Store (ec);
+ }
+ }
+
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (new EmptyAddressOf (), Argument.AType.Expression));
+
+ Invocation.EmitCall (ec, IsBase, IsStatic, new EmptyAddressOf (), setter, args, loc);
+
+ if (temp != null)
+ temp.Emit (ec);
}
override public void EmitStatement (EmitContext ec)
/// </summary>
public class EventExpr : Expression, IMemberExpr {
public readonly EventInfo EventInfo;
- public Expression instance_expr;
+ Expression instance_expr;
bool is_static;
MethodInfo add_accessor, remove_accessor;
}
}
+ bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
+ {
+ if ((instance_expr == null) && ec.IsStatic && !is_static) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
+ return false;
+ }
+
+ if (instance_expr != null) {
+ instance_expr = instance_expr.DoResolve (ec);
+ if (instance_expr == 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 && (instance_expr != null)) {
+ if ((instance_expr.Type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (instance_expr.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) {
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 (instance_expr 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)