Skip to content

Commit 272fb23

Browse files
Don't use source-map when detecting struct field shorthand
1 parent dae6dc6 commit 272fb23

File tree

4 files changed

+104
-121
lines changed

4 files changed

+104
-121
lines changed

Diff for: compiler/rustc_typeck/src/check/demand.rs

+100-117
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
1313
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1414
use rustc_middle::ty::print::with_no_trimmed_paths;
1515
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
16-
use rustc_span::symbol::sym;
16+
use rustc_span::symbol::{sym, Symbol};
1717
use rustc_span::{BytePos, Span};
1818

1919
use super::method::probe;
@@ -24,7 +24,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2424
pub fn emit_coerce_suggestions(
2525
&self,
2626
err: &mut DiagnosticBuilder<'_>,
27-
expr: &hir::Expr<'_>,
27+
expr: &hir::Expr<'tcx>,
2828
expr_ty: Ty<'tcx>,
2929
expected: Ty<'tcx>,
3030
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
109109

110110
pub fn demand_coerce(
111111
&self,
112-
expr: &hir::Expr<'_>,
112+
expr: &hir::Expr<'tcx>,
113113
checked_ty: Ty<'tcx>,
114114
expected: Ty<'tcx>,
115115
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -129,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129129
/// will be permitted if the diverges flag is currently "always".
130130
pub fn demand_coerce_diag(
131131
&self,
132-
expr: &hir::Expr<'_>,
132+
expr: &hir::Expr<'tcx>,
133133
checked_ty: Ty<'tcx>,
134134
expected: Ty<'tcx>,
135135
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -338,67 +338,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
338338
})
339339
.collect();
340340

341-
if self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span) {
342-
if let Ok(code) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
343-
match &compatible_variants[..] {
344-
[] => { /* No variants to format */ }
345-
[variant] => {
346-
// Just a single matching variant.
347-
err.span_suggestion_verbose(
348-
expr.span,
349-
&format!("try wrapping the expression in `{}`", variant),
350-
format!("{}: {}({})", code, variant, code),
351-
Applicability::MaybeIncorrect,
352-
);
353-
}
354-
_ => {
355-
// More than one matching variant.
356-
err.span_suggestions(
357-
expr.span,
358-
&format!(
359-
"try wrapping the expression in a variant of `{}`",
360-
self.tcx.def_path_str(expected_adt.did)
361-
),
362-
compatible_variants
363-
.into_iter()
364-
.map(|variant| format!("{}: {}({})", code, variant, code)),
365-
Applicability::MaybeIncorrect,
366-
);
367-
}
368-
}
369-
} else {
370-
/* Can't format this without a snippet */
341+
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
342+
Some(ident) => format!("{}: ", ident),
343+
None => format!(""),
344+
};
345+
346+
match &compatible_variants[..] {
347+
[] => { /* No variants to format */ }
348+
[variant] => {
349+
// Just a single matching variant.
350+
err.multipart_suggestion_verbose(
351+
&format!("try wrapping the expression in `{}`", variant),
352+
vec![
353+
(expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
354+
(expr.span.shrink_to_hi(), ")".to_string()),
355+
],
356+
Applicability::MaybeIncorrect,
357+
);
371358
}
372-
} else {
373-
match &compatible_variants[..] {
374-
[] => { /* No variants to format */ }
375-
[variant] => {
376-
// Just a single matching variant.
377-
err.multipart_suggestion_verbose(
378-
&format!("try wrapping the expression in `{}`", variant),
359+
_ => {
360+
// More than one matching variant.
361+
err.multipart_suggestions(
362+
&format!(
363+
"try wrapping the expression in a variant of `{}`",
364+
self.tcx.def_path_str(expected_adt.did)
365+
),
366+
compatible_variants.into_iter().map(|variant| {
379367
vec![
380-
(expr.span.shrink_to_lo(), format!("{}(", variant)),
368+
(expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
381369
(expr.span.shrink_to_hi(), ")".to_string()),
382-
],
383-
Applicability::MaybeIncorrect,
384-
);
385-
}
386-
_ => {
387-
// More than one matching variant.
388-
err.multipart_suggestions(
389-
&format!(
390-
"try wrapping the expression in a variant of `{}`",
391-
self.tcx.def_path_str(expected_adt.did)
392-
),
393-
compatible_variants.into_iter().map(|variant| {
394-
vec![
395-
(expr.span.shrink_to_lo(), format!("{}(", variant)),
396-
(expr.span.shrink_to_hi(), ")".to_string()),
397-
]
398-
}),
399-
Applicability::MaybeIncorrect,
400-
);
401-
}
370+
]
371+
}),
372+
Applicability::MaybeIncorrect,
373+
);
402374
}
403375
}
404376
}
@@ -520,33 +492,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
520492
}
521493
}
522494

