Rust: 🔬 مشكلة تتبع الأنواع العامة المرتبطة (GAT)

تم إنشاؤها على ٢ سبتمبر ٢٠١٧  ·  67تعليقات  ·  مصدر: rust-lang/rust

التعليق الأكثر فائدة

https://github.com/rust-lang/rust/issues/44265#issuecomment -568247656 هو تحديث (مقتضب إلى حد ما).

67510 هي آخر ميزة رئيسية مفقودة / ICE تحتاج إلى التنفيذ.

ال 67 كومينتر

فيما يلي نوع من خطة التنفيذ سأسعى إلى مواكبة التطورات.

  • [] الخطوة الأولى: إضافة دعم إلى AST والطباعة الجميلة

    • ربما تكون الخطوة الأولى هي البدء في تحليل النماذج الجديدة وإضافة دعم لها إلى AST.

    • انظر إلى هذا التعليق لمزيد من الأفكار التفصيلية هنا .

    • يجب أن نكون قادرين على كتابة بعض اختبارات الإعراب فقط وكذلك اختبار توظيف الطابعة الجميلة

    • عندما نصل إلى خفض HIR ، يمكننا أن نخطئ في حالة وجود أي GAT

    • يمكننا أيضًا عمل بوابة الميزة بعد ذلك

  • [ ] المزيد قادم

اسمحوا لي أن أبدأ بالكتابة عن AST بمزيد من التفصيل. أولاً ، دعنا نناقش كيف يعمل اليوم :

يتم تعريف عنصر type Foo: Bar [= Baz]; في تعريف سمة بواسطة متغير AST هذا . يتضمن ذلك الحدود ( Bar ) والقيمة الافتراضية (الاختيارية) Baz . يتم تعريف الاسم في الهيكل TraitItem .

يتم تعريف عنصر type Foo = Bar; في ضمانة سمة بواسطة متغير AST هذا - الذي يتضمن فقط النوع Bar ، لأن Foo إلخ يتم تحديده في ImplItem الهيكل .

تعتبر الأساليب حالة مثيرة للاهتمام لأنه يمكن بالفعل جعلها عامة. يتم الإعلان عن هذه المعلمات العامة في الحقل Generics # $ لهيكل MethodSig . هذا مثال على البنية Generics .

رأيي هو أن أفضل ما يمكن فعله هو "رفع" Generics من الأساليب إلى TraitItemImplItem ) بحيث ينطبق بالتساوي على جميع أشكال السمات والضمانات. في الوقت الحالي ، لن ندعم الثوابت العامة ، على ما أعتقد ، لكن بصراحة من المحتمل أنها ستسقط من العمل الذي نقوم به على أي حال ، لذا ستكون امتدادًا صغيرًا. أعتقد أن العمل سوف يتحسن إذا خططنا لهم الآن.

ربما تكون العلاقات العامة الأولى اللائقة هي القيام بهذا التغيير فقط ، مع الحفاظ على جميع الوظائف الحالية الأخرى كما هي. أي أننا سنزيد من Generics إلى TraitItemImplItem ) و من MethodSig . سنقوم بتوفير Generics فارغًا لغير الأساليب. سنعمل من خلال الكود الحالي ، وسباكة الأدوية الجنيسة حسب الحاجة لجعلها تعمل.

تضمين التغريدة شكرا جزيلا! لقد بدأت التجربة مع هذا الليلة الماضية وأنا فخور بأن أقول إنني وجدت نفس الأماكن التي أشرت إليها في تعليقك حول AST. : ابتسم: (بالنظر إلى أن هذه كانت المرة الأولى لي في الريف ، فأنا أعتبر ذلك إنجازًا!)

لم أفكر في رفع الأدوية الجنيسة إلى TraitItem . كان أسلوبي هو وضع Generics في TraitItemKind::Type لأن هذا هو المكان الذي يتم فيه تخزين إعلان النوع بالفعل. نهجك منطقي أيضًا ، لذا سأعمل على تنفيذ ذلك. نظرًا لأنني ما زلت جديدًا تمامًا على قاعدة الشفرة هذه ، فأنا مهتم بمعرفة مخاطر أسلوبي إذا تم استخدامه على الأسلوب الذي اقترحته. هل يمكن أن تعطيني نظرة ثاقبة لعملية تفكيرك؟ : مبتسم:

هذا هو التغيير الذي كنت سأقوم به:

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),
}

تحرير: الإجابة عن طريق nikomatsakis على Gitter

فيما يتعلق بمخاطر وضعها في النوع
أعتقد أن هذا يمكن أن يعمل أيضًا
السبب في أنني كنت مترددًا في القيام بذلك
هو أننا نريد حقًا أن نفعل نفس الأشياء (من الناحية النظرية على الأقل) للطرق والأنواع
و - كما قلت - من حيث المبدأ لا أرى أي سبب لعدم تمكننا من فعل نفس الأشياء للثوابت
أعتقد أنه إذا قمت بنقل Generics إلى متغير النوع
من المحتمل أن يعمل ذلك بشكل جيد ، ولكن إذا نظرت إلى الأمر ، فغالبًا ما يتعين علينا الآن القيام "بشيء واحد للأنواع / الثوابت ، وشيء واحد للأساليب" على وجه التحديد لأنهم مختلفون
لذلك أظن أن الشفرة ستصبح أكثر اتساقًا
لست متأكدًا حقًا من الطريقة التي ستسير بها الأمور لأكون صريحًا =) - قد يكون الأمر مؤلمًا
ولكن في كثير من الأحيان تكون الأشياء أكثر عمومية مما يجب أن تكون ليست سيئة للغاية ، لأنه يمكنك إدراج span_bug! المكالمات في الحالات المستحيلة في الوقت الحالي (ثم نأتي لاحقًا ونصلحها)

حسنا! الخطوة التالية هي تمديد المحلل اللغوي. هنا بعض النصائح. لنبدأ بعناصر السمات.

