Skip to content

Commit 69c65d2

Browse files
committedJun 28, 2017
Auto merge of #42850 - estebank:unwanted-return-rotj, r=nikomatsakis
Detect missing `;` on methods with return type `()` - Point out the origin of a type requirement when it is the return type of a method - Point out possibly missing semicolon when the return type is `()` and the implicit return makes sense as a statement - Suggest changing the return type of methods with default return type - Don't suggest changing the return type on `fn main()` - Don't suggest changing the return type on impl fn - Suggest removal of semicolon (instead of being help)
2 parents 47faf1d + 7dad295 commit 69c65d2

38 files changed

+549
-77
lines changed
 

‎src/librustc/hir/map/mod.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,12 @@ impl<'hir> Map<'hir> {
594594
/// last good node id we found. Note that reaching the crate root (id == 0),
595595
/// is not an error, since items in the crate module have the crate root as
596596
/// parent.
597-
fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) -> Result<NodeId, NodeId>
598-
where F: Fn(&Node<'hir>) -> bool
597+
fn walk_parent_nodes<F, F2>(&self,
598+
start_id: NodeId,
599+
found: F,
600+
bail_early: F2)
601+
-> Result<NodeId, NodeId>
602+
where F: Fn(&Node<'hir>) -> bool, F2: Fn(&Node<'hir>) -> bool
599603
{
600604
let mut id = start_id;
601605
loop {
@@ -616,6 +620,8 @@ impl<'hir> Map<'hir> {
616620
Some(ref node) => {
617621
if found(node) {
618622
return Ok(parent_node);
623+
} else if bail_early(node) {
624+
return Err(parent_node);
619625
}
620626
}
621627
None => {
@@ -626,6 +632,56 @@ impl<'hir> Map<'hir> {
626632
}
627633
}
628634

635+
/// Retrieve the NodeId for `id`'s enclosing method, unless there's a
636+
/// `while` or `loop` before reacing it, as block tail returns are not
637+
/// available in them.
638+
///
639+
/// ```
640+
/// fn foo(x: usize) -> bool {
641+
/// if x == 1 {
642+
/// true // `get_return_block` gets passed the `id` corresponding
643+
/// } else { // to this, it will return `foo`'s `NodeId`.
644+
/// false
645+
/// }
646+
/// }
647+
/// ```
648+
///
649+
/// ```
650+
/// fn foo(x: usize) -> bool {
651+
/// loop {
652+
/// true // `get_return_block` gets passed the `id` corresponding
653+
/// } // to this, it will return `None`.
654+
/// false
655+
/// }
656+
/// ```
657+
pub fn get_return_block(&self, id: NodeId) -> Option<NodeId> {
658+
let match_fn = |node: &Node| {
659+
match *node {
660+
NodeItem(_) |
661+
NodeForeignItem(_) |
662+
NodeTraitItem(_) |
663+
NodeImplItem(_) => true,
664+
_ => false,
665+
}
666+
};
667+
let match_non_returning_block = |node: &Node| {
668+
match *node {
669+
NodeExpr(ref expr) => {
670+
match expr.node {
671+
ExprWhile(..) | ExprLoop(..) => true,
672+
_ => false,
673+
}
674+
}
675+
_ => false,
676+
}
677+
};
678+
679+
match self.walk_parent_nodes(id, match_fn, match_non_returning_block) {
680+
Ok(id) => Some(id),
681+
Err(_) => None,
682+
}
683+
}
684+
629685
/// Retrieve the NodeId for `id`'s parent item, or `id` itself if no
630686
/// parent item is in this map. The "parent item" is the closest parent node
631687
/// in the AST which is recorded by the map and is an item, either an item
@@ -637,7 +693,7 @@ impl<'hir> Map<'hir> {
637693
NodeTraitItem(_) |
638694
NodeImplItem(_) => true,
639695
_ => false,
640-
}) {
696+
}, |_| false) {
641697
Ok(id) => id,
642698
Err(id) => id,
643699
}
@@ -649,7 +705,7 @@ impl<'hir> Map<'hir> {
649705
let id = match self.walk_parent_nodes(id, |node| match *node {
650706
NodeItem(&Item { node: Item_::ItemMod(_), .. }) => true,
651707
_ => false,
652-
}) {
708+
}, |_| false) {
653709
Ok(id) => id,
654710
Err(id) => id,
655711
};
@@ -668,7 +724,7 @@ impl<'hir> Map<'hir> {
668724
NodeImplItem(_) |
669725
NodeBlock(_) => true,
670726
_ => false,
671-
}) {
727+
}, |_| false) {
672728
Ok(id) => Some(id),
673729
Err(_) => None,
674730
}

