Skip to content

Commit 33a281c

Browse files
committed
Deduplicate ?Sized binding errors to only their declaration, not use
* Point at let binding type or init that is `?Sized`, as appropriate * On `?Sized` binding *access*, do not emit an error as we will already have emitted one on the binding
1 parent f604b28 commit 33a281c

File tree

16 files changed

+160
-60
lines changed

16 files changed

+160
-60
lines changed

compiler/rustc_hir_typeck/src/gather_locals.rs

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
6161
// *distinct* cases. so track when we are hitting a pattern *within* an fn
6262
// parameter.
6363
outermost_fn_param_pat: Option<(Span, hir::HirId)>,
64+
let_binding_init: Option<Span>,
6465
}
6566

6667
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
6768
pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self {
68-
Self { fcx, outermost_fn_param_pat: None }
69+
Self { fcx, outermost_fn_param_pat: None, let_binding_init: None }
6970
}
7071

7172
fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
@@ -92,18 +93,40 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
9293
/// again during type checking by querying [`FnCtxt::local_ty`] for the same hir_id.
9394
fn declare(&mut self, decl: Declaration<'tcx>) {
9495
let local_ty = match decl.ty {
95-
Some(ref ty) => {
96-
let o_ty = self.fcx.lower_ty(ty);
96+
Some(ref hir_ty) => {
97+
let o_ty = self.fcx.lower_ty(hir_ty);
9798

9899
let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
99-
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
100+
debug!(?hir_ty.hir_id, ?o_ty, ?c_ty, "visit_local");
100101
self.fcx
101102
.typeck_results
102103
.borrow_mut()
103104
.user_provided_types_mut()
104-
.insert(ty.hir_id, c_ty);
105-
106-
Some(o_ty.normalized)
105+
.insert(hir_ty.hir_id, c_ty);
106+
107+
let ty = o_ty.normalized;
108+
if let hir::PatKind::Wild = decl.pat.kind {
109+
// We explicitly allow `let _: dyn Trait;` (!)
110+
} else {
111+
if self.outermost_fn_param_pat.is_some() {
112+
if !self.fcx.tcx.features().unsized_fn_params {
113+
self.fcx.require_type_is_sized(
114+
ty,
115+
hir_ty.span,
116+
traits::SizedArgumentType(Some(decl.pat.hir_id)),
117+
);
118+
}
119+
} else {
120+
if !self.fcx.tcx.features().unsized_locals {
121+
self.fcx.require_type_is_sized(
122+
ty,
123+
hir_ty.span,
124+
traits::VariableType(decl.pat.hir_id),
125+
);
126+
}
127+
}
128+
}
129+
Some(ty)
107130
}
108131
None => None,
109132
};
@@ -121,14 +144,20 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
121144
// Add explicitly-declared locals.
122145
fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
123146
self.declare(local.into());
124-
intravisit::walk_local(self, local)
147+
let sp = self.let_binding_init.take();
148+
self.let_binding_init = local.init.map(|e| e.span);
149+
intravisit::walk_local(self, local);
150+
self.let_binding_init = sp;
125151
}
126152

127153
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
154+
let sp = self.let_binding_init.take();
128155
if let hir::ExprKind::Let(let_expr) = expr.kind {
156+
self.let_binding_init = Some(let_expr.init.span);
129157
self.declare((let_expr, expr.hir_id).into());
130158
}
131-
intravisit::walk_expr(self, expr)
159+
intravisit::walk_expr(self, expr);
160+
self.let_binding_init = sp;
132161
}
133162

134163
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
@@ -163,7 +192,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
163192
}
164193
} else {
165194
if !self.fcx.tcx.features().unsized_locals {
166-
self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
195+
self.fcx.require_type_is_sized(
196+
var_ty,
197+
self.let_binding_init.unwrap_or(p.span),
198+
traits::VariableType(p.hir_id),
199+
);
167200
}
168201
}
169202