يوزع هذا الروتين عناصر السمات . نريد تمديد الحالة التي تتعامل مع الأنواع المرتبطة لتحليل أشياء مثل type Foo<....> = ...; (ربما أيضًا جمل أين). ( <...> هو "الأدوية" التي أضفناها للتو إلى AST.)

يستخدم حاليًا parse_ty_param ، والذي يقوم بشكل أساسي بتحليل شيء مثل T: Foo إلخ. سيتعين علينا التوقف عن القيام بذلك ، لأن القواعد النحوية لإقرارات النوع المرتبطة لم تعد تتطابق مع معلمات النوع. لذلك ربما نرغب في إضافة شيء مثل parse_trait_item_assoc_ty . يمكن أن يبدأ هذا كنوع من استنساخ parse_ty_param() ، ولكن بعد ذلك سنرغب في تعديله لاستدعاء parse_generics() هنا. سيقوم هذا الروتين بتحليل إعلان الأدوية ( <...> ) إذا كان أحدهم موجودًا ، وإلا فإنه سيعيد فقط الأدوية الفارغة. ثم نريد إضافة استدعاء لتحليل الجمل هنا - يمكنك نمذجة ذلك في الاستدعاء الذي يحدث عند تحليل الطرق ، لاحظ أن النتيجة مخزنة في generics الذي قمنا بتحليله سابقًا.

بمجرد القيام بذلك ، يجب أن نتمكن من إضافة بعض اختبارات التحليل. سأفعل ذلك عن طريق إنشاء دليل مثل src/test/run-pass/rfc1598-generic-associated-types/ وإضافة الملفات التي تتوقع تحليلها بنجاح هناك. في الوقت الحالي لن يعملوا بشكل صحيح ، لكن هذا لا يهم. فقط أضف وظيفة رئيسية فارغة. ثم يمكننا أيضًا إضافة أمثلة لا ينبغي تحليلها إلى src/test/ui/rfc1598-generic-associated-types/ (انظر COMPILER_TESTS.md للحصول على توجيهات حول إضافة اختبارات واجهة المستخدم ).

شيء آخر - نحتاج إلى تمييز بوابة هذا العمل في هذه المرحلة ، لتجنب استخدام الأشخاص لهذه الأشياء في إنشاءات مستقرة. هناك بعض التعليمات لإضافة ميزة بوابة هنا على التزوير (انظر القسم الأخير). يجب أن نضيف visit_trait_item و visit_impl_item للزائر في feature_gate.rs ؛ إذا لم يكن هذا العنصر طريقة ، ولكنه يحتوي على أدوية غير فارغة ، فيمكننا استدعاء gate_feature_post ( مثال ).

لإعداد تحليل الاسم ، أعتقد أن كل ما يتعين علينا القيام به هو الحصول على "الأضلاع" المناسبة في مكانها (عناصر تحليل الاسم تنظم مجموعات الأسماء الموجودة في النطاق في أضلاع ؛ يمثل كل ضلع مستوى ربط واحدًا). على سبيل المثال للحصول على:

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

سيكون لدينا الأضلاع التالية:

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

بشكل عام ، نمذجة الأشياء حول كيفية عمل الأساليب ليست فكرة سيئة. قد نقوم أيضًا ببعض "التدقيق المستقبلي" هنا ، على ما أعتقد.

إليك الكود الذي يجلب معلمات نوع الطريقة إلى النطاق (هذا خاص بالطريقة المحددة في سمة):

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

بينما بالنسبة لـ type المُعرَّفة في سمة ، فقد تم تشفيرنا بشكل ثابت لإضافة ضلع معلمة فارغ ( NoTypeParameters ):

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

الآن بعد أن تم وضع الأدوية الجنيسة في مكانها الصحيح على كل عنصر سمة / ضمني ، أعتقد أننا ربما نرغب في إزالة المعالجة لـ type واستخراج معالجة الطريقة بحيث تحدث عند مستوى أعلى. بالنسبة للعناصر (على سبيل المثال ، const ) حيث لا توجد أدوية عامة ، يجب أن يكون الضلع الذي تم إدخاله حديثًا فارغًا وبالتالي غير ضار (آمل).

نقاط أخرى مهمة:

انت وجدت الفكرة.

petrochenkov - الصوت عن الحق؟

تضمين التغريدة

الصوت عن الحق؟

كل شيء يبدو صحيحا.

الخطوة التالية. قرار مدى الحياة.

للأفضل أو للأسوأ ، يتم ذلك حاليًا في جزء منفصل تمامًا من التعليمات البرمجية من تحليل الاسم الآخر. هذا لأنه يحدث بعد إنشاء HIR. يكاد يكون من المؤكد أن هذا سيتغير لكنه لم يتغير بعد.

الأفكار الأساسية هي نفسها الموجودة في تحليل الاسم العادي ، على الرغم من أننا لا نسمي الأشياء "أضلاعًا" بل "نطاقات". =)

هناك بعض المضاعفات الخفيفة بسبب مفهوم الأعمار "المتأخرة". إنها ليست ذات صلة هنا حقًا - كل الأعمار لنوع عام مرتبط ستكون "مقيدة مبكرًا" ، وهو نوع من الحالة البسيطة. عمر "الالتزام المتأخر" هو عمر تم الإعلان عنه في أسلوب أو دالة لا يتم توفير قيمتها حتى يتم استدعاء الأسلوب. لن أخوض في التفاصيل هنا لأنها ليست ذات صلة - الشيء الرئيسي هو أننا لا نريد أن نتبع نفس نموذج الأساليب بدقة كما نفعل مع الأنواع الأخرى من العناصر العامة ، على عكس تحليل الاسم الآخر حالات.

هنا مثال قليلا من التعليمات البرمجية. هذا هو الرمز الذي يزور impl أو struct أو عنصر آخر غير وظيفي. في هذه الحالات ، كما هو الحال في GATs ، نريد أساسًا إحضار جميع المعلمات الدائمة من Generics إلى النطاق وتعيينها إلى فترات العمر "المبكرة":

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