‎src/librustc/traits/error_reporting.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10881088
ObligationCauseCode::VariableType(_) => {
10891089
err.note("all local variables must have a statically known size");
10901090
}
1091-
ObligationCauseCode::ReturnType => {
1091+
ObligationCauseCode::SizedReturnType => {
10921092
err.note("the return type of a function must have a \
10931093
statically known size");
10941094
}
@@ -1133,6 +1133,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11331133
but not on the corresponding trait method",
11341134
predicate));
11351135
}
1136+
ObligationCauseCode::ReturnType(_) |
1137+
ObligationCauseCode::BlockTailExpression(_) => (),
11361138
}
11371139
}
11381140

‎src/librustc/traits/mod.rs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,65 +118,76 @@ pub enum ObligationCauseCode<'tcx> {
118118
/// Obligation incurred due to an object cast.
119119
ObjectCastObligation(/* Object type */ Ty<'tcx>),
120120

121-
/// Various cases where expressions must be sized/copy/etc:
122-
AssignmentLhsSized, // L = X implies that L is Sized
123-
StructInitializerSized, // S { ... } must be Sized
124-
VariableType(ast::NodeId), // Type of each variable must be Sized
125-
ReturnType, // Return type must be Sized
126-
RepeatVec, // [T,..n] --> T must be Copy
127-
128-
// Types of fields (other than the last) in a struct must be sized.
121+
// Various cases where expressions must be sized/copy/etc:
122+
/// L = X implies that L is Sized
123+
AssignmentLhsSized,
124+
/// S { ... } must be Sized
125+
StructInitializerSized,
126+
/// Type of each variable must be Sized
127+
VariableType(ast::NodeId),
128+
/// Return type must be Sized
129+
SizedReturnType,
130+
/// [T,..n] --> T must be Copy
131+
RepeatVec,
132+
133+
/// Types of fields (other than the last) in a struct must be sized.
129134
FieldSized,
130135

131-
// Constant expressions must be sized.
136+
/// Constant expressions must be sized.
132137
ConstSized,
133138

134-
// static items must have `Sync` type
139+
/// static items must have `Sync` type
135140
SharedStatic,
136141

137142
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
138143

139144
ImplDerivedObligation(DerivedObligationCause<'tcx>),
140145

141-
// error derived when matching traits/impls; see ObligationCause for more details
146+
/// error derived when matching traits/impls; see ObligationCause for more details
142147
CompareImplMethodObligation {
143148
item_name: ast::Name,
144149
impl_item_def_id: DefId,
145150
trait_item_def_id: DefId,
146151
lint_id: Option<ast::NodeId>,
147152
},
148153

149-
// Checking that this expression can be assigned where it needs to be
154+
/// Checking that this expression can be assigned where it needs to be
150155
// FIXME(eddyb) #11161 is the original Expr required?
151156
ExprAssignable,
152157

153-
// Computing common supertype in the arms of a match expression
158+
/// Computing common supertype in the arms of a match expression
154159
MatchExpressionArm { arm_span: Span,
155160
source: hir::MatchSource },
156161

157-
// Computing common supertype in an if expression
162+
/// Computing common supertype in an if expression
158163
IfExpression,
159164

160-
// Computing common supertype of an if expression with no else counter-part
165+
/// Computing common supertype of an if expression with no else counter-part
161166
IfExpressionWithNoElse,
162167

163-
// `where a == b`
168+
/// `where a == b`
164169
EquatePredicate,
165170

166-
// `main` has wrong type
171+
/// `main` has wrong type
167172
MainFunctionType,
168173

169-
// `start` has wrong type
174+
/// `start` has wrong type
170175
StartFunctionType,
171176

172-
// intrinsic has wrong type
177+
/// intrinsic has wrong type
173178
IntrinsicType,
174179

175-
// method receiver
180+
/// method receiver
176181
MethodReceiver,
177182

178-
// `return` with no expression
183+
/// `return` with no expression
179184
ReturnNoExpression,
185+
186+
/// `return` with an expression
187+
ReturnType(ast::NodeId),
188+
189+
/// Block implicit return
190+
BlockTailExpression(ast::NodeId),
180191
}
181192

182193
#[derive(Clone, Debug, PartialEq, Eq)]

‎src/librustc/traits/structural_impls.rs

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
191191
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
192192
super::StructInitializerSized => Some(super::StructInitializerSized),
193193
super::VariableType(id) => Some(super::VariableType(id)),
194-
super::ReturnType => Some(super::ReturnType),
194+
super::ReturnType(id) => Some(super::ReturnType(id)),
195+
super::SizedReturnType => Some(super::SizedReturnType),
195196
super::RepeatVec => Some(super::RepeatVec),
196197
super::FieldSized => Some(super::FieldSized),
197198
super::ConstSized => Some(super::ConstSized),
@@ -213,34 +214,19 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
213214
lint_id: lint_id,
214215
})
215216
}
216-
super::ExprAssignable => {
217-
Some(super::ExprAssignable)
218-
}
217+
super::ExprAssignable => Some(super::ExprAssignable),
219218
super::MatchExpressionArm { arm_span, source } => {
220219
Some(super::MatchExpressionArm { arm_span: arm_span,
221220
source: source })
222221
}
223-
super::IfExpression => {
224-
Some(super::IfExpression)
225-
}
226-
super::IfExpressionWithNoElse => {
227-
Some(super::IfExpressionWithNoElse)
228-
}
229-
super::EquatePredicate => {
230-
Some(super::EquatePredicate)
231-
}
232-
super::MainFunctionType => {
233-
Some(super::MainFunctionType)
234-
}
235-
super::StartFunctionType => {
236-
Some(super::StartFunctionType)
237-
}
238-
super::IntrinsicType => {
239-
Some(super::IntrinsicType)
240-
}
241-
super::MethodReceiver => {
242-
Some(super::MethodReceiver)
243-
}
222+
super::IfExpression => Some(super::IfExpression),
223+
super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
224+
super::EquatePredicate => Some(super::EquatePredicate),
225+
super::MainFunctionType => Some(super::MainFunctionType),
226+
super::StartFunctionType => Some(super::StartFunctionType),
227+
super::IntrinsicType => Some(super::IntrinsicType),
228+
super::MethodReceiver => Some(super::MethodReceiver),
229+
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
244230
}
245231
}
246232
}
@@ -492,12 +478,14 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
492478
super::AssignmentLhsSized |
493479
super::StructInitializerSized |
494480
super::VariableType(_) |
495-
super::ReturnType |
481+
super::ReturnType(_) |
482+
super::SizedReturnType |
496483
super::ReturnNoExpression |
497484
super::RepeatVec |
498485
super::FieldSized |
499486
super::ConstSized |
500487
super::SharedStatic |
488+
super::BlockTailExpression(_) |
501489
super::CompareImplMethodObligation { .. } => self.clone(),
502490

