Skip to content

Commit

Permalink
Inline expected_inputs_for_expected_output into check_argument_types
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Aug 25, 2024
1 parent 83695e0 commit 7246d31
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 66 deletions.
21 changes: 4 additions & 17 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,18 +502,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
let fn_sig = self.normalize(call_expr.span, fn_sig);

// Call the generic checker.
let expected_arg_tys = self.expected_inputs_for_expected_output(
call_expr.span,
expected,
fn_sig.output(),
fn_sig.inputs(),
);
self.check_argument_types(
call_expr.span,
call_expr,
fn_sig.inputs(),
expected_arg_tys,
fn_sig.output(),
expected,
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::DontTupleArguments,
Expand Down Expand Up @@ -865,19 +859,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
// do know the types expected for each argument and the return
// type.

let expected_arg_tys = self.expected_inputs_for_expected_output(
call_expr.span,
expected,
fn_sig.output(),
fn_sig.inputs(),
);

self.check_argument_types(
call_expr.span,
call_expr,
fn_sig.inputs(),
expected_arg_tys,
fn_sig.output(),
expected,
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::TupleArguments,
Expand Down
36 changes: 0 additions & 36 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,42 +688,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![ty_error; len]
}

/// Unifies the output type with the expected type early, for more coercions
/// and forward type information on the input expressions.
#[instrument(skip(self, call_span), level = "debug")]
pub(crate) fn expected_inputs_for_expected_output(
&self,
call_span: Span,
expected_ret: Expectation<'tcx>,
formal_ret: Ty<'tcx>,
formal_args: &[Ty<'tcx>],
) -> Option<Vec<Ty<'tcx>>> {
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
let ret_ty = expected_ret.only_has_type(self)?;

let expect_args = self
.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);

// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}

// Record all the argument types, with the args
// produced from the above subtyping unification.
Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()))
})
.unwrap_or_default();
debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret);
expect_args
}

pub(crate) fn resolve_lang_item_path(
&self,
lang_item: hir::LangItem,
Expand Down
57 changes: 44 additions & 13 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_index::IndexVec;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
Expand All @@ -25,7 +26,7 @@ use rustc_span::symbol::{kw, Ident};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
use {rustc_ast as ast, rustc_hir as hir};

use crate::coercion::CoerceMany;
Expand Down Expand Up @@ -123,6 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Err(guar) = has_error {
let err_inputs = self.err_args(args_no_rcvr.len(), guar);
let err_output = Ty::new_error(self.tcx, guar);

let err_inputs = match tuple_arguments {
DontTupleArguments => err_inputs,
Expand All @@ -133,28 +135,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sp,
expr,
&err_inputs,
None,
err_output,
NoExpectation,
args_no_rcvr,
false,
tuple_arguments,
method.ok().map(|method| method.def_id),
);
return Ty::new_error(self.tcx, guar);
return err_output;
}

let method = method.unwrap();
// HACK(eddyb) ignore self in the definition (see above).
let expected_input_tys = self.expected_inputs_for_expected_output(
sp,
expected,
method.sig.output(),
&method.sig.inputs()[1..],
);
self.check_argument_types(
sp,
expr,
&method.sig.inputs()[1..],
expected_input_tys,
method.sig.output(),
expected,
args_no_rcvr,
method.sig.c_variadic,
tuple_arguments,
Expand All @@ -174,8 +171,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr: &'tcx hir::Expr<'tcx>,
// Types (as defined in the *signature* of the target function)
formal_input_tys: &[Ty<'tcx>],
// More specific expected types, after unifying with caller output types
expected_input_tys: Option<Vec<Ty<'tcx>>>,
formal_output: Ty<'tcx>,
// Expected output from the parent expression or statement
expectation: Expectation<'tcx>,
// The expressions for each provided argument
provided_args: &'tcx [hir::Expr<'tcx>],
// Whether the function is variadic, for example when imported from C
Expand Down Expand Up @@ -209,6 +207,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}

// First, let's unify the formal method signature with the expectation eagerly.
// We use this to guide coercion inference; it's output is "fudged" which means
// any remaining type variables are assigned to new, unrelated variables. This
// is because the inference guidance here is only speculative.
let expected_input_tys: Option<Vec<_>> = expectation
.only_has_type(self)
.and_then(|expected_output| {
self.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);

// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
ocx.sup(&origin, self.param_env, expected_output, formal_output)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}

// Record all the argument types, with the args
// produced from the above subtyping unification.
Ok(Some(
formal_input_tys
.iter()
.map(|&ty| self.resolve_vars_if_possible(ty))
.collect(),
))
})
.ok()
})
.unwrap_or_default();

let mut err_code = E0061;

// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
Expand Down

0 comments on commit 7246d31

Please sign in to comment.