يمكنك أن ترى أنه ينشئ أولاً متجهًا للأعمار ، ويستدعي Region::early لكل واحد:

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

بعد ذلك يقوم بإنشاء Scope . المتغير next_early_index يقوم فقط بحساب عدد الأعمار المبكرة في النطاق. نظرًا لأن هذا الرمز خاص بالعناصر ، فسيكون هذا دائمًا عدد الأعمار المحددة المبكرة المُعلن عنها في هذا العنصر الحالي. (سننظر لاحقًا في حالة نضع فيها عمرًا إضافيًا في النطاق ، وهو ما نريده أكثر لاتفاقيات الجات.)

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

أخيرًا ، نستدعي with() . ستعمل هذه الطريقة على إدخال النطاق في النطاق واستدعاء الإغلاق. ستشاهد أي عمر نزوره داخل هذا الإغلاق تلك الأسماء التي حددناها للتو على أنها في النطاق:

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

حسنًا ، لنلقِ نظرة الآن على مثال آخر. تغطي هذه القضية "السمات الضمنية". تفاصيل ما يفعله ليست بهذه الأهمية (أي أنك لست مضطرًا إلى تقليل impl Trait في حد ذاتها). يكفي أن نقول إنها تضع بعض الأعمار الجديدة المبكرة في نطاقها - وهذا بالضبط ما نريد أن نفعله لاتفاقيات الجات.

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

اسمحوا لي أن أبرز بعض الأشياء. أولاً ، تقوم الطريقة next_early_index بإرجاع الفهرس التالي غير المحدد مسبقًا:

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

هذا يوفر نقطة انطلاق. بعد ذلك ، نستخدم Region::early مرة أخرى لإنشاء تعريفات عمرية مبكرة جديدة سيتم حلها مقابل:

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

أخيرًا ، نضع هؤلاء في النطاق عن طريق استدعاء with مرة أخرى:

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

حسنًا ، هذان مثالان. سنرغب في القيام بشيء يشبه إلى حد كبير الأمر الثاني. سنريد تعديل تعريفات هاتين الطريقتين:

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

سيحتاج كلاهما ، بالنسبة للأنواع المرتبطة ، إلى معالجة الأدوية ذات الصلة. (يجب أن يؤكدوا بشكل محتمل ، في الحالات الأخرى ، أن الأدوية الجنسية فارغة).

لذا فقد تعاملت مع هذا في وقت سابق اليوم. أود التأكد من أنني على الطريق الصحيح:

  • كل ما يجب القيام به هو إدخال العمر الافتراضي على الخريطة ثم السير في السمة / العنصر الضمني؟ يبدو أن الفحص يعمل ، على الرغم من صعوبة تحديده (انظر لاحقًا) ... قد يعمل فقط في الحالة البسيطة (غير المحدودة).
  • لقد أسقطت محظورات معلمات النوع لـ qpath_to_ty و associated_path_def_to_ty في librustc_typeck/astconv.rs لإصلاح أخطاء type parameters are not allowed on this type . أعتقد أن هذا يحتاج إلى استبداله ببعض الشيكات. أيضا...
  • أنا أتعرض لحوادث من الطباعة الآن. (الكتابة ، على وجه التحديد)

يتم تشغيل حالات فشل الطباعة في src/test/compile-fail/struct-path-associated-type.rs لأنها توفر أدوية عامة للقيم التي ليس لها نوع مرتبط.

إذا كنت أقرأ الأشياء بشكل صحيح ، فأنا بحاجة على الأقل إلى إضافة تحقق من تطابق الأعداد العامة المرتبطة (محاولة معرفة مكان القيام بذلك ...) ، وربما أيضًا إجراء فحوصات أخرى لإضافة أنواع للعقد وما إلى ذلك.

الذهاب إلى العمل على ذلك ، ولكن يتم تقدير المؤشرات حول ما إذا كنت أسير في الاتجاه الصحيح.

مرحبًاbrandonson! أنا أكره عدم تشجيع أي شخص على اختراق مترجم Rust ، لكنني أعتقد أن sunjay كان يعمل بالفعل على اختراق نفس الأشياء وكان نوعًا ما يسعى إلى هذا التغيير منذ البداية ، لذلك ربما يكون من المنطقي بالنسبة لهم الانتهاء هذا التغيير أيضًا (أعتقد أنهم بدأوا بالفعل). لست متأكدًا مما إذا كانت هناك طريقة واضحة لموازاة هذا الجهد (بالتأكيد هذا ممكن ، لكن علينا أن نلعب الخطوات قليلاً قبل توزيع الورق).

ومع ذلك ، إذا كنت مهتمًا بالعثور على شيء ما لمعالجته ، فهل يمكنني أن أوصي بمعالجة بعض الأخطاء في هذا المعلم الهام ؟ https://github.com/rust-lang/rust/issues/46472 لا يبدو أنه يتم التحدث عنها ، يمكنني محاولة ترك بعض التعليقات هناك قريبًا.

بالتأكيد لا أقصد أن أخطو على أصابع قدم أي شخص ، لكنني لم أر أي شيء يشير إلى حدوث تقدم إضافي بالفعل (على الرغم من الاعتراف بأن التعليق المتعلق بالخطوات التالية حديث نوعًا ما). حقًا ، لقد بدأت في محاولة حل هذا لأنني أردت GAT عدة مرات في اليومين الماضيين ، لذلك في حين أنني لا أمانع بالضرورة في العمل من خلال بعض عناصر NLL في المستقبل ، فهذا أمر أعلى في قائمة الأشياء التي يجب حلها في اللحظة.

sunjay ، إذا كنت لا تزال تعمل بنشاط / تخطط للعمل على هذا ، فيرجى إبلاغي بذلك - لا جدوى من أن أقوم بتكرار عملك على هذا.