503491
super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
@@ -537,12 +525,14 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
537525
super::AssignmentLhsSized |
538526
super::StructInitializerSized |
539527
super::VariableType(_) |
540-
super::ReturnType |
528+
super::ReturnType(_) |
529+
super::SizedReturnType |
541530
super::ReturnNoExpression |
542531
super::RepeatVec |
543532
super::FieldSized |
544533
super::ConstSized |
545534
super::SharedStatic |
535+
super::BlockTailExpression(_) |
546536
super::CompareImplMethodObligation { .. } => false,
547537

548538
super::ProjectionWf(proj) => proj.visit_with(visitor),

‎src/librustc/ty/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,18 @@ impl<'tcx> TyS<'tcx> {
481481
_ => false,
482482
}
483483
}
484+
485+
pub fn is_suggestable(&self) -> bool {
486+
match self.sty {
487+
TypeVariants::TyAnon(..) |
488+
TypeVariants::TyFnDef(..) |
489+
TypeVariants::TyFnPtr(..) |
490+
TypeVariants::TyDynamic(..) |
491+
TypeVariants::TyClosure(..) |
492+
TypeVariants::TyProjection(..) => false,
493+
_ => true,
494+
}
495+
}
484496
}
485497

486498
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::TyS<'tcx> {

‎src/librustc_errors/emitter.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ impl Emitter for EmitterWriter {
4747
// don't display multiline suggestions as labels
4848
sugg.substitution_parts[0].substitutions[0].find('\n').is_none() {
4949
let substitution = &sugg.substitution_parts[0].substitutions[0];
50-
let msg = format!("help: {} `{}`", sugg.msg, substitution);
50+
let msg = if substitution.len() == 0 {
51+
// This substitution is only removal, don't show it
52+
format!("help: {}", sugg.msg)
53+
} else {
54+
format!("help: {} `{}`", sugg.msg, substitution)
55+
};
5156
primary_span.push_span_label(sugg.substitution_spans().next().unwrap(), msg);
5257
} else {
5358
// if there are multiple suggestions, print them all in full

‎src/librustc_typeck/check/coercion.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,18 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
11681168
"`return;` in a function whose return type is not `()`");
11691169
db.span_label(cause.span, "return type is not ()");
11701170
}
1171+
ObligationCauseCode::BlockTailExpression(blk_id) => {
1172+
db = fcx.report_mismatched_types(cause, expected, found, err);
1173+
1174+
let expr = expression.unwrap_or_else(|| {
1175+
span_bug!(cause.span,
1176+
"supposed to be part of a block tail expression, but the \
1177+
expression is empty");
1178+
});
1179+
fcx.suggest_mismatched_types_on_tail(&mut db, expr,
1180+
expected, found,
1181+
cause.span, blk_id);
1182+
}
11711183
_ => {
11721184
db = fcx.report_mismatched_types(cause, expected, found, err);
11731185
}

‎src/librustc_typeck/check/demand.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7373
}
7474
}
7575