523-
crate fn is_hir_id_from_struct_pattern_shorthand_field(
495+
crate fn maybe_get_struct_pattern_shorthand_field(
524496
&self,
525-
hir_id: hir::HirId,
526-
sp: Span,
527-
) -> bool {
528-
let sm = self.sess().source_map();
529-
let parent_id = self.tcx.hir().get_parent_node(hir_id);
530-
if let Some(parent) = self.tcx.hir().find(parent_id) {
531-
// Account for fields
532-
if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent
533-
{
534-
if let Ok(src) = sm.span_to_snippet(sp) {
535-
for field in *fields {
536-
if field.ident.as_str() == src && field.is_shorthand {
537-
return true;
538-
}
497+
expr: &hir::Expr<'_>,
498+
) -> Option<Symbol> {
499+
let hir = self.tcx.hir();
500+
let local = match expr {
501+
hir::Expr {
502+
kind:
503+
hir::ExprKind::Path(hir::QPath::Resolved(
504+
None,
505+
hir::Path {
506+
res: hir::def::Res::Local(_),
507+
segments: [hir::PathSegment { ident, .. }],
508+
..
509+
},
510+
)),
511+
..
512+
} => Some(ident),
513+
_ => None,
514+
}?;
515+
516+
match hir.find(hir.get_parent_node(expr.hir_id))? {
517+
Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => {
518+
for field in *fields {
519+
if field.ident.name == local.name && field.is_shorthand {
520+
return Some(local.name);
539521
}
540522
}
541523
}
524+
_ => {}
542525
}
543-
false
526+
527+
None
544528
}
545529

546530
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
547-
crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
548-
match self.tcx.hir().find(hir_id)? {
549-
Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
531+
crate fn maybe_get_block_expr(&self, expr: &hir::Expr<'tcx>) -> Option<&'tcx hir::Expr<'tcx>> {
532+
match expr {
533+
hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
550534
_ => None,
551535
}
552536
}
@@ -584,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584568
/// `&mut`!".
585569
pub fn check_ref(
586570
&self,
587-
expr: &hir::Expr<'_>,
571+
expr: &hir::Expr<'tcx>,
588572
checked_ty: Ty<'tcx>,
589573
expected: Ty<'tcx>,
590574
) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
@@ -602,9 +586,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
602586
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
603587
};
604588

605-
let is_struct_pat_shorthand_field =
606-
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
607-
608589
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
609590
let expr = expr.peel_drop_temps();
610591

@@ -698,11 +679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
698679
false,
699680
));
700681
}
701-
let field_name = if is_struct_pat_shorthand_field {
702-
format!("{}: ", sugg_expr)
703-
} else {
704-
String::new()
682+
683+
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
684+
Some(ident) => format!("{}: ", ident),
685+
None => format!(""),
705686
};
687+
706688
if let Some(hir::Node::Expr(hir::Expr {
707689
kind: hir::ExprKind::Assign(left_expr, ..),
708690
..
@@ -732,14 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
732714
hir::Mutability::Mut => (
733715
sp,
734716
"consider mutably borrowing here",
735-
format!("{}&mut {}", field_name, sugg_expr),
717+
format!("{}&mut {}", prefix, sugg_expr),
736718
Applicability::MachineApplicable,
737719
false,
738720
),
739721
hir::Mutability::Not => (
740722
sp,
741723
"consider borrowing here",
742-
format!("{}&{}", field_name, sugg_expr),
724+
format!("{}&{}", prefix, sugg_expr),
743725
Applicability::MachineApplicable,
744726
false,
745727
),
@@ -883,32 +865,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
883865
if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
884866
|| checked_ty.is_box()
885867
{
886-
if let Ok(code) = sm.span_to_snippet(expr.span) {
887-
let message = if checked_ty.is_box() {
888-
"consider unboxing the value"
889-
} else if checked_ty.is_region_ptr() {
890-
"consider dereferencing the borrow"
891-
} else {
892-
"consider dereferencing the type"
893-
};
894-
let (span, suggestion) = if is_struct_pat_shorthand_field {
895-
(expr.span, format!("{}: *{}", code, code))
896-
} else if self.is_else_if_block(expr) {
897-
// Don't suggest nonsense like `else *if`
898-
return None;
899-
} else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
900-
(expr.span.shrink_to_lo(), "*".to_string())
901-
} else {
902-
(expr.span.shrink_to_lo(), "*".to_string())
903-
};
904-
return Some((
905-
span,
906-
message,
907-
suggestion,
908-
Applicability::MachineApplicable,
909-
true,
910-
));
911-
}
868+
let message = if checked_ty.is_box() {
869+
"consider unboxing the value"
870+
} else if checked_ty.is_region_ptr() {
871+
"consider dereferencing the borrow"
872+
} else {
873+
"consider dereferencing the type"
874+
};
875+
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
876+
Some(ident) => format!("{}: ", ident),
877+
None => format!(""),
878+
};
879+
let (span, suggestion) = if self.is_else_if_block(expr) {
880+
// Don't suggest nonsense like `else *if`
881+
return None;
882+
} else if let Some(expr) = self.maybe_get_block_expr(expr) {
883+
// prefix should be empty here..
884+
(expr.span.shrink_to_lo(), "*".to_string())
885+
} else {
886+
(expr.span.shrink_to_lo(), format!("{}*", prefix))
887+
};
888+
return Some((
889+
span,
890+
message,
891+
suggestion,
892+
Applicability::MachineApplicable,
893+
true,
894+
));
912895
}
913896
}
914897
}

Diff for: compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
208208
pub fn suggest_deref_ref_or_into(
209209
&self,
210210
err: &mut DiagnosticBuilder<'_>,
211-
expr: &hir::Expr<'_>,
211+
expr: &hir::Expr<'tcx>,
212212
expected: Ty<'tcx>,
213213
found: Ty<'tcx>,
214214
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
231231
}
232232
} else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
233233
let is_struct_pat_shorthand_field =
234-
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
234+
self.maybe_get_struct_pattern_shorthand_field(expr).is_some();
235235
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
236236
if !methods.is_empty() {
237237
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {

Diff for: src/test/ui/did_you_mean/compatible-variants.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ LL | let _ = Foo { bar };
143143
help: try wrapping the expression in `Some`
144144
|
145145
LL | let _ = Foo { bar: Some(bar) };
146-
| ~~~~~~~~~~~~~~
146+
| ++++++++++ +
147147

148148
error: aborting due to 9 previous errors
149149

Diff for: src/test/ui/inference/deref-suggestion.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ LL | let r = R { i };
8787
help: consider dereferencing the borrow
8888
|
8989
LL | let r = R { i: *i };
90-
| ~~~~~
90+
| ++++
9191

9292
error[E0308]: mismatched types
9393
--> $DIR/deref-suggestion.rs:46:20

0 commit comments

Comments
 (0)