مرحبًا brandonson ، شكرًا لك على حرصك واستعدادك للمساعدة. :) أنا بالفعل أعمل بنشاط على هذا. لقد مررت بكل جزء من التنفيذ خطوة بخطوة أثناء العمل عن كثب مع Niko لفهمه بشكل صحيح.

سأفعل كل ما بوسعي لإخراج هذا في أقرب وقت ممكن. أنا حقا أريد هذه الميزة أيضا!

كيف يجري التقدم؟ =) لا أستطيع الانتظار لتجربة هذا في كل ليلة <3

أتساءل كيف سيعمل المقطع العرضي لـ GAT و const genics وما إذا كان جزءًا من المقترحات عند وضعها معًا؟

مثال على ما أعنيه:

trait Foo {
    type Bar<const N>;
}

مرحبًا sunjay ، أعتقد أن هذه ميزة مهمة جدًا ، فقد ورد ذكرها بشدة في تعليقات خارطة الطريق لعام 2018. كيف تتقدم؟ شكرا لعملكم!

هذه هي أكثر ميزة مرغوبة في الوقت الحالي. آمل أن تصبح هذه أولوية وأن تجد طريقها إلى الليل قريبًا!

لقد التقيت مؤخرًا بـ sunjay ، المشغول الآن بالمدرسة وأشياء أخرى ، لمحاولة وضع الخطوات التالية هنا. لقد التقينا أنا وهم في مرحلة ما وناقشنا استراتيجية التنفيذ الشاملة ، وبلغت ذروتها في الالتزام بإعادة الشراء الخاصة بهم حيث تركنا مجموعة من التعليقات المضمنة .

أعتقد أن الإستراتيجية الأكثر منطقية للمضي قدمًا هي ذات شقين:

  • أولاً ، نحتاج إلى كتابة المزيد من الاختبارات.
  • هناك بعض أوجه القصور المعروفة في المحلل اللغوي وبعض أجزاء "الواجهة الأمامية" الأخرى للنظام ، نحتاج إلى تعدادها وإصلاحها. من المحتمل أن نجد المزيد في الاختبارات.
  • في هذه المرحلة ، نحن على استعداد لبدء اختراق نظام السمات المناسب:

    • لقد تم بالفعل وضع بعض الأسس ، لذا نأمل أن تكون هذه مهمة "إعادة بناء" إلى حد كبير

    • لكن علي أن أكتب بالتفصيل ، لا يوجد وصف مكتوب للخطة التي أعرفها وليس لدي وقت لذلك في هذه اللحظة.

سأبدأ بمحاولة كتابة بعض التعليمات المتعلقة بإعادة: الاختبارات ، نظرًا لأن هذه تكون قابلة للتنفيذ على الفور ، ثم حدد موعدًا لبعض الوقت لاحقًا هذا الأسبوع لكتابة كيفية عمل بقية التصميم وكيفية الحصول على الكود من مكانه الآن إلى حيث يجب أن يكون.

هذا رائع !! حظًا موفقًا لـ sunjay في هذا وجميع المساعي الأخرى.

ستكون الخطوة الأولى هي التأكد من أن لدينا مجموعة كاملة من الاختبارات. يمكن العثور على الاختبارات الحالية في:

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

بمجرد النظر إلى هؤلاء ، يمكننا بالفعل رؤية بعض الأعمال التي يتعين القيام بها:

  • [] construct_with_other_type.rs - يعطي خطأ E0110 غير متوقع
  • [x] empty_generics - يتحقق من أن type Bar<,> يعطي خطأ ، يبدو جيدًا
  • [x] generic-associated-types-where.rs - التحقق من أنه يمكننا تحليل عبارات where في الأماكن الصحيحة ، يبدو جيدًا
  • [] generic_associated_type_undeclared_lifetimes.rs - يعطي خطأ E0110 غير متوقع
  • [] iterable.rs - يعطي خطأ E0110 غير متوقع
  • [] pointer_family.rs - يعطي خطأ E0109 غير متوقع
  • [] streaming_iterator.rs - يعطي خطأ E0110 غير متوقع

الأماكن التي تفتقر إلى التغطية

  • [] ليس لدينا حاليًا الكثير من اختبارات "الاستخدام المتوقع" - أي الأشياء التي يجب أن تنجح

    • يبدو أن pointer_family في هذا الاتجاه

    • أتوقع نوعًا من الاختبار trait Iterable { type Item; type Iter<'a>: Iterator<Item = &'a Self::Item>; }

  • [] اختبارات التظليل مدى الحياة - نحظر عمومًا التظليل مدى الحياة ، لذا يجب أن تكون هذه غير قانونية:

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

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

  • [] يبدو أن بناء الجملة "مؤهل بالكامل" لم يتم اختباره

    • على سبيل المثال ، الاختبار pointer_family يتضمن $ # Self::Pointer<T> ، لكن ليس <Self as PointerFamily>::Pointer<T>

  • [] عدد خاطئ من الحجج لـ GAT. على سبيل المثال ، بالنظر إلى تعريف Iterable أعلاه:

    • <T as Iterable>::Item - ألا توجد معلمات على الإطلاق؟ سيئة.

    • لاحظ أننا قد نقبل هذا في بعض السياقات ، حيث أننا في بعض السياقات المماثلة نسمح بإلغاء فترات الحياة.

      يمكنني الذهاب في أي من الاتجاهين هنا ؛ أفضل أن يكتب الناس '_ صريحًا في مثل هذه الحالات.

    • <T as Iterable>::Item<'_> - صحيح!

    • <T as Iterable>::Item<T> - أنواع كثيرة جدًا!

    • إلخ ، سيكون من الجيد إجراء اختبارات تستغرق كلا النوعين وعمرًا بالطبع

  • [] الافتراضات على الأنواع المرتبطة؟ trait Foo { type Bar<T, U = T> where T: PartialEq<U>; }

    • في هذه الحالة ، سيكون SomeType::Bar<u32> shor لـ SomeType::Bar<u32,u32> ، والذي يجب علينا التحقق منه.

إصلاح أخطاء E0110 غير المتوقعة