76+
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
77+
if let Some(mut err) = self.demand_coerce_diag(expr, checked_ty, expected) {
78+
err.emit();
79+
}
80+
}
81+
7682
// Checks that the type of `expr` can be coerced to `expected`.
7783
//
7884
// NB: This code relies on `self.diverges` to be accurate. In
7985
// particular, assignments to `!` will be permitted if the
8086
// diverges flag is currently "always".
81-
pub fn demand_coerce(&self,
82-
expr: &hir::Expr,
83-
checked_ty: Ty<'tcx>,
84-
expected: Ty<'tcx>) {
87+
pub fn demand_coerce_diag(&self,
88+
expr: &hir::Expr,
89+
checked_ty: Ty<'tcx>,
90+
expected: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
8591
let expected = self.resolve_type_vars_with_obligations(expected);
8692

8793
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
@@ -105,8 +111,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
105111
self.get_best_match(&suggestions).join("\n")));
106112
}
107113
}
108-
err.emit();
114+
return Some(err);
109115
}
116+
None
110117
}
111118

112119
fn format_method_suggestion(&self, method: &AssociatedItem) -> String {

‎src/librustc_typeck/check/mod.rs

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ use syntax_pos::{self, BytePos, Span};
124124

125125
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
126126
use rustc::hir::itemlikevisit::ItemLikeVisitor;
127+
use rustc::hir::map::Node;
127128
use rustc::hir::{self, PatKind};
128129
use rustc::middle::lang_items;
129130
use rustc_back::slice;
@@ -977,7 +978,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
977978
*fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
978979

979980
let ret_ty = fn_sig.output();
980-
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
981+
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
981982
let ret_ty = fcx.instantiate_anon_types(&ret_ty);
982983
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
983984
fn_sig = fcx.tcx.mk_fn_sig(
@@ -1900,7 +1901,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
19001901

19011902
// Require that the predicate holds for the concrete type.
19021903
let cause = traits::ObligationCause::new(span, self.body_id,
1903-
traits::ReturnType);
1904+
traits::SizedReturnType);
19041905
self.register_predicate(traits::Obligation::new(cause,
19051906
self.param_env,
19061907
predicate));
@@ -2839,10 +2840,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
28392840
"check_return_expr called outside fn body"));
28402841

