From c9d4b3fb3093c6c44e223ae61a6e16143565e408 Mon Sep 17 00:00:00 2001 From: Sad Lang Dev Date: Mon, 6 Jul 2026 05:52:15 +0300 Subject: [PATCH] =?UTF-8?q?RFC:=20=D9=81=D8=B5=D9=84=20=D8=A7=D9=84=D8=AA?= =?UTF-8?q?=D8=AD=D8=B0=D9=8A=D8=B1=D8=A7=D8=AA=20=D8=B9=D9=86=20=D8=A7?= =?UTF-8?q?=D9=84=D8=A3=D8=AE=D8=B7=D8=A7=D8=A1=20=D9=81=D9=8A=20=D8=A8?= =?UTF-8?q?=D8=A7=D9=86=D9=90=D9=8A=20SIR=20(=D8=A5=D9=86=D9=87=D8=A7?= =?UTF-8?q?=D8=A1=20=D8=A7=D9=84=D8=A8=D9=86=D8=A7=D8=A1=20=D8=A7=D9=84?= =?UTF-8?q?=D9=86=D8=A7=D8=AC=D8=AD=20=D8=A7=D9=84=D8=B5=D8=A7=D9=85=D8=AA?= =?UTF-8?q?=20=D8=AE=D8=B7=D8=A3=D9=8B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit يعالج ثغرة د-١ الأعمق المكتشَفة أثناء P0: SIRBuilder يخلط التحذيرات والأخطاء في errors_ واحد، وbuildModule يُرجع وحدةً غير فارغة رغم امتلائه، فيفحص السائق !sir_module_ فقط ⇒ أخطاء بناء SIR (مثل اطبع(طول())) تُهمَل صمتًا والبناء ينجح خطأً (exit 0)، بينما الإصلاح الساذج (فشل على hasErrors) يحوّل تحذير المطابقة غير الشاملة إلى فشل = انحدار. المقترح: قناة تشخيص موسومة بالخطورة (Error/Warning)؛ hasErrors أخطاء فقط؛ السائق يفشل على الأخطاء ويطبع التحذيرات دون إفشال؛ تصنيف مواقع push فرادى؛ ربط اختياريّ بكتالوج الأخطاء. مؤكَّد بمراجع مصدر dev الدقيقة (statement_match.cpp :546-560، sir_builder_module.cpp:1689، compiler_driver_analysis.cpp:541). الحالة: مقترَح. المدقّق أخضر (15/15). Co-Authored-By: Claude Opus 4.8 (1M context) --- ...2-\330\250\330\247\331\206\331\212-SIR.md" | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 "text/0000-\331\201\330\265\331\204-\330\247\331\204\330\252\330\255\330\260\331\212\330\261\330\247\330\252-\330\271\331\206-\330\247\331\204\330\243\330\256\330\267\330\247\330\241-\331\201\331\212-\330\250\330\247\331\206\331\212-SIR.md" diff --git "a/text/0000-\331\201\330\265\331\204-\330\247\331\204\330\252\330\255\330\260\331\212\330\261\330\247\330\252-\330\271\331\206-\330\247\331\204\330\243\330\256\330\267\330\247\330\241-\331\201\331\212-\330\250\330\247\331\206\331\212-SIR.md" "b/text/0000-\331\201\330\265\331\204-\330\247\331\204\330\252\330\255\330\260\331\212\330\261\330\247\330\252-\330\271\331\206-\330\247\331\204\330\243\330\256\330\267\330\247\330\241-\331\201\331\212-\330\250\330\247\331\206\331\212-SIR.md" new file mode 100644 index 0000000..ea0761b --- /dev/null +++ "b/text/0000-\331\201\330\265\331\204-\330\247\331\204\330\252\330\255\330\260\331\212\330\261\330\247\330\252-\330\271\331\206-\330\247\331\204\330\243\330\256\330\267\330\247\330\241-\331\201\331\212-\330\250\330\247\331\206\331\212-SIR.md" @@ -0,0 +1,178 @@ +- **عنوان المقترح:** فصل التحذيرات عن الأخطاء في بانِي SIR (إنهاء البناء الناجح الصامت خطأً) +- **النطاق:** لغة `text/` (المترجم `sadc` — الواجهة الأماميّة/بانِي SIR) +- **تاريخ البدء:** 2026-07-06 +- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج) +- **الحالة:** مقترَح (PR مفتوح) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +يخلط بانِي SIR (`SIRBuilder`) في المترجم اليوم **التحذيرات والأخطاء في وعاء واحد** +(`errors_`)، بينما تُرجِع `buildModule` وحدةً **غير فارغة** حتّى حين يمتلئ هذا الوعاء +بأخطاء حقيقيّة. فيفحص سائق المترجم `!sir_module_` فقط، فتُهمَل أخطاء بناء SIR **صمتًا** +ويُعَدّ البناء ناجحًا خطأً (`exit 0`). يقترح هذا الـRFC **فصل قناتَي التشخيص** +(أخطاء قاتلة ≠ تحذيرات غير قاتلة) بحيث يفشل البناء عند وجود خطأ واحد، ولا يفشل قطّ +بسبب تحذير — منهيًا صنفًا كاملًا من «النجاح الكاذب». + +# الدافع (Motivation) + +المستخدم يتوقّع أنّ برنامجًا خاطئًا **لا يُترجَم**. اليوم قد يُترجَم ويُعلَن نجاحه. + +مثال ملموس رُصِد أثناء تنفيذ P0 لتجربة محراب: برنامج يستدعي دالّة مضمَّنة بعدد وسائط +خاطئ: + +```sad +اطبع(طول()) # طول تتطلّب وسيطًا واحدًا؛ هنا صفر +``` + +المفسّر يرفضه برسالة خطأ ودودة (نظام الأخطاء ناضج). أمّا المترجم فيبني الوحدة، ويدفع +الخطأ إلى `errors_`، ثمّ **يُرجع الوحدة غير الفارغة** فيمرّ الفحص `!sir_module_` +ويُنتِج ثنائيًّا و`exit 0`. النتيجة: **تباعد صامت بين المحرّكين** وثقة زائفة بالبناء. + +الجذر البنيويّ (مؤكَّد في مصدر `dev`): + +- `compiler/src/frontend/builders/statement_match.cpp:546–560` يبني نصّ + «`Warning: Non-exhaustive match on enum …`» ويدفعه إلى **`b_.errors_`** — أي أنّ + **تحذيرًا** يسكن وعاء **الأخطاء**. +- `compiler/src/frontend/sir_builder_module.cpp:1689` ينهي `buildModule` بـ + `return module_;` بصرف النظر عن محتوى `errors_` (يُرجِع `nullptr` فقط لبرنامج فارغ، + السطر 205). +- `tools/compiler/compiler_driver_analysis.cpp:541` يفحص `!sir_module_` فقط. + +هذا الخلط يجعل الإصلاح الساذج (فشل البناء عند `hasErrors()`) **انحدارًا**: إذ سيحوّل +تحذير «المطابقة غير الشاملة» إلى فشل بناء. لذا يلزم فصلٌ بنيويّ، لا فحص أعمى. + +> ملاحظة سياق: PR اللغة #155 طبّق **إصلاحًا آمنًا مؤقّتًا** — عند `!sir_module_` يُفرِّغ +> `getErrors()` بدل رسالة عامّة صمّاء — ووثّق هذا الحدّ صراحةً كـ«يستحقّ RFC». هذا هو ذاك الـRFC. + +# الشرح التوجيهي (Guide-level explanation) + +بعد التنفيذ، يميّز المترجم بين مستويَي خطورة: + +- **خطأ (Error):** يمنع إنتاج ثنائيّ. البناء يفشل بحالة خروج غير صفريّة ويطبع السبب. +- **تحذير (Warning):** لا يمنع البناء. يُطبَع على `stderr` ويستمرّ البناء. + +فالبرنامج `اطبع(طول())` يصير: + +``` +خطأ: الدالّة «طول» تتطلّب وسيطًا واحدًا، لكن مُرِّر صفر. + → لم يُنتَج ثنائيّ. (حالة الخروج ≠ 0) +``` + +بينما مطابقة غير شاملة على تعداد: + +``` +تحذير: مطابقة غير شاملة على التعداد «لون» — ناقص: أزرق. + → أُنتِج الثنائيّ. (تحذير لا يمنع البناء) +``` + +يوائم هذا سلوك المفسّر ويجعل «يُترجَم» تعني «صحيح بنيويًّا» فعلًا، لا مجرّد «لم ينهَر البانِي». + +# الشرح المرجعي (Reference-level explanation) + +## قناة تشخيص موسومة بالخطورة + +يُستبدَل `std::vector errors_` في `SIRBuilder` بقناة موسومة. الشكل المفضّل: + +```cpp +enum class DiagSeverity { Error, Warning }; +struct SIRDiagnostic { + DiagSeverity severity; + std::string message; // أو رمز كتالوج (انظر أدناه) + SourceLocation location; // موقع المصدر (إن توفّر) +}; +std::vector diagnostics_; +``` + +- `hasErrors()` تُعيد `true` فقط إن وُجِد تشخيص بخطورة `Error` (لا تحذير). +- تُضاف `warnings()`/`errors()` كمرشِّحات مشتقّة؛ يبقى `getErrors()` متوافقًا لكنّه يُرجِع + الأخطاء فقط (لا التحذيرات) — تغيير دلاليّ مقصود لمستهلكيه. +- **قرار `buildModule`:** الخيار الأنظف أن يبقى التوقيع كما هو ويُرجِع الوحدة، ويحكم + **السائق** على النجاح عبر `hasErrors()` (أخطاء فقط). بديلًا: يُرجِع `nullptr` عند وجود + خطأ — لكنّه يفقد التشخيص الجزئيّ ويصعّب الاستمرار لجمع أخطاء متعدّدة. **نوصي بالأوّل.** + +## مواقع الاستدعاء (migration) + +كلّ `errors_.push_back(...)` الحاليّة تُصنَّف صراحةً: + +- `statement_match.cpp:48` «Failed to build match expression» ⇒ **Error**. +- `statement_match.cpp:560` «Non-exhaustive match …» ⇒ **Warning** (نقلة الخطورة الجوهريّة). +- `sir_builder_module.cpp:204` «Null program AST» ⇒ **Error** (يبقى `nullptr`). +- بقيّة المواقع تُراجَع فرادى (لا تحويل جماعيّ أعمى). + +## السائق (`compiler_driver_analysis.cpp`) + +بعد `buildModule`: + +```cpp +for (const auto& w : sir_builder_->warnings()) + diagnostics_.report_warning(w, file); // يُطبَع، لا يُفشِل +if (sir_builder_->hasErrors()) { // أخطاء فقط + for (const auto& e : sir_builder_->errors()) + diagnostics_.report_error(e, file); + return false; // فشل حقيقيّ +} +// وإلّا: تابِع توليد الشيفرة حتّى لو وُجِدت تحذيرات +``` + +يُلغى فحص `!sir_module_` كبوّابة وحيدة (يبقى تحقّقًا دفاعيًّا من null فقط). + +## الأنظمة المتشابكة + +- **مصدر الحقيقة (`language-truth/`):** لا كلمات/أنواع جديدة. لكن رسائل SIR الحاليّة سلاسل + إنجليزيّة خام («Error: …», «Warning: …») تخالف مبدأ الكتالوج. **يُفضَّل** ربطها بكتالوج + الأخطاء (`language-truth/errors/`) برموز جديدة (خطأ لعدد الوسائط، تحذير للمطابقة غير + الشاملة) — يوائم [[0002-فرض-كل-الأخطاء-عبر-الكتالوج]] ونمط + `buildBilingualMessage`. يجوز فصله كعمل تابع كي لا يتضخّم هذا الـRFC. +- **Lexer/Parser/AST:** لا تغيير. +- **المفسّر:** لا تغيير (سلوكه صحيح أصلًا — هو المرجع). +- **المترجم (sadc):** جوهر التغيير (بانِي SIR + السائق). لا أثر على LLVM IR ذاته. +- **نظام الأخطاء:** إدخال مفهوم «الخطورة» في قناة SIR؛ ربط اختياريّ بالكتالوج. +- **الأدوات:** LSP قد يستهلك التحذيرات مستقبلًا كتشخيصات صفراء (تحسين تابع، خارج النطاق). +- **التوافق الخلفي:** برامج **صحيحة** لا تتأثّر. برامج **خاطئة تُترجَم اليوم خطأً** + ستفشل صوابًا (تصحيح مقصود، لا كسر). التحذيرات القائمة تبقى غير قاتلة (لا انحدار). + +## اختبارات منع الانحدار + +- حالة `@expect_error` للمترجم على `اطبع(طول())` — يجب أن يفشل البناء (يكشف الثغرة). + ⚠️ فخّ معروف: harness الاختبار الحاليّ لـ`@expect_error` يتوقّف عند خطأ المفسّر ولا + يشغّل المترجم — يلزم توسيعه ليؤكّد فشل المترجم أيضًا، وإلّا يبقى التباعد خفيًّا. +- حالة إيجابيّة: برنامج بمطابقة غير شاملة **يُترجَم بنجاح** مع طبع التحذير (يمنع انحدار + تحويل التحذير إلى فشل). +- `tests/system/builtin_errors/` تبقى خضراء. + +# السلبيات (Drawbacks) + +- لمسة على كلّ مواقع `errors_.push_back` (تصنيف يدويّ) — جهد لمرّة واحدة. +- برامج كانت «تُبنى» ستتوقّف عن البناء؛ قد يفاجئ من اعتمد على السلوك الخاطئ (لكنّه خلل يُصحَّح). +- إدخال الخطورة يزيد سطح واجهة `SIRBuilder` قليلًا. + +# المبرّرات والبدائل (Rationale and alternatives) + +- **لماذا الفصل بالخطورة؟** يعالج الجذر (خلط القناتين) لا العَرَض، ويتجنّب انحدار + تحويل التحذيرات إلى أخطاء. +- **بديل: فشل على أيّ `errors_`.** مرفوض — يحوّل تحذير المطابقة غير الشاملة إلى فشل بناء. +- **بديل: `buildModule` يُرجِع `nullptr` عند خطأ.** مرفوض كخيار أساس — يفقد التشخيص الجزئيّ + ويعيق جمع أخطاء متعدّدة في مرور واحد. +- **أثر عدم الفعل:** يبقى «النجاح الصامت خطأً» وتباعد المحرّكين — تآكل ثقة جوهريّ في المترجم. + +# أعمال سابقة (Prior art) + +- **Rust/Clang/GCC:** تشخيصات موسومة بالخطورة (`error`/`warning`/`note`)؛ الأخطاء وحدها + تمنع الإنتاج، والتحذيرات قابلة للترقية (`-Werror`) اختياريًّا — نموذج مطابق لما نقترحه. +- **Go:** يرفض الشيفرة غير الصحيحة صراحةً ولا «ينجح صامتًا». +- الدرس: **قناة تشخيص واحدة موسومة بالخطورة** هي المعيار الصناعيّ؛ خلط القناتين شذوذ. + +# توجّهات مستقبلية (Future possibilities) + +- **ترقية التحذيرات إلى أخطاء** (نظير `-Werror`): علمٌ يجعل التحذيرات قاتلة للبناءات الصارمة. +- **ربط كامل بكتالوج الأخطاء:** تحويل كلّ رسائل SIR الخام إلى رموز كتالوج ثنائيّة اللغة بمواقع + مصدر — يوائم [[0002-فرض-كل-الأخطاء-عبر-الكتالوج]]. +- **تشخيصات LSP الصفراء:** استهلاك قناة التحذيرات في خادم اللغة لعرضها كتسطير أصفر حيّ في محراب. +- **جمع أخطاء متعدّدة في مرور واحد:** الاستفادة من عدم إجهاض `buildModule` لعرض كلّ الأخطاء دفعةً. + +# أسئلة غير محسومة (Unresolved questions) + +- هل نربط رسائل SIR بكتالوج الأخطاء ضمن هذا الـRFC، أم كعمل تابع مباشرة بعده؟ +- هل نضيف مبكّرًا مفهوم «ترقية التحذير إلى خطأ» (نظير `-Werror`) أم نؤجّله؟ +- الصيغة الدقيقة لتوسيع harness `@expect_error` ليغطّي مسار المترجم (يُحسَم مع تنفيذ الاختبار).