mirror of https://github.com/rust-lang/rust.git
Inline expected_inputs_for_expected_output into check_argument_types/check_expr_struct_fields
This commit is contained in:
parent
c3f9c4f4d4
commit
95b9ecd6d6
|
@ -503,18 +503,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.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
|
||||||
let fn_sig = self.normalize(call_expr.span, 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(
|
self.check_argument_types(
|
||||||
call_expr.span,
|
call_expr.span,
|
||||||
call_expr,
|
call_expr,
|
||||||
fn_sig.inputs(),
|
fn_sig.inputs(),
|
||||||
expected_arg_tys,
|
fn_sig.output(),
|
||||||
|
expected,
|
||||||
arg_exprs,
|
arg_exprs,
|
||||||
fn_sig.c_variadic,
|
fn_sig.c_variadic,
|
||||||
TupleArgumentsFlag::DontTupleArguments,
|
TupleArgumentsFlag::DontTupleArguments,
|
||||||
|
@ -866,19 +860,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
||||||
// do know the types expected for each argument and the return
|
// do know the types expected for each argument and the return
|
||||||
// type.
|
// 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(
|
self.check_argument_types(
|
||||||
call_expr.span,
|
call_expr.span,
|
||||||
call_expr,
|
call_expr,
|
||||||
fn_sig.inputs(),
|
fn_sig.inputs(),
|
||||||
expected_arg_tys,
|
fn_sig.output(),
|
||||||
|
expected,
|
||||||
arg_exprs,
|
arg_exprs,
|
||||||
fn_sig.c_variadic,
|
fn_sig.c_variadic,
|
||||||
TupleArgumentsFlag::TupleArguments,
|
TupleArgumentsFlag::TupleArguments,
|
||||||
|
|
|
@ -1673,15 +1673,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let expected_inputs =
|
let adt_ty = self.resolve_vars_with_obligations(adt_ty);
|
||||||
self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]);
|
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
|
||||||
let adt_ty_hint = if let Some(expected_inputs) = expected_inputs {
|
self.fudge_inference_if_ok(|| {
|
||||||
expected_inputs.get(0).cloned().unwrap_or(adt_ty)
|
let ocx = ObligationCtxt::new(self);
|
||||||
} else {
|
ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
|
||||||
adt_ty
|
if !ocx.select_where_possible().is_empty() {
|
||||||
};
|
return Err(TypeError::Mismatch);
|
||||||
// re-link the regions that EIfEO can erase.
|
}
|
||||||
self.demand_eqtype(span, adt_ty_hint, adt_ty);
|
Ok(self.resolve_vars_if_possible(adt_ty))
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
if let Some(adt_ty_hint) = adt_ty_hint {
|
||||||
|
// re-link the variables that the fudging above can create.
|
||||||
|
self.demand_eqtype(span, adt_ty_hint, adt_ty);
|
||||||
|
}
|
||||||
|
|
||||||
let ty::Adt(adt, args) = adt_ty.kind() else {
|
let ty::Adt(adt, args) = adt_ty.kind() else {
|
||||||
span_bug!(span, "non-ADT passed to check_expr_struct_fields");
|
span_bug!(span, "non-ADT passed to check_expr_struct_fields");
|
||||||
|
|
|
@ -20,7 +20,6 @@ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryRespons
|
||||||
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
||||||
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
|
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc_middle::ty::error::TypeError;
|
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
@ -36,7 +35,7 @@ use rustc_span::Span;
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
|
self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt,
|
||||||
};
|
};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
@ -689,42 +688,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
vec![ty_error; len]
|
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(
|
pub(crate) fn resolve_lang_item_path(
|
||||||
&self,
|
&self,
|
||||||
lang_item: hir::LangItem,
|
lang_item: hir::LangItem,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
|
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
|
||||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
|
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
|
@ -25,7 +26,7 @@ use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{sym, Span, DUMMY_SP};
|
use rustc_span::{sym, Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
|
use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
|
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use {rustc_ast as ast, rustc_hir as hir};
|
use {rustc_ast as ast, rustc_hir as hir};
|
||||||
|
|
||||||
|
@ -124,6 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
if let Err(guar) = has_error {
|
if let Err(guar) = has_error {
|
||||||
let err_inputs = self.err_args(args_no_rcvr.len(), guar);
|
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 {
|
let err_inputs = match tuple_arguments {
|
||||||
DontTupleArguments => err_inputs,
|
DontTupleArguments => err_inputs,
|
||||||
|
@ -134,28 +136,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
sp,
|
sp,
|
||||||
expr,
|
expr,
|
||||||
&err_inputs,
|
&err_inputs,
|
||||||
None,
|
err_output,
|
||||||
|
NoExpectation,
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
false,
|
false,
|
||||||
tuple_arguments,
|
tuple_arguments,
|
||||||
method.ok().map(|method| method.def_id),
|
method.ok().map(|method| method.def_id),
|
||||||
);
|
);
|
||||||
return Ty::new_error(self.tcx, guar);
|
return err_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
let method = method.unwrap();
|
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(
|
self.check_argument_types(
|
||||||
sp,
|
sp,
|
||||||
expr,
|
expr,
|
||||||
&method.sig.inputs()[1..],
|
&method.sig.inputs()[1..],
|
||||||
expected_input_tys,
|
method.sig.output(),
|
||||||
|
expected,
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
method.sig.c_variadic,
|
method.sig.c_variadic,
|
||||||
tuple_arguments,
|
tuple_arguments,
|
||||||
|
@ -175,8 +172,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
call_expr: &'tcx hir::Expr<'tcx>,
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
// Types (as defined in the *signature* of the target function)
|
// Types (as defined in the *signature* of the target function)
|
||||||
formal_input_tys: &[Ty<'tcx>],
|
formal_input_tys: &[Ty<'tcx>],
|
||||||
// More specific expected types, after unifying with caller output types
|
formal_output: Ty<'tcx>,
|
||||||
expected_input_tys: Option<Vec<Ty<'tcx>>>,
|
// Expected output from the parent expression or statement
|
||||||
|
expectation: Expectation<'tcx>,
|
||||||
// The expressions for each provided argument
|
// The expressions for each provided argument
|
||||||
provided_args: &'tcx [hir::Expr<'tcx>],
|
provided_args: &'tcx [hir::Expr<'tcx>],
|
||||||
// Whether the function is variadic, for example when imported from C
|
// Whether the function is variadic, for example when imported from C
|
||||||
|
@ -210,6 +208,40 @@ 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 formal_output = self.resolve_vars_with_obligations(formal_output);
|
||||||
|
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;
|
let mut err_code = E0061;
|
||||||
|
|
||||||
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
|
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
|
|
||||||
|
// Regression test for for #129286.
|
||||||
|
// Makes sure that we don't have unconstrained type variables that come from
|
||||||
|
// bivariant type parameters due to the way that we construct expectation types
|
||||||
|
// when checking call expressions in HIR typeck.
|
||||||
|
|
||||||
trait Trait {
|
trait Trait {
|
||||||
type Item;
|
type Item;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue