summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs91
1 files changed, 60 insertions, 31 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a46bdeb41..ea1b52daa 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -24,14 +24,14 @@ use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::InferOk;
use rustc_infer::infer::TypeTrace;
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
+use rustc_middle::ty::{self, IsSuggestable, Ty};
use rustc_session::Session;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, sym, Span};
+use rustc_span::{self, sym, BytePos, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
@@ -301,9 +301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 3. Check if the formal type is a supertype of the checked one
// and register any such obligations for future type checks
- let supertype_error = self
- .at(&self.misc(provided_arg.span), self.param_env)
- .sup(formal_input_ty, coerced_ty);
+ let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
+ DefineOpaqueTypes::No,
+ formal_input_ty,
+ coerced_ty,
+ );
let subtyping_error = match supertype_error {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
@@ -470,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err_code: &str,
fn_def_id: Option<DefId>,
call_span: Span,
- call_expr: &hir::Expr<'tcx>,
+ call_expr: &'tcx hir::Expr<'tcx>,
) {
// Next, let's construct the error
let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
@@ -585,7 +587,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Using probe here, since we don't want this subtyping to affect inference.
let subtyping_error = self.probe(|_| {
- self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err()
+ self.at(&self.misc(arg_span), self.param_env)
+ .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty)
+ .err()
});
// Same as above: if either the coerce type or the checked type is an error type,
@@ -764,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
- if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
+ if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true;
}
@@ -803,24 +807,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
full_call_span,
format!("arguments to this {} are incorrect", call_name),
);
- if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) =
- (callee_ty, &call_expr.kind)
+
+ if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
+ && provided_idx.as_usize() == expected_idx.as_usize()
{
- // Type that would have accepted this argument if it hadn't been inferred earlier.
- // FIXME: We leave an inference variable for now, but it'd be nice to get a more
- // specific type to increase the accuracy of the diagnostic.
- let expected = self.infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: full_call_span,
- });
- self.point_at_expr_source_of_inferred_type(
+ self.note_source_of_type_mismatch_constraint(
&mut err,
rcvr,
- expected,
- callee_ty,
- provided_arg_span,
+ crate::demand::TypeMismatchSource::Arg {
+ call_expr,
+ incompatible_arg: provided_idx.as_usize(),
+ },
);
}
+
// Call out where the function is defined
self.label_fn_like(
&mut err,
@@ -890,8 +890,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut errors = errors.into_iter().peekable();
+ let mut only_extras_so_far = errors
+ .peek()
+ .map_or(false, |first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
let mut suggestions = vec![];
while let Some(error) = errors.next() {
+ only_extras_so_far &= matches!(error, Error::Extra(_));
+
match error {
Error::Invalid(provided_idx, expected_idx, compatibility) => {
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
@@ -937,10 +942,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if arg_idx.index() > 0
&& let Some((_, prev)) = provided_arg_tys
.get(ProvidedIdx::from_usize(arg_idx.index() - 1)
- ) {
- // Include previous comma
- span = prev.shrink_to_hi().to(span);
- }
+ ) {
+ // Include previous comma
+ span = prev.shrink_to_hi().to(span);
+ }
+
+ // Is last argument for deletion in a row starting from the 0-th argument?
+ // Then delete the next comma, so we are not left with `f(, ...)`
+ //
+ // fn f() {}
+ // - f(0, 1,)
+ // + f()
+ if only_extras_so_far
+ && errors
+ .peek()
+ .map_or(true, |next_error| !matches!(next_error, Error::Extra(_)))
+ {
+ let next = provided_arg_tys
+ .get(arg_idx + 1)
+ .map(|&(_, sp)| sp)
+ .unwrap_or_else(|| {
+ // Subtract one to move before `)`
+ call_expr.span.with_lo(call_expr.span.hi() - BytePos(1))
+ });
+
+ // Include next comma
+ span = span.until(next);
+ }
+
suggestions.push((span, String::new()));
suggestion_text = match suggestion_text {
@@ -1158,11 +1187,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// index position where it *should have been*, which is *after* the previous one.
if let Some(provided_idx) = provided_idx {
prev = provided_idx.index() as i64;
+ continue;
}
let idx = ProvidedIdx::from_usize((prev + 1) as usize);
- if let None = provided_idx
- && let Some((_, arg_span)) = provided_arg_tys.get(idx)
- {
+ if let Some((_, arg_span)) = provided_arg_tys.get(idx) {
+ prev += 1;
// There is a type that was *not* found anywhere, so it isn't a move, but a
// replacement and we look at what type it should have been. This will allow us
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def
@@ -1380,7 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_eqtype(init.span, local_ty, init_ty);
init_ty
} else {
- self.check_expr_coercable_to_type(init, local_ty, None)
+ self.check_expr_coercible_to_type(init, local_ty, None)
}
}
@@ -1665,7 +1694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
- self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+ self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
}
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail