Skip to content

Commit 673301a

Browse files
authored
Add new section in debugging chapter to use custom Rust compiler (#16)
* Add new section in debugging chapter to use custom Rust compiler * Re-ignore error code
1 parent badb3ae commit 673301a

File tree

1 file changed

+92
-39
lines changed

1 file changed

+92
-39
lines changed

content/debugging-techniques.md

Lines changed: 92 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -185,40 +185,52 @@ error that looks like follows:
185185

186186
```text
187187
error[E0599]: the method `format_to_string` exists for struct `Person`, but its trait bounds were not satisfied
188+
--> debugging-techniques.md:180:23
188189
|
189-
46 | pub struct Person {
190+
54 | pub struct Person {
190191
| ----------------- method `format_to_string` not found for this struct because it doesn't satisfy `Person: CanFormatToString`
191192
...
192-
51 | pub struct PersonComponents;
193+
59 | pub struct PersonComponents;
193194
| --------------------------- doesn't satisfy `PersonComponents: StringFormatter<Person>`
194195
...
195-
65 | println!("{}", person.format_to_string().unwrap());
196+
73 | println!("{}", person.format_to_string().unwrap());
196197
| -------^^^^^^^^^^^^^^^^--
197198
| | |
198199
| | this is an associated function, not a method
199200
| help: use associated function syntax instead: `Person::format_to_string()`
200201
|
201202
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
202203
note: the candidate is defined in the trait `StringFormatter`
204+
--> debugging-techniques.md:125:5
203205
|
204-
14 | fn format_to_string(&self) -> Result<String, Error>;
206+
18 | fn format_to_string(&self) -> Result<String, Error>;
205207
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
206208
note: trait bound `PersonComponents: StringFormatter<Person>` was not satisfied
209+
--> debugging-techniques.md:119:1
207210
|
208-
12 | #[derive_component(StringFormatterComponent, StringFormatter<Context>)]
209-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
211+
12 | / #[cgp_component {
212+
13 | | name: StringFormatterComponent,
213+
14 | | provider: StringFormatter,
214+
15 | | context: Context,
215+
| | ^^^^^^^
216+
16 | | }]
217+
| |__^
210218
note: the trait `StringFormatter` must be implemented
219+
--> debugging-techniques.md:124:1
211220
|
212-
13 | / pub trait CanFormatToString {
213-
14 | | fn format_to_string(&self) -> Result<String, Error>;
214-
15 | | }
221+
17 | / pub trait CanFormatToString {
222+
18 | | fn format_to_string(&self) -> Result<String, Error>;
223+
19 | | }
215224
| |_^
216225
= help: items from traits can only be used if the trait is implemented and in scope
217226
note: `CanFormatToString` defines an item `format_to_string`, perhaps you need to implement it
227+
--> debugging-techniques.md:124:1
218228
|
219-
13 | pub trait CanFormatToString {
229+
17 | pub trait CanFormatToString {
220230
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
221-
= note: this error originates in the attribute macro `derive_component` (in Nightly builds, run with -Z macro-backtrace for more info)
231+
= note: this error originates in the attribute macro `cgp_component` (in Nightly builds, run with -Z macro-backtrace for more info)
232+
233+
error: aborting due to 1 previous error
222234
```
223235

224236
Unfortunately, the error message returned from Rust is very confusing, and not
@@ -343,29 +355,44 @@ same example code as before, we would get the following error message:
343355

344356
```text
345357
error[E0277]: the trait bound `FormatAsJsonString: StringFormatter<Person>` is not satisfied
358+
--> debugging-techniques.md:330:23
346359
|
347-
69 | impl CanUsePerson for Person {}
360+
77 | impl CanUsePerson for Person {}
348361
| ^^^^^^ the trait `StringFormatter<Person>` is not implemented for `FormatAsJsonString`, which is required by `Person: CanFormatToString`
349362
|
350363
= help: the trait `StringFormatter<Context>` is implemented for `FormatAsJsonString`
351364
note: required for `PersonComponents` to implement `StringFormatter<Person>`
365+
--> debugging-techniques.md:265:1
352366
|
353-
12 | #[derive_component(StringFormatterComponent, StringFormatter<Context>)]
354-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
367+
12 | / #[cgp_component {
368+
13 | | name: StringFormatterComponent,
369+
14 | | provider: StringFormatter,
370+
15 | | context: Context,
371+
16 | | }]
372+
| |__^
355373
note: required for `Person` to implement `CanFormatToString`
374+
--> debugging-techniques.md:265:1
356375
|
357-
12 | #[derive_component(StringFormatterComponent, StringFormatter<Context>)]
358-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
376+
12 | / #[cgp_component {
377+
13 | | name: StringFormatterComponent,
378+
14 | | provider: StringFormatter,
379+
15 | | context: Context,
380+
| | ^^^^^^^
381+
16 | | }]
382+
| |__^
359383
note: required by a bound in `CanUsePerson`
384+
--> debugging-techniques.md:326:5
360385
|
361-
64 | pub trait CanUsePerson:
386+
72 | pub trait CanUsePerson:
362387
| ------------ required by a bound in this trait
363-
65 | CanFormatToString
388+
73 | CanFormatToString
364389
| ^^^^^^^^^^^^^^^^^ required by this bound in `CanUsePerson`
365-
= note: `CanUsePerson` is a "sealed trait", because to implement it you also need to implement `main::_doctest_main_check_traits_md_229_0::CanFormatToString`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
390+
= note: `CanUsePerson` is a "sealed trait", because to implement it you also need to implement `main::_doctest_main_debugging_techniques_md_255_0::CanFormatToString`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
366391
= help: the following type implements the trait:
367392
Context
368-
= note: this error originates in the attribute macro `derive_component` (in Nightly builds, run with -Z macro-backtrace for more info)
393+
= note: this error originates in the attribute macro `cgp_component` (in Nightly builds, run with -Z macro-backtrace for more info)
394+
395+
error: aborting due to 1 previous error
369396
```
370397

371398
The error message is still pretty confusing, but it is slightly more informative
@@ -525,24 +552,50 @@ pub trait CanUsePerson:
525552
This technique can hopefully help speed up the debugging process, and determine
526553
which dependency is missing.
527554

528-
## Future Improvements
555+
## Improving The Compiler Error Message
529556

530557
The need of manual debugging using check traits is probably one of the major blockers
531-
for spreading CGP for wider adoption. Although it is not technically an unsolvable
532-
problem, it is a matter of allocating sufficient time and resource to improve the
533-
error messages from Rust.
534-
535-
When the opportunity arise, we plan to eventually work on submitting pull requests
536-
for improving the error messages when the constraints from blanket implementations
537-
cannot be satisfied. This book will be updated once we get an experimental version
538-
of the Rust compiler working with improved error messages.
539-
540-
We also consider exploring the option of building a custom compiler plugin similar
541-
to Clippy, which can be used to explain CGP-related errors in more direct ways.
542-
Similarly, it should not be too challenging to build IDE extensions similar to
543-
Rust Analyzer, which can provide more help in fixing CGP-related errors.
544-
545-
Until improved tooling becomes available, we hope that the use of check traits
546-
for debugging is at least sufficient for early adopters. From this chapter onward,
547-
we are just starting to explore what can be done with the basic framework of CGP
548-
in place.
558+
for spreading CGP for wider adoption. However, it is possible to improve the error
559+
messages returned from the Rust compiler so that we can more easily find out what
560+
went wrong.
561+
562+
When Rust fails to resolve the constraints for `Person: CanFormatString`, it in fact
563+
knows that the reason for the failure is caused by unsatisfied _indirect_ constraints
564+
such as `Person: Serialize`. So what we need to do is to make Rust prints out the
565+
unsatisfied constraints.
566+
567+
We have a fix for this on an [experimental fork](https://github.com/contextgeneric/rust/tree/show-pending-constraints-in-fulfillment-error)
568+
of the Rust compiler. The changes made are roughly 30 lines of code, and we are preparing
569+
to contribute the patch upstream. But until that is merged and stabilized, you can try
570+
to use the custom Rust compiler to debug any CGP error.
571+
572+
Following are the steps to use the modified Rust compiler:
573+
574+
- Clone our fork of the Rust compiler at `https://github.com/contextgeneric/rust.git`, or add it as a secondary git remote.
575+
- Checkout the branch `show-pending-constraints-in-fulfillment-error`.
576+
- Build the Rust compiler following the [official guide](https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html).
577+
- Link the compiled custom compiler using `rustup link`, aliasing it to a custom name like `cgp`. e.g. `rustup toolchain link cgp build/host/stage1`.
578+
- Run your project using the custom compiler, e.g. `cargo +cgp check`.
579+
580+
If everything is working, you should see similar error messages as before, but with additional information included:
581+
582+
```text
583+
error[E0277]: the trait bound `FormatAsJsonString: StringFormatter<Person>` is not satisfied
584+
--> content/debugging-techniques.md:330:23
585+
|
586+
77 | impl CanUsePerson for Person {}
587+
| ^^^^^^ the trait `StringFormatter<Person>` is not implemented for `FormatAsJsonString`
588+
|
589+
= help: the following constraint is not satisfied: `Person: Serialize`
590+
= help: the trait `StringFormatter<Context>` is implemented for `FormatAsJsonString`
591+
note: required for `PersonComponents` to implement `StringFormatter<Person>`
592+
```
593+
594+
After the main error is shown, we can also see an extra help hint that says:
595+
`the following constraint is not satisfied: Person: Serialize`. Thanks to that,
596+
we can now much more easily pin point the source of error, and proceed to fix
597+
our CGP program.
598+
599+
We hope that our patch will soon be accepted by the Rust project, so that future
600+
versions of Rust will be more accessible for CGP. When that happens, we will
601+
update this chapter to reflect the changes.

0 commit comments

Comments
 (0)