Skip to content

Commit 544e871

Browse files
committed
Track HirId instead of Span in ObligationCauseCode::SizedArgumentType
This gets us more accurate suggestions.
1 parent 98eb0c1 commit 544e871

File tree

8 files changed

+96
-82
lines changed

8 files changed

+96
-82
lines changed

compiler/rustc_hir_typeck/src/check.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,22 @@ pub(super) fn check_fn<'a, 'tcx>(
114114
let inputs_fn = fn_sig.inputs().iter().copied();
115115
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
116116
// Check the pattern.
117-
let ty_span = try { inputs_hir?.get(idx)?.span };
117+
let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? };
118+
let ty_span = ty.map(|ty| ty.span);
118119
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
119120

120121
// Check that argument is Sized.
121122
if !params_can_be_unsized {
122123
fcx.require_type_is_sized(
123124
param_ty,
124125
param.pat.span,
125-
// ty_span == binding_span iff this is a closure parameter with no type ascription,
126+
// ty.span == binding_span iff this is a closure parameter with no type ascription,
126127
// or if it's an implicit `self` parameter
127128
traits::SizedArgumentType(
128129
if ty_span == Some(param.span) && tcx.is_closure(fn_def_id.into()) {
129130
None
130131
} else {
131-
ty_span
132+
ty.map(|ty| ty.hir_id)
132133
},
133134
),
134135
);

compiler/rustc_hir_typeck/src/gather_locals.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
6060
// parameters are special cases of patterns, but we want to handle them as
6161
// *distinct* cases. so track when we are hitting a pattern *within* an fn
6262
// parameter.
63-
outermost_fn_param_pat: Option<Span>,
63+
outermost_fn_param_pat: Option<(Span, hir::HirId)>,
6464
}
6565

6666
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
@@ -131,7 +131,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
131131
}
132132