تم الإبلاغ عن الخطأ E0110 بواسطة prohibit_type_params :

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

الخطوة الأولى هي معرفة من أين يتم استدعاء ذلك. أفضل طريقة للقيام بذلك هي الحصول على بنية محلية واستخدام -Ztreat-err-as-bug مع RUST_BACKTRACE=1 . لكن لا يمكنني عرض هذه النتائج لأن rustc لا يزال يتشكل. : P لذا بدلاً من ذلك قمت بإجراء سريع rg prohibit_type_params ، دعني أذهب سريعًا لأشير إلى حالة واحدة مشبوهة أراها.

طلب واحد من associated_path_def_to_ty :

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

كما يشير التعليق ، يتم استدعاء هذا لحل المكون Pointer<T> في مسار مثل Self::Pointer<T> (لاحظ أن معلمات النوع تعتبر جزءًا من مقطع المسار ، جنبًا إلى جنب مع الاسم الذي يتم إرفاقها به ). حتى GAT ، لم تكن معلمات النوع قانونية هناك (على سبيل المثال ، T::Item ) ، لذلك لدينا قيد شامل:

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

من الواضح أن هذا لن ينجح. يجب علينا إزالة هذا السطر واستبداله بنوع من التحقق من أنه إذا تم توفير المعلمات ، فإنها تتطابق مع الرقم المتوقع. للقيام بذلك ، من المفترض أننا نريد بعض رموز التحقق من الأخطاء المشابهة لما هو موجود في create_substs_for_ast_path . ربما نرغب في إنشاء بعض التعليمات البرمجية المشتركة هنا ، خاصةً للمحاسبة باستخدام الإعدادات الافتراضية - ربما يمكننا بالفعل إعادة استخدام هذه الوظيفة؟

هل مازال أحد يعمل على هذا؟ يبدو لي أن هذا الطريق طويل لنقطعه. GAT هو بلدي RFC المطلوب. إذا لم يكن الأمر كذلك ، فأنا أحب المشاركة في بعض الاختبارات ...

rickyhan ، لذا كان Centril و gavento يتحدثان عن سمات WG حول تقسيم عمل الاختبار ، لكنني لا أعرف ما إذا كان قد تم إحراز أي تقدم. ربما يمكنهم أن يتناغموا. أعتقد أن العلاقات العامة ستكون موضع ترحيب. =)

آسف إذا كنت غبيًا ، لكن هل هذا النوع من الأشياء سيكون قانونيًا مع GATs؟

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>;
}

ما هي حالة هذا؟ أعلم أن الطباشير اكتسب مؤخرًا دعم الجات. هل هذا ينوي الهبوط في الصدأ قريبًا؟

@ mark-im لقد أعطيته لقطة الأسبوع الماضي. من وجهة نظري ، هناك محلل لغوي (على الرغم من عدم وجود اختبارات). لكن "التنفيذ" لم يكتب بعد. (انظر https://github.com/rust-lang/rust/issues/44265#issuecomment-330915766 لمزيد من التفاصيل)

quadrupleslap AIUI ، سيكون ذلك ممكنًا في وقت لاحق ، ولكن في البداية ، ستدعم GAT فقط معلمات العمر ..

Boscop يحدد RFC أن معلمات النوع سيتم دعمها أيضًا.

هل يعرف شخص ما الحالة الدقيقة لتنفيذ بناء الجملة في rustc؟ يبدو في الغالب هناك ، ولكن الحدود ذات التصنيف الأعلى تولد ICEs:
http://play.rust-lang.org/؟gist=a48959858ed5dd432c2396feae5c3cc1&version=nightly&mode=debug

سأحتاج على الأقل إلى تنفيذ بناء الجملة بالكامل من أجل المضي قدمًا في عمل الطباشير. إذا كان أي شخص لا يزال يعمل على بناء الجملة ، فيرجى إبلاغي بذلك ، وإلا فقد أذهب وأصلحها بنفسي :)

بالنسبة لي ، يبدو أن الاتصال هو المشكلة الرئيسية التي تؤدي إلى إبطاء تنفيذ اتفاقية الجات. يبدو أن هناك على الأقل عددًا قليلاً من الأشخاص المهتمين بالعمل على هذا ، ولكن لا أحد يعرف حقًا حالة التنفيذ الدقيقة ومن يعمل على هذا بالفعل. ما رأيك في قناة Discord (أو IRC؟) لتتحدث فقط عن تطبيق GATs؟ أعتقد أن ذلك سيساعد بالتأكيد.

أيضًا ، يمكنني بالتأكيد المساهمة ببضعة أيام عمل في الأسابيع التالية للعمل على هذا (لكنني لا أعرف شيئًا عن هذا الجزء من المترجم حتى الآن).

لذلك طلبت قناة مخصصة على Discord. لكن بدلاً من الحصول على قناة ، تعلمت بعض الأشياء. لقد بحثت أيضًا عن كل ما يتعلق بـ GAT. لذلك سأحاول تلخيص جميع المعلومات المتعلقة بهذه الميزة ؛ ربما يكون مفيدًا لبعض الناس. لكني لا أعرف شيئًا ، لذا خذ هذا بحبة من الملح! أيضًا: من فضلك أخبرني إذا كانت بعض المعلومات غير صحيحة حتى أتمكن من إصلاحها.

ملخص جهود التنفيذ المتعلقة باتفاقيات الجات

  • sunjay هبطت اثنين من العلاقات العامة الرائعة:

  • ثم ، لبعض الوقت ، لم يحدث الكثير. ثم لخص نيكو ما لا يزال يجب أن يحدث في هذا التعليق (2018-03-12). بشكل أساسي (أ) كتابة الاختبارات ، (ب) إصلاح الأخطاء في / تحسين المحلل اللغوي / الواجهة الأمامية و (ج) التنفيذ في نظام السمات. تم توضيح النقطة (أ) بمزيد من التفصيل في هذا التعليق (13 مارس 2018).

  • gavento هبطت تمديد اختبارات RFC1598 (GAT) (تم دمج 2018-05-11)

    • لست متأكدًا مما إذا كان تعليق نيكو حول الاختبارات يعكس بالفعل التغييرات التي تم إجراؤها في هذه العلاقات العامة. آخر تعديل من 2018-03-27 ، في نفس اليوم الذي افتتح فيه gavento العلاقات العامة. ( gavento هل يمكنك إخبارنا عن الحالة؟)

