Reject inaccessible members based on declaring type in dynamic context
authorMarek Safar <marek.safar@gmail.com>
Thu, 4 Nov 2010 10:41:28 +0000 (10:41 +0000)
committerMarek Safar <marek.safar@gmail.com>
Thu, 4 Nov 2010 14:57:45 +0000 (14:57 +0000)
mcs/mcs/ecore.cs
mcs/tests/dtest-error-02.cs [new file with mode: 0644]

index 25b11ab66a3fb166153c8938aa6dcb9be53911ff..506768e797b6ced1eb257de19db5a3d8713817f8 100644 (file)
@@ -604,8 +604,27 @@ namespace Mono.CSharp {
                                        if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
                                                continue;
 
-                                       if (rc != null && !member.IsAccessible (currentType))
-                                               continue;
+                                       if (rc != null) {
+                                               if (!member.IsAccessible (currentType))
+                                                       continue;
+
+                                               //
+                                               // With runtime binder we can have a situation where queried type is inaccessible
+                                               // because it came via dynamic object, the check about inconsisted accessibility
+                                               // had no effect as the type was unknown during compilation
+                                               //
+                                               // class A {
+                                               //              private class N { }
+                                               //
+                                               //              public dynamic Foo ()
+                                               //              {
+                                               //                      return new N ();
+                                               //              }
+                                               //      }
+                                               //
+                                               if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (currentType))
+                                                       continue;
+                                       }
 
                                        if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
                                                if (member is MethodSpec)
@@ -4090,8 +4109,13 @@ namespace Mono.CSharp {
                                                        if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
                                                                continue;
 
-                                                       if (!member.IsAccessible (current_type) && !error_mode)
-                                                               continue;
+                                                       if (!error_mode) {
+                                                               if (!member.IsAccessible (current_type))
+                                                                       continue;
+
+                                                               if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
+                                                                       continue;
+                                                       }
 
                                                        IParametersMember pm = member as IParametersMember;
                                                        if (pm == null) {
@@ -4357,7 +4381,7 @@ namespace Mono.CSharp {
                                int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
                                if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
                                        // Reject any inaccessible member
-                                       if (!best_candidate.IsAccessible (rc.CurrentType)) {
+                                       if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
                                                rc.Report.SymbolRelatedToPreviousError (best_candidate);
                                                Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
                                                return;
diff --git a/mcs/tests/dtest-error-02.cs b/mcs/tests/dtest-error-02.cs
new file mode 100644 (file)
index 0000000..b8b4eb0
--- /dev/null
@@ -0,0 +1,35 @@
+using System;
+using Microsoft.CSharp.RuntimeBinder;
+
+class A
+{
+       private class N
+       {
+               public void Foo ()
+               {
+               }
+       }
+       
+       public static dynamic Factory ()
+       {
+               return new N ();
+       }
+}
+
+public class Test
+{
+       public static int Main ()
+       {
+               dynamic d = A.Factory ();
+               
+               try {
+                       d.Foo ();
+                       return 1;
+               } catch (RuntimeBinderException e) {
+                       if (e.Message != "`A.N.Foo()' is inaccessible due to its protection level")
+                               return 2;
+               }
+               
+               return 0;
+       }
+}