28412842
let ret_ty = ret_coercion.borrow().expected_ty();
2842-
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
2843+
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone());
28432844
ret_coercion.borrow_mut()
28442845
.coerce(self,
2845-
&self.misc(return_expr.span),
2846+
&self.cause(return_expr.span,
2847+
ObligationCauseCode::ReturnType(return_expr.id)),
28462848
return_expr,
28472849
return_expr_ty,
28482850
self.diverges.get());
@@ -4161,8 +4163,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41614163
let mut coerce = ctxt.coerce.as_mut().unwrap();
41624164
if let Some(tail_expr_ty) = tail_expr_ty {
41634165
let tail_expr = tail_expr.unwrap();
4166+
let cause = self.cause(tail_expr.span,
4167+
ObligationCauseCode::BlockTailExpression(blk.id));
41644168
coerce.coerce(self,
4165-
&self.misc(tail_expr.span),
4169+
&cause,
41664170
tail_expr,
41674171
tail_expr_ty,
41684172
self.diverges.get());
@@ -4201,6 +4205,130 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42014205
ty
42024206
}
42034207

4208+
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
4209+
/// `fn main` if it is a method, `None` otherwise.
4210+
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
4211+
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
4212+
// `while` before reaching it, as block tail returns are not available in them.
4213+
if let Some(fn_id) = self.tcx.hir.get_return_block(blk_id) {
4214+
let parent = self.tcx.hir.get(fn_id);
4215+
4216+
if let Node::NodeItem(&hir::Item {
4217+
name, node: hir::ItemFn(ref decl, ..), ..
4218+
}) = parent {
4219+
decl.clone().and_then(|decl| {
4220+
// This is less than ideal, it will not present the return type span on any
4221+
// method called `main`, regardless of whether it is actually the entry point.
4222+
Some((decl, name == Symbol::intern("main")))
4223+
})
4224+
} else if let Node::NodeTraitItem(&hir::TraitItem {
4225+
node: hir::TraitItemKind::Method(hir::MethodSig {
4226+
ref decl, ..
4227+
}, ..), ..
4228+
}) = parent {
4229+
decl.clone().and_then(|decl| {
4230+
Some((decl, false))
4231+
})
4232+
} else {
4233+
None
4234+
}
4235+
} else {
4236+
None
4237+
}
4238+
}
4239+
4240+
/// On implicit return expressions with mismatched types, provide the following suggestions:
4241+
///
4242+
/// - Point out the method's return type as the reason for the expected type
4243+
/// - Possible missing semicolon
4244+
/// - Possible missing return type if the return type is the default, and not `fn main()`
4245+
pub fn suggest_mismatched_types_on_tail(&self,
4246+
err: &mut DiagnosticBuilder<'tcx>,
4247+
expression: &'gcx hir::Expr,
4248+
expected: Ty<'tcx>,
4249+
found: Ty<'tcx>,
4250+
cause_span: Span,
4251+
blk_id: ast::NodeId) {
4252+
self.suggest_missing_semicolon(err, expression, expected, cause_span);
4253+
4254+
if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
4255+
// `fn main()` must return `()`, do not suggest changing return type
4256+
if !is_main {
4257+
self.suggest_missing_return_type(err, &fn_decl, found);
4258+
}
4259+
}
4260+
}
4261+
4262+
/// A common error is to forget to add a semicolon at the end of a block:
4263+
///
4264+
/// ```
4265+
/// fn foo() {
4266+
/// bar_that_returns_u32()
4267+
/// }
4268+
/// ```
4269+
///
4270+
/// This routine checks if the return expression in a block would make sense on its own as a
4271+
/// statement and the return type has been left as defaultor has been specified as `()`. If so,
4272+
/// it suggests adding a semicolon.
4273+
fn suggest_missing_semicolon(&self,
4274+
err: &mut DiagnosticBuilder<'tcx>,
4275+
expression: &'gcx hir::Expr,
4276+
expected: Ty<'tcx>,
4277+
cause_span: Span) {
4278+
if expected.is_nil() {
4279+
// `BlockTailExpression` only relevant if the tail expr would be
4280+
// useful on its own.
4281+
match expression.node {
4282+
hir::ExprCall(..) |
4283+
hir::ExprMethodCall(..) |
4284+
hir::ExprIf(..) |
4285+
hir::ExprWhile(..) |
4286+
hir::ExprLoop(..) |
4287+
hir::ExprMatch(..) |
4288+
hir::ExprBlock(..) => {
4289+
let sp = cause_span.next_point();
4290+
err.span_suggestion(sp,
4291+
"did you mean to add a semicolon here?",
4292+
";".to_string());
4293+
}
4294+
_ => (),
4295+
}
4296+
}
4297+
}
4298+
4299+
4300+
/// A possible error is to forget to add a return type that is needed:
4301+
///
4302+
/// ```
4303+
/// fn foo() {
4304+
/// bar_that_returns_u32()
4305+
/// }
4306+
/// ```
4307+
///
4308+
/// This routine checks if the return type is left as default, the method is not part of an
4309+
/// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
4310+
/// type.
4311+
fn suggest_missing_return_type(&self,
4312+
err: &mut DiagnosticBuilder<'tcx>,
4313+
fn_decl: &hir::FnDecl,
4314+
ty: Ty<'tcx>) {
4315+
4316+
// Only recommend changing the return type for methods that
4317+
// haven't set a return type at all (and aren't `fn main()` or an impl).
4318+
if let &hir::FnDecl {
4319+
output: hir::FunctionRetTy::DefaultReturn(span), ..
4320+
} = fn_decl {
4321+
if ty.is_suggestable() {
4322+
err.span_suggestion(span,
4323+
"possibly return type missing here?",
4324+
format!("-> {} ", ty));
4325+
} else {
4326+
err.span_label(span, "possibly return type missing here?");
4327+
}
4328+
}
4329+
}
4330+
4331+
42044332
/// A common error is to add an extra semicolon:
42054333
///
42064334
/// ```
@@ -4236,7 +4364,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42364364
hi: original_span.hi,
42374365
ctxt: original_span.ctxt,
42384366
};
4239-
err.span_help(span_semi, "consider removing this semicolon:");
4367+
err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string());
42404368
}
42414369