منذ ذلك الحين لم تتم إضافة أي اختبارات لواجهة المستخدم . ولا يمكنني العثور على أي علاقات عامة أخرى مرتبطة مباشرة بـ GATs.

ومع ذلك ، يتم العمل على النقطة (ج) من أعلى (نظام السمات) "سرا". بقدر ما أفهمها ، فإن الخطة هي الانتقال إلى أداة حل السمات الجديدة القائمة على الطباشير قريبًا وعدم جعل GATs تعمل على النظام القديم. يتم تتبع تكامل أداة حل السمات الجديدة بواسطة مشكلة تتبع "Chalkification" . كان هناك عدد غير قليل من العلاقات العامة المتعلقة بالطباشير والطباشير. والجدير بالذكر أن هناك طباشير للعلاقات العامة يسمى "إنهاء تنفيذ GATs" (تم دمجه في 2018-05-24). لذلك يبدو أن النظام الأساسي لاتفاقيات الجات موجود بالفعل.

ومع ذلك ، فإن "GATs" في الطباشير هي تطبيق نموذج أولي واستخدامه في rustc ليس مجرد use chalk; . كما أخبرني scalexm : "يبدو أن هناك الكثير من الأشياء التي يجب القيام بها".


لمزيد من المعلومات وللمساعدة ، ربما يكون من المفيد إلقاء نظرة على قناة Discord #wg-traits ومسألة تتبع السمات WG .

لذا أنشأnikomatsakis القناة #wg-traits-gat على خادم rust-lang discord ( انضم هنا ). سيكون من الرائع لو تمكنا من الحصول على كل من يريد المساعدة هناك. بالإضافة إلى عدد قليل من الأشخاص الذين يعرفون حالة هذه الميزة (على وجه الخصوص ، ما الذي لا يزال يتعين القيام به وأين يمكننا المساعدة). يجب أن يجعل ذلك التواصل أسهل وأسرع ، خاصة بالنسبة للأشخاص مثلي الذين لم يشاركوا بعمق / جزء من السمات WG :)

هل هناك أي تحديث لهذا مؤخرا؟ هل ننتظر دمج Chalk في المترجم؟ (ربما هناك مشكلة منفصلة لذلك.)

ربما هناك مشكلة منفصلة لذلك.

48049

تمامًا كملاحظة (ربما تكون معروفة) ، فإن هذا الرمز يزعج المترجم:

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]; }

wdanilo : أعتقد أن هذا هو https://github.com/rust-lang/rust/issues/64755.

varkor رائع ، شكرا!

ملاحظة أخرى (مرة أخرى ، ربما تكون معروفة). بعد تطبيق GAT ، سنكون قادرين على تجريد أكثر من & و &mut ، لذا يمكننا إيقاف نسخ ولصق الكود باستمرار بين الدالتين my_func و my_func_mut :) فيما يلي تنفيذ محتمل لمثل هذا التجريد (المعروف أيضًا باسم 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!()
    }
}

يكاد يجمع. يمكننا أيضًا تنفيذه بدون GAT لكن الأنواع تنفجر:

#![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!()
    }
}

(هذا يجمع في الواقع)

ربما يكون هذا سؤال دعم ولكني أعتقد أنه قد يكون مفيدًا لأولئك الذين يأتون إلى هذه الصفحة لفهم هذا الاقتراح لأنه لم يكن واضحًا تمامًا بالنسبة لي من RFC أو التعليقات هنا:

مع 1.41 ليلاً ، جربت ما يلي:

pub trait MyTrait {
    type MyType<U>;

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

وهذا فشل في التحويل البرمجي ، الخطأ هو "نوع الوسيطة غير مسموح بها" MyType .

بعد ذلك أزلت <U> ، والذي بدا مريبًا لكنني اعتقدت أنني سأجربه:

pub trait MyTrait {
    type MyType<U>;

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

الذي من المستغرب فعل تجميع. ولكن بعد ذلك عندما كتبت إشارة ضمنية:

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

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

هذا أصاب المترجم بالذعر.

أسئلتي هي:

  1. هل هذا النوع من المخطط ممكن الآن لكني أفعله بشكل خاطئ؟
  2. إذا لم يكن ذلك ممكنًا الآن ، فهل سيكون ذلك ممكنًا في ظل هذا الاقتراح؟
  3. إذا كان الأمر كذلك ، فهل هناك أي فكرة عن نوع الجدول الزمني الذي سأتمكن من القيام بذلك كل ليلة؟

شكرا مقدما على وقتك في الإجابة على هذا.

clintonmead أعتقد أنه سيكون ممكنًا في النهاية ، لكن تنفيذ الميزة لم ينته بعد (في الواقع ، يحذرك المترجم من أنه قد يتعطل عند محاولة استخدامه!). لا أعرف ما هو الجدول الزمني.

ربما يستحق التحقق من فريق Chalk لمعرفة ما إذا كان التكامل متقدمًا بدرجة كافية لاستئناف العمل على هذه الميزة؟

تم حظر هذا الآن على

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

هل يمكننا تحديث وصف المشكلة بأدوات الحظر الحالية؟

تمت إضافة المزيد من مشكلات الحظر التي أثارها DutchGhost

ستكون هذه خطوة كبيرة في محاكاة الأنواع الأعلى من النوع.

أتخيل شيئًا كهذا:

// 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)
    }
}

سؤال حول التنفيذ المقترح:

لدي سمة تبدو مثل هذا

trait TradeableResource{
}

ومنفذ يشبه هذا

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

