Rust: Masalah pelacakan untuk jenis terkait generik (GAT)

Dibuat pada 2 Sep 2017  ·  67Komentar  ·  Sumber: rust-lang/rust

Komentar yang paling membantu

https://github.com/rust-lang/rust/issues/44265#issuecomment -568247656 adalah pembaruan (agak singkat).

67510 adalah fitur ICE/hilang terakhir yang perlu diterapkan.

Semua 67 komentar

Berikut adalah jenis rencana implementasi yang akan saya usahakan untuk terus diperbarui.

  • [ ] Langkah pertama: tambahkan dukungan ke AST dan pencetakan cantik

    • Mungkin langkah pertama adalah mulai menguraikan formulir baru dan menambahkan dukungan untuk mereka ke AST.

    • Lihat komentar ini untuk pemikiran yang lebih rinci di sini .

    • Kita harus bisa menulis beberapa tes parsing saja dan juga menguji printer cantik hir

    • Ketika kita sampai pada penurunan HIR , kita dapat error jika ada GAT yang ada

    • Kami juga dapat melakukan gerbang fitur

  • [ ] Akan datang lebih banyak lagi

Mari saya mulai dengan menulis tentang AST secara lebih rinci. Pertama mari kita bahas cara kerjanya hari ini :

Item type Foo: Bar [= Baz]; dalam definisi sifat ditentukan oleh varian AST ini . Itu termasuk batas ( Bar ) dan nilai default (opsional) Baz . Nama didefinisikan dalam TraitItem struct .

Item type Foo = Bar; dalam sifat impl ditentukan oleh varian AST ini -- yang hanya menyertakan tipe Bar , karena Foo dll didefinisikan dalam ImplItem struktur .

Metode merupakan kasus yang menarik karena sudah dapat dibuat generik. Parameter generik tersebut dideklarasikan di bidang Generics dari MethodSig structure . Ini adalah contoh dari Generics struct .

Pendapat saya adalah bahwa hal terbaik yang harus dilakukan adalah "mengangkat" Generics dari metode ke TraitItem (dan ImplItem ) sehingga itu berlaku sama untuk semua bentuk item sifat dan implisit. Untuk saat ini, kami tidak akan mendukung konstanta generik, saya kira, tetapi sejujurnya mereka mungkin hanya jatuh dari pekerjaan yang kami lakukan dalam hal apa pun, jadi mereka akan menjadi ekstensi kecil. Saya pikir pekerjaan akan berjalan lebih baik jika kita hanya merencanakannya sekarang.

Mungkin PR pertama yang layak adalah melakukan perubahan itu , menjaga semua fungsi lain yang ada tetap sama. Artinya, kita akan menambahkan Generics menjadi TraitItem (dan ImplItem ) dan dari MethodSig . Kami akan menyediakan Generics kosong untuk non-metode. Kami akan mengerjakan kode yang ada, menyalurkan obat generik sesuai kebutuhan untuk membuatnya berfungsi.

@nikomatsakis Keren! Terima kasih banyak! Saya mulai bereksperimen dengan ini tadi malam dan saya bangga mengatakan bahwa saya menemukan tempat yang sama yang Anda tunjukkan dalam komentar Anda tentang AST. :smile: (Mengingat ini adalah pertama kalinya saya di rustc, saya menganggap itu sebagai pencapaian!)

Saya tidak berpikir untuk mengangkat obat generik menjadi TraitItem . Pendekatan saya adalah memasukkan Generics ke dalam TraitItemKind::Type karena di situlah deklarasi tipe disimpan. Pendekatan Anda juga masuk akal, jadi saya akan berusaha mengimplementasikannya. Karena saya masih benar-benar baru dalam basis kode ini, saya tertarik untuk mengetahui apa jebakan pendekatan saya jika digunakan di atas yang Anda sarankan. Bisakah Anda memberi saya beberapa wawasan tentang proses berpikir Anda? :senyum:

Inilah perubahan yang akan saya buat:

pub enum TraitItemKind {
    // Generics aren't supported here yet
    Const(P<Ty>, Option<P<Expr>>),
    // `Generics` is already a field in `MethodSig`
    Method(MethodSig, Option<P<Block>>),
    // Added `Generics` here:
    Type(Generics, TyParamBounds, Option<P<Ty>>),
    Macro(Mac),
}

Sunting: Jawaban oleh nikomatsakis di Gitter

tentang jebakan menempatkan mereka dalam tipe
Saya pikir itu bisa berhasil juga
alasan mengapa saya enggan melakukan itu
adalah bahwa kami benar-benar ingin melakukan hal yang sama (setidaknya secara teori) untuk metode dan tipe
dan -- seperti yang saya katakan -- pada prinsipnya saya tidak melihat alasan mengapa kita tidak dapat melakukan hal yang sama untuk konstanta
Saya pikir jika Anda hanya memindahkan Generik ke varian tipe
itu mungkin akan bekerja dengan baik, tetapi jika Anda melihat-lihat, saat ini kita sering harus melakukan "satu hal untuk tipe/konstanta, satu hal untuk metode" justru karena mereka berbeda
jadi saya curiga kodenya akan menjadi lebih seragam
Saya tidak begitu yakin bagaimana ini akan menjadi jujur ​​=) -- mungkin menyakitkan
tetapi sering kali memiliki hal-hal yang lebih umum daripada yang seharusnya tidak terlalu buruk, karena Anda dapat memasukkan span_bug! panggilan dalam kasus yang tidak mungkin untuk saat ini (dan kemudian kami datang dan memperbaikinya)

Baiklah! Langkah selanjutnya adalah memperluas parser. Berikut adalah beberapa tips. Mari kita mulai dengan item sifat.

Rutin ini mengurai item sifat . Kami ingin memperluas kasus yang menangani tipe terkait untuk juga mengurai hal-hal seperti type Foo<....> = ...; (juga mungkin di mana-klausa). ( <...> adalah "generik" yang baru saja kita tambahkan ke AST.)

Saat ini menggunakan parse_ty_param , yang pada dasarnya mem-parsing sesuatu seperti T: Foo dll. Kita harus berhenti melakukan itu, karena tata bahasa untuk deklarasi tipe terkait tidak lagi cocok dengan itu untuk parameter tipe. Jadi kita mungkin ingin menambahkan sesuatu seperti parse_trait_item_assoc_ty . Ini bisa dimulai sebagai semacam tiruan dari parse_ty_param() , tetapi kemudian kita ingin memodifikasinya untuk memanggil parse_generics() di sini. Rutinitas itu akan mengurai deklarasi generik ( <...> ) jika ada, jika tidak maka hanya mengembalikan generik kosong. Kemudian kami ingin menambahkan panggilan untuk mengurai klausa where di sini -- Anda dapat memodelkannya pada panggilan yang terjadi saat metode parsing , perhatikan bahwa hasilnya disimpan ke dalam generics yang telah kami parsing sebelumnya.