42424370
// Instantiates the given path, which must refer to an item with the given
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/block-must-not-have-result-do.rs:13:9
3+
|
4+
13 | true //~ ERROR mismatched types
5+
| ^^^^ expected (), found bool
6+
|
7+
= note: expected type `()`
8+
found type `bool`
9+
10+
error: aborting due to previous error(s)
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/block-must-not-have-result-res.rs:15:9
3+
|
4+
15 | true //~ ERROR mismatched types
5+
| ^^^^ expected (), found bool
6+
|
7+
= note: expected type `()`
8+
found type `bool`
9+
10+
error: aborting due to previous error(s)
11+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/block-must-not-have-result-while.rs:13:9
3+
|
4+
13 | true //~ ERROR mismatched types
5+
| ^^^^ expected (), found bool
6+
|
7+
= note: expected type `()`
8+
found type `bool`
9+
10+
error: aborting due to previous error(s)
11+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/consider-removing-last-semi.rs:11:18
3+
|
4+
11 | fn f() -> String { //~ ERROR mismatched types
5+
| __________________^
6+
12 | | 0u8;
7+
13 | | "bla".to_string(); //~ HELP consider removing this semicolon
8+
| | - help: consider removing this semicolon
9+
14 | | }
10+
| |_^ expected struct `std::string::String`, found ()
11+
|
12+
= note: expected type `std::string::String`
13+
found type `()`
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/consider-removing-last-semi.rs:16:18
17+
|
18+
16 | fn g() -> String { //~ ERROR mismatched types
19+
| __________________^
20+
17 | | "this won't work".to_string();
21+
18 | | "removeme".to_string(); //~ HELP consider removing this semicolon
22+
| | - help: consider removing this semicolon
23+
19 | | }
24+
| |_^ expected struct `std::string::String`, found ()
25+
|
26+
= note: expected type `std::string::String`
27+
found type `()`
28+
29+
error: aborting due to previous error(s)
30+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-11714.rs:11:18
3+
|
4+
11 | fn blah() -> i32 { //~ ERROR mismatched types
5+
| __________________^
6+
12 | | 1
7+
13 | |
8+
14 | | ; //~ HELP consider removing this semicolon:
9+
| | - help: consider removing this semicolon
10+
15 | | }
11+
| |_^ expected i32, found ()
12+
|
13+
= note: expected type `i32`
14+
found type `()`
15+
16+
error: aborting due to previous error(s)
17+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-13428.rs:13:20
3+
|
4+
13 | fn foo() -> String { //~ ERROR mismatched types
5+
| ____________________^
6+
14 | | format!("Hello {}",
7+
15 | | "world")
8+
16 | | // Put the trailing semicolon on its own line to test that the
9+
17 | | // note message gets the offending semicolon exactly
10+
18 | | ; //~ HELP consider removing this semicolon
11+
| | - help: consider removing this semicolon
12+
19 | | }
13+
| |_^ expected struct `std::string::String`, found ()
14+
|
15+
= note: expected type `std::string::String`
16+
found type `()`
17+
18+
error[E0308]: mismatched types
19+
--> $DIR/issue-13428.rs:21:20
20+
|
21+
21 | fn bar() -> String { //~ ERROR mismatched types
22+
| ____________________^
23+
22 | | "foobar".to_string()
24+
23 | | ; //~ HELP consider removing this semicolon
25+
| | - help: consider removing this semicolon
26+
24 | | }
27+
| |_^ expected struct `std::string::String`, found ()
28+
|
29+
= note: expected type `std::string::String`
30+
found type `()`
31+
32+
error: aborting due to previous error(s)
33+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-13624.rs:17:5
3+
|
4+
17 | Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
6+
|
7+
= note: expected type `()`
8+
found type `a::Enum`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/issue-13624.rs:32:9
12+
|
13+
32 | a::Enum::EnumStructVariant { x, y, z } => {
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
15+
|
16+
= note: expected type `()`
17+
found type `a::Enum`
18+
19+
error: aborting due to previous error(s)
20+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-20862.rs:12:5
3+
|
4+
11 | fn foo(x: i32) {
5+
| - possibly return type missing here?
6+
12 | |y| x + y
7+
| ^^^^^^^^^ expected (), found closure
8+
|
9+
= note: expected type `()`
10+
found type `[closure@$DIR/issue-20862.rs:12:5: 12:14 x:_]`
11+
12+
error[E0618]: expected function, found `()`
13+
--> $DIR/issue-20862.rs:17:13
14+
|
15+
17 | let x = foo(5)(2);
16+
| ^^^^^^^^^
17+
18+
error: aborting due to previous error(s)
19+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0277]: the trait bound `{integer}: Scalar` is not satisfied
2+
--> $DIR/issue-22645.rs:25:5
3+
|
4+
25 | b + 3 //~ ERROR E0277
5+
| ^ the trait `Scalar` is not implemented for `{integer}`
6+
|
7+
= help: the following implementations were found:
8+
<f64 as Scalar>
9+
= note: required because of the requirements on the impl of `std::ops::Add<{integer}>` for `Bob`
10+
11+
error[E0308]: mismatched types
12+
--> $DIR/issue-22645.rs:25:3
13+
|
14+
25 | b + 3 //~ ERROR E0277
15+
| ^^^^^ expected (), found struct `Bob`
16+
|
17+
= note: expected type `()`
18+
found type `Bob`
19+
20+
error: aborting due to previous error(s)
21+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0599]: no method named `b` found for type `&Self` in the current scope
2+
--> $DIR/issue-3563.rs:13:17
3+
|
4+
13 | || self.b()
5+
| ^
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-3563.rs:13:9
9+
|
10+
12 | fn a(&self) {
11+
| - possibly return type missing here?
12+
13 | || self.b()
13+
| ^^^^^^^^^^^ expected (), found closure
14+
|
15+
= note: expected type `()`
16+
found type `[closure@$DIR/issue-3563.rs:13:9: 13:20 self:_]`
17+
18+
error: aborting due to previous error(s)
19+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-5500.rs:12:5
3+
|
4+
12 | &panic!()
5+
| ^^^^^^^^^ expected (), found reference
6+
|
7+
= note: expected type `()`
8+
found type `&_`
9+
10+
error: aborting due to previous error(s)
11+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we do some basic error correcton in the tokeniser (and don't spew
12+
// too many bogus errors).
13+
14+
fn foo() -> usize {
15+
3
16+
}
17+
18+
fn bar() {
19+
foo()
20+
}
21+
22+
fn main() {
23+
bar()
24+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/unexpected-return-on-unit.rs:19:5
3+
|
4+
19 | foo()
5+
| ^^^^^ expected (), found usize
6+
|
7+
= note: expected type `()`
8+
found type `usize`
9+
help: did you mean to add a semicolon here?
10+
| foo();
11+
help: possibly return type missing here?
12+
| fn bar() -> usize {
13+
14+
error: aborting due to previous error(s)
15+

‎src/test/ui/coercion-missing-tail-expected-type.stderr

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,25 @@ error[E0308]: mismatched types
44
13 | fn plus_one(x: i32) -> i32 {
55
| ____________________________^
66
14 | | x + 1;
7+
| | - help: consider removing this semicolon
78
15 | | }
89
| |_^ expected i32, found ()
910
|
1011
= note: expected type `i32`
1112
found type `()`
12-
help: consider removing this semicolon:
13-
--> $DIR/coercion-missing-tail-expected-type.rs:14:10
14-
|
15-
14 | x + 1;
16-
| ^
1713

1814
error[E0308]: mismatched types
1915
--> $DIR/coercion-missing-tail-expected-type.rs:17:29
2016
|
2117
17 | fn foo() -> Result<u8, u64> {
2218
| _____________________________^
2319
18 | | Ok(1);
20+
| | - help: consider removing this semicolon
2421
19 | | }
2522
| |_^ expected enum `std::result::Result`, found ()
2623
|
2724
= note: expected type `std::result::Result<u8, u64>`
2825
found type `()`
29-
help: consider removing this semicolon:
30-
--> $DIR/coercion-missing-tail-expected-type.rs:18:10
31-
|
32-
18 | Ok(1);
33-
| ^
3426

3527
error: aborting due to previous error(s)
3628

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/for-loop-has-unit-body.rs:13:9
3+
|
4+
13 | x //~ ERROR mismatched types
5+
| ^ expected (), found integral variable
6+
|
7+
= note: expected type `()`
8+
found type `{integer}`
9+
10+
error: aborting due to previous error(s)
11+

‎src/test/ui/mismatched_types/issue-19109.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-19109.rs:14:5
33
|
4+
13 | fn function(t: &mut Trait) {
5+
| - help: possibly return type missing here? `-> *mut Trait `
46
14 | t as *mut Trait
57
| ^^^^^^^^^^^^^^^ expected (), found *-ptr
68
|

‎src/test/ui/resolve/token-error-correct-3.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ error[E0308]: mismatched types
3535
--> $DIR/token-error-correct-3.rs:25:13
3636
|
3737
25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
38-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: did you mean to add a semicolon here? `;`
39+
| |
40+
| expected (), found enum `std::result::Result`
3941
|
4042
= note: expected type `()`
4143
found type `std::result::Result<bool, std::io::Error>`

0 commit comments

Comments
 (0)
Please sign in to comment.