Skip to content

Commit a364c0a

Browse files
authored
Rollup merge of #74228 - estebank:unsized-param, r=davidtwco
Provide structured suggestion on unsized fields and fn params * Suggest borrowing or boxing unsized fields * Suggest borrowing fn parameters * Remove some verbosity of unsized errors * Remove `on_unimplemented` note from `trait Sized` Fix #23286, fix #28653. r? @davidtwco
2 parents be5c7ab + ff75395 commit a364c0a

File tree

131 files changed

+554
-437
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+554
-437
lines changed

src/libcore/marker.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,8 @@ impl<T: ?Sized> !Send for *mut T {}
8484
#[stable(feature = "rust1", since = "1.0.0")]
8585
#[lang = "sized"]
8686
#[rustc_on_unimplemented(
87-
on(parent_trait = "std::path::Path", label = "borrow the `Path` instead"),
8887
message = "the size for values of type `{Self}` cannot be known at compilation time",
89-
label = "doesn't have a size known at compile-time",
90-
note = "to learn more, visit <https://doc.rust-lang.org/book/\
91-
ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
88+
label = "doesn't have a size known at compile-time"
9289
)]
9390
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
9491
#[rustc_specialization_trait]

src/librustc_ast_lowering/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
526526
Ident::with_dummy_span(sym::_task_context),
527527
hir::BindingAnnotation::Mutable,
528528
);
529-
let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span };
529+
let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, ty_span: span, span };
530530
let params = arena_vec![self; param];
531531

532532
let body_id = self.lower_body(move |this| {

src/librustc_ast_lowering/item.rs

+2
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
972972
attrs: self.lower_attrs(&param.attrs),
973973
hir_id: self.lower_node_id(param.id),
974974
pat: self.lower_pat(&param.pat),
975+
ty_span: param.ty.span,
975976
span: param.span,
976977
}
977978
}
@@ -1098,6 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10981099
attrs: parameter.attrs,
10991100
hir_id: parameter.hir_id,
11001101
pat: new_parameter_pat,
1102+
ty_span: parameter.ty_span,
11011103
span: parameter.span,
11021104
};
11031105

src/librustc_hir/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,7 @@ pub struct Param<'hir> {
21482148
pub attrs: &'hir [Attribute],
21492149
pub hir_id: HirId,
21502150
pub pat: &'hir Pat<'hir>,
2151+
pub ty_span: Span,
21512152
pub span: Span,
21522153
}
21532154

src/librustc_middle/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> {
215215
/// Type of each variable must be `Sized`.
216216
VariableType(hir::HirId),
217217
/// Argument type must be `Sized`.
218-
SizedArgumentType,
218+
SizedArgumentType(Option<Span>),
219219
/// Return type must be `Sized`.
220220
SizedReturnType,
221221
/// Yield type must be `Sized`.
@@ -229,6 +229,7 @@ pub enum ObligationCauseCode<'tcx> {
229229
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
230230
FieldSized {
231231
adt_kind: AdtKind,
232+
span: Span,
232233
last: bool,
233234
},
234235

src/librustc_middle/traits/structural_impls.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,14 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
151151
super::VariableType(id) => Some(super::VariableType(id)),
152152
super::ReturnValue(id) => Some(super::ReturnValue(id)),
153153
super::ReturnType => Some(super::ReturnType),
154-
super::SizedArgumentType => Some(super::SizedArgumentType),
154+
super::SizedArgumentType(sp) => Some(super::SizedArgumentType(sp)),
155155
super::SizedReturnType => Some(super::SizedReturnType),
156156
super::SizedYieldType => Some(super::SizedYieldType),
157157
super::InlineAsmSized => Some(super::InlineAsmSized),
158158
super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
159-
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
159+
super::FieldSized { adt_kind, span, last } => {
160+
Some(super::FieldSized { adt_kind, span, last })
161+
}
160162
super::ConstSized => Some(super::ConstSized),
161163
super::ConstPatternStructural => Some(super::ConstPatternStructural),
162164
super::SharedStatic => Some(super::SharedStatic),

src/librustc_trait_selection/traits/error_reporting/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
376376
// If it has a custom `#[rustc_on_unimplemented]`
377377
// error message, let's display it as the label!
378378
err.span_label(span, s.as_str());
379-
err.help(&explanation);
379+
if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) {
380+
// When the self type is a type param We don't need to "the trait
381+
// `std::marker::Sized` is not implemented for `T`" as we will point
382+
// at the type param with a label to suggest constraining it.
383+
err.help(&explanation);
384+
}
380385
} else {
381386
err.span_label(span, explanation);
382387
}
@@ -403,7 +408,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
403408
}
404409

405410
self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
406-
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
407411
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
408412
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
409413
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+82-55
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ pub trait InferCtxtExt<'tcx> {
4343
body_id: hir::HirId,
4444
);
4545

46-
fn suggest_borrow_on_unsized_slice(
47-
&self,
48-
code: &ObligationCauseCode<'tcx>,
49-
err: &mut DiagnosticBuilder<'_>,
50-
);
51-
5246
fn suggest_dereferences(
5347
&self,
5448
obligation: &PredicateObligation<'tcx>,
@@ -515,32 +509,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
515509
}
516510
}
517511