Setelah kita selesai melakukannya, kita harus dapat menambahkan beberapa tes parsing. Saya akan melakukannya dengan membuat direktori seperti src/test/run-pass/rfc1598-generic-associated-types/ dan menambahkan file yang Anda harapkan berhasil diurai di sana. Saat ini mereka tidak akan bekerja dengan benar, tetapi itu tidak masalah. Cukup tambahkan fungsi utama yang kosong. Kemudian kita juga dapat menambahkan contoh yang tidak boleh diurai menjadi src/test/ui/rfc1598-generic-associated-types/ (lihat COMPILER_TESTS.md untuk petunjuk cara menambahkan pengujian UI ).

Hal lain -- kita perlu fitur gerbang ini berfungsi pada saat ini, untuk menghindari orang menggunakan barang ini di build stabil. Ada beberapa instruksi untuk menambahkan gerbang fitur di sini di bengkel (lihat bagian terakhir). Kita harus menambahkan visit_trait_item dan visit_impl_item kepada pengunjung di feature_gate.rs ; jika item itu bukan metode, tetapi memiliki generik yang tidak kosong, kita dapat memanggil gate_feature_post ( example ).

Untuk mengatur resolusi nama, saya pikir yang harus kita lakukan adalah mendapatkan "tulang rusuk" yang tepat (hal-hal resolusi nama mengatur kumpulan nama yang ada dalam ruang lingkup menjadi rusuk; setiap rusuk mewakili satu tingkat pengikatan). misalnya untuk impl:

impl<A,B> Foo<B> for Vec<A> {
   fn bar<T,U>(x: ...) { 
       for y in ... {
       }
   }
}

kita akan memiliki tulang rusuk berikut:

- <A,B> (from the impl)
   - <T,U> (from the `bar` method's generics)
      - `x` (from the parameter list)
          - `y` (from the let)

Secara umum, memodelkan hal-hal tentang cara kerja metode bukanlah ide yang buruk. Kami mungkin juga melakukan sedikit "pemeriksaan masa depan" di sini, saya kira.

Berikut adalah kode yang membawa parameter tipe metode ke dalam cakupan (ini untuk metode yang didefinisikan dalam suatu sifat):

https://github.com/rust-lang/rust/blob/a35a3abcda67a729edbb7d649dbc663c6feabd4c/src/librustc_resolve/lib.rs#L1890 -L1892

Sedangkan untuk type yang didefinisikan dalam suatu sifat, kita di-hardcode untuk menambahkan rib parameter tipe kosong ( NoTypeParameters ):

https://github.com/rust-lang/rust/blob/a35a3abcda67a729edbb7d649dbc663c6feabd4c/src/librustc_resolve/lib.rs#L1897 -L1901

Sekarang generik sudah ada di setiap item sifat/impl, saya pikir kita mungkin ingin menghapus penanganan untuk type dan mengekstrak penanganan metode sehingga terjadi pada tingkat yang lebih tinggi. Untuk item (misalnya, const ) di mana tidak ada obat generik, maka rusuk yang baru diperkenalkan harus kosong dan karenanya tidak berbahaya (saya harap).

Tempat menarik lainnya:

Anda mendapatkan idenya.

@petrochenkov -- terdengar benar?

@nikomatsakis

terdengar tentang benar?

Semuanya terlihat benar.

Langkah berikutnya. Resolusi seumur hidup.

Untuk lebih baik atau lebih buruk, ini saat ini dilakukan dalam bit kode yang sepenuhnya terpisah dari resolusi nama lainnya. Hal ini karena terjadi setelah HIR dibangun. Hampir pasti ini akan berubah tetapi belum berubah.

Ide dasarnya sama seperti dalam resolusi nama normal, kecuali kita tidak menyebut hal-hal "tulang rusuk" melainkan "lingkup". =)

Ada beberapa komplikasi ringan karena konsep masa hidup "terikat akhir" ini. Ini tidak terlalu relevan di sini -- semua masa hidup untuk tipe terkait generik akan "terikat awal", yang merupakan jenis kasus sederhana. Seumur hidup "terikat terlambat" adalah seumur hidup yang dideklarasikan pada metode atau fungsi yang nilainya tidak diberikan sampai metode dipanggil. Saya tidak akan membahas detailnya di sini karena tidak terlalu relevan -- hal utama adalah kami tidak ingin mengikuti model metode yang sama persis seperti yang kami lakukan untuk jenis item generik lainnya, tidak seperti dalam resolusi nama lainnya kasus.

Berikut adalah contoh sedikit kode. Ini adalah kode yang mengunjungi impl , struct atau item non-fungsi lainnya. Dalam kasus ini, seperti dalam GAT, pada dasarnya kami ingin membawa semua parameter masa pakai dari Generics ke dalam cakupan dan memetakannya ke masa pakai "terikat awal":

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L370 -L388

Anda dapat melihat bahwa itu pertama kali membuat vektor masa hidup, memanggil Region::early untuk masing-masing:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L376 -L378

Selanjutnya ia menciptakan Scope . Variabel next_early_index hanya menghitung berapa banyak masa hidup terikat awal dalam cakupan. Karena kode ini khusus untuk item, itu akan selalu menjadi jumlah masa pakai terikat awal yang dideklarasikan pada item saat ini. (Nanti kita akan melihat kasus di mana kita membawa masa pakai tambahan ke dalam cakupan, yang lebih seperti yang kita inginkan untuk GAT.)

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L379 -L384

Akhirnya, kami memanggil with() . Metode ini akan membawa ruang lingkup ke dalam ruang lingkup dan meminta penutupan. Kehidupan apa pun yang kami kunjungi di dalam penutupan ini akan melihat nama-nama yang baru saja kami definisikan sebagai dalam cakupan:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L385 -L388

Oke, sekarang mari kita lihat satu contoh lagi. Kasus ini mencakup "sifat tersirat". Detail dari apa yang dilakukannya tidak begitu penting (yaitu, Anda tidak harus di bawah impl Trait desugaring per se). Cukuplah untuk mengatakan bahwa ini membawa beberapa masa hidup awal yang baru ke dalam ruang lingkup -- itulah yang ingin kami lakukan untuk GAT.

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L482 -L501

Izinkan saya menyoroti beberapa hal. Pertama, metode next_early_index mengembalikan indeks terikat awal yang belum ditetapkan berikutnya:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L488

Itu memberikan titik awal. Selanjutnya, kami menggunakan Region::early lagi untuk membuat definisi seumur hidup terikat awal baru yang akan diselesaikan terhadap:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L490 -L492

Akhirnya, kami memasukkannya ke dalam cakupan dengan memanggil with lagi:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L494 -L501

Oke, itu dua contoh. Kami akan ingin melakukan sesuatu seperti yang kedua. Kami ingin mengubah definisi dari dua metode ini:

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L509

https://github.com/rust-lang/rust/blob/ddaebe938b8eb1f5e17570ae8091743972e02bdd/src/librustc/middle/resolve_lifetime.rs#L520

