diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index fcf0eaa289e94a0057e283495093926bc7ce3eff..e18ba6cae9decfdeea69653ea58e6a5d3988f14a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -6041,9 +6041,13 @@ private BoundExpression BindIndexedPropertyAccess(CSharpSyntaxNode syntax, Bound if (analyzedArguments.HasDynamicArgument && overloadResolutionResult.HasAnyApplicableMember) { - var result = BindDynamicIndexer(syntax, receiverOpt, analyzedArguments, overloadResolutionResult.GetAllApplicableMembers(), diagnostics); + // Note that the runtime binder may consider candidates that haven't passed compile-time final validation + // and an ambiguity error may be reported. Also additional checks are performed in runtime final validation + // that are not performed at compile-time. + // Only if the set of final applicable candidates is empty we know for sure the call will fail at runtime. + var finalApplicableCandidates = GetCandidatesPassingFinalValidation(syntax, overloadResolutionResult, receiverOpt, default(ImmutableArray), diagnostics); overloadResolutionResult.Free(); - return result; + return BindDynamicIndexer(syntax, receiverOpt, analyzedArguments, finalApplicableCandidates, diagnostics); } if (!overloadResolutionResult.Succeeded) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index c7f1efde932dbd712726e39dfcb74994c26b6654..17816772c11d548547b3627ac1b61cfaad5e8512 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -542,7 +542,10 @@ private static bool HasApplicableConditionalMethod(OverloadResolutionResult 0) { result = BindDynamicInvocation(syntax, methodGroup, resolution.AnalyzedArguments, finalApplicableCandidates, diagnostics, queryClause); @@ -569,11 +572,16 @@ private static bool HasApplicableConditionalMethod(OverloadResolutionResult GetCandidatesPassingFinalValidation(CSharpSyntaxNode syntax, OverloadResolutionResult overloadResolutionResult, BoundMethodGroup methodGroup, DiagnosticBag diagnostics) + private ImmutableArray GetCandidatesPassingFinalValidation( + CSharpSyntaxNode syntax, + OverloadResolutionResult overloadResolutionResult, + BoundExpression receiverOpt, + ImmutableArray typeArgumentsOpt, + DiagnosticBag diagnostics) where TMethodOrPropertySymbol : Symbol { Debug.Assert(overloadResolutionResult.HasAnyApplicableMember); - var finalCandidates = ArrayBuilder.GetInstance(); + var finalCandidates = ArrayBuilder.GetInstance(); DiagnosticBag firstFailed = null; DiagnosticBag candidateDiagnostics = DiagnosticBag.GetInstance(); @@ -590,8 +598,8 @@ private ImmutableArray GetCandidatesPassingFinalValidation(CSharpS // * If F is an instance method, the method group must have resulted from a simple-name, a member-access through a variable or value, // or a member-access whose receiver can't be classified as a type or value until after overload resolution (see ยง7.6.4.1). - if (!MemberGroupFinalValidationAccessibilityChecks(methodGroup.ReceiverOpt, result.Member, syntax, candidateDiagnostics, invokedAsExtensionMethod: false) && - (methodGroup.TypeArgumentsOpt.IsDefault || result.Member.CheckConstraints(this.Conversions, syntax, this.Compilation, candidateDiagnostics))) + if (!MemberGroupFinalValidationAccessibilityChecks(receiverOpt, result.Member, syntax, candidateDiagnostics, invokedAsExtensionMethod: false) && + (typeArgumentsOpt.IsDefault || ((MethodSymbol)(object)result.Member).CheckConstraints(this.Conversions, syntax, this.Compilation, candidateDiagnostics))) { finalCandidates.Add(result.Member); continue; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index 53d3104e5875f31f710c7b45812e8291d7967351..1f6b116f7313c78340e1e268c632977488f31f1e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -3550,5 +3550,260 @@ .maxstack 8 Assert.Equal(typeGConstructed, typeD.GetMember("ExtraTrue").Type); Assert.Equal(typeGConstructed, typeD.GetMember("ExtraFalse").Type); } + + [ClrOnlyFact(ClrOnlyReason.Ilasm)] + [WorkItem(204561, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=204561&_a=edit")] + public void SuppressDynamicIndexerAccessOffOfType_01() + { + var iLSource = @" +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} + +.assembly Microsoft.Office.Interop.Excel +{ + .custom instance void [mscorlib]System.Runtime.InteropServices.ImportedFromTypeLibAttribute::.ctor(string) = ( 01 00 05 45 78 63 65 6C 00 00 ) // ...Excel.. + .custom instance void [mscorlib]System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute::.ctor(int32, + int32) = ( 01 00 01 00 00 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 30 30 32 30 38 31 33 2D 30 30 30 30 // ..$00020813-0000 + 2D 30 30 30 30 2D 63 30 30 30 2D 30 30 30 30 30 // -0000-c000-00000 + 30 30 30 30 30 34 36 00 00 ) // 0000046.. + .custom instance void [mscorlib]System.Runtime.InteropServices.TypeLibVersionAttribute::.ctor(int32, + int32) = ( 01 00 01 00 00 00 08 00 00 00 00 00 ) + .hash algorithm 0x00008004 + .ver 15:0:0:0 +} +.module Excel.dll +// MVID: {C7C599B3-5C80-48BC-9637-7CADFEF6DEB8} +.imagebase 0x00400000 +.file alignment 0x00001000 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000009 // ILONLY +// Image base: 0x050E0000 + +.class interface public abstract auto ansi import Microsoft.Office.Interop.Excel.Worksheet + implements Microsoft.Office.Interop.Excel._Worksheet +{ + .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 30 30 32 30 38 44 38 2D 30 30 30 30 // ..$000208D8-0000 + 2D 30 30 30 30 2D 43 30 30 30 2D 30 30 30 30 30 // -0000-C000-00000 + 30 30 30 30 30 34 36 00 00 ) // 0000046.. +} // end of class Microsoft.Office.Interop.Excel.Worksheet + +.class interface public abstract auto ansi import Microsoft.Office.Interop.Excel._Worksheet +{ + .custom instance void [mscorlib]System.Runtime.InteropServices.TypeLibTypeAttribute::.ctor(int16) = ( 01 00 C0 10 00 00 ) + .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 30 30 32 30 38 44 38 2D 30 30 30 30 // ..$000208D8-0000 + 2D 30 30 30 30 2D 43 30 30 30 2D 30 30 30 30 30 // -0000-C000-00000 + 30 30 30 30 30 34 36 00 00 ) // 0000046.. + + .method public hidebysig newslot specialname abstract virtual + instance class Microsoft.Office.Interop.Excel.Range + marshal( interface ) + get_Range([in] object marshal( struct) Cell1, + [in][opt] object marshal( struct) Cell2) runtime managed internalcall + { + .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 C5 00 00 00 00 00 ) + } // end of method _Worksheet::get_Range + + .property class Microsoft.Office.Interop.Excel.Range + Range(object, + object) + { + .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 C5 00 00 00 00 00 ) + .get instance class Microsoft.Office.Interop.Excel.Range Microsoft.Office.Interop.Excel._Worksheet::get_Range(object, + object) + } // end of property _Worksheet::Range + + .method public hidebysig newslot specialname abstract virtual + instance class Microsoft.Office.Interop.Excel.Range + marshal( interface ) + MRange([in] object marshal( struct) Cell1, + [in][opt] object marshal( struct) Cell2) runtime managed internalcall + { + .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 C5 00 00 00 00 00 ) + } // end of method _Worksheet::get_Range +} + +.class interface public abstract auto ansi import Microsoft.Office.Interop.Excel.Range + implements [mscorlib]System.Collections.IEnumerable +{ + .custom instance void [mscorlib]System.Runtime.InteropServices.InterfaceTypeAttribute::.ctor(int16) = ( 01 00 02 00 00 00 ) + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 08 5F 44 65 66 61 75 6C 74 00 00 ) // ..._Default.. + .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 30 30 32 30 38 34 36 2D 30 30 30 30 // ..$00020846-0000 + 2D 30 30 30 30 2D 43 30 30 30 2D 30 30 30 30 30 // -0000-C000-00000 + 30 30 30 30 30 34 36 00 00 ) // 0000046.. + .custom instance void [mscorlib]System.Runtime.InteropServices.TypeLibTypeAttribute::.ctor(int16) = ( 01 00 00 10 00 00 ) +} +"; + + MetadataReference reference = CompileIL(iLSource, appendDefaultHeader: false, embedInteropTypes: false); + + string consumer1 = @" +using Microsoft.Office.Interop.Excel; + +class Test +{ + public static void Main() + { + dynamic x = 1; + dynamic y = 1; + + var z2 = Worksheet.MRange(x, y); + } +} +"; + + var compilation1 = CreateCompilationWithMscorlib(consumer1, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { reference, CSharpRef, SystemCoreRef }); + + compilation1.VerifyDiagnostics( + // (11,18): error CS0120: An object reference is required for the non-static field, method, or property '_Worksheet.MRange(object, object)' + // var z2 = Worksheet.MRange(x, y); + Diagnostic(ErrorCode.ERR_ObjectRequired, "Worksheet.MRange(x, y)").WithArguments("Microsoft.Office.Interop.Excel._Worksheet.MRange(object, object)").WithLocation(11, 18) + ); + + string consumer2 = @" +using Microsoft.Office.Interop.Excel; + +class Test +{ + public static void Main() + { + dynamic x = 1; + dynamic y = 1; + var z1 = Worksheet.Range[x, y]; + } +} +"; + + var compilation2 = CreateCompilationWithMscorlib(consumer2, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { reference, CSharpRef, SystemCoreRef }); + + compilation2.VerifyDiagnostics( + // (10,18): error CS0120: An object reference is required for the non-static field, method, or property '_Worksheet.Range[object, object]' + // var z1 = Worksheet.Range[x, y]; + Diagnostic(ErrorCode.ERR_ObjectRequired, "Worksheet.Range[x, y]").WithArguments("Microsoft.Office.Interop.Excel._Worksheet.Range[object, object]").WithLocation(10, 18) + ); + } + + [ClrOnlyFact(ClrOnlyReason.Ilasm)] + [WorkItem(204561, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=204561&_a=edit")] + public void SuppressDynamicIndexerAccessOffOfType_02() + { + var iLSource = @" +.class public auto ansi WithIndexer + extends [mscorlib]System.Object +{ + .method public specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method WithIndexer::.ctor + + .method public specialname static object + get_Indexer(object x, + object y) cil managed + { + // Code size 18 (0x12) + .maxstack 1 + .locals init (object V_0) + IL_0000: nop + IL_0001: ldstr ""Indexer"" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldnull + IL_000d: stloc.0 + IL_000e: br.s IL_0010 + + IL_0010: ldloc.0 + IL_0011: ret + } // end of method WithIndexer::get_Indexer + + .method public specialname static void + set_Indexer(object x, + object y, + object 'value') cil managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } // end of method WithIndexer::set_Indexer + + .method public static object MIndexer(object x, + object y) cil managed + { + // Code size 18 (0x12) + .maxstack 1 + .locals init (object V_0) + IL_0000: nop + IL_0001: ldstr ""MIndexer"" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldnull + IL_000d: stloc.0 + IL_000e: br.s IL_0010 + + IL_0010: ldloc.0 + IL_0011: ret + } // end of method WithIndexer::MIndexer + + .property object Indexer(object, + object) + { + .get object WithIndexer::get_Indexer(object, + object) + .set void WithIndexer::set_Indexer(object, + object, + object) + } // end of property WithIndexer::Indexer +} // end of class WithIndexer +"; + + MetadataReference reference = CompileIL(iLSource, appendDefaultHeader: true, embedInteropTypes: false); + + string consumer1 = @" +class Test +{ + public static void Main() + { + dynamic x = 1; + dynamic y = 1; + var z2 = WithIndexer.MIndexer(x, y); + } +}"; + + var compilation1 = CreateCompilationWithMscorlib(consumer1, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { reference, CSharpRef, SystemCoreRef }); + + CompileAndVerify(compilation1, expectedOutput: "MIndexer").VerifyDiagnostics(); + + string consumer2 = @" +class Test +{ + public static void Main() + { + dynamic x = 1; + dynamic y = 1; + var z1 = WithIndexer.Indexer[x, y]; + } +}"; + + var compilation2 = CreateCompilationWithMscorlib(consumer2, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { reference, CSharpRef, SystemCoreRef }); + + compilation2.VerifyDiagnostics( + // (8,30): error CS1545: Property, indexer, or event 'WithIndexer.Indexer[object, object]' is not supported by the language; try directly calling accessor methods 'WithIndexer.get_Indexer(object, object)' or 'WithIndexer.set_Indexer(object, object, object)' + // var z1 = WithIndexer.Indexer[x, y]; + Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Indexer").WithArguments("WithIndexer.Indexer[object, object]", "WithIndexer.get_Indexer(object, object)", "WithIndexer.set_Indexer(object, object, object)").WithLocation(8, 30) + ); + } } }