module mod_a
  implicit none
  type, abstract :: t_a
  end type t_a
  interface
     module subroutine p_a(this, q)
       ! t_a is accessible - no IMPORT needed
       class(t_a), intent(inout) :: this
       class(*), intent(in) :: q
     end subroutine
     module function create_a() result(r)
       class(t_a), allocatable :: r
     end function
     module subroutine print(this)
       class(t_a), intent(in) :: this
     end subroutine
  end interface
  
end module mod_a

module mod_b
  implicit none
  type t_b
     integer, allocatable :: I(:)
  end type t_b
  interface 
     module function create_b(i) result(r)
       type(t_b) :: r
       integer :: i(:)
      end function
  end interface
end module mod_b

submodule(mod_b) imp_create
contains
  module procedure create_b
    if (allocated(r%i)) deallocate(r%i)  
    allocate(r%i, source=i)
  end procedure
end submodule imp_create

submodule(mod_a) imp_p_a
  use mod_b
  type, extends(t_a) :: t_imp
     type(t_b) :: b
  end type t_imp
  integer, parameter :: ii(2) = [1,2]
contains
  module procedure create_a
    type(t_b) :: b
    b = create_b(ii)
    allocate(r, source=t_imp(b))
  end procedure
  
  module procedure  p_a
    select type (this)
    type is (t_imp)
       select type (q)
       type is (t_b)
          this%b = q
       class default
          write(*,*) 'FAIL (RTTI1)'
          error stop
       end select
    class default
       write(*,*) 'FAIL (RTTI2)'
       error stop
    end select
  end procedure p_a
  module procedure print
    select type (this)
    type is (t_imp)
       if (sum (abs(this%b%i - [3,4,5])) == 0) then
          write(*,*) 'OK'
       else
          write(*,*) 'FAIL:', this%b%i
       end if
    class default
       write(*,*) 'FAIL (RTTI3)'
    end select
  end procedure
end submodule imp_p_a

program p
  use mod_a
  use mod_b
  implicit none
  class(t_a), allocatable :: a

  allocate(a, source=create_a())
  call p_a(a, create_b([3,4,5]))
  call print(a)
  
end program p