Keduanya perlu, untuk jenis terkait, memproses obat generik terkait. (Mereka mungkin harus menegaskan, dalam kasus lain, bahwa obat generik itu kosong.)

Jadi saya melompat di ini sebelumnya hari ini. Saya ingin memastikan saya berada di jalur yang benar:

  • Yang perlu dilakukan hanyalah memperkenalkan masa hidup ke peta dan kemudian menjalankan item sifat/impl? Memeriksa tampaknya berfungsi, meskipun sulit untuk mengatakannya (lihat nanti)... mungkin hanya berfungsi dalam kasus sederhana (tidak terbatas).
  • Saya menjatuhkan larangan parameter tipe untuk qpath_to_ty dan associated_path_def_to_ty di librustc_typeck/astconv.rs untuk memperbaiki kesalahan type parameters are not allowed on this type . Saya pikir itu perlu diganti dengan beberapa pemeriksaan. Juga...
  • Saya mendapatkan crash dari typeck sekarang. (menulis ulang, khususnya)

kegagalan typeck dipicu src/test/compile-fail/struct-path-associated-type.rs karena menyediakan generik untuk nilai yang tidak memiliki tipe terkait.

Jika saya membaca semuanya dengan benar, saya setidaknya perlu menambahkan tanda centang bahwa jumlah generik yang terkait cocok (mencoba mencari tahu di mana melakukan itu ...), dan juga mungkin melakukan pemeriksaan lain untuk menambahkan jenis node, dll.

Akan bekerja untuk itu, tetapi petunjuk tentang apakah saya bahkan menuju ke arah yang benar dihargai.

Hai @brandonson! Saya benci untuk mencegah siapa pun meretas kompiler Rust, tetapi saya pikir @sunjay sudah aktif meretas hal yang sama dan telah mengejar perubahan ini sejak awal, jadi mungkin masuk akal bagi mereka untuk menyelesaikannya perubahan ini juga (saya pikir mereka sudah mulai). Saya tidak yakin apakah ada cara yang jelas untuk memparalelkan upaya ini (tentu saja itu mungkin, tetapi kita harus terlebih dahulu menyelesaikan langkah-langkahnya).

Namun, jika Anda tertarik untuk menemukan sesuatu untuk ditangani, bolehkah saya merekomendasikan untuk mengatasi beberapa bug pada pencapaian ini ? https://github.com/rust-lang/rust/issues/46472 tampaknya tidak diucapkan, saya dapat mencoba untuk meninggalkan beberapa komentar di sana segera.

Tentu saja saya tidak bermaksud menginjak kaki siapa pun, tetapi saya tidak melihat apa pun yang menunjukkan kemajuan lebih lanjut benar-benar terjadi (walaupun harus diakui bahwa komentar mengenai langkah selanjutnya agak baru). Sungguh, saya mulai mencoba menyelesaikan ini karena saya menginginkan GAT beberapa kali dalam beberapa hari terakhir, jadi sementara saya tidak keberatan mengerjakan beberapa hal NLL di masa depan, ini jauh lebih tinggi dalam daftar hal-hal yang harus saya selesaikan saat ini.

@sunjay , jika Anda masih aktif bekerja/berencana untuk mengerjakan ini, tolong beri tahu saya - tidak ada gunanya meminta saya menduplikasi pekerjaan Anda dalam hal ini.

Hai @brandonson , terima kasih atas keinginan dan kesediaan Anda untuk membantu. :) Saya memang aktif mengerjakan ini. Saya telah melalui setiap bagian dari implementasi langkah demi langkah sambil bekerja sama dengan Niko untuk melakukannya dengan benar.

Saya akan melakukan semua yang saya bisa untuk mengeluarkan ini sesegera mungkin. Saya juga sangat menginginkan fitur ini!

Bagaimana perkembangannya? =) Tidak sabar untuk bereksperimen dengan ini di malam hari <3

Saya bertanya-tanya bagaimana penampang GAT dan const generik akan bekerja dan jika itu adalah bagian dari proposal ketika disatukan?

Contoh yang saya maksud:

trait Foo {
    type Bar<const N>;
}

Hai @sunjay Saya pikir ini adalah fitur yang cukup penting, itu banyak disebutkan di komentar Roadmap 2018. Bagaimana perkembangannya? Terima kasih atas pekerjaan Anda!

Ini adalah fitur yang paling saya inginkan saat ini. Saya harap ini menjadi prioritas dan segera menemukan jalannya ke malam hari!

Jadi baru-baru ini saya bertemu dengan @sunjay , yang sekarang sedang sibuk dengan sekolah dan hal-hal lain, untuk mencoba dan menjelaskan langkah selanjutnya di sini. Mereka dan saya telah bertemu di beberapa titik dan membahas strategi implementasi keseluruhan, yang berpuncak pada komitmen pada repo mereka di mana kami meninggalkan banyak komentar sebaris .

Saya pikir strategi yang paling masuk akal ke depan adalah dua kali lipat:

  • Pertama, kita perlu menulis beberapa tes lagi.
  • Ada beberapa kekurangan yang diketahui di parser kami dan beberapa bit "front-end" lainnya dari sistem, kami perlu menghitung dan memperbaikinya. Kami mungkin akan menemukan lebih banyak dalam tes.
  • Pada saat itu, kami siap untuk mulai meretas sistem sifat yang tepat:

    • beberapa fondasi telah diletakkan, jadi ini mudah-mudahan sebagian besar merupakan tugas "refactoring"

    • tapi saya perlu menulis secara rinci, tidak ada deskripsi tertulis dari rencana yang saya tahu dan saya tidak punya waktu untuk itu menit ini.

Saya akan mulai dengan mencoba menulis beberapa instruksi tentang: tes, karena itu lebih dapat segera ditindaklanjuti, dan menjadwalkan beberapa waktu kemudian minggu ini untuk menulis bagaimana sisa desain akan bekerja dan bagaimana mendapatkan kode dari tempatnya sekarang ke tempat yang seharusnya.

indah sekali !! semoga sukses untuk @sunjay dalam hal ini dan semua upaya lainnya.

Langkah pertama adalah memastikan bahwa kita memiliki rangkaian tes yang lengkap. Tes yang ada dapat ditemukan di:

src/test/ui/rfc1598-generic-associated-types

Hanya dengan melihat itu, kita sudah dapat melihat beberapa pekerjaan yang harus dilakukan:

  • [ ] construct_with_other_type.rs -- memberikan kesalahan E0110 yang tidak terduga
  • [x] empty_generics -- memeriksa apakah type Bar<,> memberikan kesalahan, sepertinya ok
  • [x] generic-associated-types-where.rs -- memeriksa bahwa kami dapat mengurai klausa where di tempat yang tepat, sepertinya ok
  • [ ] generic_associated_type_undeclared_lifetimes.rs -- memberikan kesalahan E0110 yang tidak terduga
  • [ ] iterable.rs -- memberikan kesalahan E0110 yang tidak terduga
  • [ ] pointer_family.rs -- memberikan kesalahan E0109 yang tidak terduga
  • [ ] streaming_iterator.rs -- memberikan kesalahan E0110 yang tidak terduga

