Skip to main content

Label

Struct Label 

Source
pub struct Label {
    pub span: Span,
    pub message: Option<String>,
    pub style: LabelStyle,
}

Fields§

§span: Span§message: Option<String>§style: LabelStyle

Implementations§

Source§

impl Label

Source

pub fn primary(span: Span, message: impl Into<Option<String>>) -> Self

Examples found in repository?
examples/compiler.rs (lines 50-53)
39fn main() {
40  let source = r#"fn main() {
41    let name = "hello
42    let x = 42;
43    println(name);
44}"#;
45
46  let mut engine = DiagnosticEngine::<LangError>::new();
47
48  engine.emit(
49    Diagnostic::new(LangError::UnterminatedString, "unterminated string literal")
50      .with_label(Label::primary(
51        Span::new("main.lang", 2, 16, 6),
52        Some("string starts here but never closes".into()),
53      ))
54      .with_help("close the string with a matching `\"`"),
55  );
56
57  engine.emit(
58    Diagnostic::new(LangError::UnusedVariable, "unused variable `x`")
59      .with_label(Label::primary(
60        Span::new("main.lang", 3, 8, 1),
61        Some("declared here but never used".into()),
62      ))
63      .with_help("prefix with `_` to silence: `_x`"),
64  );
65
66  engine.print_all(source);
67}
More examples
Hide additional examples
examples/api_validator.rs (lines 50-53)
38fn main() {
39  let request_body = r#"{
40  "name": "Alice",
41  "age": -5,
42  "email": "not-an-email",
43  "role": "superadmin"
44}"#;
45
46  let mut engine = DiagnosticEngine::<ApiError>::new();
47
48  engine.emit(
49    Diagnostic::new(ApiError::ValueOutOfRange, "`age` must be a positive integer")
50      .with_label(Label::primary(
51        Span::new("POST /users", 3, 9, 2),
52        Some("negative values not allowed".into()),
53      ))
54      .with_help("age must be between 0 and 150"),
55  );
56
57  engine.emit(
58    Diagnostic::new(ApiError::InvalidFormat, "`email` is not a valid email address")
59      .with_label(Label::primary(
60        Span::new("POST /users", 4, 11, 14),
61        Some("missing @ symbol".into()),
62      ))
63      .with_help("expected format: user@domain.com"),
64  );
65
66  engine.emit(
67    Diagnostic::new(ApiError::DeprecatedEndpoint, "POST /users is deprecated, use POST /v2/users")
68      .with_label(Label::primary(Span::new("request", 1, 0, 1), None))
69      .with_note("this endpoint will be removed in v3"),
70  );
71
72  engine.print_all(request_body);
73}
examples/sql_engine.rs (lines 48-51)
37fn main() {
38  let query = r#"SELECT u.name, o.total
39FROM users u
40JOIN orders o ON u.id = o.user_id
41WHERE u.age / 0 > 10
42  AND o.status = active"#;
43
44  let mut engine = DiagnosticEngine::<SqlError>::new();
45
46  engine.emit(
47    Diagnostic::new(SqlError::DivisionByZero, "division by zero in expression")
48      .with_label(Label::primary(
49        Span::new("query.sql", 4, 6, 11),
50        Some("this will always fail at runtime".into()),
51      ))
52      .with_note("division by a literal zero is never valid"),
53  );
54
55  engine.emit(
56    Diagnostic::new(SqlError::UnknownColumn, "unknown column `active`")
57      .with_label(Label::primary(
58        Span::new("query.sql", 5, 18, 6),
59        Some("not a known column".into()),
60      ))
61      .with_help("did you mean the string `'active'`?"),
62  );
63
64  engine.emit(
65    Diagnostic::new(SqlError::FullTableScan, "query requires a full table scan on `users`")
66      .with_label(Label::primary(
67        Span::new("query.sql", 2, 5, 7),
68        Some("no index on `users.age`".into()),
69      ))
70      .with_help("consider adding an index: CREATE INDEX idx_users_age ON users(age)"),
71  );
72
73  engine.print_all(query);
74}
examples/config_linter.rs (lines 49-52)
36fn main() {
37  let config = r#"[package]
38name = "my-app"
39version = "1.0"
40edition = "2018"
41authors = ["me"]
42authors = ["you"]
43license = 42"#;
44
45  let mut engine = DiagnosticEngine::<ConfigError>::new();
46
47  engine.emit(
48    Diagnostic::new(ConfigError::DuplicateKey, "duplicate key `authors`")
49      .with_label(Label::primary(
50        Span::new("Cargo.toml", 6, 0, 7),
51        Some("second definition here".into()),
52      ))
53      .with_label(Label::secondary(
54        Span::new("Cargo.toml", 5, 0, 7),
55        Some("first defined here".into()),
56      ))
57      .with_help("remove one of the duplicate entries"),
58  );
59
60  engine.emit(
61    Diagnostic::new(ConfigError::InvalidValue, "expected string for `license`, found integer")
62      .with_label(Label::primary(
63        Span::new("Cargo.toml", 7, 10, 2),
64        Some("expected a string like \"MIT\"".into()),
65      )),
66  );
67
68  engine.emit(
69    Diagnostic::new(ConfigError::DeprecatedField, "`edition = \"2018\"` is outdated").with_label(
70      Label::primary(
71        Span::new("Cargo.toml", 4, 0, 18),
72        Some("consider updating to \"2021\" or \"2024\"".into()),
73      ),
74    ),
75  );
76
77  engine.print_all(config);
78}
examples/demo.rs (lines 88-91)
74fn demo_compiler() {
75  println!("[compiler]\n");
76
77  let source = r#"fn main() {
78    let name = "hello
79    let x = 42;
80    let result = a + b * c;
81    println(name);
82}"#;
83
84  let mut engine = DiagnosticEngine::<LangError>::new();
85
86  engine.emit(
87    Diagnostic::new(LangError::UnterminatedString, "unterminated string literal")
88      .with_label(Label::primary(
89        Span::new("main.lang", 2, 16, 6),
90        Some("string starts here but never closes".into()),
91      ))
92      .with_help("close the string with a matching `\"`"),
93  );
94
95  engine.emit(
96    Diagnostic::new(LangError::TypeMismatch, "mismatched types in expression")
97      .with_label(Label::primary(
98        Span::new("main.lang", 4, 17, 1),
99        Some("this is a string".into()),
100      ))
101      .with_label(Label::secondary(
102        Span::new("main.lang", 4, 21, 1),
103        Some("this is an int".into()),
104      ))
105      .with_note("cannot add `String` and `i32`")
106      .with_help("convert one side: `a.parse::<i32>()`"),
107  );
108
109  engine.emit(
110    Diagnostic::new(LangError::UnusedVariable, "unused variable `x`")
111      .with_label(Label::primary(
112        Span::new("main.lang", 3, 8, 1),
113        Some("declared here but never used".into()),
114      ))
115      .with_help("prefix with `_` to silence: `_x`"),
116  );
117
118  engine.print_all(source);
119}
120
121fn demo_sql() {
122  println!("\n[sql engine]\n");
123
124  let query = r#"SELECT u.name, o.total
125FROM users u
126JOIN orders o ON u.id = o.user_id
127WHERE u.age / 0 > 10
128  AND o.status = active"#;
129
130  let mut engine = DiagnosticEngine::<SqlError>::new();
131
132  engine.emit(
133    Diagnostic::new(SqlError::DivisionByZero, "division by zero in expression")
134      .with_label(Label::primary(
135        Span::new("query.sql", 4, 6, 11),
136        Some("this will always fail at runtime".into()),
137      ))
138      .with_note("division by a literal zero is never valid"),
139  );
140
141  engine.emit(
142    Diagnostic::new(SqlError::UnknownColumn, "unknown column `active`")
143      .with_label(Label::primary(
144        Span::new("query.sql", 5, 18, 6),
145        Some("not a known column".into()),
146      ))
147      .with_help("did you mean the string `'active'`?"),
148  );
149
150  engine.emit(
151    Diagnostic::new(SqlError::FullTableScan, "query requires a full table scan on `users`")
152      .with_label(Label::primary(
153        Span::new("query.sql", 2, 5, 7),
154        Some("no index on `users.age`".into()),
155      ))
156      .with_help("consider adding an index: CREATE INDEX idx_users_age ON users(age)"),
157  );
158
159  engine.print_all(query);
160}
161
162fn demo_config() {
163  println!("\n[config linter]\n");
164
165  let config = r#"[package]
166name = "my-app"
167version = "1.0"
168edition = "2018"
169authors = ["me"]
170authors = ["you"]
171license = 42"#;
172
173  let mut engine = DiagnosticEngine::<ConfigError>::new();
174
175  engine.emit(
176    Diagnostic::new(ConfigError::DuplicateKey, "duplicate key `authors`")
177      .with_label(Label::primary(
178        Span::new("Cargo.toml", 6, 0, 7),
179        Some("second definition here".into()),
180      ))
181      .with_label(Label::secondary(
182        Span::new("Cargo.toml", 5, 0, 7),
183        Some("first defined here".into()),
184      ))
185      .with_help("remove one of the duplicate entries"),
186  );
187
188  engine.emit(
189    Diagnostic::new(ConfigError::InvalidValue, "expected string for `license`, found integer")
190      .with_label(Label::primary(
191        Span::new("Cargo.toml", 7, 10, 2),
192        Some("expected a string like \"MIT\"".into()),
193      )),
194  );
195
196  engine.emit(
197    Diagnostic::new(ConfigError::DeprecatedField, "`edition = \"2018\"` is outdated")
198      .with_label(Label::primary(
199        Span::new("Cargo.toml", 4, 0, 18),
200        Some("consider updating to \"2021\" or \"2024\"".into()),
201      )),
202  );
203
204  engine.print_all(config);
205}
Source

