diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/pat.rs | 53 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/collect/type_of.rs | 5 |
4 files changed, 79 insertions, 23 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5670729253d..fb92ce41252 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1179,10 +1179,11 @@ impl<'a> Parser<'a> { // Parse the type of a `const` or `static mut?` item. // That is, the `":" $ty` fragment. - let ty = if self.eat(&token::Colon) { - self.parse_ty()? - } else { - self.recover_missing_const_type(id, m) + let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi)) + { + // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type. + (true, false) => self.parse_ty()?, + (colon, _) => self.recover_missing_const_type(colon, m), }; let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; @@ -1190,9 +1191,9 @@ impl<'a> Parser<'a> { Ok((id, ty, expr)) } - /// We were supposed to parse `:` but the `:` was missing. + /// We were supposed to parse `":" $ty` but the `:` or the type was missing. /// This means that the type is missing. - fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> { + fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> { // Construct the error and stash it away with the hope // that typeck will later enrich the error with a type. let kind = match m { @@ -1200,18 +1201,25 @@ impl<'a> Parser<'a> { Some(Mutability::Not) => "static", None => "const", }; - let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item")); + + let colon = match colon_present { + true => "", + false => ":", + }; + + let span = self.prev_token.span.shrink_to_hi(); + let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item")); err.span_suggestion( - id.span, + span, "provide a type for the item", - format!("{id}: <type>"), + format!("{colon} <type>"), Applicability::HasPlaceholders, ); - err.stash(id.span, StashKey::ItemNoType); + err.stash(span, StashKey::ItemNoType); // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. - P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None }) + P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 33a3f825ac2..660e7e4e399 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1761,13 +1761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|seg| seg.args.as_ref()) .flat_map(|a| a.args.iter()) { - if let hir::GenericArg::Type(hir_ty) = &arg { - let ty = self.resolve_vars_if_possible( - self.typeck_results.borrow().node_type(hir_ty.hir_id), - ); - if ty == predicate.self_ty() { - error.obligation.cause.span = hir_ty.span; - } + if let hir::GenericArg::Type(hir_ty) = &arg + && let Some(ty) = + self.typeck_results.borrow().node_type_opt(hir_ty.hir_id) + && self.resolve_vars_if_possible(ty) == predicate.self_ty() + { + error.obligation.cause.span = hir_ty.span; + break; } } } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 837c323553c..a13c7152582 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { - self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti); + self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti); } if let Some(p) = sub { @@ -610,7 +610,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { local_ty } - fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) { + fn check_binding_alt_eq_ty( + &self, + ba: hir::BindingAnnotation, + span: Span, + var_id: HirId, + ty: Ty<'tcx>, + ti: TopInfo<'tcx>, + ) { let var_ty = self.local_ty(span, var_id).decl_ty; if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); @@ -628,12 +635,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let pre = if in_match { "in the same arm, " } else { "" }; err.note(&format!("{}a binding must have the same type in all alternatives", pre)); - // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing - // `ref` or `&` to the pattern. + self.suggest_adding_missing_ref_or_removing_ref( + &mut err, + span, + var_ty, + self.resolve_vars_with_obligations(ty), + ba, + ); err.emit(); } } + fn suggest_adding_missing_ref_or_removing_ref( + &self, + err: &mut Diagnostic, + span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ba: hir::BindingAnnotation, + ) { + match (expected.kind(), actual.kind(), ba) { + (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated) + if self.can_eq(self.param_env, *inner_ty, actual).is_ok() => + { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider adding `ref`", + "ref ", + Applicability::MaybeIncorrect, + ); + } + (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref) + if self.can_eq(self.param_env, expected, *inner_ty).is_ok() => + { + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(4)), + "consider removing `ref`", + "", + Applicability::MaybeIncorrect, + ); + } + _ => (), + } + } + // Precondition: pat is a Ref(_) pattern fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { let tcx = self.tcx; diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 534ddfa9531..f1dbe64f13a 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -801,6 +801,9 @@ fn infer_placeholder_type<'a>( match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { Some(mut err) => { if !ty.references_error() { + // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic) + let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" }; + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`. @@ -816,7 +819,7 @@ fn infer_placeholder_type<'a>( err.span_suggestion( span, &format!("provide a type for the {item}", item = kind), - format!("{}: {}", item_ident, sugg_ty), + format!("{colon} {sugg_ty}"), Applicability::MachineApplicable, ); } else { |