Tempat-tempat yang kurang terjangkau

  • [ ] saat ini kami tidak memiliki banyak tes "penggunaan yang diharapkan" -- yaitu, hal-hal yang seharusnya berhasil

    • pointer_family tampaknya ke arah itu

    • Saya mengharapkan semacam tes trait Iterable { type Item; type Iter<'a>: Iterator<Item = &'a Self::Item>; }

  • [ ] tes bayangan seumur hidup -- kami biasanya melarang bayangan seumur hidup, jadi ini seharusnya ilegal:

    • trait Foo<'a> { type Item<'a>; }

    • impl<'a> Foo<'a> for &'a u32 { type Item<'a> = i32; }

  • [ ] Sintaks "sepenuhnya memenuhi syarat" tampaknya tidak diuji

    • misalnya, tes pointer_family memiliki Self::Pointer<T> , tetapi tidak <Self as PointerFamily>::Pointer<T>

  • [ ] Jumlah argumen yang salah untuk GAT. misalnya, dengan definisi Iterable di atas:

    • <T as Iterable>::Item -- tidak ada parameter sama sekali? Buruk.

    • Perhatikan bahwa kami mungkin menerima ini dalam beberapa konteks, karena dalam beberapa konteks yang sebanding kami mengizinkan penghapusan masa hidup.

      Saya bisa pergi ke sini; Saya lebih suka orang menulis '_ eksplisit dalam kasus seperti ini.

    • <T as Iterable>::Item<'_> -- Benar!

    • <T as Iterable>::Item<T> -- Terlalu banyak jenis!

    • dll, akan lebih baik untuk memiliki tes yang mengambil jenis dan masa hidup tentu saja

  • [ ] Default pada jenis terkait? trait Foo { type Bar<T, U = T> where T: PartialEq<U>; }

    • dalam hal ini, SomeType::Bar<u32> akan menjadi kependekan dari SomeType::Bar<u32,u32> , yang harus kita periksa.

Memperbaiki kesalahan E0110 yang tidak terduga

Kesalahan E0110 dilaporkan oleh prohibit_type_params :

https://github.com/rust-lang/rust/blob/e65547d4fad0425d1db4f33a4d8134bf2cad939e/src/librustc_typeck/astconv.rs#L912

Langkah pertama adalah mencari tahu dari mana itu dipanggil. Cara yang saya sukai untuk melakukannya adalah dengan mendapatkan build lokal dan menggunakan -Ztreat-err-as-bug dikombinasikan dengan RUST_BACKTRACE=1 . Tapi saya tidak bisa menunjukkan hasil itu karena rustc masih membangun. :P Jadi, alih-alih saya melakukan rg prohibit_type_params cepat, izinkan saya menunjukkan satu kasus mencurigakan yang saya lihat.

Satu permintaan berasal dari associated_path_def_to_ty :

https://github.com/rust-lang/rust/blob/e65547d4fad0425d1db4f33a4d8134bf2cad939e/src/librustc_typeck/astconv.rs#L791 -L803

Seperti yang ditunjukkan oleh komentar, ini dipanggil untuk menyelesaikan komponen Pointer<T> di jalur seperti Self::Pointer<T> (perhatikan bahwa parameter tipe dianggap sebagai bagian dari segmen jalur, bersama dengan nama yang dilampirkan ). Sampai GAT, parameter tipe tidak legal di sana (misalnya, T::Item ), jadi kami hanya memiliki batasan menyeluruh:

https://github.com/rust-lang/rust/blob/e65547d4fad0425d1db4f33a4d8134bf2cad939e/src/librustc_typeck/astconv.rs#L810

Jelas ini tidak akan berhasil. Kita harus menghapus baris itu dan menggantinya dengan semacam pemeriksaan bahwa, jika parameter disediakan, mereka cocok dengan angka yang diharapkan. Untuk melakukan ini, kita mungkin menginginkan beberapa kode pemeriksaan kesalahan yang mirip dengan yang ditemukan di create_substs_for_ast_path . Kami mungkin ingin membuat beberapa kode bersama di sini, terutama untuk akuntansi dengan default -- mungkin kami benar-benar dapat menggunakan kembali fungsi itu?

Apakah ada yang masih mengerjakan ini? Tampaknya bagi saya bahwa ini memiliki jalan panjang. GAT adalah RFC yang paling saya inginkan. Jika tidak, saya ingin menyumbangkan beberapa tes...

@rickyhan jadi @Centril dan @gavento berbicara tentang sifat-sifat WG tentang membagi pekerjaan tes, tetapi saya tidak tahu apakah ada kemajuan yang dibuat. Mungkin mereka bisa ikut campur. Saya pikir PR akan diterima. =)

Maaf jika saya bodoh, tetapi apakah hal semacam ini akan legal dengan GAT?

trait Sequencer {
    type Wrap<A>;
    fn chain<A, B, F>(Self::Wrap<A>, F) -> Self::Wrap<B>
        where F: FnOnce(A) -> Self::Wrap<B>;
    fn wrap<A>(A) -> Self::Wrap<A>;
}

Ini statusnya apa? Saya tahu bahwa kapur baru-baru ini mendapatkan dukungan gat. Apakah itu dimaksudkan untuk segera mendarat di karat?

@mark-im Saya mencobanya minggu lalu. Dari pemahaman saya, parser sintaks ada di sana (walaupun tesnya hilang). Tetapi "implementasi" belum ditulis. (lihat https://github.com/rust-lang/rust/issues/44265#issuecomment-330915766 untuk detail lebih lanjut)

@quadrupleslap AIUI, itu mungkin nanti, tetapi pada awalnya, GAT hanya akan mendukung parameter seumur hidup..

@Boscop RFC menentukan bahwa parameter tipe juga akan didukung.

Adakah yang tahu status pasti implementasi sintaks di rustc? Tampaknya sebagian besar ada di sana, tetapi batas peringkat yang lebih tinggi menghasilkan ICE:
http://play.rust-lang.org/?gist=a48959858ed5dd432c2396feae5c3cc1&version=nightly&mode=debug

Saya setidaknya membutuhkan seluruh sintaks untuk diimplementasikan untuk memajukan pekerjaan pengapuran. Jika ada yang masih mengerjakan sintaks, beri tahu saya, atau saya akan pergi dan memperbaikinya sendiri :)

Bagi saya sepertinya komunikasi adalah masalah utama yang memperlambat implementasi GAT. Tampaknya ada setidaknya beberapa orang yang tertarik untuk mengerjakan ini, tetapi tidak ada yang benar-benar tahu status implementasi yang tepat dan siapa yang sudah mengerjakan ini. Apa pendapat Anda tentang saluran Discord (atau IRC?) Hanya untuk membicarakan penerapan GAT? Saya pikir itu pasti akan membantu.