pub fn secondary(span: Span, message: impl Into<Option<String>>) -> Self

Examples found in repository?
examples/config_linter.rs (lines 53-56)
36fn main() {
37  let config = r#"[package]
38name = "my-app"
39version = "1.0"
40edition = "2018"
41authors = ["me"]
42authors = ["you"]
43license = 42"#;
44
45  let mut engine = DiagnosticEngine::<ConfigError>::new();
46
47  engine.emit(
48    Diagnostic::new(ConfigError::DuplicateKey, "duplicate key `authors`")
49      .with_label(Label::primary(
50        Span::new("Cargo.toml", 6, 0, 7),
51        Some("second definition here".into()),
52      ))
53      .with_label(Label::secondary(
54        Span::new("Cargo.toml", 5, 0, 7),
55        Some("first defined here".into()),
56      ))
57      .with_help("remove one of the duplicate entries"),
58  );
59
60  engine.emit(
61    Diagnostic::new(ConfigError::InvalidValue, "expected string for `license`, found integer")
62      .with_label(Label::primary(
63        Span::new("Cargo.toml", 7, 10, 2),
64        Some("expected a string like \"MIT\"".into()),
65      )),
66  );
67
68  engine.emit(
69    Diagnostic::new(ConfigError::DeprecatedField, "`edition = \"2018\"` is outdated").with_label(
70      Label::primary(
71        Span::new("Cargo.toml", 4, 0, 18),
72        Some("consider updating to \"2021\" or \"2024\"".into()),
73      ),
74    ),
75  );
76
77  engine.print_all(config);
78}
More examples
Hide additional examples
examples/demo.rs (lines 101-104)
74fn demo_compiler() {
75  println!("[compiler]\n");
76
77  let source = r#"fn main() {
78    let name = "hello
79    let x = 42;
80    let result = a + b * c;
81    println(name);
82}"#;
83
84  let mut engine = DiagnosticEngine::<LangError>::new();
85
86  engine.emit(
87    Diagnostic::new(LangError::UnterminatedString, "unterminated string literal")
88      .with_label(Label::primary(
89        Span::new("main.lang", 2, 16, 6),
90        Some("string starts here but never closes".into()),
91      ))
92      .with_help("close the string with a matching `\"`"),
93  );
94
95  engine.emit(
96    Diagnostic::new(LangError::TypeMismatch, "mismatched types in expression")
97      .with_label(Label::primary(
98        Span::new("main.lang", 4, 17, 1),
99        Some("this is a string".into()),
100      ))
101      .with_label(Label::secondary(
102        Span::new("main.lang", 4, 21, 1),
103        Some("this is an int".into()),
104      ))
105      .with_note("cannot add `String` and `i32`")
106      .with_help("convert one side: `a.parse::<i32>()`"),
107  );
108
109  engine.emit(
110    Diagnostic::new(LangError::UnusedVariable, "unused variable `x`")
111      .with_label(Label::primary(
112        Span::new("main.lang", 3, 8, 1),
113        Some("declared here but never used".into()),
114      ))
115      .with_help("prefix with `_` to silence: `_x`"),
116  );
117
118  engine.print_all(source);
119}
120
121fn demo_sql() {
122  println!("\n[sql engine]\n");
123
124  let query = r#"SELECT u.name, o.total
125FROM users u
126JOIN orders o ON u.id = o.user_id
127WHERE u.age / 0 > 10
128  AND o.status = active"#;
129
130  let mut engine = DiagnosticEngine::<SqlError>::new();
131
132  engine.emit(
133    Diagnostic::new(SqlError::DivisionByZero, "division by zero in expression")
134      .with_label(Label::primary(
135        Span::new("query.sql", 4, 6, 11),
136        Some("this will always fail at runtime".into()),
137      ))
138      .with_note("division by a literal zero is never valid"),
139  );
140
141  engine.emit(
142    Diagnostic::new(SqlError::UnknownColumn, "unknown column `active`")
143      .with_label(Label::primary(
144        Span::new("query.sql", 5, 18, 6),
145        Some("not a known column".into()),
146      ))
147      .with_help("did you mean the string `'active'`?"),
148  );
149
150  engine.emit(
151    Diagnostic::new(SqlError::FullTableScan, "query requires a full table scan on `users`")
152      .with_label(Label::primary(
153        Span::new("query.sql", 2, 5, 7),
154        Some("no index on `users.age`".into()),
155      ))
156      .with_help("consider adding an index: CREATE INDEX idx_users_age ON users(age)"),
157  );
158
159  engine.print_all(query);
160}
161
162fn demo_config() {
163  println!("\n[config linter]\n");
164
165  let config = r#"[package]
166name = "my-app"
167version = "1.0"
168edition = "2018"
169authors = ["me"]
170authors = ["you"]
171license = 42"#;
172
173  let mut engine = DiagnosticEngine::<ConfigError>::new();
174
175  engine.emit(
176    Diagnostic::new(ConfigError::DuplicateKey, "duplicate key `authors`")
177      .with_label(Label::primary(
178        Span::new("Cargo.toml", 6, 0, 7),
179        Some("second definition here".into()),
180      ))
181      .with_label(Label::secondary(
182        Span::new("Cargo.toml", 5, 0, 7),
183        Some("first defined here".into()),
184      ))
185      .with_help("remove one of the duplicate entries"),
186  );
187
188  engine.emit(
189    Diagnostic::new(ConfigError::InvalidValue, "expected string for `license`, found integer")
190      .with_label(Label::primary(
191        Span::new("Cargo.toml", 7, 10, 2),
192        Some("expected a string like \"MIT\"".into()),
193      )),
194  );
195
196  engine.emit(
197    Diagnostic::new(ConfigError::DeprecatedField, "`edition = \"2018\"` is outdated")
198      .with_label(Label::primary(
199        Span::new("Cargo.toml", 4, 0, 18),
200        Some("consider updating to \"2021\" or \"2024\"".into()),
201      )),
202  );
203
204  engine.print_all(config);
205}

Trait Implementations§

Source§

impl Clone for Label

Source§

fn clone(&self) -> Label

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Label

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Label

§

impl RefUnwindSafe for Label

§

impl Send for Label

§

impl Sync for Label

§

impl Unpin for Label

§

impl UnsafeUnpin for Label

§

impl UnwindSafe for Label

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.