Skip to content

Commit 8f726b7

Browse files
committed
Include primary span label in VS Code diagnostics
In most cases the primary label span repeats information found elsewhere in the diagnostic. For example, with E0061: ``` { "message": "this function takes 2 parameters but 3 parameters were supplied", "spans": [{"label": "expected 2 parameters"}] } ``` However, with some mismatched type errors (E0308) the expected type only appears in the primary span's label, e.g.: ``` { "message": "mismatched types", "spans": [{"label": "expected usize, found u32"}] } ``` I initially added the primary span label to the message unconditionally. However, for most error types the child diagnostics repeat the primary span label with more detail. `rustc` also renders the duplicate text but because the span label and child diagnostics appear in visually distinct places it's not as confusing. This takes a heuristic approach where it will only add the primary span label if there are no child message lines.
1 parent 27df89f commit 8f726b7

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"message": "mismatched types",
3+
"code": {
4+
"code": "E0308",
5+
"explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"
6+
},
7+
"level": "error",
8+
"spans": [
9+
{
10+
"file_name": "runtime/compiler_support.rs",
11+
"byte_start": 1589,
12+
"byte_end": 1594,
13+
"line_start": 48,
14+
"line_end": 48,
15+
"column_start": 65,
16+
"column_end": 70,
17+
"is_primary": true,
18+
"text": [
19+
{
20+
"text": " let layout = alloc::Layout::from_size_align_unchecked(size, align);",
21+
"highlight_start": 65,
22+
"highlight_end": 70
23+
}
24+
],
25+
"label": "expected usize, found u32",
26+
"suggested_replacement": null,
27+
"suggestion_applicability": null,
28+
"expansion": null
29+
}
30+
],
31+
"children": [],
32+
"rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n"
33+
}

editors/code/src/test/utils/diagnotics/rust.test.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ describe('mapRustDiagnosticToVsCode', () => {
108108
);
109109
assert.strictEqual(
110110
diagnostic.message,
111-
'this function takes 2 parameters but 3 parameters were supplied'
111+
[
112+
'this function takes 2 parameters but 3 parameters were supplied',
113+
'expected 2 parameters'
114+
].join('\n')
112115
);
113116
assert.strictEqual(diagnostic.code, 'E0061');
114117
assert.strictEqual(diagnostic.source, 'rustc');
@@ -170,4 +173,28 @@ describe('mapRustDiagnosticToVsCode', () => {
170173
SuggestionApplicability.Unspecified
171174
);
172175
});
176+
177+
it('should map a mismatched type error', () => {
178+
const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
179+
'error/E0308'
180+
);
181+
182+
assert.strictEqual(
183+
diagnostic.severity,
184+
vscode.DiagnosticSeverity.Error
185+
);
186+
assert.strictEqual(
187+
diagnostic.message,
188+
['mismatched types', 'expected usize, found u32'].join('\n')
189+
);
190+
assert.strictEqual(diagnostic.code, 'E0308');
191+
assert.strictEqual(diagnostic.source, 'rustc');
192+
assert.strictEqual(diagnostic.tags, undefined);
193+
194+
// No related information
195+
assert.deepStrictEqual(diagnostic.relatedInformation, []);
196+
197+
// There are no suggested fixes
198+
assert.strictEqual(suggestedFixes.length, 0);
199+
});
173200
});

editors/code/src/utils/diagnostics/rust.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export function mapRustDiagnosticToVsCode(
182182
const secondarySpans = rd.spans.filter(s => !s.is_primary);
183183

184184
const severity = mapLevelToSeverity(rd.level);
185+
let primarySpanLabel = primarySpan.label;
185186

186187
const vd = new vscode.Diagnostic(location.range, rd.message, severity);
187188

@@ -220,9 +221,17 @@ export function mapRustDiagnosticToVsCode(
220221
}
221222
if (messageLine) {
222223
vd.message += `\n${messageLine}`;
224+
225+
// These secondary messages usually duplicate the content of the
226+
// primary span label.
227+
primarySpanLabel = undefined;
223228
}
224229
}
225230

231+
if (primarySpanLabel) {
232+
vd.message += `\n${primarySpanLabel}`;
233+
}
234+
226235
if (isUnusedOrUnnecessary(rd)) {
227236
vd.tags = [vscode.DiagnosticTag.Unnecessary];
228237
}

0 commit comments

Comments
 (0)