Juga, saya pasti dapat berkontribusi beberapa hari kerja di minggu-minggu berikutnya untuk mengerjakan ini (tetapi saya belum benar-benar tahu apa-apa tentang bagian kompiler ini).

Jadi saya meminta saluran khusus di Discord. Tapi alih-alih mendapatkan saluran, saya belajar beberapa hal. Saya juga mencari segala sesuatu yang berhubungan dengan GAT. Jadi saya akan mencoba merangkum semua informasi mengenai fitur ini; mungkin bermanfaat bagi sebagian orang. Tapi saya tidak tahu apa-apa, jadi ambil ini dengan sebutir garam! Juga: tolong beri tahu saya jika ada informasi yang salah sehingga saya dapat memperbaikinya.

Ringkasan upaya implementasi terkait GAT

Sejak itu tidak ada tes UI yang ditambahkan . Dan saya tidak dapat menemukan PR lain yang terkait langsung dengan GAT.

Namun , poin (c) dari atas (sistem sifat) sedang dikerjakan "secara rahasia". Sejauh yang saya pahami, rencananya adalah segera bermigrasi ke pemecah sifat berbasis kapur baru dan tidak membuat GAT bekerja pada sistem lama. Integrasi pemecah sifat baru dilacak dengan masalah pelacakan "Kapurifikasi" . Sudah cukup banyak PR yang berhubungan dengan kapur dan pengapuran. Khususnya, ada PR kapur yang disebut "Selesaikan penerapan GAT" (digabungkan 24-05-2018). Jadi sepertinya sistem inti untuk GAT sudah ada.

Yang mengatakan, "GAT" di kapur adalah implementasi prototipe dan menggunakannya di rustc bukan hanya use chalk; . Seperti yang dikatakan @scalexm kepada saya: "Sepertinya ada cukup banyak [yang harus dilakukan]".


Untuk informasi lebih lanjut dan untuk membantu, mungkin berguna untuk melihat saluran Discord #wg-traits dan ciri-ciri masalah pelacakan WG .

Jadi @nikomatsakis baru saja membuat saluran #wg-traits-gat di server rust-lang discord ( gabung di sini ). Akan sangat bagus jika kita bisa mendapatkan semua orang yang ingin membantu di sana. Ditambah beberapa orang yang mengetahui tentang status fitur ini (khususnya, apa yang masih perlu dilakukan dan di mana kami dapat membantu). Itu seharusnya membuat komunikasi lebih mudah dan lebih cepat, terutama bagi orang-orang seperti saya yang belum terlibat secara mendalam/bagian dari sifat-sifat WG :)

Apakah ada pembaruan tentang ini baru-baru ini? Apakah kita menunggu integrasi Kapur ke dalam kompiler? (Mungkin ada masalah terpisah untuk itu.)

Mungkin ada masalah terpisah untuk itu.

48049

Sebagai catatan (mungkin diketahui), kode ini membuat panik kompiler:

use typenum::{U1,U2,U3,Unsigned};

trait Array {
    type Of<Elem> ;
}

impl Array for U1 { type Of<T> = [T;1]; }
impl Array for U2 { type Of<T> = [T;2]; }
impl Array for U3 { type Of<T> = [T;3]; }

@varkor luar biasa, terima kasih!

Namun catatan lain (sekali lagi, mungkin diketahui). Dengan memiliki GAT, kita akan dapat mengabstraksi dengan baik lebih dari & dan &mut , jadi kita bisa berhenti terus-menerus menyalin-tempel kode di antara fungsi my_func dan my_func_mut :) Berikut adalah kemungkinan implementasi abstraksi tersebut (alias pseudo HKT):

#![feature(arbitrary_self_types)]
#![feature(generic_associated_types)]

use std::marker::PhantomData;

struct Pure <'t> (PhantomData<&'t()>);
struct Mut  <'t> (PhantomData<&'t()>);

type Ref<M, T> = <M as Acc>::Pat<T>;

trait Acc { type Pat<T: ?Sized>; }
impl<'t> Acc for Pure <'t> { type Pat<T> = PureRef <'t, T>; }
impl<'t> Acc for Mut  <'t> { type Pat<T> = MutRef  <'t, T>; }

struct PureRef <'t, T: ?Sized> (&'t     T);
struct MutRef  <'t, T: ?Sized> (&'t mut T);


/// USAGE ///

struct Buf<T> {
    data: Vec<T>
}

impl<T> Buf<T> {
    fn as_mut<M: Acc>(s: Ref<M, Self>) -> Ref<M, [f32]>
    {
        unimplemented!()
    }
}

Itu hampir mengkompilasi. Kami juga dapat mengimplementasikannya tanpa GAT tetapi tipe meledak:

#![feature(arbitrary_self_types)]

use std::marker::PhantomData;
use std::ops::Deref;

struct Pure <'t> (PhantomData<&'t()>);
struct Mut  <'t> (PhantomData<&'t()>);

type Ref<M, T> = <M as Acc<T>>::Pat;

trait Acc<T: ?Sized> { type Pat; }
impl<'t, T: 't + ?Sized> Acc<T> for Pure <'t> { type Pat = PureRef <'t, T>; }
impl<'t, T: 't + ?Sized> Acc<T> for Mut  <'t> { type Pat = MutRef  <'t, T>; }

struct PureRef <'t, T: ?Sized> (&'t     T);
struct MutRef  <'t, T: ?Sized> (&'t mut T);


/// USAGE ///

struct Buf<T> {
    data: Vec<T>
}

impl<T> Buf<T> {
    fn as_mut<M>(self: Ref<M, Self>) -> Ref<M, [f32]>
    where M: Acc<Self> + Acc<[f32]>,
          Ref<M, Self>: Deref<Target = Self>
    {
        unimplemented!()
    }
}

(ini sebenarnya dikompilasi)

Mungkin ini lebih merupakan pertanyaan dukungan tetapi saya pikir mungkin berguna bagi mereka yang datang ke halaman ini untuk memahami proposal ini karena tidak sepenuhnya jelas bagi saya dari RFC atau komentar di sini:

Dengan 1,41 nightly, saya mencoba yang berikut:

pub trait MyTrait {
    type MyType<U>;

    fn f<U>(self, x : <Self as MyTrait>::MyType<U>);
}

Dan ini gagal dikompilasi, kesalahannya adalah "ketik argumen tidak diizinkan" MyType .

Saya kemudian menghapus <U> , yang tampak mencurigakan tetapi saya pikir saya akan mencobanya:

pub trait MyTrait {
    type MyType<U>;

    fn f<U>(self, x : <Self as MyTrait>::MyType);
}

Yang secara mengejutkan berhasil dikompilasi. Tapi kemudian ketika saya menulis sebuah impl:

impl MyTrait for u64 {
    type MyType<U> = U;

    fn f<U>(self, x : <Self as MyTrait>::MyType) -> <Self as MyTrait>::MyType {
        x;
    }
}

Ini membuat kompiler panik.