أود أن أكون قادرًا على تقييد جميع منفذي السمة الخاصة بي لتكون "نوعًا جديدًا" (هيكل عنصر واحد يلتف على f64).

هل سيكون ذلك ممكنا مع النظر في التنفيذ المقترح هنا؟

ما يلي يبدو غريبًا بعض الشيء ، لكن آمل أن يوضح ما أريد أن أكون قادرًا على القيام به.

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

ChechyLevas على حد علمي أن هذا ليس ضمن نطاق GADTs.

لكن ما تريد القيام به لا يحتاج إلى GADTs لتبدأ به ، مما يمكنني جمعه ، إذا كنت على استعداد للتخلي عن ضمان أنه نوع جديد وبدلاً من ذلك يتعين عليك الوظائف التي تلتف وتستعيد القيمة الداخلية ، على التوالي . إنها ليست مريحة ، ولكن من المحتمل أن تعمل بشكل جيد بما فيه الكفاية.

لذلك يمكنك القيام بما يلي:

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

(سيتطلب هذا منك أيضًا تنفيذ From في كلا الاتجاهين ، وهو ما أفعله عبر ماكرو)

أود أن أشعر قليلاً بالحالة الحالية لهذا. لقد كنت ألعب بسمات غير متزامنة وأعمار قليلاً.
شيء واحد أردت فعله هو إنشاء trait ReadAt<'r> # $ بنوع ReadAt: Future مرتبط. وهو ما ينجح في كثير من الحالات ، إلا عندما أرغب في استخدام كائنات السمات.

غالبًا لأن القيام بما يلي سيجبرني على إرفاق عمر غير عام كافٍ بـ 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>>`
    ...
}

لذلك فكرت ، ربما يمكن حل هذا باستخدام GAT ، لكنني واجهت مشكلات مماثلة حيث أحتاج إلى بعض السحر اللغوي مرة أخرى ، لأن كائنات السمات تتطلب كتابة أنواع مرتبطة:

يحب:

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) {
}

سأحتاج إلى طريقة لتضمين العمر في HERE . هذا ، على سبيل المثال ، مقبول ، لكن IMO لن يكون كافياً ، لأن R ملموس للغاية:

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)
    }
}

لكن لا يمكنني حقًا اختبار ما إذا كان ذلك سيعمل على أي حال ، لأنني لست متأكدًا من كيفية تحويل هذا إلى كائن سمة ، لأنني لا أعرف كيف سأدخل الأعمار في المقتطف التالي:

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!();
    }
}

نظرًا لأن T::ReadAt يستغرق وقتًا لا يمكنني توفيره ، لذلك سيفقد هذا ملحق بناء الجملة لـ dyn ReadAt<ReadAt<'r> = T::ReadAt<'r>> . (أو لمطابقة معلمات العمر IMO ، يمكن أن يعمل المقتطف أعلاه ؛-))

نظرًا لأنني أستخدم فقط معلمات العمر ، وليس معلمات النوع ، أعتقد أن هذا يجب أن يكون ممكنًا تقنيًا ، ما لم تؤثر معلمات العمر على جداول vtables وأحجام الكتابة بطريقة ما؟

jendrikw يتم تجميع التعليمات البرمجية الخاصة بك وتشغيلها مع أحدث إصدار كل ليلة (1.46). لقد أجريت بعض الاختبارات بأنواع مخصصة وما إلى ذلك. ولكني أفتقر إلى معرفة fp للتحقق من المزيد.

اليوم ، حاولت استخدام GATs لشيء اعتقدت أنه ربما لن يكون العمر عامًا بما يكفي (يتبع رمز العمل ؛ ملف التعليمات البرمجية الكامل ):

/// 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)
    }
}

ثم حاولت استخدام GATs في الكود التالي:

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)
    }
}

هذا لا يعمل. فشل مع E0309 ( the parameter type 'T' may not live long enough ) لكل من تطبيقات السمات. لست متأكدًا من كيفية إصلاح هذا أو إذا كان لدي بعض المفاهيم الخاطئة. يريد المترجم أن أقوم بإرفاق الحد على T عند مستوى impl ، لكن في هذا المستوى ، لا يوجد 'ast مدى الحياة ، ولا أريد تقييد T: 'static (وشيء مثل for<'ast> T: 'ast لا يعمل).

تحرير : لقد حاولت تطبيق GATs على جزء آخر من قاعدة التعليمات البرمجية الخاصة بي ، فقد ألقى خطأ واحدًا فقط (في الوقت الحالي) ، ولكن لا يمكن إصلاح هذا الخطأ ببساطة لأنه يعتمد على إصلاح لمشكلتي المذكورة سابقًا.

يمكن إضافة حدود العمر الافتراضي إلى النوع المرتبط (باستخدام Self: 'ast في إصدار السمة). يوضح هذا الاختبار الشكل الذي يجب أن يبدو عليه:
https://github.com/rust-lang/rust/blob/db4826dd6ca48663a0b4c5ab0681258999017c7d/src/test/ui/generic-associated-types/iterable.rs#L6 -L21

حسنًا ، هذا لا يعمل إلا جزئيًا ...


رسائل خاطئة

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

يبدو أن الكود يمر بمرحلة واحدة (سابقًا ، أخطأ في أخطاء مماثلة ، ولكن فيما بينها ، ظهرت فئة أخرى من الأخطاء تتكون فقط من E0107 s) hm.

تحرير : فاتني البيان الأول ( where Self: 'ast ). تم إصلاح هذا الجزء الآن. أحاول الاستمرار.


سياق إضافي

حسنًا ، المقتطف التالي:

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)
    }
}

أخطاء في:

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) -> _`

وأنا أعلم أن <F as view::ViewFn<T>>::Output<'x> ==> &'ast O و &'x O ليسا متساويين ، لكني لا أعرف كيفية إصلاحه (لا يقبل المترجم F: for<'x> crate::view::ViewFn<T, Output = &'x O> المربوط).
المحاولة الأخرى للأخطاء مع:

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>,
   |                                       ^^^^^^^^^^^^^^