518-
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
519-
/// suggestion to borrow the initializer in order to use have a slice instead.
520-
fn suggest_borrow_on_unsized_slice(
521-
&self,
522-
code: &ObligationCauseCode<'tcx>,
523-
err: &mut DiagnosticBuilder<'_>,
524-
) {
525-
if let &ObligationCauseCode::VariableType(hir_id) = code {
526-
let parent_node = self.tcx.hir().get_parent_node(hir_id);
527-
if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) {
528-
if let Some(ref expr) = local.init {
529-
if let hir::ExprKind::Index(_, _) = expr.kind {
530-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
531-
err.span_suggestion(
532-
expr.span,
533-
"consider borrowing here",
534-
format!("&{}", snippet),
535-
Applicability::MachineApplicable,
536-
);
537-
}
538-
}
539-
}
540-
}
541-
}
542-
}
543-
544512
/// Given a closure's `DefId`, return the given name of the closure.
545513
///
546514
/// This doesn't account for reassignments, but it's only used for suggestions.
@@ -1817,15 +1785,56 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18171785
}
18181786
}
18191787
}
1820-
ObligationCauseCode::VariableType(_) => {
1821-
err.note("all local variables must have a statically known size");
1788+
ObligationCauseCode::VariableType(hir_id) => {
1789+
let parent_node = self.tcx.hir().get_parent_node(hir_id);
1790+
match self.tcx.hir().find(parent_node) {
1791+
Some(Node::Local(hir::Local {
1792+
init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
1793+
..
1794+
})) => {
1795+
// When encountering an assignment of an unsized trait, like
1796+
// `let x = ""[..];`, provide a suggestion to borrow the initializer in
1797+
// order to use have a slice instead.
1798+
err.span_suggestion_verbose(
1799+
span.shrink_to_lo(),
1800+
"consider borrowing here",
1801+
"&".to_owned(),
1802+
Applicability::MachineApplicable,
1803+
);
1804+
err.note("all local variables must have a statically known size");
1805+
}
1806+
Some(Node::Param(param)) => {
1807+
err.span_suggestion_verbose(
1808+
param.ty_span.shrink_to_lo(),
1809+
"function arguments must have a statically known size, borrowed types \
1810+
always have a known size",
1811+
"&".to_owned(),
1812+
Applicability::MachineApplicable,
1813+
);
1814+
}
1815+
_ => {
1816+
err.note("all local variables must have a statically known size");
1817+
}
1818+
}
18221819
if !self.tcx.features().unsized_locals {
18231820
err.help("unsized locals are gated as an unstable feature");
18241821
}
18251822
}
1826-
ObligationCauseCode::SizedArgumentType => {
1827-
err.note("all function arguments must have a statically known size");
1828-
if !self.tcx.features().unsized_locals {
1823+
ObligationCauseCode::SizedArgumentType(sp) => {
1824+
if let Some(span) = sp {
1825+
err.span_suggestion_verbose(
1826+
span.shrink_to_lo(),
1827+
"function arguments must have a statically known size, borrowed types \
1828+
always have a known size",
1829+
"&".to_string(),
1830+
Applicability::MachineApplicable,
1831+
);
1832+
} else {
1833+
err.note("all function arguments must have a statically known size");
1834+
}
1835+
if tcx.sess.opts.unstable_features.is_nightly_build()
1836+
&& !self.tcx.features().unsized_locals
1837+
{
18291838
err.help("unsized locals are gated as an unstable feature");
18301839
}
18311840
}
@@ -1844,26 +1853,44 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18441853
ObligationCauseCode::StructInitializerSized => {
18451854
err.note("structs must have a statically known size to be initialized");
18461855
}
1847-
ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item {
1848-
AdtKind::Struct => {
1849-
if last {
1850-
err.note(
1851-
"the last field of a packed struct may only have a \
1852-
dynamically sized type if it does not need drop to be run",
1853-
);
1854-
} else {
1855-
err.note(
1856-
"only the last field of a struct may have a dynamically sized type",
1857-
);
1856+
ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
1857+
match *item {
1858+
AdtKind::Struct => {
1859+
if last {
1860+
err.note(
1861+
"the last field of a packed struct may only have a \
1862+
dynamically sized type if it does not need drop to be run",
1863+
);
1864+
} else {
1865+
err.note(
1866+
"only the last field of a struct may have a dynamically sized type",
1867+
);
1868+
}
1869+
}
1870+
AdtKind::Union => {
1871+
err.note("no field of a union may have a dynamically sized type");
1872+
}
1873+
AdtKind::Enum => {
1874+
err.note("no field of an enum variant may have a dynamically sized type");
18581875
}
18591876
}
1860-
AdtKind::Union => {
1861-
err.note("no field of a union may have a dynamically sized type");
1862-
}
1863-
AdtKind::Enum => {
1864-
err.note("no field of an enum variant may have a dynamically sized type");
1865-
}
1866-
},
1877+
err.help("change the field's type to have a statically known size");
1878+
err.span_suggestion(
1879+
span.shrink_to_lo(),
1880+
"borrowed types always have a statically known size",
1881+
"&".to_string(),
1882+
Applicability::MachineApplicable,
1883+
);
1884+
err.multipart_suggestion(
1885+
"the `Box` type always has a statically known size and allocates its contents \
1886+
in the heap",
1887+
vec![
1888+
(span.shrink_to_lo(), "Box<".to_string()),
1889+
(span.shrink_to_hi(), ">".to_string()),
1890+
],
1891+
Applicability::MachineApplicable,
1892+
);
1893+
}
18671894
ObligationCauseCode::ConstSized => {
18681895
err.note("constant expressions must have a statically known size");
18691896
}

src/librustc_typeck/check/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
487487
self.require_type_is_sized_deferred(
488488
input,
489489
expr.span,
490-
traits::SizedArgumentType,
490+
traits::SizedArgumentType(None),
491491
);
492492
}
493493
}

src/librustc_typeck/check/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1342,14 +1342,15 @@ fn check_fn<'a, 'tcx>(
13421342
let inputs_fn = fn_sig.inputs().iter().copied();
13431343
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
13441344
// Check the pattern.
1345-
fcx.check_pat_top(&param.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false);
1345+
let ty_span = try { inputs_hir?.get(idx)?.span };
1346+
fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
13461347

13471348
// Check that argument is Sized.
13481349
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
13491350
// for simple cases like `fn foo(x: Trait)`,
13501351
// where we would error once on the parameter as a whole, and once on the binding `x`.
13511352
if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
1352-
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType);
1353+
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
13531354
}
13541355

13551356
fcx.write_ty(param.hir_id, param_ty);

src/librustc_typeck/check/wfcheck.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ fn check_type_defn<'tcx, F>(
394394
Some(i) => i,
395395
None => bug!(),
396396
},
397+
span: field.span,
397398
last,
398399
},
399400
),
@@ -1326,10 +1327,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13261327
.iter()
13271328
.map(|field| {
13281329
let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
1329-
let field_ty = self.normalize_associated_types_in(field.span, &field_ty);
1330+
let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty);
13301331
let field_ty = self.resolve_vars_if_possible(&field_ty);
13311332
debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
1332-
AdtField { ty: field_ty, span: field.span }
1333+
AdtField { ty: field_ty, span: field.ty.span }
13331334
})
13341335
.collect();
13351336
AdtVariant { fields, explicit_discr: None }