133133
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
134-
let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span);
134+
let old_outermost_fn_param_pat =
135+
self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id));
135136
intravisit::walk_param(self, param);
136137
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
137138
}
@@ -141,7 +142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
141142
if let PatKind::Binding(_, _, ident, _) = p.kind {
142143
let var_ty = self.assign(p.span, p.hir_id, None);
143144

144-
if let Some(ty_span) = self.outermost_fn_param_pat {
145+
if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat {
145146
if !self.fcx.tcx.features().unsized_fn_params {
146147
self.fcx.require_type_is_sized(
147148
var_ty,
@@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
154155
{
155156
None
156157
} else {
157-
Some(ty_span)
158+
Some(hir_id)
158159
},
159160
),
160161
);

compiler/rustc_middle/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ pub enum ObligationCauseCode<'tcx> {
289289
/// Type of each variable must be `Sized`.
290290
VariableType(hir::HirId),
291291
/// Argument type must be `Sized`.
292-
SizedArgumentType(Option<Span>),
292+
SizedArgumentType(Option<hir::HirId>),
293293
/// Return type must be `Sized`.
294294
SizedReturnType,
295295
/// Yield type must be `Sized`.

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+76-60
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ use rustc_errors::{
1919
use rustc_hir as hir;
2020
use rustc_hir::def::{DefKind, Res};
2121
use rustc_hir::def_id::DefId;
22-
use rustc_hir::intravisit::Visitor;
22+
use rustc_hir::intravisit::{Map, Visitor};
2323
use rustc_hir::is_range_literal;
2424
use rustc_hir::lang_items::LangItem;
25-
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
26-
use rustc_hir::{Expr, HirId};
25+
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
2726
use rustc_infer::infer::error_reporting::TypeErrCtxt;
2827
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2928
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
@@ -3054,63 +3053,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30543053
err.help("unsized locals are gated as an unstable feature");
30553054
}
30563055
}
3057-
ObligationCauseCode::SizedArgumentType(ty_span) => {
3058-
if let Some(span) = ty_span {
3059-
let trait_len = if let ty::PredicateKind::Clause(clause) =
3060-
predicate.kind().skip_binder()
3061-
&& let ty::ClauseKind::Trait(trait_pred) = clause
3062-
&& let ty::Dynamic(preds, ..) = trait_pred.self_ty().kind()
3063-
{
3064-
let span = if let Ok(snippet) =
3065-
self.tcx.sess.source_map().span_to_snippet(span)
3066-
&& snippet.starts_with("dyn ")
3067-
{
3068-
let pos = snippet.len() - snippet[3..].trim_start().len();
3069-
span.with_hi(span.lo() + BytePos(pos as u32))
3070-
} else {
3071-
span.shrink_to_lo()
3072-
};
3073-
err.span_suggestion_verbose(
3074-
span,
3075-
"you can use `impl Trait` as the argument type",
3076-
"impl ".to_string(),
3077-
Applicability::MaybeIncorrect,
3078-
);
3079-
preds
3080-
.iter()
3081-
.filter(|pred| {
3082-
// We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
3083-
// because the later doesn't need parentheses.
3084-
matches!(
3085-
pred.skip_binder(),
3086-
ty::ExistentialPredicate::Trait(_)
3087-
| ty::ExistentialPredicate::AutoTrait(_)
3088-
)
3089-
})
3090-
.count()
3091-
} else {
3092-
1
3093-
};
3094-
let sugg = if trait_len == 1 {
3095-
vec![(span.shrink_to_lo(), "&".to_string())]
3096-
} else if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
3097-
&& snippet.starts_with('(')
3098-
{
3099-
// We don't want to suggest `&((dyn Foo + Bar))` when we have
3100-
// `(dyn Foo + Bar)`.
3101-
vec![(span.shrink_to_lo(), "&".to_string())]
3102-
} else {
3103-
vec![
3104-
(span.shrink_to_lo(), "&(".to_string()),
3105-
(span.shrink_to_hi(), ")".to_string()),
3106-
]
3107-
};
3108-
err.multipart_suggestion_verbose(
3109-
"function arguments must have a statically known size, borrowed types \
3110-
always have a known size",
3111-
sugg,
3112-
Applicability::MachineApplicable,
3113-
);
3056+
ObligationCauseCode::SizedArgumentType(hir_id) => {
3057+
let mut ty = None;
3058+
let borrowed_msg = "function arguments must have a statically known size, borrowed \
3059+
types always have a known size";
3060+
if let Some(hir_id) = hir_id
3061+
&& let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id)
3062+
&& let Some(item) = self.tcx.hir().find_parent(hir_id)
3063+
&& let Some(decl) = item.fn_decl()
3064+
&& let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
3065+
{
3066+
// We use `contains` because the type might be surrounded by parentheses,
3067+
// which makes `ty_span` and `t.span` disagree with each other, but one
3068+
// fully contains the other: `foo: (dyn Foo + Bar)`
3069+
// ^-------------^
3070+
// ||
3071+
// |t.span
3072+
// param._ty_span
3073+
ty = Some(t);
3074+
} else if let Some(hir_id) = hir_id
3075+
&& let Some(hir::Node::Ty(t)) = self.tcx.hir().find(hir_id)
3076+
{
3077+
ty = Some(t);
3078+
}
3079+
if let Some(ty) = ty {
3080+
match ty.kind {
3081+
hir::TyKind::TraitObject(traits, _, _) => {
3082+
let (span, kw) = match traits {
3083+
[first, ..] if first.span.lo() == ty.span.lo() => {
3084+
// Missing `dyn` in front of trait object.
3085+
(ty.span.shrink_to_lo(), "dyn ")
3086+
}
3087+
[first, ..] => (ty.span.until(first.span), ""),
3088+
[] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
3089+
};
3090+
let needs_parens = traits.len() != 1;
3091+
err.span_suggestion_verbose(
3092+
span,
3093+
"you can use `impl Trait` as the argument type",
3094+
"impl ".to_string(),
3095+
Applicability::MaybeIncorrect,
3096+
);
3097+
let sugg = if !needs_parens {
3098+
vec![(span.shrink_to_lo(), format!("&{kw}"))]
3099+
} else {
3100+
vec![
3101+
(span.shrink_to_lo(), format!("&({kw}")),
3102+
(ty.span.shrink_to_hi(), ")".to_string()),
3103+
]
3104+
};
3105+
err.multipart_suggestion_verbose(
3106+
borrowed_msg,
3107+
sugg,
3108+
Applicability::MachineApplicable,
3109+
);
3110+
}
3111+
hir::TyKind::Slice(_ty) => {
3112+
err.span_suggestion_verbose(
3113+
ty.span.shrink_to_lo(),
3114+
"function arguments must have a statically known size, borrowed \
3115+
slices always have a known size",
3116+
"&",
3117+
Applicability::MachineApplicable,
3118+
);
3119+
}
3120+
hir::TyKind::Path(_) => {
3121+
err.span_suggestion_verbose(
3122+
ty.span.shrink_to_lo(),
3123+
borrowed_msg,
3124+
"&",
3125+
Applicability::MachineApplicable,
3126+
);
3127+
}
3128+
_ => {}
3129+
}
31143130
} else {
31153131
err.note("all function arguments must have a statically known size");
31163132
}

src/tools/clippy/tests/ui/crashes/ice-6251.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
66
|
77
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
88
= help: unsized fn params are gated as an unstable feature
9-
help: function arguments must have a statically known size, borrowed types always have a known size
9+
help: function arguments must have a statically known size, borrowed slices always have a known size
1010
|
1111
LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: &[u8]| x }]> {
1212
| +

tests/ui/feature-gates/feature-gate-unsized_fn_params.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ LL | fn bar(x: impl Foo) {
2929
| ++++
3030
help: function arguments must have a statically known size, borrowed types always have a known size
3131
|
32-
LL | fn bar(x: &Foo) {
33-
| +
32+
LL | fn bar(x: &dyn Foo) {
33+
| ++++
3434

3535
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
3636
--> $DIR/feature-gate-unsized_fn_params.rs:25:8
@@ -40,7 +40,7 @@ LL | fn qux(_: [()]) {}
4040
|
4141
= help: the trait `Sized` is not implemented for `[()]`
4242
= help: unsized fn params are gated as an unstable feature
43-
help: function arguments must have a statically known size, borrowed types always have a known size
43+
help: function arguments must have a statically known size, borrowed slices always have a known size
4444
|
4545
LL | fn qux(_: &[()]) {}
4646
| +

tests/ui/resolve/issue-5035-2.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ LL | fn foo(_x: K) {}
66
|
77
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
88
= help: unsized fn params are gated as an unstable feature
9-
help: you can use `impl Trait` as the argument type
10-
|
11-
LL | fn foo(_x: impl K) {}
12-
| ++++
139
help: function arguments must have a statically known size, borrowed types always have a known size
1410
|
1511
LL | fn foo(_x: &K) {}

tests/ui/traits/bound/not-on-bare-trait.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ LL | fn foo(_x: impl Foo + Send) {
3434
| ++++
3535
help: function arguments must have a statically known size, borrowed types always have a known size
3636
|
37-
LL | fn foo(_x: &(Foo + Send)) {
38-
| ++ +
37+
LL | fn foo(_x: &(dyn Foo + Send)) {
38+
| +++++ +
3939

4040
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
4141
--> $DIR/not-on-bare-trait.rs:12:8
@@ -47,12 +47,12 @@ LL | fn bar(_x: (dyn Foo + Send)) {
4747
= help: unsized fn params are gated as an unstable feature
4848
help: you can use `impl Trait` as the argument type
4949
|
50-
LL | fn bar(_x: impl (dyn Foo + Send)) {
51-
| ++++
50+
LL | fn bar(_x: (impl Foo + Send)) {
51+
| ~~~~
5252
help: function arguments must have a statically known size, borrowed types always have a known size
5353
|
54-
LL | fn bar(_x: &(dyn Foo + Send)) {
55-
| +
54+
LL | fn bar(_x: (&(dyn Foo + Send))) {
55+
| ++ +
5656

5757
error: aborting due to 2 previous errors; 1 warning emitted
5858

0 commit comments

Comments
 (0)