Skip to content

Commit 73e3508

Browse files
committed
Suggest calling closure with resolved return type when appropriate
1 parent 7b0085a commit 73e3508

File tree

5 files changed

+103
-61
lines changed

5 files changed

+103
-61
lines changed

src/librustc/ty/sty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ impl<'tcx> ClosureSubsts<'tcx> {
385385
let ty = self.closure_sig_ty(def_id, tcx);
386386
match ty.sty {
387387
ty::FnPtr(sig) => sig,
388-
_ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty),
388+
ty::Infer(_) | ty::Error => ty::Binder::dummy(FnSig::fake()), // ignore errors
389+
_ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.sty),
389390
}
390391
}
391392
}

src/librustc_typeck/check/coercion.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -799,12 +799,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
799799
/// adjusted type of the expression, if successful.
800800
/// Adjustments are only recorded if the coercion succeeded.
801801
/// The expressions *must not* have any pre-existing adjustments.
802-
pub fn try_coerce(&self,
803-
expr: &hir::Expr,
804-
expr_ty: Ty<'tcx>,
805-
target: Ty<'tcx>,
806-
allow_two_phase: AllowTwoPhase)
807-
-> RelateResult<'tcx, Ty<'tcx>> {
802+
pub fn try_coerce(
803+
&self,
804+
expr: &hir::Expr,
805+
expr_ty: Ty<'tcx>,
806+
target: Ty<'tcx>,
807+
allow_two_phase: AllowTwoPhase,
808+
) -> RelateResult<'tcx, Ty<'tcx>> {
808809
let source = self.resolve_type_vars_with_obligations(expr_ty);
809810
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
810811

src/librustc_typeck/check/mod.rs

+77-53
Original file line numberDiff line numberDiff line change
@@ -3917,75 +3917,99 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39173917
expected: Ty<'tcx>,
39183918
found: Ty<'tcx>,
39193919
) -> bool {
3920-
match found.sty {
3921-
ty::FnDef(..) | ty::FnPtr(_) => {}
3922-
_ => return false,
3923-
}
39243920
let hir = self.tcx.hir();
3921+
let (def_id, sig) = match found.sty {
3922+
ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
3923+
ty::Closure(def_id, substs) => {
3924+
// We don't use `closure_sig` to account for malformed closures like
3925+
// `|_: [_; continue]| {}` and instead we don't suggest anything.
3926+
let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx);
3927+
(def_id, match closure_sig_ty.sty {
3928+
ty::FnPtr(sig) => sig,
3929+
_ => return false,
3930+
})
3931+
}
3932+
_ => return false,
3933+
};
39253934

3926-
let sig = found.fn_sig(self.tcx);
39273935
let sig = self
39283936
.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig)
39293937
.0;
39303938
let sig = self.normalize_associated_types_in(expr.span, &sig);
3931-
if let Ok(_) = self.try_coerce(expr, sig.output(), expected, AllowTwoPhase::No) {
3939+
if self.can_coerce(sig.output(), expected) {
39323940
let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
39333941
(String::new(), Applicability::MachineApplicable)
39343942
} else {
39353943
("...".to_string(), Applicability::HasPlaceholders)
39363944
};
39373945
let mut msg = "call this function";
3938-
if let ty::FnDef(def_id, ..) = found.sty {
3939-
match hir.get_if_local(def_id) {
3940-
Some(Node::Item(hir::Item {
3941-
node: ItemKind::Fn(.., body_id),
3942-
..
3943-
})) |
3944-
Some(Node::ImplItem(hir::ImplItem {
3945-
node: hir::ImplItemKind::Method(_, body_id),
3946-
..
3947-
})) |
3948-
Some(Node::TraitItem(hir::TraitItem {
3949-
node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)),
3950-
..
3951-
})) => {
3952-
let body = hir.body(*body_id);
3953-
sugg_call = body.arguments.iter()
3954-
.map(|arg| match &arg.pat.node {
3955-
hir::PatKind::Binding(_, _, ident, None)
3956-
if ident.name != kw::SelfLower => ident.to_string(),
3957-
_ => "_".to_string(),
3958-
}).collect::<Vec<_>>().join(", ");
3946+
match hir.get_if_local(def_id) {
3947+
Some(Node::Item(hir::Item {
3948+
node: ItemKind::Fn(.., body_id),
3949+
..
3950+
})) |
3951+
Some(Node::ImplItem(hir::ImplItem {
3952+
node: hir::ImplItemKind::Method(_, body_id),
3953+
..
3954+
})) |
3955+
Some(Node::TraitItem(hir::TraitItem {
3956+
node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)),
3957+
..
3958+
})) => {
3959+
let body = hir.body(*body_id);
3960+
sugg_call = body.arguments.iter()
3961+
.map(|arg| match &arg.pat.node {
3962+
hir::PatKind::Binding(_, _, ident, None)
3963+
if ident.name != kw::SelfLower => ident.to_string(),
3964+
_ => "_".to_string(),
3965+
}).collect::<Vec<_>>().join(", ");
3966+
}
3967+
Some(Node::Expr(hir::Expr {
3968+
node: ExprKind::Closure(_, _, body_id, closure_span, _),
3969+
span: full_closure_span,
3970+
..
3971+
})) => {
3972+
if *full_closure_span == expr.span {
3973+
return false;
39593974
}
3960-
Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
3961-
sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
3962-
match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) {
3963-
Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
3964-
msg = "instantiate this tuple variant";
3965-
}
3966-
Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => {
3967-
msg = "instantiate this tuple struct";
3968-
}
3969-
_ => {}
3975+
err.span_label(*closure_span, "closure defined here");
3976+
msg = "call this closure";
3977+
let body = hir.body(*body_id);
3978+
sugg_call = body.arguments.iter()
3979+
.map(|arg| match &arg.pat.node {
3980+
hir::PatKind::Binding(_, _, ident, None)
3981+
if ident.name != kw::SelfLower => ident.to_string(),
3982+
_ => "_".to_string(),
3983+
}).collect::<Vec<_>>().join(", ");
3984+
}
3985+
Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
3986+
sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
3987+
match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) {
3988+
Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
3989+
msg = "instantiate this tuple variant";
39703990
}
3991+
Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => {
3992+
msg = "instantiate this tuple struct";
3993+
}
3994+
_ => {}
39713995
}
3972-
Some(Node::ForeignItem(hir::ForeignItem {
3973-
node: hir::ForeignItemKind::Fn(_, idents, _),
3974-
..
3975-
})) |
3976-
Some(Node::TraitItem(hir::TraitItem {
3977-
node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)),
3978-
..
3979-
})) => sugg_call = idents.iter()
3980-
.map(|ident| if ident.name != kw::SelfLower {
3981-
ident.to_string()
3982-
} else {
3983-
"_".to_string()
3984-
}).collect::<Vec<_>>()
3985-
.join(", "),
3986-
_ => {}
39873996
}
3988-
};
3997+
Some(Node::ForeignItem(hir::ForeignItem {
3998+
node: hir::ForeignItemKind::Fn(_, idents, _),
3999+
..
4000+
})) |
4001+
Some(Node::TraitItem(hir::TraitItem {
4002+
node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)),
4003+
..
4004+
})) => sugg_call = idents.iter()
4005+
.map(|ident| if ident.name != kw::SelfLower {
4006+
ident.to_string()
4007+
} else {
4008+
"_".to_string()
4009+
}).collect::<Vec<_>>()
4010+
.join(", "),
4011+
_ => {}
4012+
}
39894013
if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) {
39904014
err.span_suggestion(
39914015
expr.span,

src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs

+2
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ fn main() {
4242
let _: usize = X::bal; //~ ERROR mismatched types
4343
let _: usize = X.ban; //~ ERROR attempted to take value of method
4444
let _: usize = X.bal; //~ ERROR attempted to take value of method
45+
let closure = || 42;
46+
let _: usize = closure; //~ ERROR mismatched types
4547
}

src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr

+15-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,21 @@ error[E0615]: attempted to take value of method `bal` on type `X`
214214
LL | let _: usize = X.bal;
215215
| ^^^ help: use parentheses to call the method: `bal()`
216216

217-
error: aborting due to 16 previous errors
217+
error[E0308]: mismatched types
218+
--> $DIR/fn-or-tuple-struct-without-args.rs:46:20
219+
|
220+
LL | let closure = || 42;
221+
| -- closure defined here
222+
LL | let _: usize = closure;
223+
| ^^^^^^^
224+
| |
225+
| expected usize, found closure
226+
| help: use parentheses to call this closure: `closure()`
227+
|
228+
= note: expected type `usize`
229+
found type `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:24]`
230+
231+
error: aborting due to 17 previous errors
218232

219233
Some errors have detailed explanations: E0308, E0423, E0615.
220234
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)