PageRenderTime 65ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/Ruby/IronRuby.Tests/Runtime/ClrTests.cs

http://github.com/IronLanguages/main
C# | 3557 lines | 2955 code | 425 blank | 177 comment | 58 complexity | 014209dbc0be4dec9eb1e47ef9acca39 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Linq.Expressions;
  20. using System.Reflection;
  21. using System.Runtime.CompilerServices;
  22. using System.Runtime.InteropServices;
  23. using IronRuby.Builtins;
  24. using IronRuby.Runtime;
  25. using Microsoft.Scripting.Hosting;
  26. using Microsoft.Scripting.Math;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. #if !CLR2
  30. using BigInt = System.Numerics.BigInteger;
  31. using System.Reflection.Emit;
  32. #endif
  33. namespace IronRuby.Tests {
  34. public partial class Tests {
  35. public readonly string FuncFullName = typeof(Func<>).FullName.Split('`')[0].Replace(".", "::");
  36. public readonly string ActionFullName = typeof(Action).FullName.Split('`')[0].Replace(".", "::");
  37. #region Members: Fields, Methods, Properties, Indexers
  38. public class ClassWithFields {
  39. public int Field = 1;
  40. public readonly int RoField = 2;
  41. public static int StaticField = 3;
  42. public const int ConstField = 4;
  43. }
  44. public void ClrFields1() {
  45. Context.DefineGlobalVariable("obj", new ClassWithFields());
  46. AssertOutput(delegate() {
  47. CompilerTest(@"
  48. C = $obj.class
  49. puts $obj.field
  50. puts $obj.RoField
  51. $obj.field = 10
  52. puts $obj.field
  53. ($obj.RoField = 20) rescue puts $!.class
  54. puts C.static_field
  55. puts C.const_field
  56. C.static_field = 30
  57. puts C.static_field
  58. (C.const_field = 40) rescue puts $!.class
  59. ");
  60. }, @"
  61. 1
  62. 2
  63. 10
  64. NoMethodError
  65. 3
  66. 4
  67. 30
  68. NoMethodError
  69. ");
  70. }
  71. public class ClassWithField1 {
  72. public int F = 1;
  73. }
  74. public class ClassWithField2 : ClassWithField1 {
  75. public new static int F = 2;
  76. }
  77. public void ClrFields2() {
  78. Context.DefineGlobalVariable("obj", new ClassWithField2());
  79. AssertOutput(delegate() {
  80. CompilerTest(@"
  81. puts $obj.class.F
  82. puts $obj.F
  83. ");
  84. }, @"
  85. 2
  86. 1
  87. ");
  88. }
  89. public class ClassWithMethods1 {
  90. public int RoProperty { get { return 3; } }
  91. public int RwProperty { get { return 4; } set { } }
  92. public int WoProperty { set { } }
  93. public int M() { return 1; }
  94. public static int StaticMethod() { return 2; }
  95. }
  96. public void ClrMethods1() {
  97. Context.DefineGlobalVariable("obj", new ClassWithMethods1());
  98. Context.DefineGlobalVariable("cls", typeof(ClassWithMethods1));
  99. AssertOutput(delegate() {
  100. CompilerTest(@"
  101. C = $obj.class
  102. puts $obj.m
  103. puts C.static_method
  104. puts $cls.static_methods rescue puts $!.class
  105. ($obj.RoProperty = 10) rescue puts $!.class
  106. $obj.WoProperty = 20
  107. $obj.RwProperty = 30
  108. puts $obj.RoProperty
  109. puts $obj.WoProperty rescue puts $!.class
  110. puts $obj.RwProperty
  111. ");
  112. }, @"
  113. 1
  114. 2
  115. NoMethodError
  116. NoMethodError
  117. 3
  118. NoMethodError
  119. 4
  120. ");
  121. }
  122. /// <summary>
  123. /// Order of initialization of CLR methods.
  124. /// </summary>
  125. public void ClrMethods2() {
  126. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithMethods1)));
  127. XTestOutput(@"
  128. class C
  129. def m; 2; end # replace CLR method with Ruby method before we use the CLR one
  130. remove_method :m # remove Ruby method
  131. new.m rescue p $! # we shouldn't call the CLR method
  132. end
  133. ", @"
  134. ");
  135. }
  136. public class ClassWithEquals1 {
  137. // define overload of Equals so that we get a method group with mixed instance and static methods inherited from Object's method group
  138. public static bool Equals(object o1, object o2, object o3) { return o1.Equals(o2); }
  139. }
  140. /// <summary>
  141. /// Mixing instance and static methods - instance Object::Equals(Object), static Object::Equals(Object, Object).
  142. /// </summary>
  143. public void ClrMethods3() {
  144. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithEquals1)));
  145. TestOutput(@"
  146. puts 1.Equals(2) # instance
  147. puts 1.Equals(2,3) rescue p $! # static invoked with instance
  148. puts C.Equals(C) # instance invoked on a class (statically)
  149. puts C.Equals(3,3) # static
  150. puts C.Equals(3,3,4) # overload
  151. ", @"
  152. false
  153. #<ArgumentError: wrong number of arguments (2 for 1)>
  154. true
  155. true
  156. true
  157. ");
  158. }
  159. /// <summary>
  160. /// Builtin types only expose CLR methods under unmangled names (mangling is no applied).
  161. /// </summary>
  162. public void ClrMethods4() {
  163. TestOutput(@"
  164. a = Exception.new
  165. p a.method(:data) rescue p $!
  166. p a.method(:Data)
  167. ", @"
  168. #<NameError: undefined method `data' for class `Exception'>
  169. #<Method: Exception#Data>
  170. ");
  171. }
  172. public void ClrMembers1() {
  173. TestOutput(@"
  174. a = [1,2,3]
  175. p m = a.clr_member(:count)
  176. p m[]
  177. p m = a.clr_member(:index_of)
  178. p m.clr_members.size
  179. p m.overload(Object).clr_members
  180. ", @"
  181. #<Method: Array#count>
  182. 3
  183. #<Method: Array#index_of>
  184. 3
  185. [Int32 IndexOf(System.Object)]
  186. ");
  187. TestOutput(@"
  188. class C < Array
  189. end
  190. p C.new.clr_member(:index_of).call(1)
  191. ", @"
  192. -1
  193. ");
  194. }
  195. public class ClassWithIndexer1 {
  196. public int[,] Values = new int[,] { { 0, 10 }, { 20, 30 } };
  197. public int this[int i, int j] { get { return Values[i, j]; } set { Values[i, j] = value; } }
  198. }
  199. public void ClrIndexers1() {
  200. Context.ObjectClass.SetConstant("CI", Context.GetClass(typeof(ClassWithIndexer1)));
  201. // default indexers:
  202. AssertOutput(() => CompilerTest(@"
  203. c = CI.new
  204. c[0,1] += 1
  205. p c[0, 1]
  206. "), @"
  207. 11
  208. ");
  209. // non-default indexers:
  210. // TODO: We need to use VB or generate IL to test this.
  211. // TODO: improve access
  212. // If a property accessor with parameters is called without arguments the result is a PropertyAccessor object with [], []= defined.
  213. // Then the calls could look like c.foo[1,2] = 3.
  214. // AssertOutput(() => CompilerTest(@"
  215. //c = CI.new
  216. //c.method(:foo=).call(1, 0, c.method(:foo).call(1, 0) + 5)
  217. //p c.method(:foo).call(1, 0)
  218. //"), @"
  219. //25
  220. //");
  221. }
  222. #endregion
  223. #region Visibility
  224. public class ProtectedA {
  225. protected string Foo(int a) { return "Foo(I): " + a; }
  226. public string Bar(int a) { return "Bar(I): " + a; }
  227. protected string PG<T>(T a) { return "PG<T>(T)"; }
  228. }
  229. public class ProtectedB : ProtectedA {
  230. public string Foo(object a) { return "Foo(O): " + a.ToString(); }
  231. internal protected string Bar(object a) { return "Bar(O): " + a; }
  232. protected int Prop1 { get; set; }
  233. public int Prop2 { get; internal protected set; }
  234. private string Baz(int a) { return "Baz(I): " + a; }
  235. public string Baz(object a) { return "Baz(O): " + a; }
  236. protected static string StaticM() { return "StaticM"; }
  237. protected static string StaticGenericM<T>(T f) { return "StaticGenericM: " + f.ToString(); }
  238. internal protected string PG<T>(T a, int b) { return "PG<T>(T,int)"; }
  239. // TODO:
  240. // protected int Fld;
  241. // protected static int Fld;
  242. // protected event Func<object> Evnt;
  243. }
  244. public void ClrVisibility1() {
  245. Debug.Assert(!Engine.Runtime.Setup.PrivateBinding);
  246. Context.ObjectClass.SetConstant("A", Context.GetClass(typeof(ProtectedA)));
  247. Context.ObjectClass.SetConstant("B", Context.GetClass(typeof(ProtectedB)));
  248. // methods:
  249. AssertOutput(delegate() {
  250. CompilerTest(@"
  251. class C < B; end
  252. a, b, c = A.new, B.new, C.new
  253. puts c.foo(1)
  254. puts b.foo(2)
  255. puts b.bar(22)
  256. a.foo(3) rescue p $!
  257. class A
  258. def foo; 4; end
  259. def bar; 5; end
  260. end
  261. puts c.foo(6)
  262. b.bar(7) rescue p $!
  263. B.StaticM rescue p $!
  264. puts C.StaticM
  265. puts C.method(:StaticGenericM).of(Fixnum)[123]
  266. ");
  267. }, @"
  268. Foo(I): 1
  269. Foo(O): 2
  270. Bar(I): 22
  271. #<NoMethodError: CLR protected method `foo' called for *ProtectedA*>
  272. Foo(O): 6
  273. #<NoMethodError: CLR protected method `bar' called for *ProtectedB*>
  274. #<NoMethodError: CLR protected method `StaticM' called for *ProtectedB*>
  275. StaticM
  276. StaticGenericM: 123
  277. ", OutputFlags.Match);
  278. // generic methods:
  279. TestOutput(@"
  280. class C < B; end
  281. c = C.new
  282. puts c.method(:PG).of(Fixnum).call(1)
  283. puts c.method(:PG).of(Fixnum).call(1,2)
  284. ", @"
  285. PG<T>(T)
  286. PG<T>(T,int)
  287. ");
  288. // properties:
  289. AssertOutput(delegate() {
  290. CompilerTest(@"
  291. class C < B; end
  292. a, b, c = A.new, B.new, C.new
  293. c.prop1 = 1
  294. c.prop2 = 2
  295. puts c.prop1
  296. puts c.prop2
  297. (b.prop2 = 10) rescue p $!
  298. puts b.prop2
  299. ");
  300. }, @"
  301. 1
  302. 2
  303. #<NoMethodError: CLR protected method `prop2=' called for *ProtectedB*>
  304. 0
  305. ", OutputFlags.Match);
  306. }
  307. [Options(PrivateBinding = true)]
  308. public void ClrVisibility2() {
  309. Debug.Assert(Engine.Runtime.Setup.PrivateBinding);
  310. if (_driver.PartialTrust) return;
  311. Context.ObjectClass.SetConstant("A", Context.GetClass(typeof(ProtectedA)));
  312. Context.ObjectClass.SetConstant("B", Context.GetClass(typeof(ProtectedB)));
  313. // methods, properties:
  314. TestOutput(@"
  315. class C < B; end
  316. a, b, c = A.new, B.new, C.new
  317. puts a.foo(3)
  318. class A
  319. def bar; 5; end
  320. end
  321. puts b.bar(7)
  322. puts b.baz(1)
  323. b.prop2 = 10
  324. puts b.prop2
  325. ",
  326. @"
  327. Foo(I): 3
  328. Bar(O): 7
  329. Baz(I): 1
  330. 10
  331. ");
  332. }
  333. public delegate void TestDelegate(string a);
  334. public void SpecialMethods() {
  335. var result = Engine.Execute(@"
  336. System::AppDomain.CurrentDomain.CreateInstance(""mscorlib"", ""System.Object"")
  337. ");
  338. Assert(result is System.Runtime.Remoting.ObjectHandle);
  339. var dm = (DynamicMethod)Engine.Execute(@"
  340. System::Reflection::Emit::DynamicMethod.new(""foo"", 1.GetType(), System::Array[System::Type].new(0))
  341. ");
  342. Assert(dm.ReturnType == typeof(int));
  343. var invoke = typeof(TestDelegate).GetMethod("Invoke");
  344. var d = invoke.CreateDelegate(typeof(Action<string>));
  345. Assert(d is Action<string>);
  346. }
  347. #endregion
  348. #region Member Enumeration
  349. /// <summary>
  350. /// No CLR names should be returned for builtin types and singletons.
  351. /// </summary>
  352. public void ClrMethodEnumeration1() {
  353. // built-ins:
  354. var irModules = new[] { "IronRuby" };
  355. using (Context.ClassHierarchyLocker()) {
  356. Context.ObjectClass.EnumerateConstants((module, name, value) => {
  357. RubyModule m = value as RubyModule;
  358. if (m != null && Array.IndexOf(irModules, m.Name) == -1) {
  359. var s = m.GetOrCreateSingletonClass();
  360. AssertNoClrNames(ModuleOps.GetInstanceMethods(m, true), m.Name);
  361. AssertNoClrNames(ModuleOps.GetPrivateInstanceMethods(m, true), m.Name);
  362. AssertNoClrNames(ModuleOps.GetInstanceMethods(s, true), m.Name);
  363. AssertNoClrNames(ModuleOps.GetPrivateInstanceMethods(s, true), m.Name);
  364. }
  365. return false;
  366. });
  367. }
  368. // singletons:
  369. AssertNoClrNames(Engine.Execute<object>(@"class << self; instance_methods + private_instance_methods; end"), null);
  370. AssertNoClrNames(Engine.Execute<object>(@"class << self; class << self; instance_methods + private_instance_methods; end; end"), null);
  371. AssertNoClrNames(Engine.Execute<object>(@"class << Class; instance_methods + private_instance_methods; end"), null);
  372. }
  373. public void ClrMethodEnumeration2() {
  374. TestOutput(@"
  375. class System::Decimal
  376. instance_methods(false).each do |name|
  377. mangled = '__' + name
  378. alias_method(mangled, name)
  379. private mangled
  380. define_method(name) do |*args|
  381. puts ""method called: #{name}""
  382. send mangled, *args
  383. end
  384. end
  385. end
  386. x, y = System::Decimal.new(1), System::Decimal.new(2)
  387. x + y
  388. x.CompareTo(y)
  389. ", @"
  390. method called: +
  391. method called: compare_to
  392. ");
  393. }
  394. public class ClassWithGeneratedMembers1 : I1 {
  395. private class OK {
  396. }
  397. // C# generates display class, anonymous type, anonymos methods and a static field:
  398. private IEnumerable<int> GetInts() {
  399. var t = new { a = 1, b = 2 };
  400. Func<int> f = () => 1;
  401. yield return f();
  402. yield return t.a;
  403. yield return Field;
  404. }
  405. private static int Field = 3;
  406. int I1.f() { return 0; }
  407. }
  408. [Options(PrivateBinding = true)]
  409. public void ClrMethodEnumeration_InvalidNames1() {
  410. Context.ObjectClass.SetConstant("Foo", Context.GetClass(typeof(ClassWithGeneratedMembers1)));
  411. TestOutput(@"
  412. class Foo
  413. def <=>; end
  414. def <<; end
  415. def &; end
  416. def f?; end
  417. def f!; end
  418. def f=; end
  419. end
  420. puts Foo.constants
  421. puts Foo.singleton_methods(false).sort
  422. puts Foo.instance_methods(false).sort
  423. ", @"
  424. OK
  425. field
  426. field=
  427. &
  428. <<
  429. <=>
  430. f!
  431. f=
  432. f?
  433. get_ints
  434. ");
  435. }
  436. private void AssertNoClrNames(object/*!*/ methods, string moduleName) {
  437. var array = (RubyArray)methods;
  438. int idx = array.FindIndex((name) => name is ClrName);
  439. Assert(idx == -1, moduleName + "::" + (idx == -1 ? null : ((ClrName)array[idx]).ActualName));
  440. }
  441. #endregion
  442. #region Generic Methods
  443. #pragma warning disable 67 // event not used
  444. public class GenericMethods {
  445. public static string M0<T>() {
  446. return "M0<" + typeof(T).Name + ">()";
  447. }
  448. public static string M1() {
  449. return "M1()";
  450. }
  451. public static string M1<T>() {
  452. return "M1<" + typeof(T).Name + ">()";
  453. }
  454. public static string M1<S, T>() {
  455. return "M1<" + typeof(S).Name + ", " + typeof(T).Name + ">()";
  456. }
  457. public static string M1<T>(int foo) {
  458. return "M1<" + typeof(T).Name + ">(Fixnum)";
  459. }
  460. public static string M2(int foo) {
  461. return "M2(Fixnum)";
  462. }
  463. public static string M2<T>(int foo) {
  464. return "M2<" + typeof(T).Name + ">(Fixnum)";
  465. }
  466. public static int Field;
  467. public static object Property { get; set; }
  468. public static event Action<Object> Event;
  469. }
  470. #pragma warning restore
  471. public void ClrGenericMethods1() {
  472. Context.ObjectClass.SetConstant("GM", Context.GetClass(typeof(GenericMethods)));
  473. TestOutput(@"
  474. m = GM.method(:M1)
  475. puts m.call
  476. puts m.of().call
  477. puts m.of(String).call
  478. puts m.of(String, Fixnum).call
  479. puts m.call(1) rescue p $!
  480. puts m.of(String, String, String) rescue p $!
  481. ", @"
  482. M1()
  483. M1()
  484. M1<MutableString>()
  485. M1<MutableString, Int32>()
  486. #<ArgumentError: generic arguments could not be infered for method 'M1'>
  487. #<ArgumentError: wrong number of generic arguments for `M1'>
  488. "
  489. );
  490. TestOutput(@"
  491. m = GM.method(:M2)
  492. puts m.call(1)
  493. puts GM.method(:field).of(Fixnum) rescue p $!
  494. puts GM.method(:property).of(Fixnum) rescue p $!
  495. puts GM.method(:event).of(Fixnum) rescue p $!
  496. ", @"
  497. M2(Fixnum)
  498. #<ArgumentError: wrong number of generic arguments for `field'>
  499. #<ArgumentError: wrong number of generic arguments for `property'>
  500. #<ArgumentError: wrong number of generic arguments for `event'>
  501. "
  502. );
  503. }
  504. public abstract class GenericMethods2 {
  505. public abstract T Foo<T>(T arg);
  506. }
  507. internal class GenericMethods3 : GenericMethods2 {
  508. public override T Foo<T>(T arg) {
  509. return arg;
  510. }
  511. }
  512. public void ClrGenericMethods2() {
  513. Context.ObjectClass.SetConstant("GM3", new GenericMethods3());
  514. TestOutput(@"
  515. puts GM3.foo(123)
  516. ", @"
  517. 123
  518. ");
  519. }
  520. public class Inference1 {
  521. public int ByRef<T>(ref T x) {
  522. x = (T)(object)((int)(object)x + 1);
  523. return 0;
  524. }
  525. public int Array<T>(T[] x) {
  526. return 1;
  527. }
  528. public int Multiple<S, R>(IEnumerable<S> source, Func<S, R> selector) {
  529. return 2;
  530. }
  531. public int DeepShape<T>(Dictionary<Dictionary<T, string>, Dictionary<int, T>> arg) {
  532. return 3;
  533. }
  534. public int Complex<A,B,C>(ref Dictionary<List<Dictionary<Func<A, B[][,,,][], C>[], int>>, Func<Dictionary<int, A>, B, C>>[] arg) {
  535. return 4;
  536. }
  537. public int Where<T>(IEnumerable<T> e, Func<T, bool> f) {
  538. return 5;
  539. }
  540. public int Where<T>(IEnumerable<T> e, Func<T, int, bool> f) {
  541. return 6;
  542. }
  543. public int Where<T>(IEnumerable<T> e, object f) {
  544. return 7;
  545. }
  546. public int Apply<T>(IEnumerable<T> e, Action<T> f) {
  547. return 8;
  548. }
  549. public int Mixed<T>(T arg) {
  550. return 8;
  551. }
  552. public int Mixed(object arg) {
  553. return 9;
  554. }
  555. }
  556. public void ClrGenericParametersInference1() {
  557. Context.ObjectClass.SetConstant("F", Context.GetClass(typeof(Func<object,string>)));
  558. Context.ObjectClass.SetConstant("SB", Context.GetClass(typeof(StrongBox<int>)));
  559. Context.ObjectClass.SetConstant("SBx",
  560. new StrongBox<Dictionary<List<Dictionary<Func<int, bool[][,,,][], double>[], int>>, Func<Dictionary<int, int>, bool, double>>[]>(null)
  561. );
  562. Context.ObjectClass.SetConstant("I", new Inference1());
  563. Context.ObjectClass.SetConstant("E", Context.GetClass(typeof(InteropTests.Generics1.Extensions)));
  564. TestOutput(@"
  565. p I.Array(System::Array[Fixnum].new(3))
  566. p I.Multiple([1,2,3], F.new { |x| x.to_s })
  567. E.Select([1,2], F.new { |x| x.to_s + '!' }).each { |a| puts a }
  568. E.Select([1,2], lambda { |x| x + 1 }).each { |a| puts a }
  569. ", @"
  570. 1
  571. 2
  572. 1!
  573. 2!
  574. 2
  575. 3
  576. ");
  577. TestOutput(@"
  578. p I.ByRef(2)
  579. sb = SB.new(10)
  580. p I.ByRef(sb), sb.Value
  581. ", @"
  582. [0, 3]
  583. 0
  584. 11
  585. ");
  586. TestOutput(@"
  587. include System::Collections::Generic
  588. p I.DeepShape(Dictionary[List[Fixnum], Dictionary[Fixnum, Fixnum]].new) rescue p $!
  589. p I.DeepShape(Dictionary[Dictionary[Fixnum, System::String], Dictionary[Fixnum, Fixnum]].new)
  590. ", @"
  591. #<ArgumentError: generic arguments could not be infered for method 'DeepShape'>
  592. 3
  593. ");
  594. TestOutput(@"
  595. p I.Complex(SBx)
  596. ", @"
  597. 4
  598. ");
  599. TestOutput(@"
  600. l1 = lambda { |x| }
  601. l2 = lambda { |x, y| }
  602. l3 = lambda { |*| }
  603. a = System::Array[Object].new(1)
  604. p I.Where(a, l1)
  605. p I.Where(a, l2)
  606. p I.Where(a, l3) rescue puts 'ambiguous'
  607. p I.Where(a, 123)
  608. ", @"
  609. 5
  610. 6
  611. ambiguous
  612. 7
  613. ");
  614. // TODO:
  615. // XTestOutput(@"
  616. //a = System::Array[Fixnum].new(1)
  617. //p I.Apply(a, lambda { |x| })
  618. //", @"
  619. //5
  620. //");
  621. // an inferred type is more specific than object:
  622. TestOutput(@"
  623. p I.Mixed(1)
  624. ", @"
  625. 8
  626. ");
  627. }
  628. #endregion
  629. #region Extension Methods
  630. public void ClrExtensionMethods0() {
  631. bool expectExact = typeof(Enumerable).Assembly.FullName == "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
  632. Dictionary<string, int> expected = new Dictionary<string, int>();
  633. foreach (string name in new[] {
  634. "AsQueryable", "AsQueryable", "Where", "Where", "OfType", "Cast", "Select", "Select", "SelectMany", "SelectMany", "SelectMany", "SelectMany", "Join", "Join", "GroupJoin",
  635. "GroupJoin", "OrderBy", "OrderBy", "OrderByDescending", "OrderByDescending", "ThenBy", "ThenBy", "ThenByDescending", "ThenByDescending", "Take", "TakeWhile",
  636. "TakeWhile", "Skip", "SkipWhile", "SkipWhile", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "Distinct", "Distinct",
  637. "Concat", "Zip", "Union", "Union", "Intersect", "Intersect", "Except", "Except", "First", "First", "FirstOrDefault", "FirstOrDefault", "Last", "Last",
  638. "LastOrDefault", "LastOrDefault", "Single", "Single", "SingleOrDefault", "SingleOrDefault", "ElementAt", "ElementAtOrDefault", "DefaultIfEmpty", "DefaultIfEmpty",
  639. "Contains", "Contains", "Reverse", "SequenceEqual", "SequenceEqual", "Any", "Any", "All", "Count", "Count", "LongCount", "LongCount", "Min", "Min", "Max", "Max",
  640. "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Average", "Average",
  641. "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average",
  642. "Average", "Average", "Average", "Aggregate", "Aggregate", "Aggregate", "Where", "Where", "Select", "Select", "SelectMany", "SelectMany", "SelectMany", "SelectMany",
  643. "Take", "TakeWhile", "TakeWhile", "Skip", "SkipWhile", "SkipWhile", "Join", "Join", "GroupJoin", "GroupJoin", "OrderBy", "OrderBy", "OrderByDescending",
  644. "OrderByDescending", "ThenBy", "ThenBy", "ThenByDescending", "ThenByDescending", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy",
  645. "GroupBy", "Concat", "Zip", "Distinct", "Distinct", "Union", "Union", "Intersect", "Intersect", "Except", "Except", "Reverse", "SequenceEqual", "SequenceEqual",
  646. "AsEnumerable", "ToArray", "ToList", "ToDictionary", "ToDictionary", "ToDictionary", "ToDictionary", "ToLookup", "ToLookup", "ToLookup", "ToLookup", "DefaultIfEmpty",
  647. "DefaultIfEmpty", "OfType", "Cast", "First", "First", "FirstOrDefault", "FirstOrDefault", "Last", "Last", "LastOrDefault", "LastOrDefault", "Single", "Single",
  648. "SingleOrDefault", "SingleOrDefault", "ElementAt", "ElementAtOrDefault", "Any", "Any", "All", "Count", "Count", "LongCount", "LongCount", "Contains", "Contains",
  649. "Aggregate", "Aggregate", "Aggregate", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum",
  650. "Sum", "Sum", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min",
  651. "Min", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max",
  652. "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average",
  653. "Average", "Average", "Average", "Average", "Average", "AsParallel", "AsParallel", "AsOrdered", "AsOrdered", "AsUnordered", "AsParallel", "AsSequential",
  654. "WithDegreeOfParallelism", "WithCancellation", "WithExecutionMode", "WithMergeOptions", "ForAll", "Where", "Where", "Select", "Select", "Zip", "Zip", "Join", "Join",
  655. "Join", "Join", "GroupJoin", "GroupJoin", "GroupJoin", "GroupJoin", "SelectMany", "SelectMany", "SelectMany", "SelectMany", "OrderBy", "OrderBy", "OrderByDescending",
  656. "OrderByDescending", "ThenBy", "ThenBy", "ThenByDescending", "ThenByDescending", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy", "GroupBy",
  657. "Aggregate", "Aggregate", "Aggregate", "Aggregate", "Aggregate", "Count", "Count", "LongCount", "LongCount", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum",
  658. "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Sum", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min",
  659. "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Min", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max",
  660. "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Max", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average",
  661. "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Average", "Any", "Any", "All", "Contains", "Contains", "Take",
  662. "TakeWhile", "TakeWhile", "Skip", "SkipWhile", "SkipWhile", "Concat", "Concat", "SequenceEqual", "SequenceEqual", "SequenceEqual", "SequenceEqual", "Distinct",
  663. "Distinct", "Union", "Union", "Union", "Union", "Intersect", "Intersect", "Intersect", "Intersect", "Except", "Except", "Except", "Except", "AsEnumerable", "ToArray",
  664. "ToList", "ToDictionary", "ToDictionary", "ToDictionary", "ToDictionary", "ToLookup", "ToLookup", "ToLookup", "ToLookup", "Reverse", "OfType", "Cast", "First", "First",
  665. "FirstOrDefault", "FirstOrDefault", "Last", "Last", "LastOrDefault", "LastOrDefault", "Single", "Single", "SingleOrDefault", "SingleOrDefault", "DefaultIfEmpty",
  666. "DefaultIfEmpty", "ElementAt", "ElementAtOrDefault", "Unwrap", "Unwrap",
  667. }) {
  668. int count;
  669. if (!expected.TryGetValue(name, out count)) {
  670. count = 0;
  671. }
  672. expected[name] = count + 1;
  673. }
  674. var methods = ReflectionUtils.GetVisibleExtensionMethods(typeof(Enumerable).Assembly);
  675. new List<MethodInfo>(ReflectionUtils.GetVisibleExtensionMethodsSlow(typeof(Enumerable).Assembly));
  676. Dictionary<string, int> actual = new Dictionary<string, int>();
  677. foreach (MethodInfo method in methods) {
  678. int count;
  679. if (!actual.TryGetValue(method.Name, out count)) {
  680. count = 0;
  681. }
  682. actual[method.Name] = count + 1;
  683. }
  684. foreach (string name in actual.Keys) {
  685. Assert(expected.ContainsKey(name));
  686. Assert(expectExact ? expected[name] == actual[name] : expected[name] >= actual[name]);
  687. }
  688. }
  689. public void ClrExtensionMethods1() {
  690. Context.ObjectClass.SetConstant("SystemCoreAssembly", typeof(Expression).Assembly.FullName);
  691. TestOutput(@"
  692. load_assembly SystemCoreAssembly
  693. using_clr_extensions System::Linq
  694. a = System::Array[Fixnum].new([1,2,3])
  695. p a.first_or_default
  696. #TODO: p a.method(:of_type).of(Fixnum).call.to_a #=> [1, 2, 3]
  697. ", @"
  698. 1
  699. ");
  700. }
  701. /// <summary>
  702. /// Loads an assembly that defines more extension methods in the given namespace.
  703. /// </summary>
  704. public void ClrExtensionMethods2() {
  705. Context.ObjectClass.SetConstant("SystemCoreAssembly", typeof(Expression).Assembly.FullName);
  706. Context.ObjectClass.SetConstant("DummyLinqAssembly", typeof(System.Linq.Dummy).Assembly.FullName);
  707. TestOutput(@"
  708. load_assembly DummyLinqAssembly
  709. using_clr_extensions System::Linq
  710. load_assembly SystemCoreAssembly
  711. p System::Array[Fixnum].new([1,2,3]).first_or_default
  712. ", @"
  713. 1
  714. ");
  715. }
  716. /// <summary>
  717. /// Extension methods not available by default onlty after their declaring namespace is "used".
  718. /// </summary>
  719. public void ClrExtensionMethods3() {
  720. Context.ObjectClass.SetConstant("SystemCoreAssembly", typeof(Expression).Assembly.FullName);
  721. Context.ObjectClass.SetConstant("DummyLinqAssembly", typeof(System.Linq.Dummy).Assembly.FullName);
  722. TestOutput(@"
  723. load_assembly DummyLinqAssembly
  724. load_assembly SystemCoreAssembly
  725. a = System::Array[Fixnum].new([1,2,3])
  726. a.first_or_default rescue p $!
  727. using_clr_extensions System::Linq
  728. p a.first_or_default
  729. ", @"
  730. #<NoMethodError: undefined method `first_or_default' for [1, 2, 3]:System::Int32[]>
  731. 1
  732. ");
  733. }
  734. /// <summary>
  735. /// Extension methods defined using generic parameters and constraints.
  736. /// </summary>
  737. public void ClrExtensionMethods4() {
  738. Runtime.LoadAssembly(typeof(IronRubyTests.ExtensionMethods2.EMs).Assembly);
  739. TestOutput(@"
  740. L = System::Collections::Generic::List
  741. D = System::Collections::Generic::Dictionary
  742. using_clr_extensions IronRubyTests::ExtensionMethods2
  743. include IronRubyTests::ExtensionMethods2
  744. puts L[X].new.f1
  745. L[A].new.f1 rescue puts '!f1'
  746. puts D[B, A].new.f2
  747. puts D[A, A].new.f2
  748. D[A, X].new.f2 rescue puts '!f2'
  749. puts f3 = L[X].new.method(:f3)
  750. puts f3.of(X, Object)[1]
  751. puts L[Y].new.f3(X.new)
  752. L[A].new.f3(X.new) rescue puts '!f3'
  753. puts S.new.f4
  754. puts 1.f4
  755. #TODO: A.new.method(:f4) rescue p $!
  756. A.new.f4 rescue puts '!f4'
  757. puts A.new.f5
  758. puts B.new.f5
  759. class A; def f5; 'Ruby f5'; end; end
  760. puts A.new.f5
  761. puts B.new.f5 # f5 is an extension on all types (TODO)
  762. puts System::Array[A].new(1).f6
  763. System::Array[Fixnum].new(1).f6 rescue puts '!f6'
  764. puts L[System::Array[D[B, L[A]]]].new.f6
  765. L[System::Array[D[B, L[Fixnum]]]].new.f6 rescue puts '!f6'
  766. ", @"
  767. f1
  768. !f1
  769. f2
  770. f2
  771. !f2
  772. #<Method: System::Collections::Generic::List[IronRubyTests::ExtensionMethods2::X]#f3>
  773. f3
  774. f3
  775. !f3
  776. f4
  777. f4
  778. !f4
  779. f5
  780. f5
  781. Ruby f5
  782. Ruby f5
  783. f6
  784. !f6
  785. f6
  786. !f6
  787. ");
  788. }
  789. /// <summary>
  790. /// Extension methods are available on CLR interfaces implemented by Ruby classes.
  791. /// </summary>
  792. public void ClrExtensionMethods5() {
  793. #if TODO
  794. Runtime.LoadAssembly(typeof(System.Linq.Enumerable).Assembly);
  795. XTestOutput(@"
  796. using_clr_extensions System::Linq
  797. class Sequence
  798. include System::Collections::Generic::IEnumerable[Object]
  799. def initialize array
  800. @array = array
  801. end
  802. def get_enumerator
  803. @array.GetEnumerator()
  804. end
  805. end
  806. class Array
  807. def to_seq
  808. Sequence.new self
  809. end
  810. end
  811. a = Sequence.new [1, 2, 3]
  812. p a.select(lambda { |n| n * 2 })
  813. ", @"
  814. [2, 3, 6]
  815. ");
  816. #endif
  817. }
  818. #endregion
  819. #region Overloads: Inheritance, Selection
  820. public static class OverloadInheritance1 {
  821. public class A {
  822. public string Foo(int a, int b, int c) {
  823. return "Foo: " + a.ToString() + ", " + b.ToString() + ", " + c.ToString();
  824. }
  825. public string Skip() {
  826. return "Skip";
  827. }
  828. }
  829. public class B : A {
  830. public string Foo(int a) {
  831. return "Foo: " + a.ToString();
  832. }
  833. public virtual string Foo(int a, int b) {
  834. return "Foo: " + a.ToString() + ", " + b.ToString();
  835. }
  836. public string Bar(int a) {
  837. return "Bar: " + a.ToString();
  838. }
  839. public string Hidden(int a) {
  840. return "Hidden: " + a.ToString();
  841. }
  842. public string Middle(int a) {
  843. return "Middle: " + a.ToString();
  844. }
  845. }
  846. public class C : B {
  847. public new string Foo(int a) {
  848. return "NewFoo: " + a.ToString();
  849. }
  850. public override string Foo(int a, int b) {
  851. return "OverriddenFoo: " + a.ToString() + ", " + b.ToString();
  852. }
  853. public string Bar(int a, int b) {
  854. return "Bar: " + a.ToString() + ", " + b.ToString();
  855. }
  856. public string Hidden(int a, int b) {
  857. return "Hidden: " + a.ToString() + ", " + b.ToString();
  858. }
  859. public string Skip(int a) {
  860. return "Skip: " + a.ToString();
  861. }
  862. }
  863. }
  864. public void ClrOverloadInheritance1() {
  865. Context.ObjectClass.SetConstant("Obj", new OverloadInheritance1.C());
  866. AssertOutput(() => CompilerTest(@"
  867. puts Obj.foo(1)
  868. puts Obj.foo(1, 2)
  869. puts Obj.foo(1, 2, 3)
  870. puts Obj.bar(1)
  871. puts Obj.bar(1, 2)
  872. puts Obj.middle(1)
  873. puts Obj.skip
  874. puts Obj.skip(1)
  875. Obj.GetHashCode
  876. "), @"
  877. NewFoo: 1
  878. OverriddenFoo: 1, 2
  879. Foo: 1, 2, 3
  880. Bar: 1
  881. Bar: 1, 2
  882. Middle: 1
  883. Skip
  884. Skip: 1
  885. ");
  886. AssertOutput(() => CompilerTest(@"
  887. p Obj.method(:foo)
  888. p Obj.method(:bar)
  889. p Obj.method(:middle)
  890. p Obj.method(:skip)
  891. "), @"
  892. #<Method: *C#foo>
  893. #<Method: *C#bar>
  894. #<Method: *C(*B)#middle>
  895. #<Method: *C#skip>
  896. ", OutputFlags.Match);
  897. // hides Hidden method when called using mangled name "hidden":
  898. Context.GetClass(typeof(OverloadInheritance1.B)).HideMethod("hidden");
  899. AssertOutput(() => CompilerTest(@"
  900. puts Obj.hidden(1) rescue puts 'error'
  901. puts Obj.Hidden(1)
  902. puts Obj.hidden(1, 2)
  903. puts Obj.Hidden(1, 2)
  904. "), @"
  905. error
  906. Hidden: 1
  907. Hidden: 1, 2
  908. Hidden: 1, 2
  909. ");
  910. }
  911. public static class OverloadInheritance2 {
  912. public class A { public virtual string f(int a) { return "f1"; } }
  913. public class B : A { }
  914. public class C : B { }
  915. public class D : C { public virtual string f(int a, int b) { return "f2"; } }
  916. public class E : D { }
  917. public class F : E { public virtual string f(int a, int b, int c, int d) { return "f4"; } }
  918. public class G : F { }
  919. public class X : B { public virtual string f(int a, int b, int c) { return "f3"; } }
  920. public class Y : X { }
  921. public static void Load(RubyContext/*!*/ context) {
  922. context.ObjectClass.SetConstant("A", context.GetClass(typeof(A)));
  923. context.ObjectClass.SetConstant("B", context.GetClass(typeof(B)));
  924. context.ObjectClass.SetConstant("C", context.GetClass(typeof(C)));
  925. context.ObjectClass.SetConstant("D", context.GetClass(typeof(D)));
  926. context.ObjectClass.SetConstant("E", context.GetClass(typeof(E)));
  927. context.ObjectClass.SetConstant("F", context.GetClass(typeof(F)));
  928. context.ObjectClass.SetConstant("G", context.GetClass(typeof(G)));
  929. context.ObjectClass.SetConstant("X", context.GetClass(typeof(X)));
  930. context.ObjectClass.SetConstant("Y", context.GetClass(typeof(Y)));
  931. }
  932. }
  933. /// <summary>
  934. /// Dynamic site and group caching.
  935. /// </summary>
  936. public void ClrOverloadInheritance2() {
  937. OverloadInheritance2.Load(Context);
  938. // method definition hides overloads:
  939. AssertOutput(() => CompilerTest(@"
  940. puts E.new.f(1,2) # marks D::f2 and A::f1 as used in d.s.
  941. class C; def f; 'f:C'; end; end # overrides A::f1 => invalidates all 'f'-groups in subtree of C
  942. puts E.new.f(1) rescue puts 'error' # recreates D::f2 => A::f1 not visible
  943. puts E.new.f(1,2) # D::f still visible => marked as used in d.s.
  944. "), @"
  945. f2
  946. error
  947. f2
  948. ");
  949. // module inclusion hides overloads:
  950. AssertOutput(() => CompilerTest(@"
  951. puts Y.new.f(1)
  952. module M; def f; 'f:M' end; end
  953. class X; include M; end # hides A::f1, but not X::f3
  954. puts Y.new.f(1) rescue puts 'error'
  955. puts Y.new.f(1,2,3)
  956. "), @"
  957. f1
  958. error
  959. f3
  960. ");
  961. }
  962. public void ClrOverloadInheritance3() {
  963. OverloadInheritance2.Load(Context);
  964. // method definition hides overloads:
  965. AssertOutput(() => CompilerTest(@"
  966. p D.instance_method(:f).clr_members.collect { |x| x.to_string } # creates groups in A and D that are not used in d.s.
  967. class B; def f; 'f:B'; end; end # hides A::f1
  968. p D.instance_method(:f).clr_members.collect { |x| x.to_string } # only one overload should be present in the group
  969. "), @"
  970. ['System.String f(Int32)', 'System.String f(Int32, Int32)']
  971. ['System.String f(Int32, Int32)']
  972. ");
  973. }
  974. public void ClrOverloadInheritance4() {
  975. OverloadInheritance2.Load(Context);
  976. AssertOutput(() => CompilerTest(@"
  977. puts D.new.f(1)
  978. puts D.new.f(1,2)
  979. class B;
  980. def f; 'f:B'; end
  981. end
  982. puts D.new.f(1) rescue puts 'error'
  983. puts D.new.f(1,2)
  984. class B
  985. remove_method :f # f not used in DS, DS needs to be invalidated though
  986. end
  987. puts D.new.f(1)
  988. puts D.new.f(1,2)
  989. "), @"
  990. f1
  991. f2
  992. error
  993. f2
  994. f1
  995. f2
  996. ");
  997. }
  998. /// <summary>
  999. /// Removing an overload barrier.
  1000. /// </summary>
  1001. public void ClrOverloadInheritance5() {
  1002. OverloadInheritance2.Load(Context);
  1003. AssertOutput(() => CompilerTest(@"
  1004. puts E.new.f(1)
  1005. class C; def f; 'f:C'; end; end
  1006. E.new.f(1) rescue puts 'error'
  1007. puts E.new.f(1,2)
  1008. puts G.new.f(1,2,3,4) # group created after C:f barrier defined
  1009. C.send :remove_method, :f
  1010. puts G.new.f(1)
  1011. puts E.new.f(1)
  1012. "), @"
  1013. f1
  1014. error
  1015. f2
  1016. f4
  1017. f1
  1018. f1
  1019. ");
  1020. }
  1021. /// <summary>
  1022. /// Removing an overload barrier.
  1023. /// </summary>
  1024. public void ClrOverloadInheritance6() {
  1025. OverloadInheritance2.Load(Context);
  1026. TestOutput(@"
  1027. class E; def f; 'f:E'; end; end;
  1028. f = F.new
  1029. puts f.f(1,2,3,4) # creates { f4 } group on F
  1030. class E; remove_method(:f); end # invalidates group on F
  1031. puts f.f(1)
  1032. ", @"
  1033. f4
  1034. f1
  1035. ");
  1036. }
  1037. /// <summary>
  1038. /// Removing an overload barrier.
  1039. /// </summary>
  1040. public void ClrOverloadInheritance7() {
  1041. OverloadInheritance2.Load(Context);
  1042. TestOutput(@"
  1043. D.new.f(1,2) # creates A: {f1} and D: {f1, f2} groups
  1044. class E; def f; 'f:E'; end; end;
  1045. puts F.new.f(1,2,3,4) # creates { f4 } group on F, sets E#f.InvalidateOnRemoval
  1046. class C; def f; 'f:C'; end; end; # invalidates D group, doesn't invalidate F group as it doesn't contain any overloads from above
  1047. class E; remove_method :f; end; # invalidates group on F
  1048. puts F.new.f(1,2)
  1049. puts F.new.f(1,2,3,4)
  1050. F.new.f(1) rescue puts '!f1'
  1051. ", @"
  1052. f4
  1053. f2
  1054. f4
  1055. !f1
  1056. ");
  1057. }
  1058. public void ClrOverloadInheritance_ExtensionMethods1() {
  1059. Runtime.LoadAssembly(Assembly.GetExecutingAssembly());
  1060. OverloadInheritance2.Load(Context);
  1061. TestOutput(@"
  1062. using_clr_extensions IronRubyTests::ExtensionMethods1
  1063. d = D.new
  1064. puts d.f(1) # f1 on A
  1065. puts d.f(1,2,3,4,5) # e5 on C
  1066. puts d.f(1,2,3,4,5,6) # e6 on A
  1067. class B; def f; end; end
  1068. d.f(1) rescue p $! # f1 on A
  1069. puts d.f(1,2,3,4,5) # e5 on C
  1070. d.f(1,2,3,4,5,6) rescue p $! # e6 on A
  1071. class B; remove_method :f; end
  1072. puts d.f(1) # f1 on A
  1073. puts d.f(1,2,3,4,5) # e5 on C
  1074. puts d.f(1,2,3,4,5,6) # e6 on A
  1075. ", @"
  1076. f1
  1077. e5
  1078. e6
  1079. #<ArgumentError: wrong number of arguments (1 for 2)>
  1080. e5
  1081. #<ArgumentError: wrong number of arguments (6 for 5)>
  1082. f1
  1083. e5
  1084. e6
  1085. "
  1086. );
  1087. }
  1088. public void ClrOverloadInheritance_ExtensionMethods2() {
  1089. Runtime.LoadAssembly(Assembly.GetExecutingAssembly());
  1090. OverloadInheritance2.Load(Context);
  1091. TestOutput(@"
  1092. using_clr_extensions nil
  1093. puts F.new.f(1,2,3,4,5,6,7) # no namespace
  1094. using_clr_extensions IronRubyTests::ExtensionMethods1
  1095. puts F.new.f(1,2,3,4) # same signatures => regular method is preferred
  1096. ", @"
  1097. e7
  1098. f4
  1099. "
  1100. );
  1101. }
  1102. public class OverloadInheritance_ClrMembers1 {
  1103. public class A {
  1104. public int foo(int a) { return 1; }
  1105. public int Foo(int a) { return 2; }
  1106. }
  1107. public class B : A {
  1108. public int Foo(short a) { return 3; }
  1109. }
  1110. public class C : B {
  1111. public int foo(bool a) { return 4; }
  1112. }
  1113. public class D : C {
  1114. public int Foo(double a) { return 5; }
  1115. }
  1116. public static void Load(RubyContext/*!*/ context) {
  1117. context.ObjectClass.SetConstant("A", context.GetClass(typeof(A)));
  1118. context.ObjectClass.SetConstant("B", context.GetClass(typeof(B)));
  1119. context.ObjectClass.SetConstant("C", context.GetClass(typeof(C)));
  1120. context.ObjectClass.SetConstant("D", context.GetClass(typeof(D)));
  1121. }
  1122. }
  1123. /// <summary>
  1124. /// Method group should include methods of both casings.
  1125. /// It might depend on the order of method calls what overloads are available otherwise.
  1126. /// D.new.foo finds Foo and
  1127. /// - includes [foo(double), foo(int)] into the group if C.new.foo was invoked previously
  1128. /// - includes [Foo(bool)] into the group otherwise.
  1129. /// </summary>
  1130. public void ClrOverloadInheritance_ClrMembers1() {
  1131. OverloadInheritance_ClrMembers1.Load(Context);
  1132. TestOutput(@"
  1133. p C.new.method(:foo).clr_members.size
  1134. p D.new.method(:foo).clr_members.size
  1135. p A.new.method(:foo).clr_members.size
  1136. p B.new.method(:foo).clr_members.size
  1137. ", @"
  1138. 4
  1139. 5
  1140. 2
  1141. 3
  1142. ");
  1143. TestOutput(@"
  1144. p C.new.method(:Foo).clr_members.size
  1145. p D.new.method(:Foo).clr_members.size
  1146. p A.new.method(:Foo).clr_members.size
  1147. p B.new.method(:Foo).clr_members.size
  1148. ", @"
  1149. 2
  1150. 3
  1151. 1
  1152. 2
  1153. ");
  1154. // prefer overload whose name matches the call site exactly:
  1155. TestOutput(@"
  1156. p A.new.foo(1)
  1157. ", @"
  1158. 1
  1159. ");
  1160. }
  1161. // TODO: CLR overloads
  1162. // - alias/pri/pub/pro/mf/dm/generics/explicit-overload
  1163. public class OverloadedMethods {
  1164. public static string M1(RubyScope scope) {
  1165. return "M1()";
  1166. }
  1167. public static string M1(RubyContext context, MutableString foo) {
  1168. return "M1(String)";
  1169. }
  1170. public static string M1(BinaryOpStorage storage, RubyContext context, double foo) {
  1171. return "M1(Float)";
  1172. }
  1173. public static string M1(int foo, MutableString bar) {
  1174. return "M1(Fixnum, String)";
  1175. }
  1176. public static string M1(MutableString foo, MutableString bar) {
  1177. return "M1(String, String)";
  1178. }
  1179. public static string M1(int foo, params object[] bar) {
  1180. return "M1(Fixnum, Object*)";
  1181. }
  1182. public static string M1(int foo, object bar) {
  1183. return "M1(Fixnum, Object)";
  1184. }
  1185. public static string M1(int foo) {
  1186. return "M1(Fixnum)";
  1187. }
  1188. public static string M2(int foo) {
  1189. return "M2(Fixnum)";
  1190. }
  1191. public static string M2(object foo) {
  1192. return "M2(Object)";
  1193. }
  1194. public static string M2<T>(int foo) {
  1195. return "M2<" + typeof(T).Name + ">(Fixnum)";
  1196. }
  1197. public static string M2<T>(object foo) {
  1198. return "M2<" + typeof(T).Name + ">(Object)";
  1199. }
  1200. }
  1201. public void ClrOverloadSelection1() {
  1202. Context.ObjectClass.SetConstant("OM", Context.GetClass(typeof(OverloadedMethods)));
  1203. AssertOutput(() => CompilerTest(@"
  1204. m = OM.method(:M1)
  1205. puts m.overload.call
  1206. puts m.overload(String).call('')
  1207. puts m.overload(Float).call(1.0)
  1208. puts m.overload(Fixnum, String).call(1, '')
  1209. puts m.overload(String, String).call('', '')
  1210. puts m.overload(Fixnum, System::Array.of(Object)).call(1, 2, 3)
  1211. puts m.overload(Fixnum, Object).call(1, 2)
  1212. puts m.overload(Fixnum).call(1)
  1213. "), @"
  1214. M1()
  1215. M1(String)
  1216. M1(Float)
  1217. M1(Fixnum, String)
  1218. M1(String, String)
  1219. M1(Fixnum, Object*)
  1220. M1(Fixnum, Object)
  1221. M1(Fixnum)
  1222. "
  1223. );
  1224. AssertOutput(() => CompilerTest(@"
  1225. m = OM.method(:M2)
  1226. puts m.clr_members.size
  1227. puts m.of.clr_members.size
  1228. puts m.of(Object).clr_members.size
  1229. puts m.overload(Object).clr_members.size
  1230. puts m.of(Object).overload(Object).clr_members.size
  1231. puts m.overload(Object).of(Object).clr_members.size
  1232. "), @"
  1233. 4
  1234. 2
  1235. 2
  1236. 2
  1237. 1
  1238. 1
  1239. "
  1240. );
  1241. AssertOutput(() => CompilerTest(@"
  1242. m = OM.method(:M2)
  1243. puts m.call(1)
  1244. puts m.of(Float).call('')
  1245. puts m.of(Float).overload(Fixnum).call(1)
  1246. puts m.overload(Object).of(String).call(1)
  1247. "), @"
  1248. M2(Fixnum)
  1249. M2<Double>(Object)
  1250. M2<Double>(Fixnum)
  1251. M2<MutableString>(Object)
  1252. "
  1253. );
  1254. AssertOutput(() => CompilerTest(@"
  1255. m = OM.method(:M2)
  1256. m.overload(Object, String) rescue p $!
  1257. m.overload() rescue p $!
  1258. "), @"
  1259. #<ArgumentError: no overload of `M2' matches given parameter types>
  1260. #<ArgumentError: no overload of `M2' matches given parameter types>
  1261. "
  1262. );
  1263. // overlods called on a Ruby method
  1264. AssertOutput(() => CompilerTest(@"
  1265. def foo a,b
  1266. [a,b]
  1267. end
  1268. def bar a,*b
  1269. [a,*b]
  1270. end
  1271. p method(:foo).overload(Object, Object).call(1,2)
  1272. method(:foo).overload(Object) rescue p $!
  1273. p method(:bar).overload(Object).call(1)
  1274. p method(:bar).overload(Object, Object).call(1,2)
  1275. p method(:bar).overload(Object, Object, Object).call(1,2,3)
  1276. "), @"
  1277. [1, 2]
  1278. #<ArgumentError: no overload of `foo' matches given parameter types>
  1279. [1]
  1280. [1, 2]
  1281. [1, 2, 3]
  1282. "
  1283. );
  1284. // overlods called on a Ruby attribute accessor
  1285. AssertOutput(() => CompilerTest(@"
  1286. class C
  1287. attr_reader :foo
  1288. attr_writer :foo
  1289. c = new
  1290. c.foo = 1
  1291. p instance_method(:foo).overload.bind(c).call
  1292. instance_method(:foo=).overload(Object).bind(c).call(2)
  1293. p c.foo
  1294. end
  1295. "), @"
  1296. 1
  1297. 2
  1298. "
  1299. );
  1300. }
  1301. public static class OverloadSelection2 {
  1302. public class A {
  1303. public A() {
  1304. }
  1305. public A(int a) {
  1306. }
  1307. public A(RubyClass cls, double a) {
  1308. }
  1309. public static int Foo() { return 1; }
  1310. public static int Foo(RubyScope scope, BlockParam block, int a) { return 2; }
  1311. }
  1312. public class B : A {
  1313. public static int Foo(double a) { return 3; }
  1314. public static int Foo(RubyClass cls, string b) { return 4; }
  1315. }
  1316. public static void Load(RubyContext/*!*/ context) {
  1317. context.ObjectClass.SetConstant("A", context.GetClass(typeof(A)));
  1318. context.ObjectClass.SetConstant("B", context.GetClass(typeof(B)));
  1319. }
  1320. }
  1321. public void ClrOverloadSelection2() {
  1322. OverloadSelection2.Load(Context);
  1323. // static methods:
  1324. TestOutput(@"
  1325. m = B.method(:foo)
  1326. puts m.overload(Fixnum).clr_members.size # RubyScope and BlockParam are hidden
  1327. puts m.overload(System::String) rescue p $! # RubyClass is not hidden here
  1328. ", @"
  1329. 1
  1330. #<ArgumentError: no overload of `foo' matches given parameter types>
  1331. ");
  1332. // library methods:
  1333. TestOutput(@"
  1334. m = method(:print)
  1335. puts m.arity
  1336. puts m.overload().arity
  1337. puts m.overload(Object).arity
  1338. puts m.overload(System::Array[Object]).arity
  1339. ", @"
  1340. -1
  1341. 0
  1342. 1
  1343. -1
  1344. ");
  1345. }
  1346. public class ClassWithSlot1 {
  1347. public int Foo() {
  1348. return 1;
  1349. }
  1350. public override string ToString() {
  1351. return "base";
  1352. }
  1353. }
  1354. public class ClassWithNewSlot1 : ClassWithSlot1 {
  1355. public new string ToString() {
  1356. return "subclass";
  1357. }
  1358. public new int Foo() {
  1359. return 2;
  1360. }
  1361. }
  1362. public void ClrNewSlot1() {
  1363. Context.ObjectClass.SetConstant("NewSlot", Context.GetClass(typeof(ClassWithNewSlot1)));
  1364. Context.ObjectClass.SetConstant("Base", Context.GetClass(typeof(ClassWithSlot1)));
  1365. TestOutput(@"
  1366. c = NewSlot.new
  1367. p c.to_string
  1368. p c.clr_member(Object, :to_string).call
  1369. p c.foo
  1370. p c.clr_member(Base, :foo).call
  1371. ", @"
  1372. 'subclass'
  1373. 'base'
  1374. 2
  1375. 1
  1376. ");
  1377. }
  1378. #endregion
  1379. #region Interfaces
  1380. public class ClassWithInterfaces1 : IEnumerable {
  1381. public IEnumerator GetEnumerator() {
  1382. yield return 1;
  1383. yield return 2;
  1384. yield return 3;
  1385. }
  1386. }
  1387. public interface InterfaceFoo1 {
  1388. int Foo();
  1389. }
  1390. public interface InterfaceFoo2 {
  1391. int Foo();
  1392. int this[int i] { get; }
  1393. event Action Evnt;
  1394. int EvntValue { get; }
  1395. }
  1396. public interface InterfaceBar1 {
  1397. int Bar();
  1398. int Bar(int i);
  1399. }
  1400. public interface InterfaceBaz1 {
  1401. int Baz();
  1402. }
  1403. internal class InterfaceClassBase1 {
  1404. // inherited:
  1405. public IEnumerator GetEnumerator() {
  1406. yield return 1;
  1407. yield return 2;
  1408. yield return 3;
  1409. }
  1410. }
  1411. internal class InternalClass1 : InterfaceClassBase1, IEnumerable, IComparable, InterfaceBaz1, InterfaceFoo1, InterfaceFoo2, InterfaceBar1 {
  1412. int _evntValue;
  1413. // simple:
  1414. public int Baz() { return 0; }
  1415. // simple explicit:
  1416. int IComparable.CompareTo(object obj) { return 1; }
  1417. // explicit + implicit
  1418. public int Bar() { return -1; }
  1419. int InterfaceBar1.Bar() { return 2; }
  1420. int InterfaceBar1.Bar(int i) { return 3; }
  1421. // multiple explicit with the same signature
  1422. int InterfaceFoo1.Foo() { return 4; }
  1423. int InterfaceFoo2.Foo() { return 5; }
  1424. // explicit default indexer:
  1425. int InterfaceFoo2.this[int i] { get { return 6; } }
  1426. // explicit property:
  1427. int InterfaceFoo2.EvntValue { get { return _evntValue; } }
  1428. // explicit event:
  1429. event Action InterfaceFoo2.Evnt { add { _evntValue++; } remove { _evntValue--; } }
  1430. }
  1431. public class ClassWithInterfaces2 : ClassWithInterfaces1, IComparable {
  1432. public int CompareTo(object obj) {
  1433. return 0;
  1434. }
  1435. }
  1436. public void ClrInterfaces1() {
  1437. Context.DefineGlobalVariable("obj1", new ClassWithInterfaces1());
  1438. Context.DefineGlobalVariable("obj2", new ClassWithInterfaces2());
  1439. AssertOutput(delegate() {
  1440. CompilerTest(@"
  1441. $obj1.each { |x| print x }
  1442. puts
  1443. $obj2.each { |x| print x }
  1444. puts
  1445. puts($obj2 <=> 1)
  1446. ");
  1447. }, @"
  1448. 123
  1449. 123
  1450. 0
  1451. ");
  1452. }
  1453. /// <summary>
  1454. /// Calling (explicit) interface methods on internal classes.
  1455. /// A method that is accessible via any interface should be called.
  1456. /// If there is more than one then regular overload resolution should kick in.
  1457. /// </summary>
  1458. public void ClrExplicitInterfaces1() {
  1459. Context.ObjectClass.SetConstant("Inst", new InternalClass1());
  1460. Context.ObjectClass.SetConstant("InterfaceFoo1", Context.GetModule(typeof(InterfaceFoo1)));
  1461. Context.ObjectClass.SetConstant("InterfaceFoo2", Context.GetModule(typeof(InterfaceFoo2)));
  1462. Context.ObjectClass.SetConstant("InterfaceBar1", Context.GetModule(typeof(InterfaceBar1)));
  1463. TestOutput(@"
  1464. p Inst.GetEnumerator().nil?
  1465. p Inst.baz
  1466. p Inst.clr_member(System::IComparable, :compare_to).call(nil)
  1467. p Inst.clr_member(InterfaceBar1, :bar).call
  1468. p Inst.clr_member(InterfaceBar1, :bar).call(1)
  1469. p Inst.clr_member(InterfaceFoo1, :foo).call
  1470. p Inst.clr_member(InterfaceFoo2, :foo).call
  1471. p Inst.clr_member(InterfaceFoo2, :[]).call(1)
  1472. p Inst.clr_member(InterfaceFoo2, :evnt_value).call
  1473. Inst.clr_member(InterfaceFoo2, :evnt).call { }
  1474. p Inst.clr_member(InterfaceFoo2, :evnt_value).call
  1475. ", @"
  1476. false
  1477. 0
  1478. 1
  1479. 2
  1480. 3
  1481. 4
  1482. 5
  1483. 6
  1484. 0
  1485. 1
  1486. ");
  1487. }
  1488. #endregion
  1489. #region Types, Trackers, TypeGroups, TypeHandles, Namespaces
  1490. /// <summary>
  1491. /// Type represents a class object - it is equivalent to RubyClass.
  1492. /// </summary>
  1493. public void ClrTypes1() {
  1494. TestTypeAndTracker(typeof(ClassWithMethods1));
  1495. TestTypeAndTracker(ReflectionCache.GetTypeTracker(typeof(ClassWithMethods1)));
  1496. }
  1497. public void TestTypeAndTracker(object type) {
  1498. Context.DefineGlobalVariable("type", type);
  1499. AssertOutput(delegate() {
  1500. CompilerTest(@"
  1501. puts $type
  1502. puts $type.to_s
  1503. puts $type.to_class
  1504. puts $type.to_module
  1505. puts $type.to_class.static_method
  1506. puts $type.static_method rescue puts $!.class
  1507. ");
  1508. }, String.Format(@"
  1509. {0}
  1510. {0}
  1511. {1}
  1512. {1}
  1513. 2
  1514. NoMethodError
  1515. ", type, Context.GetTypeName(typeof(ClassWithMethods1), false)), OutputFlags.Match);
  1516. }
  1517. public void ClrNamespaces1() {
  1518. TestOutput(@"
  1519. puts defined? System::Collections
  1520. module System
  1521. puts defined? Collections
  1522. remove_const(:Collections)
  1523. end
  1524. puts defined? System::Collections
  1525. class System::Collections
  1526. puts self
  1527. end
  1528. ", @"
  1529. constant
  1530. constant
  1531. nil
  1532. System::Collections
  1533. ");
  1534. }
  1535. public void ClrNamespaces2() {
  1536. Runtime.LoadAssembly(typeof(InteropTests.Namespaces2.C).Assembly);
  1537. AssertOutput(() => CompilerTest(@"
  1538. module InteropTests::Namespaces2
  1539. X = 1
  1540. N = 2
  1541. puts defined? C, defined? N, defined? X, constants.sort
  1542. remove_const :C
  1543. remove_const :N
  1544. remove_const :X
  1545. remove_const :C rescue p $!
  1546. remove_const :N rescue p $!
  1547. remove_const :X rescue p $!
  1548. puts defined? C, defined? N, defined? X, constants.sort
  1549. end
  1550. ", 0, 1), @"
  1551. constant
  1552. constant
  1553. constant
  1554. C
  1555. N
  1556. X
  1557. #<NameError: constant InteropTests::Namespaces2::C not defined>
  1558. #<NameError: constant InteropTests::Namespaces2::N not defined>
  1559. #<NameError: constant InteropTests::Namespaces2::X not defined>
  1560. nil
  1561. nil
  1562. nil
  1563. ");
  1564. }
  1565. public void ClrGenerics1() {
  1566. Runtime.LoadAssembly(typeof(Tests).Assembly);
  1567. TestOutput(@"
  1568. include InteropTests::Generics1
  1569. p C
  1570. p D
  1571. p C.new
  1572. p D.new # test if we don't use cached dispatch to C.new again
  1573. p C.clr_new
  1574. p D.clr_new
  1575. p C.superclass
  1576. p D.superclass
  1577. ", @"
  1578. #<TypeGroup: InteropTests::Generics1::C, InteropTests::Generics1::C[T], InteropTests::Generics1::C[T, S]>
  1579. #<TypeGroup: InteropTests::Generics1::D, InteropTests::Generics1::D[T]>
  1580. InteropTests.Generics1.C
  1581. InteropTests.Generics1.D
  1582. InteropTests.Generics1.C
  1583. InteropTests.Generics1.D
  1584. Object
  1585. InteropTests::Generics1::C
  1586. ");
  1587. TestOutput(@"
  1588. include InteropTests::Generics1
  1589. p C.new.arity
  1590. p C[String].new.arity
  1591. p D[String].new.arity
  1592. p C[Fixnum, Fixnum].new.arity
  1593. p D[String]
  1594. p C[Fixnum, Fixnum]
  1595. ", @"
  1596. 0
  1597. 1
  1598. 11
  1599. 2
  1600. InteropTests::Generics1::D[String]
  1601. InteropTests::Generics1::C[Fixnum, Fixnum]
  1602. ");
  1603. TestOutput(@"
  1604. include InteropTests::Generics1
  1605. p C[0]
  1606. p C[1]
  1607. p C[2]
  1608. C[30] rescue p $!
  1609. p C[1][Fixnum]
  1610. p C[Fixnum][]
  1611. p C[Fixnum][0]
  1612. C[Fixnum][Fixnum] rescue p $!
  1613. C[Fixnum][1] rescue p $!
  1614. ", @"
  1615. InteropTests::Generics1::C
  1616. InteropTests::Generics1::C[T]
  1617. InteropTests::Generics1::C[T, S]
  1618. #<ArgumentError: Type group `C' does not contain a type of generic arity 30>
  1619. InteropTests::Generics1::C[Fixnum]
  1620. InteropTests::Generics1::C[Fixnum]
  1621. InteropTests::Generics1::C[Fixnum]
  1622. #<ArgumentError: `InteropTests::Generics1::C[Fixnum]' is not a generic type definition>
  1623. #<ArgumentError: `InteropTests::Generics1::C[Fixnum]' is not a generic type definition>
  1624. ");
  1625. // C<> is a mixin for all its instantiations:
  1626. TestOutput(@"
  1627. include InteropTests::Generics1
  1628. C[1].class_eval do
  1629. def foo
  1630. p self.class
  1631. end
  1632. end
  1633. C[Fixnum].new.foo
  1634. C[String].new.foo
  1635. p C[Float].ancestors[0..2]
  1636. ", @"
  1637. InteropTests::Generics1::C[Fixnum]
  1638. InteropTests::Generics1::C[String]
  1639. [InteropTests::Generics1::C[Float], InteropTests::Generics1::C[T], Object]
  1640. ");
  1641. // It is possible to include a generic type definition into another class. It behaves like a Ruby module.
  1642. // Besides inclusion of a generic interface instantiation transitively includes its generic type definition.
  1643. TestOutput(@"
  1644. include InteropTests::Generics1
  1645. class ClassA
  1646. include C[1]
  1647. include I[1]
  1648. p ancestors
  1649. new
  1650. end
  1651. class ClassB
  1652. include C[Fixnum] rescue p $!
  1653. include I[Fixnum]
  1654. p ancestors
  1655. new
  1656. end
  1657. ", @"
  1658. [ClassA, InteropTests::Generics1::I[T], InteropTests::Generics1::C[T], Object, InteropTests::Generics1, Kernel, BasicObject]
  1659. #<TypeError: wrong argument type Class (expected Module)>
  1660. [ClassB, InteropTests::Generics1::I[Fixnum], InteropTests::Generics1::I[T], Object, InteropTests::Generics1, Kernel, BasicObject]
  1661. ");
  1662. // generic type definitions cannot be instantiated and don't expose their methods:
  1663. TestOutput(@"
  1664. include InteropTests::Generics1
  1665. p C[Fixnum].new.method(:Arity)
  1666. C[1].new rescue p $!
  1667. C[1].instance_method(:Arity) rescue p $!
  1668. ", @"
  1669. #<Method: InteropTests::Generics1::C[Fixnum]#Arity>
  1670. #<NoMethodError: undefined method `new' for InteropTests::Generics1::C[T]:Module>
  1671. #<NameError: undefined method `Arity' for module `InteropTests::Generics1::C[T]'>
  1672. ");
  1673. }
  1674. public class GenericClass1<T> {
  1675. public int Foo(T item) {
  1676. return 1;
  1677. }
  1678. }
  1679. public class GenericSubclass1<T> : GenericClass1<T> {
  1680. }
  1681. public void ClrGenerics2() {
  1682. Context.ObjectClass.SetConstant("T", Context.GetClass(GetType()));
  1683. // CLR methods with generic arguments defined on a generic type don't get duplicated:
  1684. // (C<T> inherits from C<> but the generic type definition should be ignored when looking for CLR method overloads):
  1685. TestOutput(@"
  1686. p T::GenericClass1[Fixnum].new.foo(1)
  1687. p T::GenericSubclass1[Fixnum].new.foo(1)
  1688. ", @"
  1689. 1
  1690. 1
  1691. ");
  1692. }
  1693. public class ClassWithNestedGenericTypes1 {
  1694. public class D {
  1695. }
  1696. // the order of C<T> and C is important to test (we used to have a dependency on the order);
  1697. // (see http://ironruby.codeplex.com/workitem/5037)
  1698. public class C<T> {
  1699. public int Id { get { return 1; } }
  1700. }
  1701. public class C {
  1702. public int Id { get { return 0; } }
  1703. }
  1704. }
  1705. public class ClassWithNestedGenericTypes2 : ClassWithNestedGenericTypes1 {
  1706. public new class C<T> {
  1707. public int Id { get { return 2; } }
  1708. }
  1709. public class C<T, S> {
  1710. public int Id { get { return 3; } }
  1711. }
  1712. }
  1713. public void ClrGenerics3() {
  1714. Context.ObjectClass.SetConstant("C1", Context.GetClass(typeof(ClassWithNestedGenericTypes1)));
  1715. Context.ObjectClass.SetConstant("C2", Context.GetClass(typeof(ClassWithNestedGenericTypes2)));
  1716. AssertOutput(() => CompilerTest(@"
  1717. p C1::D
  1718. p C1::C
  1719. p C2::C
  1720. "), @"
  1721. *::ClassWithNestedGenericTypes1::D
  1722. #<TypeGroup: *::ClassWithNestedGenericTypes1::C, *::ClassWithNestedGenericTypes1::C[T]>
  1723. #<TypeGroup: *::ClassWithNestedGenericTypes2::C[T], *::ClassWithNestedGenericTypes2::C[T, S]>
  1724. ", OutputFlags.Match);
  1725. }
  1726. #endregion
  1727. #region Delegates, Events
  1728. public delegate int Delegate1(string foo, int bar);
  1729. public void ClrDelegates1() {
  1730. Context.DefineGlobalVariable("delegateType", typeof(Delegate1));
  1731. CompilerTest(@"
  1732. D = $delegateType.to_class
  1733. $d = D.new { |foo, bar| $foo = foo; $bar = bar; 777 }
  1734. ");
  1735. object d = Context.GetGlobalVariable("d");
  1736. Assert(d is Delegate1);
  1737. AssertEquals(((Delegate1)d)("hello", 123), 777);
  1738. AssertEquals(Context.GetGlobalVariable("foo"), "hello");
  1739. AssertEquals(Context.GetGlobalVariable("bar"), 123);
  1740. }
  1741. public void ClrDelegates2() {
  1742. Runtime.LoadAssembly(typeof(Func<>).Assembly);
  1743. var f = Engine.Execute<Func<int, int>>(FuncFullName + @".of(Fixnum, Fixnum).new { |a| a + 1 }");
  1744. Assert(f(1) == 2);
  1745. Engine.Execute<Action>(ActionFullName + @".new { $x = 1 }")();
  1746. Assert((int)Context.GetGlobalVariable("x") == 1);
  1747. Engine.Execute<Action<int, int>>(ActionFullName + @"[Fixnum, Fixnum].new { |x,y| $x = x + y }")(10, 1);
  1748. Assert((int)Context.GetGlobalVariable("x") == 11);
  1749. AssertExceptionThrown<LocalJumpError>(() => Engine.Execute(ActionFullName + @".new(&nil)"));
  1750. }
  1751. public void ClrEvents1() {
  1752. // TODO:
  1753. if (_driver.PartialTrust) return;
  1754. AssertOutput(delegate() {
  1755. CompilerTest(@"
  1756. require 'System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
  1757. require 'System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
  1758. Form = System::Windows::Forms::Form
  1759. f = Form.new
  1760. x = 'outer var'
  1761. f.shown do |sender, args|
  1762. puts x
  1763. sender.close
  1764. end
  1765. f.Text = 'hello'
  1766. f.BackColor = System::Drawing::Color.Green
  1767. System::Windows::Forms::Application.run f
  1768. ");
  1769. }, "outer var");
  1770. }
  1771. public class ClassWithEvents {
  1772. public event Action<string, string> OnFoo;
  1773. public bool Foo() {
  1774. if (OnFoo != null) {
  1775. OnFoo("hello", "world");
  1776. return true;
  1777. } else {
  1778. return false;
  1779. }
  1780. }
  1781. }
  1782. // TODO: method comparison
  1783. public void ClrEvents2() {
  1784. Context.DefineGlobalVariable("e", new ClassWithEvents());
  1785. AssertOutput(() => CompilerTest(@"
  1786. def handler a,b
  1787. puts ""handler: #{a} #{b}""
  1788. end
  1789. h = method(:handler)
  1790. $e.on_foo.add(h)
  1791. puts $e.foo
  1792. $e.on_foo.remove(h)
  1793. puts $e.foo
  1794. "), @"
  1795. handler: hello world
  1796. true
  1797. false
  1798. ");
  1799. }
  1800. public void ClrEvents3() {
  1801. Context.DefineGlobalVariable("e", new ClassWithEvents());
  1802. AssertOutput(() => CompilerTest(@"
  1803. h = $e.on_foo do |a,b|
  1804. puts ""handler: #{a} #{b}""
  1805. end
  1806. p h.class
  1807. puts $e.foo
  1808. $e.on_foo.remove(h)
  1809. puts $e.foo
  1810. "), @"
  1811. Proc
  1812. handler: hello world
  1813. true
  1814. false
  1815. ");
  1816. }
  1817. public void ClrEvents4() {
  1818. Context.DefineGlobalVariable("e", new ClassWithEvents());
  1819. AssertOutput(() => CompilerTest(@"
  1820. handler = lambda do |a,b|
  1821. puts ""handler: #{a} #{b}""
  1822. end
  1823. p $e.on_foo(&handler) == handler
  1824. puts $e.foo
  1825. $e.on_foo.remove(handler)
  1826. puts $e.foo
  1827. "), @"
  1828. true
  1829. handler: hello world
  1830. true
  1831. false
  1832. ");
  1833. }
  1834. public class ClassWithVirtualEvent1 {
  1835. public virtual event Func<int, int> OnEvent;
  1836. public int Fire(int arg) {
  1837. return OnEvent(arg);
  1838. }
  1839. }
  1840. public void ClrEventImpl1() {
  1841. // TODO: fix
  1842. if (_driver.PartialTrust) return;
  1843. Context.ObjectClass.SetConstant("E", Context.GetClass(typeof(ClassWithVirtualEvent1)));
  1844. var f = Engine.Execute<ClassWithVirtualEvent1>(@"
  1845. class F < E
  1846. def add_OnEvent handler
  1847. puts 'add ' + handler.inspect
  1848. super
  1849. end
  1850. def remove_OnEvent handler
  1851. puts 'remove ' + handler.inspect
  1852. super
  1853. end
  1854. end
  1855. F.new
  1856. ");
  1857. var handler = new Func<int, int>((i) => i + 1);
  1858. string func = typeof(Func<,>).FullName;
  1859. AssertOutput(() => f.OnEvent += handler, @"add "+ func + "[System.Int32,System.Int32]");
  1860. var r = f.Fire(10);
  1861. Assert(r == 11);
  1862. AssertOutput(() => f.OnEvent -= handler, @"remove " + func + "[System.Int32,System.Int32]");
  1863. TestOutput(@"
  1864. f = F.new
  1865. f.on_event { |x| x * 2 }
  1866. puts f.fire(10)
  1867. ", String.Format(@"
  1868. add {0}[System.Int32,System.Int32]
  1869. 20
  1870. ", func));
  1871. }
  1872. #endregion
  1873. #region Value Types
  1874. public struct S2 {
  1875. public int X;
  1876. public int Y;
  1877. public S2(int x, int y) {
  1878. X = x;
  1879. Y = y;
  1880. }
  1881. public void SetX() {
  1882. X = 1;
  1883. }
  1884. }
  1885. public void ClrValueTypes1() {
  1886. object s = new S2(3, 4);
  1887. Context.ObjectClass.SetConstant("Inst", s);
  1888. Engine.Execute("Inst.X = 10");
  1889. S2 unboxed = (S2)s;
  1890. Assert(unboxed.X == 10);
  1891. Assert(unboxed.Y == 4);
  1892. Engine.Execute("Inst.SetX");
  1893. unboxed = (S2)s;
  1894. Assert(unboxed.X == 1);
  1895. Assert(unboxed.Y == 4);
  1896. }
  1897. public class ClassWithValueTypeField1 {
  1898. public S2 Value = new S2(1, 2);
  1899. }
  1900. // TODO: unsupported
  1901. //
  1902. // If a mutable value type is embedded into an array or an object instance as a field the element/field access operation
  1903. // returns a boxed value. It could return a dynamic proxy object that forwards all calls to the original storage.
  1904. //
  1905. public void ClrValueTypes2() {
  1906. S2[] array = new[] { new S2(1, 2), new S2(3, 4), new S2(5, 6) };
  1907. var inst = new ClassWithValueTypeField1();
  1908. Context.ObjectClass.SetConstant("Ary", array);
  1909. Context.ObjectClass.SetConstant("Inst", inst);
  1910. Engine.Execute("Ary[1].X, Inst.Value.X = 10, 10");
  1911. Assert(array[1].X == 3); // TODO: should be 10
  1912. Assert(array[1].Y == 4);
  1913. Assert(inst.Value.X == 1); // TODO: should be 10
  1914. Assert(inst.Value.Y == 2);
  1915. }
  1916. #endregion
  1917. #region Virtual method overrides
  1918. public class ClassWithVirtuals {
  1919. public virtual string M1() {
  1920. return "CM1 ";
  1921. }
  1922. public virtual string M2() {
  1923. return "CM2 ";
  1924. }
  1925. public virtual string P1 {
  1926. get { return "CP1 "; }
  1927. }
  1928. private string _p2 = "CP2 ";
  1929. public virtual string P2 {
  1930. get { return _p2; }
  1931. set { _p2 = value; }
  1932. }
  1933. public virtual string P3 {
  1934. get { return "CP3 "; }
  1935. }
  1936. public string Summary {
  1937. get { return M1() + M2() + P1 + P2 + P3; }
  1938. }
  1939. }
  1940. public void ClrOverride1() {
  1941. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithVirtuals)));
  1942. TestOutput(@"
  1943. class D < C
  1944. def m1 # mangled name works
  1945. 'RM1 '
  1946. end
  1947. def p2= value
  1948. end
  1949. def P3 # unmangled name works as well
  1950. 'RP3 '
  1951. end
  1952. end
  1953. c = C.new
  1954. c.p2 = 'RP2 '
  1955. puts c.summary
  1956. d = D.new
  1957. d.p2 = 'RP2 '
  1958. puts d.summary
  1959. ", @"
  1960. CM1 CM2 CP1 RP2 CP3
  1961. RM1 CM2 CP1 CP2 RP3
  1962. ");
  1963. }
  1964. /// <summary>
  1965. /// Virtual methods of built-in types cannot be overridden.
  1966. /// </summary>
  1967. public void ClrOverride2() {
  1968. var e = Engine.Execute<Exception>(@"
  1969. class E < Exception
  1970. def data; 123; end
  1971. new
  1972. end
  1973. ");
  1974. Assert(e.Data is IDictionary);
  1975. object obj = Engine.Execute(@"
  1976. class C < Object
  1977. def equals(other); raise; end
  1978. new
  1979. end
  1980. ");
  1981. Assert(obj.Equals(obj));
  1982. }
  1983. public class ClassCallingVirtualInCtor1 {
  1984. public ClassCallingVirtualInCtor1() {
  1985. VirtualMethod();
  1986. }
  1987. public virtual int VirtualMethod() {
  1988. return 1;
  1989. }
  1990. }
  1991. /// <summary>
  1992. /// We need to fully initialize the derived type before calling base ctor.
  1993. /// The ebase ctor can call virtual methods that require _class to be set.
  1994. /// </summary>
  1995. public void ClrOverride3() {
  1996. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassCallingVirtualInCtor1)));
  1997. TestOutput(@"
  1998. class D < C
  1999. end
  2000. p D.new.virtual_method
  2001. ", @"
  2002. 1
  2003. ");
  2004. }
  2005. /// <summary>
  2006. /// Super call in an override.
  2007. /// </summary>
  2008. public void ClrOverride4() {
  2009. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassCallingVirtualInCtor1)));
  2010. TestOutput(@"
  2011. class D < C
  2012. def virtual_method
  2013. 10 + super
  2014. end
  2015. end
  2016. class E < C
  2017. def VirtualMethod
  2018. 20 + super
  2019. end
  2020. end
  2021. p D.new.VirtualMethod
  2022. p E.new.virtual_method
  2023. ", @"
  2024. 11
  2025. 21
  2026. ");
  2027. }
  2028. public class ClassWithProperties {
  2029. private int _prop;
  2030. private int[] _values = new int[1];
  2031. public virtual int Prop {
  2032. get { return _prop; }
  2033. set { _prop = value; }
  2034. }
  2035. public virtual int this[int i] {
  2036. get { return _values[i]; }
  2037. set { _values[i] = value; }
  2038. }
  2039. public int[] Report() {
  2040. Prop = 10;
  2041. this[0] = 20;
  2042. return new int[] { Prop, _prop, this[0], _values[0] };
  2043. }
  2044. }
  2045. public void ClrOverride5() {
  2046. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithProperties)));
  2047. TestOutput(@"
  2048. class D < C
  2049. end
  2050. p D.new.report
  2051. class D < C
  2052. def prop
  2053. 4
  2054. end
  2055. def prop= value
  2056. super(5)
  2057. end
  2058. def [] index
  2059. 6
  2060. end
  2061. def []= index, value
  2062. super(index, 7)
  2063. end
  2064. end
  2065. p D.new.report
  2066. ", @"
  2067. [10, 10, 20, 20]
  2068. [4, 5, 6, 7]
  2069. ");
  2070. }
  2071. public class ClassWithVirtuals1 {
  2072. public virtual int Foo() { return 1; }
  2073. public virtual int Goo() { return 20; }
  2074. protected int Prot() { return 1000; }
  2075. public virtual int Bar() { return 1; }
  2076. }
  2077. public class ClassWithVirtuals2 : ClassWithVirtuals1 {
  2078. public int Report() {
  2079. return Foo() + Goo();
  2080. }
  2081. public sealed override int Goo() { return 30; }
  2082. public override int Bar() { return 2; }
  2083. }
  2084. public class ClassWithVirtuals3 : ClassWithVirtuals2 {
  2085. public override int Bar() { return 3; }
  2086. }
  2087. public interface I1 { int f(); }
  2088. public interface I2 { int g(); }
  2089. public void ClrOverride6() {
  2090. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithVirtuals2)));
  2091. Context.ObjectClass.SetConstant("I1", Context.GetModule(typeof(I1)));
  2092. Context.ObjectClass.SetConstant("I2", Context.GetModule(typeof(I2)));
  2093. TestOutput(@"
  2094. class D < C
  2095. include I1
  2096. end
  2097. class E < D
  2098. include I2
  2099. def foo
  2100. super + 100
  2101. end
  2102. def goo
  2103. super + prot
  2104. end
  2105. end
  2106. p E.new.report
  2107. p E.new.goo
  2108. ", @"
  2109. 131
  2110. 1030
  2111. ");
  2112. AssertOutput(() => CompilerTest(@"
  2113. class C
  2114. def bar
  2115. super + 100
  2116. end
  2117. end
  2118. C.new.bar rescue p $!
  2119. "), @"
  2120. #<NoMethodError: Virtual CLR method `bar' called via super from *; Super calls to virtual CLR methods can only be used in a Ruby subclass of the class declaring the method>
  2121. ", OutputFlags.Match);
  2122. }
  2123. /// <summary>
  2124. /// See RubyMethodGroupBase.BuildCallNoFlow.
  2125. /// </summary>
  2126. public void ClrDetachedVirtual1() {
  2127. TestOutput(@"
  2128. class C < System::Collections::ArrayList
  2129. define_method(:Count, instance_method(:Count))
  2130. end
  2131. p C.new.Count
  2132. ", @"
  2133. 0
  2134. ");
  2135. }
  2136. public class ClassWithToStringHashEquals1 {
  2137. public override string ToString() {
  2138. return "b";
  2139. }
  2140. public override int GetHashCode() {
  2141. return 1234;
  2142. }
  2143. public int Foo() {
  2144. return 10;
  2145. }
  2146. public int Field = 11;
  2147. public override bool Equals(object obj) {
  2148. return obj is int && (int)obj == 0;
  2149. }
  2150. }
  2151. public void ClrHashEqualsToString1() {
  2152. Test_HashEqlToString("get_hash_code", "equals", "to_string");
  2153. }
  2154. public void ClrHashEqualsToString2() {
  2155. Test_HashEqlToString("GetHashCode", "Equals", "ToString");
  2156. }
  2157. public void ClrHashEqualsToString3() {
  2158. Test_HashEqlToString("hash", "eql?", "to_s");
  2159. }
  2160. private void Test_HashEqlToString(string/*!*/ hashMethodName, string/*!*/ equalsMethodName, string/*!*/ toStringMethodName) {
  2161. Engine.Runtime.Globals.SetVariable("B", Context.GetClass(typeof(ClassWithToStringHashEquals1)));
  2162. var objs = Engine.Execute<RubyArray>(String.Format(@"
  2163. class Object
  2164. # Object.to_string is not defined by default since Object is a built-in class, so let's alias it
  2165. alias to_string ToString
  2166. end
  2167. class C
  2168. def {0}
  2169. 789
  2170. end
  2171. def {1}(other)
  2172. other == 1
  2173. end
  2174. def {2}
  2175. 'c'
  2176. end
  2177. end
  2178. class D
  2179. end
  2180. class E < B
  2181. end
  2182. class F < B
  2183. def {0}
  2184. 1000
  2185. end
  2186. def {1}(other)
  2187. other == 2
  2188. end
  2189. def {2}
  2190. 'f'
  2191. end
  2192. end
  2193. [C.new, D.new, E.new, F.new, E.new.{0}, E.new.{1}(0), D.new.{2}, E.new.{2}]
  2194. ", hashMethodName, equalsMethodName, toStringMethodName));
  2195. object c = objs[0], d = objs[1], e = objs[2], f = objs[3];
  2196. object eHash = objs[4], eEquals = objs[5], dToString = objs[6], eToString = objs[7];
  2197. int h = c.GetHashCode();
  2198. string s = c.ToString();
  2199. Assert(h == 789);
  2200. Assert(c.Equals(1));
  2201. Assert(s == "c");
  2202. h = d.GetHashCode();
  2203. s = d.ToString();
  2204. Assert(h == RuntimeHelpers.GetHashCode(objs[1]));
  2205. Assert(d.Equals(d) && !d.Equals(1));
  2206. Assert(s.StartsWith("#<D:0x") && s.EndsWith(">"));
  2207. h = e.GetHashCode();
  2208. s = e.ToString();
  2209. Assert(h == 1234);
  2210. Assert(e.Equals(0));
  2211. Assert(s == "b");
  2212. h = f.GetHashCode();
  2213. s = f.ToString();
  2214. Assert(h == 1000);
  2215. Assert(f.Equals(2));
  2216. Assert(s == "f");
  2217. Assert((int)eHash == 1234);
  2218. Assert((bool)eEquals);
  2219. string dToStringStr, eToStringStr;
  2220. if (toStringMethodName == "to_s") {
  2221. dToStringStr = ((MutableString)dToString).ToString();
  2222. eToStringStr = ((MutableString)eToString).ToString();
  2223. } else {
  2224. dToStringStr = (string)dToString;
  2225. eToStringStr = (string)eToString;
  2226. }
  2227. Assert(dToStringStr.StartsWith("#<D:0x") && dToStringStr.EndsWith(">"));
  2228. Assert(eToStringStr == "b");
  2229. // special ToString cases:
  2230. var range = new Range(1, 2, true);
  2231. Assert(range.ToString() == "1...2");
  2232. var regex = new RubyRegex(MutableString.CreateAscii("hello"), RubyRegexOptions.IgnoreCase | RubyRegexOptions.Multiline);
  2233. Assert(regex.ToString() == "(?mi-x:hello)");
  2234. }
  2235. public class EmptyClass1 {
  2236. }
  2237. public void ClrToString1() {
  2238. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(EmptyClass1)));
  2239. AssertOutput(() => CompilerTest(@"
  2240. class D; include System::Collections::Generic::IList[Fixnum]; end
  2241. class E < C; include System::Collections::Generic::IList[Fixnum]; end
  2242. class F; end
  2243. p D.new, E.new, F.new
  2244. "), @"
  2245. #<D:0x*>
  2246. #<E:0x*>
  2247. #<F:0x*>
  2248. ", OutputFlags.Match);
  2249. }
  2250. public void ClrHashEquals4() {
  2251. var e = new RubyObject(Context.ObjectClass);
  2252. int h;
  2253. Engine.Runtime.Globals.SetVariable("B", Context.GetClass(typeof(ClassWithToStringHashEquals1)));
  2254. Engine.Runtime.Globals.SetVariable("Empty", e);
  2255. // removing GetHashCode doesn't cause infinite recursion (Kernel#hash call doesn't dynamically dispatch to GHC):
  2256. h = Engine.Execute<int>(@"
  2257. class Object
  2258. remove_method :GetHashCode
  2259. end
  2260. Empty.hash
  2261. ");
  2262. Assert(h == RuntimeHelpers.GetHashCode(e));
  2263. // Z#eql? calls Kernel#== which should not do virtual dynamic dispatch to Equals since that would call eql? again.
  2264. bool b = Engine.Execute<bool>(@"
  2265. class Z
  2266. def eql?(other)
  2267. self == other
  2268. end
  2269. end
  2270. Z.eql?(1)
  2271. ");
  2272. Assert(!b);
  2273. // detached method groups should be considered user-defined methods:
  2274. var objs = Engine.Execute<RubyArray>(@"
  2275. class C < B
  2276. alias hash foo
  2277. end
  2278. class D < B
  2279. define_method(:hash, instance_method(:field))
  2280. end
  2281. [C.new, D.new]
  2282. ");
  2283. object c = objs[0], d = objs[1];
  2284. h = c.GetHashCode();
  2285. Assert(h == 10);
  2286. h = d.GetHashCode();
  2287. Assert(h == 11);
  2288. }
  2289. #endregion
  2290. #region Constructors
  2291. /// <summary>
  2292. /// Instantiation.
  2293. /// </summary>
  2294. public void ClrNew1() {
  2295. AssertOutput(delegate() {
  2296. CompilerTest(@"
  2297. require 'mscorlib'
  2298. b = System::Text::StringBuilder.new
  2299. b.Append 1
  2300. b.Append '-'
  2301. b.Append true
  2302. puts b.to_string
  2303. puts b.length
  2304. ");
  2305. }, @"
  2306. 1-True
  2307. 6
  2308. ");
  2309. }
  2310. public void ClrNew2() {
  2311. TestOutput(@"
  2312. puts c = Thread.clr_ctor
  2313. puts c.overload(System::Threading::ThreadStart).call(lambda { puts 'hello' }).status
  2314. puts Thread.clr_new(System::Threading::ThreadStart.new(lambda { puts 'hello' })).status
  2315. ", @"
  2316. #<Method: Class(Thread)#.ctor>
  2317. unstarted
  2318. unstarted
  2319. ");
  2320. }
  2321. public class ClassWithNonEmptyConstructor {
  2322. public int P { get; set; }
  2323. public ClassWithNonEmptyConstructor() {
  2324. }
  2325. public ClassWithNonEmptyConstructor(BinaryOpStorage storage, RubyScope scope, RubyClass self, string p) {
  2326. }
  2327. public ClassWithNonEmptyConstructor(RubyContext context, int i) {
  2328. P = i;
  2329. }
  2330. public ClassWithNonEmptyConstructor(RubyContext context, RubyClass cls1, RubyClass cls2) {
  2331. }
  2332. }
  2333. public class ClassWithNonEmptyConstructor2 {
  2334. public int P { get; set; }
  2335. public ClassWithNonEmptyConstructor2() {
  2336. P = 0;
  2337. }
  2338. public ClassWithNonEmptyConstructor2(RubyClass cls) {
  2339. P = 1;
  2340. }
  2341. public ClassWithNonEmptyConstructor2(RubyContext context) {
  2342. P = 2;
  2343. }
  2344. }
  2345. public class ExceptionWithDefaultConstructor1 : Exception {
  2346. public ExceptionWithDefaultConstructor1() {
  2347. }
  2348. }
  2349. public class ExceptionWithStdConstructors1 : Exception {
  2350. public int P { get; set; }
  2351. public ExceptionWithStdConstructors1() {
  2352. P = 0;
  2353. }
  2354. public ExceptionWithStdConstructors1(string message) : base(message) {
  2355. P = 1;
  2356. }
  2357. }
  2358. public class ClassWithNoDefaultConstructor {
  2359. public string P { get; set; }
  2360. public ClassWithNoDefaultConstructor(string p) {
  2361. P = p;
  2362. }
  2363. }
  2364. private static bool IsCtorAvailable(RubyClass cls, params Type[] parameters) {
  2365. var method = cls.GetUnderlyingSystemType().GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, parameters, null);
  2366. return method != null && !method.IsPrivate && !method.IsFamilyAndAssembly;
  2367. }
  2368. public void ClrConstructor1() {
  2369. Context.ObjectClass.SetConstant("C1", Context.GetClass(typeof(ClassWithNonEmptyConstructor)));
  2370. var cls1 = Engine.Execute<RubyClass>("class D1 < C1; self; end");
  2371. Assert(IsCtorAvailable(cls1, typeof(RubyClass)));
  2372. Assert(IsCtorAvailable(cls1, typeof(BinaryOpStorage), typeof(RubyScope), typeof(RubyClass), typeof(string)));
  2373. Assert(IsCtorAvailable(cls1, typeof(RubyClass), typeof(int)));
  2374. Assert(IsCtorAvailable(cls1, typeof(RubyClass), typeof(RubyClass), typeof(RubyClass)));
  2375. Context.ObjectClass.SetConstant("C2", Context.GetClass(typeof(ClassWithNonEmptyConstructor2)));
  2376. var cls2 = Engine.Execute<RubyClass>("class D2 < C2; self; end");
  2377. Assert(IsCtorAvailable(cls2, typeof(RubyClass)));
  2378. Assert(!IsCtorAvailable(cls2, typeof(RubyContext)));
  2379. Assert(!IsCtorAvailable(cls2));
  2380. Assert(Engine.Execute<int>("D2.new.p") == 1);
  2381. Context.ObjectClass.SetConstant("E1", Context.GetClass(typeof(ExceptionWithDefaultConstructor1)));
  2382. var ex1 = Engine.Execute<RubyClass>("class F1 < E1; self; end");
  2383. Assert(IsCtorAvailable(ex1, typeof(RubyClass)));
  2384. Context.ObjectClass.SetConstant("E2", Context.GetClass(typeof(ExceptionWithStdConstructors1)));
  2385. var ex2 = Engine.Execute<RubyClass>("class F2 < E2; self; end");
  2386. Assert(IsCtorAvailable(ex2, typeof(RubyClass)));
  2387. Assert(IsCtorAvailable(ex2, typeof(RubyClass), typeof(string)));
  2388. Assert(Engine.Execute<int>("F2.new.p") == 1);
  2389. }
  2390. public void ClrConstructor2() {
  2391. Context.ObjectClass.SetConstant("DefaultAndParam", Context.GetClass(typeof(ClassWithNonEmptyConstructor)));
  2392. AssertOutput(delegate() {
  2393. CompilerTest(@"
  2394. class D < DefaultAndParam; end
  2395. d = D.new 123
  2396. puts d.p
  2397. ");
  2398. }, @"
  2399. 123
  2400. ");
  2401. }
  2402. public class ClassWithDefaultAndParamConstructor {
  2403. public string P { get; set; }
  2404. public ClassWithDefaultAndParamConstructor() {
  2405. }
  2406. public ClassWithDefaultAndParamConstructor(string p) {
  2407. P = p;
  2408. }
  2409. }
  2410. public void ClrConstructor3() {
  2411. Context.ObjectClass.SetConstant("DefaultAndParam", Context.GetClass(typeof(ClassWithDefaultAndParamConstructor)));
  2412. Context.ObjectClass.SetConstant("NoDefault", Context.GetClass(typeof(ClassWithNoDefaultConstructor)));
  2413. AssertOutput(delegate() {
  2414. CompilerTest(@"
  2415. module I
  2416. def initialize(arg)
  2417. self.p = arg
  2418. puts 'init'
  2419. end
  2420. end
  2421. class D < DefaultAndParam
  2422. include I
  2423. end
  2424. class E < NoDefault
  2425. include I
  2426. end
  2427. class F < NoDefault
  2428. def self.new(*args)
  2429. puts 'ctor'
  2430. super args.join(' ')
  2431. end
  2432. end
  2433. puts D.new('test').p
  2434. E.new('test').p rescue p $!
  2435. puts F.new('hello', 'world').p
  2436. ");
  2437. }, @"
  2438. init
  2439. test
  2440. #<TypeError: can't allocate class `E' that derives from type `*::ClassWithNoDefaultConstructor' with no default constructor; define E#new singleton method instead of I#initialize>
  2441. ctor
  2442. hello world
  2443. ", OutputFlags.Match);
  2444. }
  2445. public class ClassWithInitialize {
  2446. public virtual string Initialize(int x) {
  2447. return "Init";
  2448. }
  2449. }
  2450. public void ClrConstructor4() {
  2451. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithInitialize)));
  2452. // C# Initialize is not called (argument is not needed):
  2453. Engine.Execute(@"class D < C; new; end");
  2454. TestOutput(@"
  2455. class E < C
  2456. def initialize
  2457. puts 'init'
  2458. end
  2459. end
  2460. e = E.new
  2461. puts e.Initialize(1)
  2462. e.send :initialize
  2463. ", @"
  2464. init
  2465. Init
  2466. init
  2467. ");
  2468. }
  2469. public struct Struct1 {
  2470. public int Foo;
  2471. }
  2472. public void ClrConstructor5() {
  2473. Context.ObjectClass.SetConstant("S", Context.GetClass(typeof(Struct1)));
  2474. var s = Engine.Execute(@"S.new");
  2475. Assert(s is Struct1);
  2476. }
  2477. #endregion
  2478. #region CLR Primitive Types: Numeric, Arrays, Char, Enums
  2479. /// <summary>
  2480. /// TODO: Currently we don't narrow results of arithmetic operations to the self-type even if the value fits.
  2481. /// That might by just fine, but in some scenarios (overload resolution) it might be better to narrow the result type.
  2482. /// Shelveset "Numerics-MetaOpsWithNarrowing" contains prototype implementation of the narrowing.
  2483. /// </summary>
  2484. public void ClrPrimitiveNumericTypes1() {
  2485. TestOutput(@"
  2486. [System::Byte, System::SByte, System::UInt16, System::Int16, System::UInt32, System::Int64, System::UInt64, System::Single].each_with_index do |t,i|
  2487. p t.ancestors
  2488. p t.new(i).class
  2489. p x = t.new(i) + 1, x.class
  2490. p t.new(i).size rescue puts 'no size method'
  2491. end
  2492. ",
  2493. @"
  2494. [System::Byte, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2495. System::Byte
  2496. 1
  2497. Fixnum
  2498. 1
  2499. [System::SByte, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2500. System::SByte
  2501. 2
  2502. Fixnum
  2503. 1
  2504. [System::UInt16, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2505. System::UInt16
  2506. 3
  2507. Fixnum
  2508. 2
  2509. [System::Int16, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2510. System::Int16
  2511. 4
  2512. Fixnum
  2513. 2
  2514. [System::UInt32, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2515. System::UInt32
  2516. 5
  2517. Fixnum
  2518. 4
  2519. [System::Int64, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2520. System::Int64
  2521. 6
  2522. Fixnum
  2523. 8
  2524. [System::UInt64, Integer, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2525. System::UInt64
  2526. 7
  2527. Fixnum
  2528. 8
  2529. [System::Single, Precision, Numeric, Comparable, Object, Kernel, BasicObject]
  2530. System::Single
  2531. 8.0
  2532. Float
  2533. no size method
  2534. ");
  2535. }
  2536. public void ClrArrays1() {
  2537. Runtime.Globals.SetVariable("A2", Context.GetClass(typeof(int[,])));
  2538. TestOutput(@"
  2539. # multi-dim array:
  2540. a2 = A2.new(2,4)
  2541. a2[0,1] = 123
  2542. p a2[0,1]
  2543. # vectors:
  2544. p System::Array[Fixnum].new(10) { |i| i + 1 }
  2545. p System::Array[Fixnum].new(3)
  2546. p System::Array[Fixnum].new([1,2,3])
  2547. p System::Array[Fixnum].new(3, 12)
  2548. ", @"
  2549. 123
  2550. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  2551. [0, 0, 0]
  2552. [1, 2, 3]
  2553. [12, 12, 12]
  2554. ");
  2555. }
  2556. public void ClrArrays2() {
  2557. TestOutput(@"
  2558. class C
  2559. def to_str
  2560. 'c'
  2561. end
  2562. end
  2563. a = System::Array[System::String].new(3)
  2564. a[0] = 'x'
  2565. a[1] = C.new
  2566. a[2] = :z
  2567. p a
  2568. p System::Array[System::String].new(3, C.new)
  2569. p System::Array[System::String].new([C.new, C.new])
  2570. p System::Array[System::Byte].new(3) { |x| x }
  2571. p System::Array[System::Byte].new(3, 1)
  2572. ", @"
  2573. ['x', 'c', 'z']
  2574. ['c', 'c', 'c']
  2575. ['c', 'c']
  2576. [0 (Byte), 1 (Byte), 2 (Byte)]
  2577. [1 (Byte), 1 (Byte), 1 (Byte)]
  2578. ");
  2579. }
  2580. public void ClrChar1() {
  2581. TestOutput(@"
  2582. p System::Char.ancestors
  2583. p System::String.ancestors
  2584. a = System::Array[System::Char].new(['a', 'b'])
  2585. p System::Char.new(a)
  2586. x = System::Char.new('foo')
  2587. p x.size
  2588. p x.index('f')
  2589. p x + 'oo'
  2590. p x == 'f'
  2591. p System::Char.new('9').to_i
  2592. ", @"
  2593. [System::Char, IronRuby::Clr::String, Enumerable, Comparable, System::ValueType, Object, Kernel, BasicObject]
  2594. [System::String, IronRuby::Clr::String, Enumerable, Comparable, Object, Kernel, BasicObject]
  2595. 'a' (Char)
  2596. 1
  2597. 0
  2598. 'foo'
  2599. true
  2600. 9
  2601. ");
  2602. }
  2603. public class ClassWithEnum {
  2604. public enum MyEnum {
  2605. Foo = 1, Bar = 2, Baz = 3
  2606. }
  2607. public MyEnum MyProperty { get; set; }
  2608. }
  2609. public void ClrEnums1() {
  2610. Context.DefineGlobalVariable("obj", new ClassWithEnum());
  2611. Context.DefineGlobalVariable("enum", typeof(ClassWithEnum.MyEnum));
  2612. AssertOutput(delegate() {
  2613. CompilerTest(@"
  2614. E = $enum.to_class
  2615. $obj.my_property = E.foo
  2616. puts $obj.my_property
  2617. $obj.my_property = E.bar
  2618. puts $obj.my_property
  2619. ");
  2620. }, @"
  2621. Foo
  2622. Bar
  2623. ");
  2624. }
  2625. public void ClrEnums2() {
  2626. Context.ObjectClass.SetConstant("C", Context.GetClass(typeof(ClassWithEnum)));
  2627. Context.ObjectClass.SetConstant("E", Context.GetClass(typeof(ClassWithEnum.MyEnum)));
  2628. TestOutput(@"
  2629. class X
  2630. def to_int
  2631. E.Baz
  2632. end
  2633. end
  2634. p System::Array[E].new([1, E.Bar])
  2635. # TODO: allow default protocol to convert to an enum?
  2636. System::Array[E].new [X.new] rescue puts $!
  2637. ", @"
  2638. [Foo, Bar]
  2639. can't convert X into IronRuby::Tests::Tests::ClassWithEnum::MyEnum
  2640. ");
  2641. }
  2642. [Flags]
  2643. public enum FlagsInt { A = 1, B = 2 }
  2644. [Flags]
  2645. public enum FlagsULong : ulong { C = Int64.MaxValue, D = 2 }
  2646. [Flags]
  2647. public enum FlagsByte : byte { N = 0, E = 4, F = 8 }
  2648. public void ClrEnums3() {
  2649. Context.ObjectClass.SetConstant("A", FlagsInt.A);
  2650. Context.ObjectClass.SetConstant("B", FlagsInt.B);
  2651. Context.ObjectClass.SetConstant("C", FlagsULong.C);
  2652. Context.ObjectClass.SetConstant("D", FlagsULong.D);
  2653. Context.ObjectClass.SetConstant("E", FlagsByte.E);
  2654. Context.ObjectClass.SetConstant("F", FlagsByte.F);
  2655. AssertOutput(delegate() {
  2656. CompilerTest(@"
  2657. p(x = A | B, x.class)
  2658. p(x = A | E, x.class) rescue puts $!
  2659. p(x = C ^ D, x.class)
  2660. p(x = E & F, x.class)
  2661. p(x = ~C, x.class)
  2662. ");
  2663. }, @"
  2664. A, B
  2665. *::FlagsInt
  2666. wrong argument type *::FlagsByte (expected *::FlagsInt)
  2667. 9223372036854775805
  2668. *::FlagsULong
  2669. N
  2670. *::FlagsByte
  2671. 9223372036854775808
  2672. *::FlagsULong
  2673. ", OutputFlags.Match);
  2674. }
  2675. #endregion
  2676. #region Operations, Conversions
  2677. public void ClrOperators1() {
  2678. AssertOutput(delegate() {
  2679. CompilerTest(@"
  2680. a = System::Decimal.new(16)
  2681. b = System::Decimal.new(4)
  2682. p a + b
  2683. p a - b
  2684. p a / b
  2685. p a * b
  2686. p a % b
  2687. p a == b
  2688. p a != b
  2689. p a > b
  2690. p a >= b
  2691. p a < b
  2692. p a <= b
  2693. p(-a)
  2694. p(+a)
  2695. ");
  2696. }, @"
  2697. 20 (Decimal)
  2698. 12 (Decimal)
  2699. 4 (Decimal)
  2700. 64 (Decimal)
  2701. 0 (Decimal)
  2702. false
  2703. true
  2704. true
  2705. true
  2706. false
  2707. false
  2708. -16 (Decimal)
  2709. 16 (Decimal)
  2710. ");
  2711. }
  2712. public void ClrOperators2() {
  2713. TestOutput(@"
  2714. p :b == true
  2715. p String == Fixnum # Only instance operator calls are allowed (MutableString::op_Equality shound be ignored)
  2716. class C < Numeric
  2717. def to_f
  2718. 1.2
  2719. end
  2720. end
  2721. p C.new.ceil # Numeric#ceil uses self with DefaultProtocol attribute
  2722. ", @"
  2723. false
  2724. false
  2725. 2
  2726. ");
  2727. }
  2728. /// <summary>
  2729. /// Operator mapping is not performed for builtin classes.
  2730. /// CLR BigInteger defines op_LessThan but we want less-than operator to call comparison method &lt;=&gt;.
  2731. /// </summary>
  2732. public void ClrOperators3() {
  2733. TestOutput(@"
  2734. class Bignum
  2735. def <=>(other)
  2736. puts '<=>'
  2737. 1
  2738. end
  2739. end
  2740. p 0x1000_0000_0 < 0x1000_0000_1
  2741. ", @"
  2742. <=>
  2743. false
  2744. ");
  2745. }
  2746. public class Conversions1 {
  2747. public int F(int? a, int? b) {
  2748. return a ?? b ?? 3;
  2749. }
  2750. public object[] Numerics(byte a, sbyte b, short c, ushort d, int e, uint f, long g, ulong h, BigInteger i, Complex64 j, Convertible1 k) {
  2751. return new object[] { a, b, c, d, e, f, g, h, i, j, k };
  2752. }
  2753. public object[] Numerics(byte a, sbyte b, short c, ushort d, int e, uint f, long g, ulong h, BigInteger i) {
  2754. return new object[] { a, b, c, d, e, f, g, h, i };
  2755. }
  2756. public Delegate Delegate(Func<object, object> d) {
  2757. return d;
  2758. }
  2759. public Delegate Delegate(int bogusOverload) {
  2760. return new Func<object, object>((x) => x);
  2761. }
  2762. public int Foo(int a) {
  2763. return a + 1;
  2764. }
  2765. public int Double(double a) {
  2766. return (int)a;
  2767. }
  2768. public string Bool([Optional]bool a) {
  2769. return a ? "T" : "F";
  2770. }
  2771. public int ListAndStrings(IList a, MutableString str1) {
  2772. return a.Count + str1.GetCharCount();
  2773. }
  2774. }
  2775. public class Convertible1 {
  2776. public object Value { get; set; }
  2777. public static implicit operator Convertible1(int value) {
  2778. return new Convertible1() { Value = value };
  2779. }
  2780. public static implicit operator int(Convertible1 value) {
  2781. return 11;
  2782. }
  2783. public static implicit operator double(Convertible1 value) {
  2784. return 16.0;
  2785. }
  2786. public static explicit operator string(Convertible1 value) {
  2787. return "foo";
  2788. }
  2789. public static explicit operator MutableString(Convertible1 value) {
  2790. return MutableString.CreateMutable("hello", RubyEncoding.UTF8);
  2791. }
  2792. public override string ToString() {
  2793. return "Convertible(" + Value + ")";
  2794. }
  2795. }
  2796. public void ClrConversions1() {
  2797. Runtime.Globals.SetVariable("Inst", new Conversions1());
  2798. Runtime.Globals.SetVariable("Conv", new Convertible1());
  2799. // Nullable<T>
  2800. TestOutput(@"
  2801. [[1, 2], [nil, 2], [nil, nil]].each { |a,b| p Inst.f(a,b) }
  2802. ", @"
  2803. 1
  2804. 2
  2805. 3
  2806. ");
  2807. // Boolean
  2808. TestOutput(@"
  2809. print Inst.Bool(), Inst.Bool(true), Inst.Bool(false), Inst.Bool(nil), Inst.Bool(0), Inst.Bool(Object.new), Inst.Bool(1.4)
  2810. ", @"
  2811. FTFFTTT
  2812. ");
  2813. // Double
  2814. TestOutput(@"
  2815. p Inst.Double(2.0), Inst.Double(4), Inst.Double(System::Byte.new(8)), Inst.Double(Conv), Inst.Double('28.4'), Inst.Double('29.5'.to_clr_string)
  2816. ", @"
  2817. 2
  2818. 4
  2819. 8
  2820. 16
  2821. 28
  2822. 29
  2823. ");
  2824. // primitive numerics:
  2825. TestOutput(@"
  2826. p(*Inst.numerics(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11))
  2827. ", @"
  2828. 1 (Byte)
  2829. 2 (SByte)
  2830. 3 (Int16)
  2831. 4 (UInt16)
  2832. 5
  2833. 6 (UInt32)
  2834. 7 (Int64)
  2835. 8 (UInt64)
  2836. 9
  2837. (10+0j)
  2838. Convertible(11)
  2839. ");
  2840. // protocol conversions:
  2841. TestOutput(@"
  2842. class C
  2843. def to_ary
  2844. [1,2,3,4,5]
  2845. end
  2846. def to_str
  2847. 'xxx'
  2848. end
  2849. def to_int
  2850. 1
  2851. end
  2852. end
  2853. c = C.new
  2854. p Inst.ListAndStrings(c, c)
  2855. p Inst.Foo(Conv)
  2856. p(*Inst.numerics(c, c, c, c, c, c, c, c, c))
  2857. ", @"
  2858. 8
  2859. 12
  2860. 1 (Byte)
  2861. 1 (SByte)
  2862. 1 (Int16)
  2863. 1 (UInt16)
  2864. 1
  2865. 1 (UInt32)
  2866. 1 (Int64)
  2867. 1 (UInt64)
  2868. 1
  2869. ");
  2870. // protocol conversions:
  2871. TestOutput(@"
  2872. a = System::Collections::ArrayList.new
  2873. p Inst.Foo(a) rescue p $!
  2874. class System::Collections::ArrayList
  2875. def to_int
  2876. 100
  2877. end
  2878. end
  2879. p Inst.Foo(a) rescue p $!
  2880. ", @"
  2881. #<TypeError: can't convert System::Collections::ArrayList into Fixnum>
  2882. 101
  2883. ");
  2884. // meta-object conversions:
  2885. var r1 = Engine.Execute<int>("Inst.delegate(Proc.new { |x| x + 1 }).invoke(123)");
  2886. Assert(r1 == 124);
  2887. // foreign meta-object conversion:
  2888. var py = Runtime.GetEngine("python");
  2889. var scope = Runtime.CreateScope();
  2890. py.Execute(@"def foo(x): return x + 2", scope);
  2891. var r2 = Engine.Execute<int>(@"Inst.delegate(foo).invoke(123)", scope);
  2892. Assert(r2 == 125);
  2893. }
  2894. #endregion
  2895. #region Misc: Inclusions, Aliases, Co/contra-variance
  2896. /// <summary>
  2897. /// CLR class re-def and inclusions.
  2898. /// </summary>
  2899. public void ClrInclude1() {
  2900. AssertOutput(delegate() {
  2901. CompilerTest(@"
  2902. include System::Collections
  2903. class ArrayList
  2904. puts self.object_id == System::Collections::ArrayList.object_id
  2905. end
  2906. ");
  2907. }, "true");
  2908. }
  2909. /// <summary>
  2910. /// Alias.
  2911. /// </summary>
  2912. public void ClrAlias1() {
  2913. AssertOutput(delegate() {
  2914. CompilerTest(@"
  2915. require 'mscorlib'
  2916. include System::Collections
  2917. class ArrayList
  2918. alias :old_add :Add
  2919. def foo x
  2920. old_add x
  2921. end
  2922. end
  2923. a = ArrayList.new
  2924. a.Add 1
  2925. a.add 2
  2926. a.foo 3
  2927. puts a.count");
  2928. }, "3");
  2929. }
  2930. public class ClassWithTypeVariance1 {
  2931. public int Foo(IEnumerable<object> e) {
  2932. int i = 0;
  2933. foreach (var item in e) {
  2934. i++;
  2935. }
  2936. return i;
  2937. }
  2938. }
  2939. public void ClrTypeVariance1() {
  2940. Context.ObjectClass.SetConstant("C", new ClassWithTypeVariance1());
  2941. TestOutput(@"
  2942. include System::Collections::Generic
  2943. class E
  2944. include IEnumerable[System::String]
  2945. def get_enumerator
  2946. list = List[System::String].new
  2947. list.add 'a'
  2948. list.add 'b'
  2949. list.add 'c'
  2950. list.get_enumerator
  2951. end
  2952. end
  2953. p C.foo(E.new) rescue p $!
  2954. ",
  2955. #if CLR2
  2956. "#<TypeError: can't convert E into System::Collections::Generic::IEnumerable[Object]>"
  2957. #else
  2958. "3"
  2959. #endif
  2960. );
  2961. }
  2962. #if !CLR2
  2963. public void ClrBigIntegerV4() {
  2964. Context.ObjectClass.SetConstant("BI", new BigInt(100000000000));
  2965. TestOutput(@"
  2966. p BI + BI
  2967. p BI + 1000000000000
  2968. p 1000000000000 / BI
  2969. ", @"
  2970. 200000000000
  2971. 1100000000000
  2972. 10
  2973. ");
  2974. }
  2975. #endif
  2976. #endregion
  2977. }
  2978. }