src/test/ui/asm/type-check-1.stderr

-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ LL | asm!("{}", in(reg) v[..]);
1717
| ^^^^^ doesn't have a size known at compile-time
1818
|
1919
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
20-
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
2120
= note: all inline asm arguments must have a statically known size
2221

2322
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -27,7 +26,6 @@ LL | asm!("{}", out(reg) v[..]);
2726
| ^^^^^ doesn't have a size known at compile-time
2827
|
2928
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
30-
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
3129
= note: all inline asm arguments must have a statically known size
3230

3331
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -37,7 +35,6 @@ LL | asm!("{}", inout(reg) v[..]);
3735
| ^^^^^ doesn't have a size known at compile-time
3836
|
3937
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
40-
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
4138
= note: all inline asm arguments must have a statically known size
4239

4340
error: aborting due to 5 previous errors

src/test/ui/associated-types/associated-types-unsized.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ LL | let x = t.get();
55
| ^ doesn't have a size known at compile-time
66
|
77
= help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
8-
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
98
= note: all local variables must have a statically known size
109
= help: unsized locals are gated as an unstable feature
1110
help: consider further restricting the associated type

src/test/ui/associated-types/defaults-suitability.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ LL | pub struct Vec<T> {
139139
| - required by this bound in `std::vec::Vec`
140140
|
141141
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
142-
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
143142

144143
error: aborting due to 11 previous errors
145144

src/test/ui/associated-types/defaults-unsound-62211-1.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized {
2121
LL | + AddAssign<&'static str>
2222
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
2323
|
24-
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
2524
help: consider further restricting `Self`
2625
|
2726
LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
@@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized {
5049
LL | + Display = Self;
5150
| ^^^^^^^ `Self` cannot be formatted with the default formatter
5251
|
53-
= help: the trait `std::fmt::Display` is not implemented for `Self`
5452
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
5553
help: consider further restricting `Self`
5654
|
@@ -69,7 +67,6 @@ LL | + Display = Self;
6967
LL | impl<T> UncheckedCopy for T {}
7068
| ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
7169
|
72-
= help: the trait `std::fmt::Display` is not implemented for `T`
7370
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
7471
help: consider restricting type parameter `T`
7572
|
@@ -105,7 +102,6 @@ LL | + AddAssign<&'static str>
105102
LL | impl<T> UncheckedCopy for T {}
106103
| ^^^^^^^^^^^^^ no implementation for `T += &'static str`
107104
|
108-
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
109105
help: consider restricting type parameter `T`
110106
|
111107
LL | impl<T: std::ops::AddAssign<&'static str>> UncheckedCopy for T {}

0 commit comments

Comments
 (0)