Pertanyaan saya adalah:

  1. Apakah skema semacam ini mungkin sekarang tetapi saya salah melakukannya?
  2. Jika tidak mungkin sekarang, apakah mungkin di bawah proposal ini?
  3. Jika demikian, apakah ada ide tentang timeline yang bisa saya lakukan setiap malam?

Terima kasih sebelumnya atas waktu Anda dalam menjawab ini.

@clintonmead Saya percaya itu pada akhirnya akan mungkin, tetapi implementasi fitur belum selesai (memang, kompiler memperingatkan Anda bahwa itu mungkin macet ketika Anda mencoba menggunakannya!). Saya tidak tahu kronologinya seperti apa.

Mungkin perlu diperiksa dengan orang-orang Kapur untuk melihat apakah integrasi cukup maju untuk bekerja pada fitur ini untuk melanjutkan?

Ini sekarang diblokir di

  • #30472
  • #67509
  • #67510
  • #67512
  • #67513

Bisakah kami memperbarui Deskripsi Masalah dengan pemblokir saat ini?

Menambahkan lebih banyak masalah pemblokiran yang diangkat oleh @DutchGhost

Ini akan menjadi langkah besar dalam meniru tipe yang lebih tinggi.

Saya membayangkan sesuatu seperti ini:

// the plug/unplug idea is from https://gist.github.com/edmundsmith/855fcf0cb35dd467c29a9350481f0ecf

trait Monad /* : Applicative (for pure/return, doesn't matter for this example) */ {
    // Self is like the "f a" in haskell

    /// extract the "a" from "f a"
    type Unplug;

    /// exchange the "a" in "f a" in the type of Self with B
    type Plug<B>: Monad;

    fn bind<B, F>(this: Self, f: F) -> Self::Plug<B>
    where
        F: Fn(Self::Unplug) -> Self::Plug<B>;
}

impl<A> Monad for Option<A> {
    type Unplug = A;
    type Plug<B> = Option<B>;
    fn bind<B, F>(this: Self, f: F) -> Option<B>
    where
        F: Fn(A) -> Option<B> {
        this.and_then(f)
    }
}

Pertanyaan tentang implementasi yang diusulkan:

Saya memiliki sifat yang terlihat seperti ini

trait TradeableResource{
}

dan pelaksana yang terlihat seperti ini

struct Food(f64);
impl TradeableResource for Food{}

Saya ingin dapat membatasi semua pelaksana sifat saya menjadi "tipe baru" (struktur tuple elemen tunggal yang membungkus f64).

Apakah itu mungkin dengan implementasi yang diusulkan dipertimbangkan di sini?

Yang berikut ini memang terlihat agak aneh tetapi mudah-mudahan menunjukkan apa yang ingin saya lakukan.

trait TradeableResource{
    type Wrapper<T>:T(f64)
}

@ChechyLevas sejauh yang saya tahu ini tidak termasuk dalam cakupan GADT.

Tetapi apa yang ingin Anda lakukan tidak memerlukan GADT untuk memulai, dari apa yang dapat saya kumpulkan, jika Anda bersedia menyerah pada jaminan bahwa itu adalah tipe baru dan sebagai gantinya harus fungsi yang membungkus dan mengambil nilai dalam, masing-masing . Ini tidak nyaman, tetapi mungkin harus bekerja dengan cukup baik.

Jadi Anda bisa melakukan hal berikut:

trait Traceable resource: From<f64> + Into<f64> { }

(ini akan mengharuskan Anda untuk juga mengimplementasikan From di kedua arah, yang akan saya lakukan melalui makro)

Saya ingin mendapatkan sedikit perasaan untuk keadaan saat ini. Saya telah bermain-main dengan ciri-ciri dan masa hidup async sedikit.
Satu hal yang ingin saya lakukan adalah membuat trait ReadAt<'r> dengan tipe ReadAt: Future terkait. Yang berfungsi untuk banyak kasus, kecuali ketika saya ingin menggunakan objek sifat.

Sebagian besar karena melakukan hal berikut akan memaksa saya untuk melampirkan masa hidup yang tidak cukup umum ke R :

impl<'a, 'r, R> ReadAt<'r> for &'a dyn for<'z> ReadAt<'z, ReadAt = R> + 'a {
    type ReadAt = R; // cannot have an `impl<R<'lifetime>>`
    ...
}

Jadi saya pikir, mungkin ini bisa diselesaikan dengan GAT, tetapi saya mengalami masalah serupa di mana saya memerlukan sihir sintaksis lagi, karena objek sifat memerlukan tipe terkait untuk ditulis:

Suka:

trait ReadAt {
    type ReadAt<'r>: Future<Output = io::Result<usize>>;

    fn read_at<'a>(&'a self, buf: &'a mut [u8], at: u64) -> Self::ReadAt<'a>;
}

impl<'d> ReadAt for &'d (dyn ReadAt<HERE> + 'd) {
}

Saya membutuhkan cara untuk memasukkan masa hidup dalam HERE . Ini, misalnya, diterima, tetapi IMO tidak akan cukup, karena R terlalu konkret:

impl<'d, R> ReadAt for &'d (dyn ReadAt<ReadAt = R> + 'd) {
    type ReadAt<'r> = R;

    fn read_at<'a>(&'a self, buf: &'a mut [u8], at: u64) -> Self::ReadAt<'a> {
        (**self).read_at(buf, at)
    }
}

Tetapi saya tidak dapat benar-benar menguji apakah itu akan berhasil, karena saya tidak yakin bagaimana mengubahnya menjadi objek sifat, karena saya tidak tahu bagaimana saya memasukkan masa hidup ke dalam cuplikan berikut:

struct Test<T: ReadAt>(T);

impl<T: ReadAt> Test<T> {
    fn into_trait_object<'a>(&'a self) -> Test<&'a dyn ReadAt<ReadAt = T::ReadAt>> {
        todo!();
    }
}

Karena T::ReadAt membutuhkan waktu seumur hidup yang tidak dapat saya berikan, jadi ini akan kehilangan ekstensi sintaks untuk dyn ReadAt<ReadAt<'r> = T::ReadAt<'r>> . (Atau untuk mencocokkan parameter seumur hidup IMO, cuplikan di atas bisa berfungsi ;-))

Karena saya hanya menggunakan parameter seumur hidup, bukan parameter tipe, saya pikir ini secara teknis mungkin, kecuali jika parameter seumur hidup dapat memengaruhi vtables dan ukuran tipe entah bagaimana?

@jendrikw kode Anda dikompilasi dan dijalankan dengan nightly(1.46) terbaru. Saya melakukan beberapa tes dengan tipe khusus dll. tetapi saya tidak memiliki pengetahuan fp untuk memeriksa lebih lanjut.

Hari ini, saya mencoba menggunakan GAT untuk sesuatu yang saya pikir mungkin seumur hidup tidak akan cukup umum (kode kerja berikut; file kode lengkap ):