لا أعرف كيفية التعبير عن ربط forall<'x> في تعيين نوع إخراج سمة ، على سبيل المثال

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

لا يحلل حتى ("توقع واحد من + ، , ، :: ، أو > ، تم العثور على = ").

67510 مسارات قادرة على كتابة ذلك الحد. قد يحتاج هذا المثال أيضًا إلى تسوية كسولة (# 60471).

هل نوع خرج السمة self.clone().map هو نوع O::as_unindented ، أي نوع الوسيطة للخريطة
لا تعرف ما هو crate::View ، لكن الدالة map قد تتوقع وسيطة مختلفة ، وبالتالي فإن النوع غير متطابق.

sighoya لقد ربطت المستودع في المنشورات السابقة ، وهذا رابط مباشر إلى الضمانة crate::view::ViewFn::map

ماذا قال المترجم عن هذا ؟:

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

لا تحلل (حتى الآن).

matthewjasper ،

من Rust Nomicon ، التحليلات التالية:

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

هل بسبب استخدام Output<'x> = &'x 0> أنه لا يتم تحليله؟

نعم ، لا يتم تحليل Output<'x>=... في هذا الموضع.

لدي ملف grdf لا يتم تجميعه بعد الآن باستخدام rustc 1.46.0-nightly . هل تغير أي شيء بخصوص GAT مؤخرًا؟

حالتي غريبة بعض الشيء لأنني اضطررت إلى استخدام خدعة لجعلها تعمل في المقام الأول. من الضروري أن أمتلك سمة Graph مع أنواع المكرر المرتبطة. لجعلها تعمل ، لقد وضعت كل التكرارات في سمة أخرى ، 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>;

    ...
}

لدي تطبيق واحد Graph والذي نجح بشكل جيد حتى الآن:

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;

    ...
}

الآن بعد أن قمت بتحديث rustc ، فشل في ما يلي:

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

هذا غير منطقي بالنسبة لي لأن T مرتبط بالفعل بـ 'a بـ Iter ...

حسنًا ، لقد جعلتها تعمل مرة أخرى بإضافة بعض الحدود where .
في السمة:

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

وفي التنفيذ:

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

لكنني لست متأكدًا من فهم الدلالات الدقيقة لحدود where ، لا سيما في التنفيذ (أول مرة رأيت ذلك). وأيضًا لماذا عملت سابقًا.

تحرير: لقد تمكنت حتى من إزالة الاختراق السيئ الخاص بي ووضع التكرارات المرتبطة به في السمة نفسها.

تمت إضافة المزيد من مشكلات الحظر التي أثارهاDutchGhost

يمكنك إضافة https://github.com/rust-lang/rust/issues/74684 أيضًا :)

لا أحب أن أكتب ، من فضلك أسرع المنشورات بالفعل ، لكن هذه الميزة متوقفة منذ ما يقرب من ثلاث سنوات بالفعل ، وأعتقد أن تصنيفها كواحدة من أكثر الميزات الجديدة المرغوبة.

أين نحن مع هذا؟ أحدث ملخص للحالة هنا هو بواسطة LukasKalbertodt من يونيو 2018 . هل تنتظر "الطباشير" ؟

ملاحظة ساذجة: تتطلب جميع استخداماتي المرغوبة لـ GAT تقريبًا معلمة واحدة مدى الحياة. هل سيكون من الأسهل تقديم نسخة مختصرة مدى الحياة من اتفاقيات الجات؟

https://github.com/rust-lang/rust/issues/44265#issuecomment -568247656 هو تحديث (مقتضب إلى حد ما).

67510 هي آخر ميزة رئيسية مفقودة / ICE تحتاج إلى التنفيذ.

هل سيجعل RFC هذا Monad و Functor ممكنًا بشكل مباشر؟ أم أن هناك المزيد من العمل الذي يجب القيام به على HKT؟

هل سيجعل هذا RFC Monad و Functor ممكنين بشكل مباشر؟ أم أن هناك المزيد من العمل الذي يجب القيام به على HKT؟

ibraheemdev يقول RFC

هذا لا يضيف كل الميزات التي يريدها الناس عندما يتحدثون عن الأنواع الأعلى. على سبيل المثال ، لا يقوم بتمكين سمات مثل Monad. قد يفضل بعض الأشخاص تنفيذ كل هذه الميزات معًا مرة واحدة. ومع ذلك ، فإن هذه الميزة متوافقة مع الأنواع الأخرى من تعدد الأشكال العالي النوع ، ولا تمنع تنفيذها بأي شكل من الأشكال. في الواقع ، إنه يمهد الطريق من خلال حل بعض تفاصيل التنفيذ التي ستؤثر أيضًا على أنواع أخرى من اللطف الأعلى ، مثل التطبيق الجزئي.

ibraheemdev : شعوري هو أن الطريقة الأكثر اصطلاحًا لجعل الموناد والمفكرين ممكنة هي تقديم سمات عامة مرتبطة ، لكن الأنواع العامة المرتبطة هي بالتأكيد شرط أساسي.

هل هناك مسار إلى Monad لا يتطلب GAT؟

ibraheemdev افتراضيًا ، سيكون من الممكن تنفيذ HKTs مباشرةً ثم تنفيذ سمة Monad في الأعلى. ومع ذلك ، لا يوجد عمل يحدث في هذا الاتجاه ، وربما لن يحدث أبدًا ، لأن هذا النهج لا يحل بالفعل المشكلات التي يعاني منها روست: https://twitter.com/withoutboats/status/1027702531361857536

ربما أكون مخطئًا ، لكنني أعتقد أن GAT تسمح بشيء مثل

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>;
}

تضمين التغريدة

هل هناك مسار إلى Monad لا يتطلب GAT؟

نعم ، راجع طريقة محاكاة أنواع الصدأ الأعلى نوعًا . حتى أنها تعمل على مستقرة الآن.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات