1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//! This module has two purposes:
//!
//! 1. Provide the convenience method `emit_with_attr_note` and add it via
//! extension trait to `Diagnostic`.
//!
//! 2. Make `Diagnostic` work on stable by providing an own `Diagnostic` type
//! that prints the messages in a less-nice way. That way, other modules
//! don't have to worry about the stable/nightly distinction. `SpanExt` is
//! an extension trait that adds the `err()` method to the `Span` type. That
//! method works exactly like `Span::error()` but returns "our"
//! `Diagnostic`. Other modules can simply `use diag::SpanExt` and use
//! `.err()` on spans.
//!
use crate;
/// Extension trait that adds a convenience method to `Diagnostic`. This is
/// simply to reduce duplicate code in other modules.
// ==============================================================
// Logic for stable/nightly mode starts here.
//
// First, we define a `Diagnostic` type. If we compile with the `nightly`
// feature, it's simple a typedef to `proc_macro::Diagnostic`. If we don't
// compile in nightly mode, we can't use that type, since it's still unstable.
// So in that case, we define our own type that tries to mimic the original
// `Diagnostic`.
pub type Diagnostic = crateDiagnostic;
pub
// We provide the methods that `proc_macro::Diagnostic` also has here. Or
// rather: we only implement the subset that this crate actually uses.
//
// When we're not on the nightly compiler, we can't show a nice error. So how
// do we show the error then? The idea is to generate a token stream that
// contains `compile_error!(msg)` macro invocations. This macro is part of the
// standard library and emits `msg` as error. This is fairly useful for our
// case. However, a big limitation is that we can only emit one message. So in
// order to also show notes later added to the `Diagnostic`, we simply add
// "note: {the_note}" to the error string. This is crude and ugly, but it
// works.
//
// What about spans? Good question! Spans are important, but without a proper
// `Diagnostic` API, we can't properly support spans on errors and notes. The
// compiler will point to the `compile_error!()` invocation we generate. But we
// can use another hack to improve the situation slightly! On the token stream
// (containing `compile_error!()`) we generate, we can modify the spans of the
// individual token trees. If we set all spans to the span the error originates
// from, the compiler thinks that the `compile_error!()` code snippet has the
// span from the actual error source. That means that the error message will
// point to the actual error source!
//
// There is only a small problem: this only works when we get a proper span.
// Sadly, on stable, we can only get correct spans for individual token trees,
// not even token streams. We can't combine spans. As a consequence, spans are
// only correct if they come directly from a `TokenTree`. In general, errors
// coming from the `proxy` module have proper spans while errors from other
// modules don't have proper spans (on stable!). "Not proper" means that the
// span is simply `call_site()` -- it points to the `#[auto_impl()]` attribute.
//
// It could be worse, but it's simply true: for good error messages, nightly is
// required.
// Another problem with our `Diagnostic` hack on stable: the real
// `Diagnostic::emit()` doesn't return anything and modifies global state (it
// prints directly to stdout). We can't simply print! In our case it would be
// correct to pass a `TokenStream` ass the `Err()` variant of a result back up
// the stack and display it at the end. Two problems with that approach:
//
// - That's not how this application was build. Instead, it's build with the
// future `proc_macro` API in mind. And we wouldn't want to change everything
// back once it's stable.
// - On nightly, we don't want to pass TokenStreams up the stack. We can't have
// a completely different structure on nightly vs. on stable.
//
// Thus, we just "simulate" the original `emit()` by also modifying global
// state. We simply have a list of error token streams. This list is added to
// the final token stream at the end (in case of an error). It's not a very
// nice solution, but it's only a hack while stable doesn't offer something
// proper.
use RefCell;
thread_local!
/// On stable, we just copy the error token streams from the global variable.
pub
/// On nightly, we don't use and don't have a strange global variable. Instead,
/// we just return an empty token stream. That's not a problem because all of
/// our errors were already printed.
pub
/// Extension trait to add the `err()` method to `Span`. This makes it easy to
/// start a `Diagnostic` from a span.
pub