/// Helper trait for "stripping indention" from an object reference
pub trait AsUnindented<'ast> {
    type Output;

    /// Returns a reference to the unindented part of `Self`
    fn as_unindented(&'ast self) -> Self::Output;
}

impl<'ast, T: 'ast> AsUnindented<'ast> for Indented<T> {
    type Output = &'ast T;

    #[inline]
    fn as_unindented(&'ast self) -> &'ast T {
        &self.data
    }
}

impl<'ast, T: 'ast> AsUnindented<'ast> for crate::Block<T>
where
    T: AsUnindented<'ast> + 'ast,
{
    type Output = crate::View<'ast, T, fn(&'ast T) -> T::Output>;

    #[inline]
    fn as_unindented(&'ast self) -> Self::Output {
        crate::View::new(self, T::as_unindented)
    }
}

Kemudian, saya mencoba menggunakan GAT dalam kode berikut:

pub trait AsUnindented {
    type Output<'ast>;

    /// Returns a reference to the unindented part of `Self`
    fn as_unindented<'ast>(&'ast self) -> Self::Output<'ast>;
}

impl<T> AsUnindented for Indented<T> {
    type Output<'ast> = &'ast T;

    #[inline]
    fn as_unindented<'ast>(&'ast self) -> &'ast T {
        &self.data
    }
}

impl<T> AsUnindented for crate::Block<T>
where
    T: AsUnindented,
{
    type Output<'ast> = crate::View<'ast, T, fn(&'ast T) -> T::Output<'ast>>;

    #[inline]
    fn as_unindented<'ast>(&'ast self) -> Self::Output<'ast> {
        crate::View::new(self, T::as_unindented)
    }
}

Itu tidak bekerja. Gagal dengan E0309 ( the parameter type 'T' may not live long enough ) untuk kedua implementasi sifat. Saya tidak yakin bagaimana cara memperbaikinya atau jika saya memiliki beberapa kesalahpahaman. Kompiler ingin saya melampirkan ikatan pada T pada level impl , tetapi pada level itu, tidak ada seumur hidup 'ast , dan saya tidak ingin membatasi T: 'static (dan sesuatu seperti for<'ast> T: 'ast tidak berfungsi).

edit : Saya mencoba menerapkan GAT ke bagian lain dari basis kode saya, itu hanya menimbulkan satu kesalahan (untuk saat ini), tetapi kesalahan itu tidak dapat diperbaiki begitu saja karena tergantung pada perbaikan untuk masalah saya yang disebutkan sebelumnya.

Batas hidup yang lebih lama dapat ditambahkan ke tipe terkait (menggunakan Self: 'ast pada versi sifat). Tes ini menunjukkan seperti apa tampilannya:
https://github.com/rust-lang/rust/blob/db4826dd6ca48663a0b4c5ab0681258999017c7d/src/test/ui/generic-associated-types/iterable.rs#L6 -L21

Yah, itu hanya berfungsi sebagian ...


pesan kesalahan

error[E0309]: the parameter type `T` may not live long enough
  --> src/indention.rs:33:5
   |
33 |     type Output<'ast> where T: 'ast = &'ast T;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `T: 'ast`...
   = note: ...so that the type `T` will meet its required lifetime bounds

error[E0309]: the parameter type `T` may not live long enough
  --> src/indention.rs:45:5
   |
45 |     type Output<'ast> where T: 'ast = crate::View<'ast, T, fn(&'ast T) -> T::Output<'ast>>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `T: 'ast`...
   = note: ...so that the type `T` will meet its required lifetime bounds

error[E0309]: the parameter type `T` may not live long enough
  --> src/indention.rs:59:5
   |
59 | /     type Output<'ast2>
60 | |         where
61 | |             T: 'ast2,
62 | |             O: 'ast2
63 | |         = crate::View<'ast2, T, crate::view::MapViewFn<F, fn(F::Output<'ast2>) -> O::Output<'ast2>>>;
   | |_____________________________________________________________________________________________________^
   |
   = help: consider adding an explicit lifetime bound `T: 'ast2`...
   = note: ...so that the type `T` will meet its required lifetime bounds

error[E0309]: the parameter type `O` may not live long enough
  --> src/indention.rs:59:5
   |
59 | /     type Output<'ast2>
60 | |         where
61 | |             T: 'ast2,
62 | |             O: 'ast2
63 | |         = crate::View<'ast2, T, crate::view::MapViewFn<F, fn(F::Output<'ast2>) -> O::Output<'ast2>>>;
   | |_____________________________________________________________________________________________________^
   |
   = help: consider adding an explicit lifetime bound `O: 'ast2`...
   = note: ...so that the type `O` will meet its required lifetime bounds

Sepertinya kode melewati satu tahap (sebelumnya, kesalahan itu terjadi dengan kesalahan serupa, tetapi di antara mereka, kategori kesalahan lain muncul yang hanya terdiri dari E0107 s) hm.

edit : Saya melewatkan pernyataan pertama ( where Self: 'ast ). Bagian itu sudah diperbaiki sekarang. Saya mencoba untuk melanjutkan.


konteks tambahan

oke berikut cuplikannya :

impl<'ast, T, F, O> AsUnindented for crate::View<'ast, T, F>
where
    Self: Clone,
    F: crate::view::ViewFn<T, Output = &'ast O>,
    O: AsUnindented + 'ast,
{
    type Output<'ast2>
        where
            T: 'ast2,
        = crate::View<'ast, T, crate::view::MapViewFn<F, fn(&'ast O) -> O::Output<'ast>>>;

    #[inline]
    fn as_unindented<'ast2>(&'ast2 self) -> Self::Output<'ast2> {
        self.clone().map::<for<'x> fn(&'x O) -> O::Output<'x>, _>(O::as_unindented)
    }
}

kesalahan dengan:

error[E0631]: type mismatch in function arguments
  --> src/indention.rs:66:67
   |
66 |         self.clone().map::<for<'x> fn(&'x O) -> O::Output<'x>, _>(O::as_unindented)
   |                                                                   ^^^^^^^^^^^^^^^^
   |                                                                   |
   |                                                                   expected signature of `for<'x> fn(<F as view::ViewFn<T>>::Output<'x>) -> _`
   |                                                                   found signature of `for<'x> fn(&'x O) -> _`

dan saya tahu bahwa <F as view::ViewFn<T>>::Output<'x> ==> &'ast O dan &'x O tidak sama, tetapi saya tidak tahu cara memperbaikinya (kompiler tidak menerima F: for<'x> crate::view::ViewFn<T, Output = &'x O> terikat).
Kesalahan percobaan lainnya dengan:

error[E0582]: binding for associated type `Output` references lifetime `'x`, which does not appear in the trait input types
  --> src/indention.rs:56:39
   |
56 |     F: for<'x> crate::view::ViewFn<T, Output = &'x O>,
   |                                       ^^^^^^^^^^^^^^

Saya tidak tahu bagaimana mengekspresikan ikatan forall<'x> dalam penugasan tipe keluaran sifat, misalnya

