Rollup merge of #102863 - compiler-errors:call-suggestion-on-unimplemented, r=nagisa
Standardize "use parentheses to call" suggestions between typeck and trait selection 1. Suggest calling constructors, since they're basically `FnDef`s but they have a different def kind and hir representation, so we were leaving them out. 2. Standardize the call suggestions between trait fulfillment errors and type mismatch. In the type mismatch suggestion, we suggest `/* Ty */` as the placeholder for an arg, and not the parameter's name, which is less helpful. 3. Use `predicate_must_hold_modulo_regions` instead of matching on `EvaluationResult` -- this might cause some suggestions to be filtered out, but we really shouldn't be suggesting a call if it "may" hold, only when it "must" hold. 4. Borrow some logic from `extract_callable_info` to generalize this suggestion to fn pointers, type parameters, and opaque types. Fixes #102852
This commit is contained in:
commit
5c2c476ad1
@ -1,6 +1,6 @@
|
||||
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||
use super::method::MethodCallee;
|
||||
use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
use crate::type_error_struct;
|
||||
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
@ -27,6 +27,7 @@
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
||||
use std::iter;
|
||||
|
@ -2,7 +2,6 @@
|
||||
use crate::astconv::AstConv;
|
||||
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
||||
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
@ -19,6 +18,7 @@
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
@ -90,7 +90,7 @@ pub(crate) fn suggest_fn_call(
|
||||
if ty.is_suggestable(self.tcx, false) {
|
||||
format!("/* {ty} */")
|
||||
} else {
|
||||
"".to_string()
|
||||
"/* value */".to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
@ -102,10 +102,8 @@ pub(crate) fn suggest_fn_call(
|
||||
|
||||
let msg = match def_id_or_name {
|
||||
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
|
||||
DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
|
||||
DefKind::Ctor(CtorOf::Variant, _) => {
|
||||
"instantiate this tuple variant".to_string()
|
||||
}
|
||||
DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
|
||||
DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
|
||||
kind => format!("call this {}", kind.descr(def_id)),
|
||||
},
|
||||
DefIdOrName::Name(name) => format!("call this {name}"),
|
||||
@ -1209,8 +1207,3 @@ pub(crate) fn consider_removing_semicolon(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DefIdOrName {
|
||||
DefId(DefId),
|
||||
Name(&'static str),
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
pub mod suggestions;
|
||||
|
||||
use super::{
|
||||
EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
|
||||
MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
|
||||
OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
|
||||
PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
|
||||
FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
|
||||
Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
|
||||
OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
|
||||
SelectionContext, SelectionError, TraitNotObjectSafe,
|
||||
};
|
||||
|
||||
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
|
||||
@ -2796,3 +2796,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DefIdOrName {
|
||||
DefId(DefId),
|
||||
Name(&'static str),
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
|
||||
DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
|
||||
SelectionContext,
|
||||
};
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::normalize_to;
|
||||
|
||||
use hir::def::CtorOf;
|
||||
use hir::HirId;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@ -22,6 +23,7 @@
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_middle::hir::map;
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
||||
@ -29,7 +31,7 @@
|
||||
ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_middle::ty::{TypeAndMut, TypeckResults};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use std::fmt;
|
||||
@ -812,74 +814,136 @@ fn suggest_fn_call(
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
// Skipping binder here, remapping below
|
||||
let self_ty = trait_pred.self_ty().skip_binder();
|
||||
if let ty::PredicateKind::Trait(trait_pred) = obligation.predicate.kind().skip_binder()
|
||||
&& Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
|
||||
{
|
||||
// Don't suggest calling to turn an unsized type into a sized type
|
||||
return false;
|
||||
}
|
||||
|
||||
let (def_id, output_ty, callable) = match *self_ty.kind() {
|
||||
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
|
||||
ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
|
||||
_ => return false,
|
||||
};
|
||||
let msg = format!("use parentheses to call the {}", callable);
|
||||
|
||||
// "We should really create a single list of bound vars from the combined vars
|
||||
// from the predicate and function, but instead we just liberate the function bound vars"
|
||||
let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
|
||||
// This is duplicated from `extract_callable_info` in typeck, which
|
||||
// relies on autoderef, so we can't use it here.
|
||||
let found = trait_pred.self_ty().skip_binder().peel_refs();
|
||||
let Some((def_id_or_name, output, inputs)) = (match *found.kind()
|
||||
{
|
||||
ty::FnPtr(fn_sig) => {
|
||||
Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
|
||||
}
|
||||
ty::FnDef(def_id, _) => {
|
||||
let fn_sig = found.fn_sig(self.tcx);
|
||||
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
|
||||
}
|
||||
ty::Closure(def_id, substs) => {
|
||||
let fn_sig = substs.as_closure().sig();
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
fn_sig.output(),
|
||||
fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
|
||||
))
|
||||
}
|
||||
ty::Opaque(def_id, substs) => {
|
||||
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
|
||||
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
|
||||
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||
// args tuple will always be substs[1]
|
||||
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::DefId(def_id),
|
||||
pred.kind().rebind(proj.term.ty().unwrap()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::Dynamic(data, _, ty::Dyn) => {
|
||||
data.iter().find_map(|pred| {
|
||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||
// for existential projection, substs are shifted over by 1
|
||||
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::Name("trait object"),
|
||||
pred.rebind(proj.term.ty().unwrap()),
|
||||
pred.rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::Param(_) => {
|
||||
obligation.param_env.caller_bounds().iter().find_map(|pred| {
|
||||
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
|
||||
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||
&& proj.projection_ty.self_ty() == found
|
||||
// args tuple will always be substs[1]
|
||||
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
|
||||
{
|
||||
Some((
|
||||
DefIdOrName::Name("type parameter"),
|
||||
pred.kind().rebind(proj.term.ty().unwrap()),
|
||||
pred.kind().rebind(args.as_slice()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}) else { return false; };
|
||||
let output = self.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
output,
|
||||
);
|
||||
let inputs = inputs.skip_binder().iter().map(|ty| {
|
||||
self.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
inputs.rebind(*ty),
|
||||
)
|
||||
});
|
||||
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
|
||||
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
|
||||
|
||||
let new_obligation =
|
||||
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
|
||||
|
||||
match self.evaluate_obligation(&new_obligation) {
|
||||
Ok(
|
||||
EvaluationResult::EvaluatedToOk
|
||||
| EvaluationResult::EvaluatedToOkModuloRegions
|
||||
| EvaluationResult::EvaluatedToOkModuloOpaqueTypes
|
||||
| EvaluationResult::EvaluatedToAmbig,
|
||||
) => {}
|
||||
_ => return false,
|
||||
if !self.predicate_must_hold_modulo_regions(&new_obligation) {
|
||||
return false;
|
||||
}
|
||||
let hir = self.tcx.hir();
|
||||
|
||||
// Get the name of the callable and the arguments to be used in the suggestion.
|
||||
let (snippet, sugg) = match hir.get_if_local(def_id) {
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
|
||||
..
|
||||
})) => {
|
||||
err.span_label(*fn_decl_span, "consider calling this closure");
|
||||
let Some(name) = self.get_closure_name(def_id, err, &msg) else {
|
||||
return false;
|
||||
};
|
||||
let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
|
||||
let sugg = format!("({})", args);
|
||||
(format!("{}{}", name, sugg), sugg)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(.., body_id),
|
||||
..
|
||||
})) => {
|
||||
err.span_label(ident.span, "consider calling this function");
|
||||
let body = hir.body(*body_id);
|
||||
let args = body
|
||||
.params
|
||||
.iter()
|
||||
.map(|arg| match &arg.pat.kind {
|
||||
hir::PatKind::Binding(_, _, ident, None)
|
||||
// FIXME: provide a better suggestion when encountering `SelfLower`, it
|
||||
// should suggest a method call.
|
||||
if ident.name != kw::SelfLower => ident.to_string(),
|
||||
_ => "_".to_string(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let sugg = format!("({})", args);
|
||||
(format!("{}{}", ident, sugg), sugg)
|
||||
}
|
||||
_ => return false,
|
||||
let hir = self.tcx.hir();
|
||||
|
||||
let msg = match def_id_or_name {
|
||||
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
|
||||
DefKind::Ctor(CtorOf::Struct, _) => {
|
||||
"use parentheses to construct this tuple struct".to_string()
|
||||
}
|
||||
DefKind::Ctor(CtorOf::Variant, _) => {
|
||||
"use parentheses to construct this tuple variant".to_string()
|
||||
}
|
||||
kind => format!("use parentheses to call this {}", kind.descr(def_id)),
|
||||
},
|
||||
DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
|
||||
};
|
||||
|
||||
let args = inputs
|
||||
.map(|ty| {
|
||||
if ty.is_suggestable(self.tcx, false) {
|
||||
format!("/* {ty} */")
|
||||
} else {
|
||||
"/* value */".to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
|
||||
&& obligation.cause.span.can_be_used_for_suggestions()
|
||||
{
|
||||
@ -890,11 +954,36 @@ fn suggest_fn_call(
|
||||
err.span_suggestion_verbose(
|
||||
obligation.cause.span.shrink_to_hi(),
|
||||
&msg,
|
||||
sugg,
|
||||
format!("({args})"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.help(&format!("{}: `{}`", msg, snippet));
|
||||
} else if let DefIdOrName::DefId(def_id) = def_id_or_name {
|
||||
let name = match hir.get_if_local(def_id) {
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
|
||||
..
|
||||
})) => {
|
||||
err.span_label(*fn_decl_span, "consider calling this closure");
|
||||
let Some(name) = self.get_closure_name(def_id, err, &msg) else {
|
||||
return false;
|
||||
};
|
||||
name.to_string()
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
|
||||
err.span_label(ident.span, "consider calling this function");
|
||||
ident.to_string()
|
||||
}
|
||||
Some(hir::Node::Ctor(..)) => {
|
||||
let name = self.tcx.def_path_str(def_id);
|
||||
err.span_label(
|
||||
self.tcx.def_span(def_id),
|
||||
format!("consider calling the constructor for `{}`", name),
|
||||
);
|
||||
name
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
err.help(&format!("{msg}: `{name}({args})`"));
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ LL | assert_eq!(foo, y);
|
||||
| ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
= help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}`
|
||||
= help: use parentheses to call the function: `foo(s)`
|
||||
= help: use parentheses to call this function: `foo(/* &i32 */)`
|
||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -11,6 +11,10 @@ note: required by a bound in `take_const_owned`
|
||||
|
|
||||
LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
|
||||
| ^^^^ required by this bound in `take_const_owned`
|
||||
help: use parentheses to call this type parameter
|
||||
|
|
||||
LL | take_const_owned(f());
|
||||
| ++
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | fn give_owned<F>(f: F) where F: FnOnce() + Send + std::marker::Sync {
|
||||
|
@ -11,7 +11,7 @@ LL | fn test() -> Foo { Foo }
|
||||
|
|
||||
= note: expected struct `Foo`
|
||||
found fn item `fn(u32) -> Foo {Foo}`
|
||||
help: use parentheses to instantiate this tuple struct
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | fn test() -> Foo { Foo(/* u32 */) }
|
||||
| +++++++++++
|
||||
|
@ -29,7 +29,7 @@ LL | assert_eq!(a, 0);
|
||||
| ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
= help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}`
|
||||
= help: use parentheses to call the function: `a()`
|
||||
= help: use parentheses to call this function: `a()`
|
||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -327,7 +327,7 @@ LL | let _: Z = Z::Fn;
|
||||
|
|
||||
= note: expected enum `Z`
|
||||
found fn item `fn(u8) -> Z {Z::Fn}`
|
||||
help: use parentheses to instantiate this tuple variant
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | let _: Z = Z::Fn(/* u8 */);
|
||||
| ++++++++++
|
||||
@ -362,7 +362,7 @@ LL | let _: E = m::E::Fn;
|
||||
|
|
||||
= note: expected enum `E`
|
||||
found fn item `fn(u8) -> E {E::Fn}`
|
||||
help: use parentheses to instantiate this tuple variant
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | let _: E = m::E::Fn(/* u8 */);
|
||||
| ++++++++++
|
||||
@ -397,7 +397,7 @@ LL | let _: E = E::Fn;
|
||||
|
|
||||
= note: expected enum `E`
|
||||
found fn item `fn(u8) -> E {E::Fn}`
|
||||
help: use parentheses to instantiate this tuple variant
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | let _: E = E::Fn(/* u8 */);
|
||||
| ++++++++++
|
||||
|
@ -1,9 +1,6 @@
|
||||
error[E0277]: `fn() -> impl Future<Output = ()> {foo}` is not a future
|
||||
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
|
||||
|
|
||||
LL | async fn foo() {}
|
||||
| --- consider calling this function
|
||||
...
|
||||
LL | bar(foo);
|
||||
| --- ^^^ `fn() -> impl Future<Output = ()> {foo}` is not a future
|
||||
| |
|
||||
@ -16,7 +13,7 @@ note: required by a bound in `bar`
|
||||
|
|
||||
LL | fn bar(f: impl Future<Output=()>) {}
|
||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `bar`
|
||||
help: use parentheses to call the function
|
||||
help: use parentheses to call this function
|
||||
|
|
||||
LL | bar(foo());
|
||||
| ++
|
||||
@ -24,8 +21,6 @@ LL | bar(foo());
|
||||
error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
|
||||
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
|
||||
|
|
||||
LL | let async_closure = async || ();
|
||||
| -------- consider calling this closure
|
||||
LL | bar(async_closure);
|
||||
| --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
|
||||
| |
|
||||
@ -38,7 +33,7 @@ note: required by a bound in `bar`
|
||||
|
|
||||
LL | fn bar(f: impl Future<Output=()>) {}
|
||||
| ^^^^^^^^^^^^^^^^^ required by this bound in `bar`
|
||||
help: use parentheses to call the closure
|
||||
help: use parentheses to call this closure
|
||||
|
|
||||
LL | bar(async_closure());
|
||||
| ++
|
||||
|
17
src/test/ui/suggestions/call-on-unimplemented-ctor.rs
Normal file
17
src/test/ui/suggestions/call-on-unimplemented-ctor.rs
Normal file
@ -0,0 +1,17 @@
|
||||
fn main() {
|
||||
insert_resource(Marker);
|
||||
insert_resource(Time);
|
||||
//~^ ERROR the trait bound `fn(u32) -> Time {Time}: Resource` is not satisfied
|
||||
//~| HELP use parentheses to construct this tuple struct
|
||||
}
|
||||
|
||||
trait Resource {}
|
||||
|
||||
fn insert_resource<R: Resource>(resource: R) {}
|
||||
|
||||
struct Marker;
|
||||
impl Resource for Marker {}
|
||||
|
||||
struct Time(u32);
|
||||
|
||||
impl Resource for Time {}
|
21
src/test/ui/suggestions/call-on-unimplemented-ctor.stderr
Normal file
21
src/test/ui/suggestions/call-on-unimplemented-ctor.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0277]: the trait bound `fn(u32) -> Time {Time}: Resource` is not satisfied
|
||||
--> $DIR/call-on-unimplemented-ctor.rs:3:21
|
||||
|
|
||||
LL | insert_resource(Time);
|
||||
| --------------- ^^^^ the trait `Resource` is not implemented for fn item `fn(u32) -> Time {Time}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `insert_resource`
|
||||
--> $DIR/call-on-unimplemented-ctor.rs:10:23
|
||||
|
|
||||
LL | fn insert_resource<R: Resource>(resource: R) {}
|
||||
| ^^^^^^^^ required by this bound in `insert_resource`
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | insert_resource(Time(/* u32 */));
|
||||
| +++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
15
src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs
Normal file
15
src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs
Normal file
@ -0,0 +1,15 @@
|
||||
struct Foo;
|
||||
|
||||
trait Bar {}
|
||||
|
||||
impl Bar for Foo {}
|
||||
|
||||
fn needs_bar<T: Bar>(_: T) {}
|
||||
|
||||
fn blah(f: fn() -> Foo) {
|
||||
needs_bar(f);
|
||||
//~^ ERROR the trait bound `fn() -> Foo: Bar` is not satisfied
|
||||
//~| HELP use parentheses to call this function pointer
|
||||
}
|
||||
|
||||
fn main() {}
|
21
src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr
Normal file
21
src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0277]: the trait bound `fn() -> Foo: Bar` is not satisfied
|
||||
--> $DIR/call-on-unimplemented-fn-ptr.rs:10:15
|
||||
|
|
||||
LL | needs_bar(f);
|
||||
| --------- ^ the trait `Bar` is not implemented for `fn() -> Foo`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `needs_bar`
|
||||
--> $DIR/call-on-unimplemented-fn-ptr.rs:7:17
|
||||
|
|
||||
LL | fn needs_bar<T: Bar>(_: T) {}
|
||||
| ^^^ required by this bound in `needs_bar`
|
||||
help: use parentheses to call this function pointer
|
||||
|
|
||||
LL | needs_bar(f());
|
||||
| ++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -1,9 +1,6 @@
|
||||
error[E0277]: the trait bound `fn() -> impl T<O = ()> {foo}: T` is not satisfied
|
||||
--> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9
|
||||
|
|
||||
LL | fn foo() -> impl T<O=()> { S }
|
||||
| --- consider calling this function
|
||||
...
|
||||
LL | bar(foo);
|
||||
| --- ^^^ the trait `T` is not implemented for fn item `fn() -> impl T<O = ()> {foo}`
|
||||
| |
|
||||
@ -14,7 +11,7 @@ note: required by a bound in `bar`
|
||||
|
|
||||
LL | fn bar(f: impl T<O=()>) {}
|
||||
| ^^^^^^^ required by this bound in `bar`
|
||||
help: use parentheses to call the function
|
||||
help: use parentheses to call this function
|
||||
|
|
||||
LL | bar(foo());
|
||||
| ++
|
||||
@ -22,8 +19,6 @@ LL | bar(foo());
|
||||
error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]: T` is not satisfied
|
||||
--> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9
|
||||
|
|
||||
LL | let closure = || S;
|
||||
| -- consider calling this closure
|
||||
LL | bar(closure);
|
||||
| --- ^^^^^^^ the trait `T` is not implemented for closure `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]`
|
||||
| |
|
||||
@ -34,7 +29,7 @@ note: required by a bound in `bar`
|
||||
|
|
||||
LL | fn bar(f: impl T<O=()>) {}
|
||||
| ^^^^^^^ required by this bound in `bar`
|
||||
help: use parentheses to call the closure
|
||||
help: use parentheses to call this closure
|
||||
|
|
||||
LL | bar(closure());
|
||||
| ++
|
||||
|
@ -49,7 +49,7 @@ LL | let _: S = S;
|
||||
|
|
||||
= note: expected struct `S`
|
||||
found fn item `fn(usize, usize) -> S {S}`
|
||||
help: use parentheses to instantiate this tuple struct
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | let _: S = S(/* usize */, /* usize */);
|
||||
| ++++++++++++++++++++++++++
|
||||
@ -85,7 +85,7 @@ LL | let _: V = V;
|
||||
|
|
||||
= note: expected struct `V`
|
||||
found fn item `fn() -> V {V}`
|
||||
help: use parentheses to instantiate this tuple struct
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | let _: V = V();
|
||||
| ++
|
||||
@ -139,7 +139,7 @@ LL | let _: E = E::A;
|
||||
|
|
||||
= note: expected enum `E`
|
||||
found fn item `fn(usize) -> E {E::A}`
|
||||
help: use parentheses to instantiate this tuple variant
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | let _: E = E::A(/* usize */);
|
||||
| +++++++++++++
|
||||
|
@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the
|
||||
LL | thing.bar.foo();
|
||||
| ^^^ method not found in `fn() -> Foo {Foo}`
|
||||
|
|
||||
help: use parentheses to instantiate this tuple struct
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | (thing.bar)().foo();
|
||||
| + +++
|
||||
|
@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` i
|
||||
LL | thing.bar.foo();
|
||||
| ^^^ method not found in `fn() -> Foo {Foo::Tup}`
|
||||
|
|
||||
help: use parentheses to instantiate this tuple variant
|
||||
help: use parentheses to construct this tuple variant
|
||||
|
|
||||
LL | (thing.bar)().foo();
|
||||
| + +++
|
||||
|
@ -4,7 +4,7 @@ error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
|
||||
LL | thing.bar.0;
|
||||
| ^
|
||||
|
|
||||
help: use parentheses to instantiate this tuple struct
|
||||
help: use parentheses to construct this tuple struct
|
||||
|
|
||||
LL | (thing.bar)(/* char */, /* u16 */).0;
|
||||
| + ++++++++++++++++++++++++
|
||||
|
Loading…
Reference in New Issue
Block a user