/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs

http://github.com/icsharpcode/ILSpy · C# · 739 lines · 639 code · 55 blank · 45 comment · 0 complexity · 42f953389141299f3b84bf7a08de39f4 MD5 · raw file

  1. // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Linq;
  20. using ICSharpCode.NRefactory.Semantics;
  21. using ICSharpCode.NRefactory.TypeSystem;
  22. using ICSharpCode.NRefactory.TypeSystem.Implementation;
  23. using NUnit.Framework;
  24. namespace ICSharpCode.NRefactory.CSharp.Resolver
  25. {
  26. [TestFixture]
  27. public class InvocationTests : ResolverTestBase
  28. {
  29. [Test]
  30. public void MethodCallTest()
  31. {
  32. string program = @"class A {
  33. void Method() {
  34. $TargetMethod()$;
  35. }
  36. int TargetMethod() {
  37. return 3;
  38. }
  39. }
  40. ";
  41. InvocationResolveResult result = Resolve<CSharpInvocationResolveResult>(program);
  42. Assert.AreEqual("A.TargetMethod", result.Member.FullName);
  43. Assert.AreEqual("System.Int32", result.Type.ReflectionName);
  44. }
  45. [Test]
  46. public void InvalidMethodCall()
  47. {
  48. string program = @"class A {
  49. void Method(string b) {
  50. $b.ThisMethodDoesNotExistOnString(b)$;
  51. }
  52. }
  53. ";
  54. UnknownMethodResolveResult result = Resolve<UnknownMethodResolveResult>(program);
  55. Assert.AreEqual("ThisMethodDoesNotExistOnString", result.MemberName);
  56. Assert.AreEqual("System.String", result.TargetType.FullName);
  57. Assert.AreEqual(1, result.Parameters.Count);
  58. Assert.AreEqual("b", result.Parameters[0].Name);
  59. Assert.AreEqual("System.String", result.Parameters[0].Type.ReflectionName);
  60. Assert.AreSame(SpecialType.UnknownType, result.Type);
  61. }
  62. [Test]
  63. public void OverriddenMethodCall()
  64. {
  65. string program = @"class A {
  66. void Method() {
  67. $new B().GetRandomNumber()$;
  68. }
  69. public abstract int GetRandomNumber();
  70. }
  71. class B : A {
  72. public override int GetRandomNumber() {
  73. return 4; // chosen by fair dice roll.
  74. // guaranteed to be random
  75. }
  76. }
  77. ";
  78. InvocationResolveResult result = Resolve<CSharpInvocationResolveResult>(program);
  79. Assert.AreEqual("B.GetRandomNumber", result.Member.FullName);
  80. }
  81. [Test]
  82. public void OverriddenMethodCall2()
  83. {
  84. string program = @"class A {
  85. void Method() {
  86. $new B().GetRandomNumber(""x"", this)$;
  87. }
  88. public abstract int GetRandomNumber(string a, A b);
  89. }
  90. class B : A {
  91. public override int GetRandomNumber(string b, A a) {
  92. return 4;
  93. }
  94. }
  95. ";
  96. InvocationResolveResult result = Resolve<CSharpInvocationResolveResult>(program);
  97. Assert.AreEqual("B.GetRandomNumber", result.Member.FullName);
  98. }
  99. [Test]
  100. public void ThisMethodCallTest()
  101. {
  102. string program = @"class A {
  103. void Method() {
  104. $this.TargetMethod()$;
  105. }
  106. int TargetMethod() {
  107. return 3;
  108. }
  109. }
  110. ";
  111. InvocationResolveResult result = Resolve<CSharpInvocationResolveResult>(program);
  112. Assert.AreEqual("A.TargetMethod", result.Member.FullName);
  113. Assert.AreEqual("System.Int32", result.Type.ReflectionName);
  114. }
  115. [Test]
  116. public void VoidTest()
  117. {
  118. string program = @"using System;
  119. class A {
  120. void TestMethod() {
  121. $TestMethod()$;
  122. }
  123. }
  124. ";
  125. Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName);
  126. }
  127. [Test]
  128. public void EventCallTest()
  129. {
  130. string program = @"using System;
  131. class A {
  132. void Method() {
  133. $TestEvent(this, EventArgs.Empty)$;
  134. }
  135. public event EventHandler TestEvent;
  136. }
  137. ";
  138. Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName);
  139. }
  140. [Test]
  141. public void DelegateCallTest()
  142. {
  143. string program = @"using System; using System.Reflection;
  144. class A {
  145. void Method(ModuleResolveEventHandler eh) {
  146. $eh(this, new ResolveEventArgs())$;
  147. }
  148. }
  149. ";
  150. Assert.AreEqual("System.Reflection.Module", Resolve(program).Type.ReflectionName);
  151. }
  152. [Test]
  153. public void DelegateReturnedFromMethodCallTest()
  154. {
  155. string program = @"using System;
  156. class A {
  157. void Method() {
  158. $GetHandler()(abc)$;
  159. }
  160. abstract Predicate<string> GetHandler();
  161. }
  162. ";
  163. Assert.AreEqual("System.Boolean", Resolve(program).Type.ReflectionName);
  164. }
  165. /* TODO
  166. [Test]
  167. public void MethodGroupResolveTest()
  168. {
  169. string program = @"class A {
  170. void Method() {
  171. }
  172. void TargetMethod(int a) { }
  173. void TargetMethod<T>(T a) { }
  174. }
  175. ";
  176. MethodGroupResolveResult result = Resolve<MethodGroupResolveResult>(program, "TargetMethod", 3);
  177. Assert.AreEqual("TargetMethod", result.Name);
  178. Assert.AreEqual(2, result.Methods.Count);
  179. result = Resolve<MethodGroupResolveResult>(program, "TargetMethod<string>", 3);
  180. Assert.AreEqual("TargetMethod", result.Name);
  181. Assert.AreEqual(1, result.Methods[0].Count);
  182. Assert.AreEqual("System.String", result.GetMethodIfSingleOverload().Parameters[0].ReturnType.FullyQualifiedName);
  183. }
  184. */
  185. [Test]
  186. public void TestOverloadingByRef()
  187. {
  188. string program = @"using System;
  189. class Program {
  190. public static void Main() {
  191. int a = 42;
  192. T(a);
  193. T(ref a);
  194. }
  195. static void T(int x) {}
  196. static void T(ref int y) {}
  197. }";
  198. InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(program.Replace("T(a)", "$T(a)$"));
  199. Assert.IsFalse(mrr.Member.Parameters[0].IsRef);
  200. mrr = Resolve<CSharpInvocationResolveResult>(program.Replace("T(ref a)", "$T(ref a)$"));
  201. Assert.IsTrue(mrr.Member.Parameters[0].IsRef);
  202. }
  203. [Test]
  204. public void AddedOverload()
  205. {
  206. string program = @"class BaseClass {
  207. static void Main(DerivedClass d) {
  208. $d.Test(3)$;
  209. }
  210. public void Test(int a) { }
  211. }
  212. class DerivedClass : BaseClass {
  213. public void Test(object a) { }
  214. }";
  215. InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(program);
  216. Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
  217. }
  218. [Test]
  219. public void AddedOverloadOnInterface()
  220. {
  221. string program = @"
  222. interface IBase { void Method(int a); }
  223. interface IDerived { void Method(object a); }
  224. class Test {
  225. static void Main(IDerived d) {
  226. $d.Method(3)$;
  227. }
  228. }";
  229. InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(program);
  230. Assert.AreEqual("IDerived.Method", mrr.Member.FullName);
  231. }
  232. [Test]
  233. public void AddedNonApplicableOverload()
  234. {
  235. string program = @"class BaseClass {
  236. static void Main(DerivedClass d) {
  237. $d.Test(3)$;
  238. }
  239. public void Test(int a) { }
  240. }
  241. class DerivedClass : BaseClass {
  242. public void Test(string a) { }
  243. }";
  244. InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(program);
  245. Assert.AreEqual("BaseClass.Test", mrr.Member.FullName);
  246. mrr = Resolve<CSharpInvocationResolveResult>(program.Replace("(3)", "(\"3\")"));
  247. Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
  248. }
  249. [Test]
  250. public void OverrideShadowed()
  251. {
  252. string program = @"using System;
  253. class BaseClass {
  254. static void Main() {
  255. $new DerivedClass().Test(3)$;
  256. }
  257. public virtual void Test(int a) { }
  258. }
  259. class MiddleClass : BaseClass {
  260. public void Test(object a) { }
  261. }
  262. class DerivedClass : MiddleClass {
  263. public override void Test(int a) { }
  264. }";
  265. InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(program);
  266. Assert.AreEqual("MiddleClass.Test", mrr.Member.FullName);
  267. }
  268. [Test]
  269. public void SubstituteClassAndMethodTypeParametersAtOnce()
  270. {
  271. string program = @"class C<X> { static void M<T>(X a, T b) { $C<T>.M(b, a)$; } }";
  272. var rr = Resolve<CSharpInvocationResolveResult>(program);
  273. Assert.IsFalse(rr.IsError);
  274. var m = (SpecializedMethod)rr.Member;
  275. Assert.AreEqual("X", m.TypeArguments.Single().Name);
  276. Assert.AreEqual("T", m.Parameters[0].Type.Name);
  277. Assert.AreEqual("X", m.Parameters[1].Type.Name);
  278. }
  279. [Test]
  280. public void MemberHiddenOnOneAccessPath()
  281. {
  282. // If a member is hidden in any access path, it is hidden in all access paths
  283. string program = @"
  284. interface IBase { int F { get; } }
  285. interface ILeft: IBase { new int F { get; } }
  286. interface IRight: IBase { void G(); }
  287. interface IDerived: ILeft, IRight {}
  288. class A {
  289. void Test(IDerived d) { var a = $d.F$; }
  290. }";
  291. var rr = Resolve<MemberResolveResult>(program);
  292. Assert.AreEqual("ILeft.F", rr.Member.FullName);
  293. }
  294. [Test]
  295. public void PropertyClashesWithMethod()
  296. {
  297. string program = @"
  298. interface IList { int Count { get; set; } }
  299. interface ICounter { void Count(int i); }
  300. interface IListCounter: IList, ICounter {}
  301. class A {
  302. void Test(IListCounter x) { var a = $x.Count$; }
  303. }";
  304. var rr = Resolve<MethodGroupResolveResult>(program);
  305. Assert.IsFalse(rr.IsError);
  306. Assert.AreEqual("ICounter.Count", rr.Methods.Single().FullName);
  307. }
  308. [Test]
  309. public void OverloadAmbiguousWithMethodInTwoInterfaces()
  310. {
  311. string program = @"
  312. interface ILeft { void Method(); }
  313. interface IRight { void Method(); }
  314. interface IBoth : ILeft, IRight {}
  315. class A {
  316. void Test(IBoth x) { $x.Method()$; }
  317. }";
  318. var rr = Resolve<CSharpInvocationResolveResult>(program);
  319. Assert.IsTrue(rr.IsError);
  320. Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, rr.OverloadResolutionErrors);
  321. }
  322. [Test]
  323. public void AddedOverloadInOneInterfaceAndBetterOverloadInOtherInterface1()
  324. {
  325. string program = @"
  326. interface IBase { void Method(int x); }
  327. interface ILeft : IBase { void Method(object x); }
  328. interface IRight { void Method(int x); }
  329. interface IBoth : ILeft, IRight {}
  330. class A {
  331. void Test(IBoth x) { $x.Method(1)$; }
  332. }";
  333. // IBase.Method is "hidden" because ILeft.Method is also applicable,
  334. // so IRight.Method is unambiguously the chosen overload.
  335. var rr = Resolve<CSharpInvocationResolveResult>(program);
  336. Assert.IsFalse(rr.IsError);
  337. Assert.AreEqual("IRight.Method", rr.Member.FullName);
  338. }
  339. [Test]
  340. public void AddedOverloadInOneInterfaceAndBetterOverloadInOtherInterface2()
  341. {
  342. // repeat the above test with Left/Right swapped to make sure we aren't order-sensitive
  343. string program = @"
  344. interface IBase { void Method(int x); }
  345. interface ILeft : IBase { void Method(object x); }
  346. interface IRight { void Method(int x); }
  347. interface IBoth : IRight, ILeft {}
  348. class A {
  349. void Test(IBoth x) { $x.Method(1)$; }
  350. }";
  351. var rr = Resolve<CSharpInvocationResolveResult>(program);
  352. Assert.IsFalse(rr.IsError);
  353. Assert.AreEqual("IRight.Method", rr.Member.FullName);
  354. }
  355. [Test]
  356. public void AddedOverloadHidesCommonBaseMethod_Generic1()
  357. {
  358. string program = @"
  359. interface IBase<T> {
  360. void Method(int x);
  361. }
  362. interface ILeft : IBase<int> { void Method(object x); }
  363. interface IRight : IBase<int> { }
  364. interface IBoth : ILeft, IRight {}
  365. class A {
  366. void Test(IBoth x) { $x.Method(1)$; }
  367. }";
  368. var rr = Resolve<CSharpInvocationResolveResult>(program);
  369. Assert.IsFalse(rr.IsError);
  370. Assert.AreEqual("ILeft.Method", rr.Member.FullName);
  371. }
  372. [Test]
  373. public void AddedOverloadHidesCommonBaseMethod_Generic2()
  374. {
  375. string program = @"
  376. interface IBase<T> {
  377. void Method(int x);
  378. }
  379. interface ILeft : IBase<int> { void Method(object x); }
  380. interface IRight : IBase<int> { }
  381. interface IBoth : ILeft, IRight {}
  382. class A {
  383. void Test(IBoth x) { $x.Method(1)$; }
  384. }";
  385. var rr = Resolve<CSharpInvocationResolveResult>(program);
  386. Assert.IsFalse(rr.IsError);
  387. Assert.AreEqual("ILeft.Method", rr.Member.FullName);
  388. }
  389. [Test]
  390. public void AddedOverloadDoesNotHideCommonBaseMethodWithDifferentTypeArgument1()
  391. {
  392. string program = @"
  393. interface IBase<T> {
  394. void Method(int x);
  395. }
  396. interface ILeft : IBase<int> { void Method(object x); }
  397. interface IRight : IBase<long> { }
  398. interface IBoth : IRight, ILeft {}
  399. class A {
  400. void Test(IBoth x) { $x.Method(1)$; }
  401. }";
  402. var rr = Resolve<CSharpInvocationResolveResult>(program);
  403. Assert.IsFalse(rr.IsError);
  404. Assert.AreEqual("IBase`1[[System.Int64]]", rr.Member.DeclaringType.ReflectionName);
  405. }
  406. [Test]
  407. public void AddedOverloadDoesNotHideCommonBaseMethodWithDifferentTypeArgument2()
  408. {
  409. string program = @"
  410. interface IBase<T> {
  411. void Method(int x);
  412. }
  413. interface ILeft : IBase<int> { void Method(object x); }
  414. interface IRight : IBase<long> { }
  415. interface IBoth : IRight, ILeft {}
  416. class A {
  417. void Test(IBoth x) { $x.Method(1)$; }
  418. }";
  419. var rr = Resolve<CSharpInvocationResolveResult>(program);
  420. Assert.IsFalse(rr.IsError);
  421. Assert.AreEqual("IBase`1[[System.Int64]]", rr.Member.DeclaringType.ReflectionName);
  422. }
  423. [Test]
  424. public void AmbiguityBetweenMemberAndMethodIsNotAnError()
  425. {
  426. string program = @"
  427. interface ILeft { void Method(object x); }
  428. interface IRight { Action<object> Method { get; } }
  429. interface IBoth : ILeft, IRight {}
  430. class A {
  431. void Test(IBoth x) { $x.Method(null)$; }
  432. }";
  433. var rr = Resolve<CSharpInvocationResolveResult>(program);
  434. Assert.IsFalse(rr.IsError);
  435. Assert.AreEqual("ILeft.Method", rr.Member.FullName);
  436. }
  437. [Test]
  438. public void AcceptVisitor()
  439. {
  440. string program = @"
  441. interface IVisitor<in T, out S> { }
  442. class Test : IVisitor<object, object> {
  443. void M() {
  444. $Accept(this, null)$;
  445. }
  446. S Accept<T, S>(IVisitor<T, S> v, T input) { }
  447. }";
  448. var rr = Resolve<CSharpInvocationResolveResult>(program);
  449. Assert.IsFalse(rr.IsError);
  450. var typeArguments = ((SpecializedMethod)rr.Member).TypeArguments;
  451. Assert.AreEqual("System.Object", typeArguments[0].ReflectionName);
  452. Assert.AreEqual("System.Object", typeArguments[1].ReflectionName);
  453. }
  454. [Test]
  455. public void FirstParameterToExtensionMethod()
  456. {
  457. string program = @"
  458. public class X {}
  459. public static class Ex {
  460. public static void F(this X x, int y, int z) {}
  461. }
  462. class C {
  463. public void M() {
  464. X a = null;
  465. int b = 0, c = 0;
  466. $a.F(b, c)$;
  467. }
  468. }";
  469. var rr = Resolve<CSharpInvocationResolveResult>(program);
  470. Assert.IsFalse(rr.IsError);
  471. Assert.That(rr.IsExtensionMethodInvocation, Is.True);
  472. Assert.That(rr.Arguments[0], Is.InstanceOf<LocalResolveResult>());
  473. Assert.That(((LocalResolveResult)rr.Arguments[0]).Variable.Name, Is.EqualTo("a"));
  474. Assert.That(rr.Arguments[1], Is.InstanceOf<LocalResolveResult>());
  475. Assert.That(((LocalResolveResult)rr.Arguments[1]).Variable.Name, Is.EqualTo("b"));
  476. Assert.That(rr.Arguments[2], Is.InstanceOf<LocalResolveResult>());
  477. Assert.That(((LocalResolveResult)rr.Arguments[2]).Variable.Name, Is.EqualTo("c"));
  478. Assert.That(rr.TargetResult, Is.InstanceOf<TypeResolveResult>());
  479. }
  480. [Test]
  481. public void BaseInvocation()
  482. {
  483. string program = @"
  484. class B {
  485. public virtual void F(int x, int y) {}
  486. }
  487. class D : B {
  488. public override void F(int x, int y) {}
  489. public void M() {
  490. $base.F(0, 1)$;
  491. }
  492. }";
  493. var rr = Resolve<CSharpInvocationResolveResult>(program);
  494. Assert.IsFalse(rr.IsError);
  495. Assert.IsFalse(rr.IsVirtualCall);
  496. }
  497. [Test]
  498. public void NamedArgument()
  499. {
  500. string program = @"
  501. class Test {
  502. public void F(int x) {}
  503. public void Test() {
  504. F($x: 0$);
  505. }
  506. }";
  507. var narr = Resolve<NamedArgumentResolveResult>(program);
  508. Assert.IsInstanceOf<ConstantResolveResult>(narr.Argument);
  509. Assert.AreEqual("x", narr.ParameterName);
  510. Assert.AreEqual("Test.F", narr.Member.FullName);
  511. Assert.AreSame(narr.Member.Parameters.Single(), narr.Parameter);
  512. }
  513. [Test]
  514. public void NamedArgumentInInvocation()
  515. {
  516. string program = @"
  517. class Test {
  518. public void F(int x) {}
  519. public void Test() {
  520. $F(x: 0)$;
  521. }
  522. }";
  523. var rr = Resolve<CSharpInvocationResolveResult>(program);
  524. Assert.IsInstanceOf<NamedArgumentResolveResult>(rr.Arguments.Single());
  525. var narr = (NamedArgumentResolveResult)rr.Arguments.Single();
  526. Assert.IsInstanceOf<ConstantResolveResult>(narr.Argument);
  527. Assert.AreEqual("x", narr.ParameterName);
  528. Assert.AreEqual("Test.F", narr.Member.FullName);
  529. Assert.AreSame(narr.Member.Parameters.Single(), narr.Parameter);
  530. // but GetArgumentsForCall() should directly return the constant:
  531. Assert.IsInstanceOf<ConstantResolveResult>(rr.GetArgumentsForCall().Single());
  532. }
  533. [Test]
  534. public void UnknownNamedArgument()
  535. {
  536. string program = @"
  537. class Test {
  538. public void F(int x) {}
  539. public void Test() {
  540. F($y: 0$);
  541. }
  542. }";
  543. var narr = Resolve<NamedArgumentResolveResult>(program);
  544. Assert.IsInstanceOf<ConstantResolveResult>(narr.Argument);
  545. Assert.AreEqual("y", narr.ParameterName);
  546. Assert.IsNull(narr.Parameter);
  547. }
  548. [Test]
  549. public void NamedArgumentInMissingMethod()
  550. {
  551. string program = @"
  552. class Test {
  553. public void Test() {
  554. Missing($x: 0$);
  555. }
  556. }";
  557. var narr = Resolve<NamedArgumentResolveResult>(program);
  558. Assert.IsInstanceOf<ConstantResolveResult>(narr.Argument);
  559. Assert.AreEqual("x", narr.ParameterName);
  560. Assert.IsNull(narr.Parameter);
  561. }
  562. [Test]
  563. public void GenericMethodInvocationWithConstraintMismatch()
  564. {
  565. string program = @"
  566. interface IA
  567. {
  568. }
  569. class Test
  570. {
  571. void F()
  572. {
  573. string o = null;
  574. $M(o)$;
  575. }
  576. void M<T>(T arg) where T : IA
  577. {
  578. }
  579. void M(object arg) {
  580. }
  581. }";
  582. var rr = Resolve<CSharpInvocationResolveResult>(program);
  583. Assert.AreEqual(OverloadResolutionErrors.MethodConstraintsNotSatisfied, rr.OverloadResolutionErrors);
  584. Assert.IsTrue(rr.IsError);
  585. }
  586. [Test]
  587. public void MethodCanBeInvokedWithNullableTypeArgument1() {
  588. string program = @"
  589. public class C {
  590. static T F<T>() {
  591. return default(T);
  592. }
  593. void M() {
  594. $F<int?>()$;
  595. }
  596. }";
  597. var rr = Resolve<CSharpInvocationResolveResult>(program);
  598. Assert.IsFalse(rr.IsError);
  599. }
  600. [Test]
  601. public void MethodCanBeInvokedWithNullableTypeArgument2() {
  602. string program = @"
  603. public class C {
  604. static T F<T>(T t) {
  605. return default(T);
  606. }
  607. void M() {
  608. $F((int?)null)$;
  609. }
  610. }";
  611. var rr = Resolve<CSharpInvocationResolveResult>(program);
  612. Assert.IsFalse(rr.IsError);
  613. }
  614. [Test]
  615. public void MethodCanBeInvokedWithNullableTypeArgument3() {
  616. string program = @"
  617. public class C {
  618. static T F<T, U>() where T : U {
  619. return default(T);
  620. }
  621. void M() {
  622. $F<int?, object>()$;
  623. }
  624. }";
  625. var rr = Resolve<CSharpInvocationResolveResult>(program);
  626. Assert.IsFalse(rr.IsError);
  627. }
  628. [Test]
  629. public void MethodWithStructContraintCanBeInvokedWithValueType() {
  630. string program = @"
  631. public class C {
  632. static T F<T>() where T : struct {
  633. return default(T);
  634. }
  635. void M() {
  636. $F<int>()$;
  637. }
  638. }";
  639. var rr = Resolve<CSharpInvocationResolveResult>(program);
  640. Assert.IsFalse(rr.IsError);
  641. }
  642. [Test]
  643. public void MethodWithStructContraintCannotBeInvokedWithNullableValueType() {
  644. string program = @"
  645. public class C {
  646. static T F<T>() where T : struct {
  647. return default(T);
  648. }
  649. void M() {
  650. $F<int?>()$;
  651. }
  652. }";
  653. var rr = Resolve<CSharpInvocationResolveResult>(program);
  654. Assert.IsTrue(rr.IsError);
  655. Assert.AreEqual(OverloadResolutionErrors.MethodConstraintsNotSatisfied, rr.OverloadResolutionErrors);
  656. }
  657. [Test]
  658. public void CanConstructGenericTypeWithNullableTypeArgument() {
  659. string program = @"
  660. public class X<T> {}
  661. public class C {
  662. void M() {
  663. $new X<int?>()$;
  664. }
  665. }";
  666. var rr = Resolve<CSharpInvocationResolveResult>(program);
  667. Assert.IsFalse(rr.IsError);
  668. }
  669. }
  670. }