where
    F: crate::view::ViewFn<T, for<'x> Output<'x> = &'x O>,

bahkan tidak mengurai ("mengharapkan salah satu dari + , , , :: , atau > , ditemukan = ").

67510 trek mampu menulis ikatan itu. Contoh itu mungkin juga memerlukan normalisasi malas (#60471).

Apakah tipe keluaran sifat self.clone().map benar-benar tipe O::as_unindented , yaitu tipe argumen peta
Tidak tahu apa itu crate::View , tetapi fungsi map mungkin mengharapkan argumen yang berbeda, oleh karena itu jenisnya tidak cocok.

@sighoya Saya telah menautkan repositori di posting sebelumnya, inilah tautan langsung ke impl crate::view::ViewFn::map

Apa yang dikatakan kompiler tentang ini?:

where
    for<'x> F: crate::view::ViewFn<T, Output<'x> = &'x O>,

Itu tidak mengurai (belum).

@matthewjasper ,

Dari Rust Nomicon , parsing berikut:

where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,

Apakah karena penggunaan Output<'x> = &'x 0> tidak dapat diurai?

Ya, Output<'x>=... tidak diurai di posisi itu.

Saya memiliki buat, grdf yang tidak dapat dikompilasi lagi dengan rustc 1.46.0-nightly . Apakah ada yang berubah di sekitar GAT baru-baru ini?

Kasus saya agak aneh karena saya harus menggunakan trik untuk membuatnya bekerja di tempat pertama. Saya penting memiliki sifat Graph dengan tipe iterator terkait. Untuk membuatnya berfungsi, saya telah menempatkan semua iterator di sifat lain, Iter :

pub trait Iter<'a, T: 'a> {
    type Triples: Iterator<Item = Triple<&'a T>>;
    type Subjects: Iterator<Item = (&'a T, Self::Predicates)>;
    type Predicates: Iterator<Item = (&'a T, Self::Objects)>;
    type Objects: Iterator<Item = &'a T>;
}

pub trait Graph<T = crate::Term> {
    /// Iterators.
    type Iter<'a>: Iter<'a, T>;

    ...
}

Saya memiliki satu implementasi Graph yang berfungsi dengan baik sampai sekarang:

impl<'a, T: 'a + Hash + Eq> crate::Iter<'a, T> for Iterators {
    type Objects = Objects<'a, T>;
    type Predicates = Predicates<'a, T>;
    type Subjects = Subjects<'a, T>;
    type Triples = Iter<'a, T>;
}

impl<T: Hash + Eq> crate::Graph<T> for HashGraph<T> {
    type Iter<'a> = Iterators;

    ...
}

Sekarang saya telah memperbarui rustc gagal dengan yang berikut:

error[E0309]: the parameter type `T` may not live long enough
  --> src/hash_dataset.rs:50:2
   |
50 |     type Iter<'a> = Iterators;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `T: 'a`...
   = note: ...so that the type `T` will meet its required lifetime bounds

Ini tidak masuk akal bagi saya karena T sudah terikat oleh 'a di Iter ...

Oke saya membuatnya bekerja lagi dengan menambahkan beberapa batas where .
Dalam sifat:

type Iter<'a>: Iter<'a, T> where T: 'a;

dan dalam pelaksanaannya:

type Iter<'a> where T: 'a = Iterators;

Tapi saya tidak yakin untuk memahami semantik yang tepat dari batas where , terutama dalam implementasinya (pertama kali saya melihatnya). Dan juga mengapa itu berhasil sebelumnya.

EDIT: Saya bahkan dapat menghapus peretasan jahat saya dan menempatkan iterator terkait dalam sifat itu sendiri.

Menambahkan lebih banyak masalah pemblokiran yang diangkat oleh @DutchGhost

Anda dapat menambahkan https://github.com/rust-lang/rust/issues/74684 juga :)

Saya tidak suka menulis, tolong cepat posting, tetapi fitur ini telah terhenti selama hampir tiga tahun, dan saya percaya peringkat sebagai salah satu fitur baru yang paling diinginkan.

Di mana kita dengan ini? Rangkuman status terbaru di sini adalah oleh @LukasKalbertodt mulai Juni 2018 . Apakah menunggu di "pengkapuran" ?

Pengamatan naif: hampir semua penggunaan yang saya inginkan untuk GAT hanya memerlukan satu parameter seumur hidup. Apakah versi GAT yang hanya berlaku seumur hidup akan lebih mudah dikirimkan?

https://github.com/rust-lang/rust/issues/44265#issuecomment -568247656 adalah pembaruan (agak singkat).

67510 adalah fitur ICE/hilang terakhir yang perlu diterapkan.

Apakah RFC ini memungkinkan Monad dan Functor secara langsung? Atau ada lagi pekerjaan yang perlu dilakukan di HKT?

Apakah RFC ini memungkinkan Monad dan Functor secara langsung? Atau ada lagi pekerjaan yang perlu dilakukan di HKT?

@ibraheemdev RFC menyatakan

Ini tidak menambahkan semua fitur yang diinginkan orang ketika mereka berbicara tentang tipe-tipe yang lebih tinggi. Misalnya, itu tidak mengaktifkan ciri-ciri seperti Monad. Beberapa orang mungkin lebih suka menerapkan semua fitur ini sekaligus. Namun, fitur ini kompatibel dengan jenis polimorfisme jenis lain yang lebih tinggi, dan tidak menghalangi penerapannya dengan cara apa pun. Faktanya, ini membuka jalan dengan memecahkan beberapa detail implementasi yang juga akan berdampak pada jenis kebaikan yang lebih tinggi, seperti aplikasi parsial.

@ibraheemdev : perasaan saya adalah bahwa cara paling idiomatis untuk memungkinkan monad dan functors adalah dengan memperkenalkan ciri-ciri umum yang terkait , tetapi tipe terkait generik tentu saja merupakan prasyarat.

Apakah ada jalur ke Monad yang tidak memerlukan GAT?

@ibraheemdev Secara hipotesis ya, dimungkinkan untuk mengimplementasikan HKT secara langsung dan kemudian menerapkan sifat Monad di atas. Namun, tidak ada pekerjaan yang terjadi ke arah itu, dan mungkin tidak akan pernah, karena pendekatan itu tidak benar-benar menyelesaikan masalah yang dimiliki Rust: https://twitter.com/withoutboats/status/1027702531361857536

Mungkin saya salah, tapi saya pikir GAT mengizinkan sesuatu seperti

trait MonadFamily {
    type Monad<T>;
    fn pure<T>(inner: T) -> Self::Monad<T>;
    fn bind<T, U, F: FnOnce(T) -> U>(this: Self::Monad<T>, f: F) -> Self::Monad<U>;
}

@ibraheemdev

Apakah ada jalur ke Monad yang tidak memerlukan GAT?

Yup, lihat Metode Meniru Jenis yang Lebih Tinggi di Karat . Ia bahkan bekerja pada stabil sekarang.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat