bridge.scm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. ;;; Tests for the existence and proper behavior of bridge methods.
  2. (test-begin "bridge-methods" 11)
  3. (define (find-method (cls ::class)
  4. (name ::String)
  5. (ptypes ::class[])
  6. (return-type ::class)
  7. (bridge ::boolean)
  8. (synthetic ::boolean))
  9. ::java.lang.reflect.Method
  10. "`find-method' looks for a method with the given NAME and signature
  11. PTYPES/RETURN-TYPE in CLS, ignoring methods inherited from
  12. superclasses. If no such method is found, returns #!null."
  13. (define methods ::java.lang.reflect.Method[] (*:get-methods cls))
  14. (let loop ((i ::int 0))
  15. (if (= i methods:length) #!null
  16. (let ((mtd (methods i)))
  17. (if (and (eq? mtd:declaring-class cls)
  18. (eq? mtd:name name)
  19. (eq? mtd:return-type return-type)
  20. (equal? mtd:parameter-types ptypes)
  21. ;; Why a different way of checking for bridge than for
  22. ;; checking synthetic? For improved test coverage of
  23. ;; reflection - specifically handling of "isXxx" methods.
  24. (eq? mtd:bridge bridge)
  25. (eq? (mtd:synthetic?) synthetic))
  26. mtd
  27. (loop (+ i 1)))))))
  28. (define (method-exists? (cls ::class)
  29. (name ::String)
  30. (ptypes ::class[])
  31. (return-type ::class)
  32. (bridge ::boolean)
  33. (synthetic ::boolean))
  34. ::boolean
  35. "`method-exists?' checks to see whether the class CLS has a method
  36. with the given NAME which has a signature of taking PTYPES arguments
  37. and returning an instance of RETURN-TYPE. We ignore inherited methods,
  38. so this is suitable for checking for the existence of a bridge
  39. method."
  40. (not (eq? #!null (find-method cls name ptypes return-type bridge
  41. synthetic))))
  42. ;;; Covariant return type (returning a more specific subtype)
  43. (define-simple-class CanBeCloned (java.lang.Cloneable)
  44. (x ::long)
  45. ((clone) ::CanBeCloned
  46. (invoke-special java.lang.Object (this) 'clone)))
  47. (define no-args ::class[] (class[]))
  48. (test-equal "covariant return type source method" #t
  49. (method-exists? CanBeCloned "clone" no-args
  50. CanBeCloned #f #f))
  51. (test-equal "covariant return type bridge method" #t
  52. (method-exists? CanBeCloned "clone" no-args
  53. java.lang.Object #t #t))
  54. ;; Now test that the two methods produce identical results (i.e. that
  55. ;; the bridge method is actually invoking the source method).
  56. ;; In this case, the cloned object should also have its x set to 4.
  57. (test-equal "covariant return source result" 4
  58. (with-compile-options
  59. warn-unknown-member: #f
  60. (*:invoke (find-method CanBeCloned "clone" no-args
  61. CanBeCloned #f #f)
  62. (CanBeCloned x: 4)):x))
  63. (test-equal "covariant return bridge result" 4
  64. (with-compile-options
  65. warn-unknown-member: #f
  66. (*:invoke (find-method CanBeCloned "clone" no-args
  67. java.lang.Object #t #t)
  68. (CanBeCloned x: 4)):x))
  69. ;;; Covariant return type with classes defined in the same module.
  70. (define-simple-class A ()
  71. ((get (x ::int)) ::A #!null))
  72. (define-simple-class B (A)
  73. ((get (x ::int)) ::B (this)))
  74. (define inttype ::class java.lang.Integer:TYPE)
  75. (define int-arg ::class[] (class[] inttype))
  76. (test-equal "covariant return source 2" #t
  77. (method-exists? B "get" int-arg B #f #f))
  78. (test-equal "covariant return bridge 2" #t
  79. (method-exists? B "get" int-arg A #t #t))
  80. ;; Test the result. If "public A get(int)" is inherited from A or is
  81. ;; invoking A's implementation, then this test will fail.
  82. (define my-b ::B (B))
  83. (test-equal
  84. "covariant return result 2"
  85. my-b
  86. (*:invoke (find-method B "get" int-arg A #t #t) my-b (as int 0)))
  87. ;;; Parameterized interface (bridge for type erasure)
  88. (define-simple-class CanBeCompared
  89. (java.lang.Comparable[CanBeCompared])
  90. (x ::int)
  91. ((compareTo (o ::CanBeCompared)) ::int
  92. (- x o:x)))
  93. (test-equal "type erasure source method" #t
  94. (method-exists? CanBeCompared "compareTo"
  95. (class[] CanBeCompared)
  96. inttype #f #f))
  97. (test-equal "type erasure bridge method" #t
  98. (method-exists? CanBeCompared "compareTo"
  99. (class[] object)
  100. inttype #t #t))
  101. (define comp1 ::CanBeCompared (CanBeCompared x: 10))
  102. (define comp2 ::CanBeCompared (CanBeCompared x: 5))
  103. (test-equal "type erasure bridge result"
  104. 5
  105. (*:invoke (find-method CanBeCompared "compareTo"
  106. (class[] object) inttype #t #t)
  107. comp1 comp2))
  108. (test-error "bridge method arg casting" java.lang.ClassCastException
  109. (comp1:compareTo (Object)))
  110. (test-end)