@@ -174,6 +207,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
174207
var_ty
175208
);
176209
}
210+
// We only point at the init expression if this is the top level pattern, otherwise we point
211+
// at the specific binding, because we might not be able to tie the binding to the,
212+
// expression, like `let (a, b) = foo();`. FIXME: We could specialize
213+
// `let (a, b) = (unsized(), bar());` to point at `unsized()` instead of `a`.
214+
self.let_binding_init.take();
177215
let old_outermost_fn_param_pat = self.outermost_fn_param_pat.take();
178216
intravisit::walk_pat(self, p);
179217
self.outermost_fn_param_pat = old_outermost_fn_param_pat;

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

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use rustc_session::config::DumpSolverProofTree;
4646
use rustc_session::Limit;
4747
use rustc_span::def_id::LOCAL_CRATE;
4848
use rustc_span::symbol::sym;
49-
use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
49+
use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
5050
use std::borrow::Cow;
5151
use std::fmt;
5252
use std::iter;
@@ -94,6 +94,52 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
9494
predicate: ty::Predicate<'tcx>,
9595
index: Option<usize>, // None if this is an old error
9696
}
97+
let dedup_span = |obligation: &Obligation<'_, ty::Predicate<'_>>| {
98+
// We want to ignore desugarings here: spans are equivalent even
99+
// if one is the result of a desugaring and the other is not.
100+
let mut span = obligation.cause.span;
101+
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
102+
obligation.predicate.kind().skip_binder()
103+
&& Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
104+
{
105+
// For `Sized` bounds exclusively, we deduplicate based on `let` binding origin.
106+
// We could do this for other traits, but in cases like the tests at
107+
// `tests/ui/coroutine/clone-impl-async.rs` we'd end up with fewer errors than we do
108+
// now, because different `fn` calls might have different sources of the obligation,
109+
// which are unrelated between calls. FIXME: We could rework the dedup logic below
110+
// to go further from evaluating only a single span, instead grouping multiple
111+
// errors associated to the same binding and emitting a single error with *all* the
112+
// appropriate context.
113+
match obligation.cause.code() {
114+
ObligationCauseCode::VariableType(hir_id) => {
115+
if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
116+
// `let` binding obligations will not necessarily point at the
117+
// identifier, so point at it.
118+
span = pat.span;
119+
}
120+
}
121+
ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } => {
122+
if let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)
123+
&& let hir::ExprKind::Path(hir::QPath::Resolved(
124+
None,
125+
hir::Path { res: hir::def::Res::Local(hir_id), .. },
126+
)) = expr.peel_borrows().kind
127+
&& let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
128+
{
129+
// When we have a call argument that is a `!Sized` `let` binding,
130+
// deduplicate all the `!Sized` errors referencing that binding.
131+
span = pat.span;
132+
}
133+
}
134+
_ => {}
135+
}
136+
}
137+
let expn_data = span.ctxt().outer_expn_data();
138+
if let ExpnKind::Desugaring(_) = expn_data.kind {
139+
span = expn_data.call_site;
140+
}
141+
span
142+
};
97143

98144
let mut error_map: FxIndexMap<_, Vec<_>> = self
99145
.reported_trait_errors
@@ -125,7 +171,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
125171
});
126172

