use std::iter;
use std::slice;
+struct FnArgsAsTuple<'hir> {
+ first: &'hir hir::Expr<'hir>,
+ last: &'hir hir::Expr<'hir>,
+}
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_casts(&self) {
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
let expected_arg_count = formal_input_tys.len();
- // expected_count, arg_count, error_code, sugg_unit
- let mut error: Option<(usize, usize, &str, bool)> = None;
+ // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args
+ let mut error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> = None;
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
ty::Tuple(arg_types) => {
// Argument length differs
if arg_types.len() != provided_args.len() {
- error = Some((arg_types.len(), provided_args.len(), "E0057", false));
+ error = Some((arg_types.len(), provided_args.len(), "E0057", false, None));
}
let expected_input_tys = match expected_input_tys.get(0) {
Some(&ty) => match ty.kind() {
if supplied_arg_count >= expected_arg_count {
(formal_input_tys.to_vec(), expected_input_tys)
} else {
- error = Some((expected_arg_count, supplied_arg_count, "E0060", false));
+ error = Some((expected_arg_count, supplied_arg_count, "E0060", false, None));
(self.err_args(supplied_arg_count), vec![])
}
} else {
} else {
false
};
- error = Some((expected_arg_count, supplied_arg_count, "E0061", sugg_unit));
+
+ // are we passing elements of a tuple without the tuple parentheses?
+ let expected_input_tys = if expected_input_tys.is_empty() {
+ // In most cases we can use expected_input_tys, but some callers won't have the type
+ // information, in which case we fall back to the types from the input expressions.
+ formal_input_tys
+ } else {
+ &*expected_input_tys
+ };
+
+ let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
+
+ error = Some((
+ expected_arg_count,
+ supplied_arg_count,
+ "E0061",
+ sugg_unit,
+ sugg_tuple_wrap_args,
+ ));
(self.err_args(supplied_arg_count), vec![])
};
}
// If there was an error in parameter count, emit that here
- if let Some((expected_count, arg_count, err_code, sugg_unit)) = error {
+ if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error
+ {
let (span, start_span, args, ctor_of) = match &call_expr.kind {
hir::ExprKind::Call(
hir::Expr {
String::from("()"),
Applicability::MachineApplicable,
);
+ } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args {
+ err.multipart_suggestion(
+ "use parentheses to construct a tuple",
+ vec![
+ (first.span.shrink_to_lo(), '('.to_string()),
+ (last.span.shrink_to_hi(), ')'.to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
} else {
err.span_label(
span,
}
}
+ fn suggested_tuple_wrap(
+ &self,
+ expected_input_tys: &[Ty<'tcx>],
+ provided_args: &'tcx [hir::Expr<'tcx>],
+ ) -> Option<FnArgsAsTuple<'_>> {
+ let [expected_arg_type] = &expected_input_tys[..] else { return None };
+
+ let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind()
+ else { return None };
+
+ let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect();
+ let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
+
+ let all_match = iter::zip(expected_types, supplied_types)
+ .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok());
+
+ if all_match {
+ match provided_args {
+ [] => None,
+ [_] => unreachable!(
+ "shouldn't reach here - need count mismatch between 1-tuple and 1-argument"
+ ),
+ [first, .., last] => Some(FnArgsAsTuple { first, last }),
+ }
+ } else {
+ None
+ }
+ }
+
// AST fragment checking
pub(in super::super) fn check_lit(
&self,
_ => bug!("unexpected type: {:?}", ty),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
- | Res::SelfTy(..) => match ty.kind() {
+ | Res::SelfTy { .. } => match ty.kind() {
ty::Adt(adt, substs) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did, substs))
}
ObligationCauseCode::BuiltinDerivedObligation(code) |
ObligationCauseCode::ImplDerivedObligation(code) |
ObligationCauseCode::DerivedObligation(code) => {
- code.parent_trait_ref.self_ty().skip_binder().into()
+ code.parent_trait_pred.self_ty().skip_binder().into()
}
_ if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder() => {