127173
for (index, error) in errors.iter().enumerate() {
128-
error_map.entry(error.obligation.cause.span).or_default().push(ErrorDescriptor {
174+
error_map.entry(dedup_span(&error.obligation)).or_default().push(ErrorDescriptor {
129175
predicate: error.obligation.predicate,
130176
index: Some(index),
131177
});
@@ -171,7 +217,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
171217
reported = Some(guar);
172218
self.reported_trait_errors
173219
.borrow_mut()
174-
.entry(error.obligation.cause.span)
220+
.entry(dedup_span(&error.obligation))
175221
.or_insert_with(|| (vec![], guar))
176222
.0
177223
.push(error.obligation.predicate);

tests/ui/associated-types/associated-types-unsized.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
2-
--> $DIR/associated-types-unsized.rs:10:9
2+
--> $DIR/associated-types-unsized.rs:10:13
33
|
44
LL | let x = t.get();
5-
| ^ doesn't have a size known at compile-time
5+
| ^^^^^^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `<T as Get>::Value`
88
= note: all local variables must have a statically known size

tests/ui/associated-types/issue-20005.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ trait To {
99
self //~ ERROR the size for values of type
1010
) -> <Dst as From<Self>>::Result where Dst: From<Self> { //~ ERROR the size for values of type
1111
From::from(self) //~ ERROR the size for values of type
12+
//~^ ERROR the size for values of type
1213
}
1314
}
1415

tests/ui/associated-types/issue-20005.stderr

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ help: consider relaxing the implicit `Sized` restriction
5454
LL | trait From<Src: ?Sized> {
5555
| ++++++++
5656

57-
error: aborting due to 3 previous errors
57+
error[E0277]: the size for values of type `Self` cannot be known at compilation time
58+
--> $DIR/issue-20005.rs:11:20
59+
|
60+
LL | From::from(self)
61+
| ^^^^ doesn't have a size known at compile-time
62+
|
63+
= note: all function arguments must have a statically known size
64+
= help: unsized fn params are gated as an unstable feature
65+
help: consider further restricting `Self`
66+
|
67+
LL | ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: Sized {
68+
| +++++++++++++
69+
70+
error: aborting due to 4 previous errors
5871

5972
For more information about this error, try `rustc --explain E0277`.

tests/ui/closures/issue-111932.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ trait Foo: std::fmt::Debug {}
22

33
fn print_foos(foos: impl Iterator<Item = dyn Foo>) {
44
foos.for_each(|foo| { //~ ERROR [E0277]
5-
println!("{:?}", foo); //~ ERROR [E0277]
5+
println!("{:?}", foo); // no `!Sized` error, already reported above
66
});
77
}
88

tests/ui/closures/issue-111932.stderr

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,6 @@ LL | foos.for_each(|foo| {
88
= note: all function arguments must have a statically known size
99
= help: unsized fn params are gated as an unstable feature
1010

11-
error[E0277]: the size for values of type `dyn Foo` cannot be known at compilation time
12-
--> $DIR/issue-111932.rs:5:26
13-
|
14-
LL | println!("{:?}", foo);
15-
| ---- ^^^ doesn't have a size known at compile-time
16-
| |
17-
| required by a bound introduced by this call
18-
|
19-
= help: the trait `Sized` is not implemented for `dyn Foo`
20-
note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug`
21-
--> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
22-
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
23-
24-
error: aborting due to 2 previous errors
11+
error: aborting due to 1 previous error
2512

2613
For more information about this error, try `rustc --explain E0277`.

tests/ui/error-codes/E0038.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ LL | fn foo(&self) -> Self;
2929
= help: consider moving `foo` to another trait
3030

3131
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
32-
--> $DIR/E0038.rs:7:9
32+
--> $DIR/E0038.rs:7:13
3333
|
3434
LL | let y = x.foo();
35-
| ^ doesn't have a size known at compile-time
35+
| ^^^^^^^ doesn't have a size known at compile-time
3636
|
3737
= help: the trait `Sized` is not implemented for `dyn Trait`
3838
= note: all local variables must have a statically known size

tests/ui/impl-trait/dyn-impl-type-mismatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn main() {
1010
} else {
1111
foo() //~ ERROR E0308
1212
};
13-
let a: dyn Trait = if true {
13+
let a: dyn Trait = if true { //~ ERROR E0277
1414
Struct //~ ERROR E0308
1515
} else {
1616
foo() //~ ERROR E0308

tests/ui/impl-trait/dyn-impl-type-mismatch.stderr

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
2+
--> $DIR/dyn-impl-type-mismatch.rs:13:12
3+
|
4+
LL | let a: dyn Trait = if true {
5+
| ^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `dyn Trait`
8+
= note: all local variables must have a statically known size
9+
= help: unsized locals are gated as an unstable feature
10+
help: consider borrowing here
11+
|
12+
LL | let a: &dyn Trait = if true {
13+
| +
14+
115
error[E0308]: mismatched types
216
--> $DIR/dyn-impl-type-mismatch.rs:11:9
317
|
@@ -38,6 +52,7 @@ LL | foo()
3852
found opaque type `impl Trait`
3953
= help: you can box the `impl Trait` to coerce it to `Box<dyn Trait>`, but you'll have to change the expected type as well
4054

41-
error: aborting due to 3 previous errors
55+
error: aborting due to 4 previous errors
4256

43-
For more information about this error, try `rustc --explain E0308`.
57+
Some errors have detailed explanations: E0277, E0308.
58+
For more information about an error, try `rustc --explain E0277`.

tests/ui/iterators/collect-into-slice.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ note: required by a bound in `collect`
99
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
1010

1111
error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
12-
--> $DIR/collect-into-slice.rs:6:9
12+
--> $DIR/collect-into-slice.rs:6:30
1313
|
1414
LL | let some_generated_vec = (0..10).collect();
15-
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
15+
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
1616
|
1717
= help: the trait `Sized` is not implemented for `[i32]`
1818
= note: all local variables must have a statically known size

tests/ui/sized/unsized-binding.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the size for values of type `str` cannot be known at compilation time
2-
--> $DIR/unsized-binding.rs:2:9
2+
--> $DIR/unsized-binding.rs:2:13
33
|
44
LL | let x = *"";
5-
| ^ doesn't have a size known at compile-time
5+
| ^^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `str`
88
= note: all local variables must have a statically known size

tests/ui/str/str-array-assignment.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ LL | let u: &str = if true { &s[..2] } else { s };
1818
| +
1919

2020
error[E0277]: the size for values of type `str` cannot be known at compilation time
21-
--> $DIR/str-array-assignment.rs:7:7
21+
--> $DIR/str-array-assignment.rs:7:11
2222
|
2323
LL | let v = s[..2];
24-
| ^ doesn't have a size known at compile-time
24+
| ^^^^^^ doesn't have a size known at compile-time
2525
|
2626
= help: the trait `Sized` is not implemented for `str`
2727
= note: all local variables must have a statically known size

tests/ui/unsized-locals/suggest-borrow.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2-
--> $DIR/suggest-borrow.rs:2:9
2+
--> $DIR/suggest-borrow.rs:2:12
33
|
44
LL | let x: [u8] = vec!(1, 2, 3)[..];
5-
| ^ doesn't have a size known at compile-time
5+
| ^^^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `[u8]`
88
= note: all local variables must have a statically known size
@@ -44,10 +44,10 @@ LL | let x: &[u8] = &vec!(1, 2, 3)[..];
4444
| +
4545

4646
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
47-
--> $DIR/suggest-borrow.rs:4:9
47+
--> $DIR/suggest-borrow.rs:4:19
4848
|
4949
LL | let x: [u8] = &vec!(1, 2, 3)[..];
50-
| ^ doesn't have a size known at compile-time
50+
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
5151
|
5252
= help: the trait `Sized` is not implemented for `[u8]`
5353
= note: all local variables must have a statically known size

tests/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ LL | fn f2((_x, _y): (i32, [i32])) {}
1919
= help: unsized locals are gated as an unstable feature
2020

2121
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
22-
--> $DIR/unsized-locals-using-unsized-fn-params.rs:13:9
22+
--> $DIR/unsized-locals-using-unsized-fn-params.rs:13:15
2323
|
2424
LL | let _foo: [u8] = *foo;
25-
| ^^^^ doesn't have a size known at compile-time
25+
| ^^^^ doesn't have a size known at compile-time
2626
|
2727
= help: the trait `Sized` is not implemented for `[u8]`
2828
= note: all local variables must have a statically known size

0 commit comments

Comments
 (0)