Auto merge of #49419 - leodasvacas:small-typeck-refactorings, r=nikomatsakis
Small typeck refactorings Some code improvements I noticed while reading the code.
This commit is contained in:
commit
e0a9bd0f3c
|
@ -2507,7 +2507,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
sp: Span,
|
||||
expr_sp: Span,
|
||||
fn_inputs: &[Ty<'tcx>],
|
||||
expected_arg_tys: &[Ty<'tcx>],
|
||||
mut expected_arg_tys: &[Ty<'tcx>],
|
||||
args: &'gcx [hir::Expr],
|
||||
variadic: bool,
|
||||
tuple_arguments: TupleArgumentsFlag,
|
||||
|
@ -2528,19 +2528,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
|
||||
}
|
||||
|
||||
let mut expected_arg_tys = expected_arg_tys;
|
||||
let expected_arg_count = fn_inputs.len();
|
||||
|
||||
fn parameter_count_error<'tcx>(sess: &Session,
|
||||
sp: Span,
|
||||
expr_sp: Span,
|
||||
expected_count: usize,
|
||||
arg_count: usize,
|
||||
error_code: &str,
|
||||
variadic: bool,
|
||||
def_span: Option<Span>,
|
||||
sugg_unit: bool) {
|
||||
let mut err = sess.struct_span_err_with_code(sp,
|
||||
let param_count_error = |expected_count: usize,
|
||||
arg_count: usize,
|
||||
error_code: &str,
|
||||
variadic: bool,
|
||||
sugg_unit: bool| {
|
||||
let mut err = tcx.sess.struct_span_err_with_code(sp,
|
||||
&format!("this function takes {}{} parameter{} but {} parameter{} supplied",
|
||||
if variadic {"at least "} else {""},
|
||||
expected_count,
|
||||
|
@ -2549,11 +2544,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if arg_count == 1 {" was"} else {"s were"}),
|
||||
DiagnosticId::Error(error_code.to_owned()));
|
||||
|
||||
if let Some(def_s) = def_span.map(|sp| sess.codemap().def_span(sp)) {
|
||||
if let Some(def_s) = def_span.map(|sp| tcx.sess.codemap().def_span(sp)) {
|
||||
err.span_label(def_s, "defined here");
|
||||
}
|
||||
if sugg_unit {
|
||||
let sugg_span = sess.codemap().end_point(expr_sp);
|
||||
let sugg_span = tcx.sess.codemap().end_point(expr_sp);
|
||||
// remove closing `)` from the span
|
||||
let sugg_span = sugg_span.shrink_to_lo();
|
||||
err.span_suggestion(
|
||||
|
@ -2567,14 +2562,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if expected_count == 1 {""} else {"s"}));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
};
|
||||
|
||||
let formal_tys = if tuple_arguments == TupleArguments {
|
||||
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
|
||||
match tuple_type.sty {
|
||||
ty::TyTuple(arg_types) if arg_types.len() != args.len() => {
|
||||
parameter_count_error(tcx.sess, sp, expr_sp, arg_types.len(), args.len(),
|
||||
"E0057", false, def_span, false);
|
||||
param_count_error(arg_types.len(), args.len(), "E0057", false, false);
|
||||
expected_arg_tys = &[];
|
||||
self.err_args(args.len())
|
||||
}
|
||||
|
@ -2602,8 +2596,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
if supplied_arg_count >= expected_arg_count {
|
||||
fn_inputs.to_vec()
|
||||
} else {
|
||||
parameter_count_error(tcx.sess, sp, expr_sp, expected_arg_count,
|
||||
supplied_arg_count, "E0060", true, def_span, false);
|
||||
param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
|
||||
expected_arg_tys = &[];
|
||||
self.err_args(supplied_arg_count)
|
||||
}
|
||||
|
@ -2616,11 +2609,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
} else {
|
||||
false
|
||||
};
|
||||
parameter_count_error(tcx.sess, sp, expr_sp, expected_arg_count,
|
||||
supplied_arg_count, "E0061", false, def_span, sugg_unit);
|
||||
param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
|
||||
|
||||
expected_arg_tys = &[];
|
||||
self.err_args(supplied_arg_count)
|
||||
};
|
||||
// If there is no expectation, expect formal_tys.
|
||||
let expected_arg_tys = if !expected_arg_tys.is_empty() {
|
||||
expected_arg_tys
|
||||
} else {
|
||||
&formal_tys
|
||||
};
|
||||
|
||||
debug!("check_argument_types: formal_tys={:?}",
|
||||
formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>());
|
||||
|
@ -2672,28 +2671,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
// The special-cased logic below has three functions:
|
||||
// 1. Provide as good of an expected type as possible.
|
||||
let expected = expected_arg_tys.get(i).map(|&ty| {
|
||||
Expectation::rvalue_hint(self, ty)
|
||||
});
|
||||
let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
|
||||
|
||||
let checked_ty = self.check_expr_with_expectation(
|
||||
&arg,
|
||||
expected.unwrap_or(ExpectHasType(formal_ty)));
|
||||
let checked_ty = self.check_expr_with_expectation(&arg, expected);
|
||||
|
||||
// 2. Coerce to the most detailed type that could be coerced
|
||||
// to, which is `expected_ty` if `rvalue_hint` returns an
|
||||
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
|
||||
let coerce_ty = expected.and_then(|e| e.only_has_type(self));
|
||||
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
|
||||
// We're processing function arguments so we definitely want to use
|
||||
// two-phase borrows.
|
||||
self.demand_coerce(&arg,
|
||||
checked_ty,
|
||||
coerce_ty.unwrap_or(formal_ty),
|
||||
AllowTwoPhase::Yes);
|
||||
self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes);
|
||||
|
||||
// 3. Relate the expected type and the formal one,
|
||||
// if the expected type was used for the coercion.
|
||||
coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
|
||||
self.demand_suptype(arg.span, formal_ty, coerce_ty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2839,18 +2831,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
fn check_expr_coercable_to_type(&self,
|
||||
expr: &'gcx hir::Expr,
|
||||
expected: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.check_expr_coercable_to_type_with_needs(expr, expected, Needs::None)
|
||||
}
|
||||
|
||||
fn check_expr_coercable_to_type_with_needs(&self,
|
||||
expr: &'gcx hir::Expr,
|
||||
expected: Ty<'tcx>,
|
||||
needs: Needs)
|
||||
-> Ty<'tcx> {
|
||||
let ty = self.check_expr_with_expectation_and_needs(
|
||||
expr,
|
||||
ExpectHasType(expected),
|
||||
needs);
|
||||
let ty = self.check_expr_with_hint(expr, expected);
|
||||
// checks don't need two phase
|
||||
self.demand_coerce(expr, ty, expected, AllowTwoPhase::No)
|
||||
}
|
||||
|
@ -2900,45 +2881,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
formal_args: &[Ty<'tcx>])
|
||||
-> Vec<Ty<'tcx>> {
|
||||
let formal_ret = self.resolve_type_vars_with_obligations(formal_ret);
|
||||
let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
|
||||
self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || {
|
||||
// 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);
|
||||
let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
|
||||
let ret_ty = match expected_ret.only_has_type(self) {
|
||||
Some(ret) => ret,
|
||||
None => return Vec::new()
|
||||
};
|
||||
let expect_args = self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || {
|
||||
// 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);
|
||||
let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
|
||||
|
||||
// FIXME(#27336) can't use ? here, Try::from_error doesn't default
|
||||
// to identity so the resulting type is not constrained.
|
||||
match ures {
|
||||
Ok(ok) => {
|
||||
// Process any obligations locally as much as
|
||||
// we can. We don't care if some things turn
|
||||
// out unconstrained or ambiguous, as we're
|
||||
// just trying to get hints here.
|
||||
self.save_and_restore_in_snapshot_flag(|_| {
|
||||
let mut fulfill = TraitEngine::new(self.tcx);
|
||||
for obligation in ok.obligations {
|
||||
fulfill.register_predicate_obligation(self, obligation);
|
||||
}
|
||||
fulfill.select_where_possible(self)
|
||||
}).map_err(|_| ())?;
|
||||
}
|
||||
Err(_) => return Err(()),
|
||||
// FIXME(#27336) can't use ? here, Try::from_error doesn't default
|
||||
// to identity so the resulting type is not constrained.
|
||||
match ures {
|
||||
Ok(ok) => {
|
||||
// Process any obligations locally as much as
|
||||
// we can. We don't care if some things turn
|
||||
// out unconstrained or ambiguous, as we're
|
||||
// just trying to get hints here.
|
||||
self.save_and_restore_in_snapshot_flag(|_| {
|
||||
let mut fulfill = TraitEngine::new(self.tcx);
|
||||
for obligation in ok.obligations {
|
||||
fulfill.register_predicate_obligation(self, obligation);
|
||||
}
|
||||
fulfill.select_where_possible(self)
|
||||
}).map_err(|_| ())?;
|
||||
}
|
||||
Err(_) => return Err(()),
|
||||
}
|
||||
|
||||
// Record all the argument types, with the substitutions
|
||||
// produced from the above subtyping unification.
|
||||
Ok(formal_args.iter().map(|ty| {
|
||||
self.resolve_type_vars_if_possible(ty)
|
||||
}).collect())
|
||||
}).ok()
|
||||
}).unwrap_or(vec![]);
|
||||
// Record all the argument types, with the substitutions
|
||||
// produced from the above subtyping unification.
|
||||
Ok(formal_args.iter().map(|ty| {
|
||||
self.resolve_type_vars_if_possible(ty)
|
||||
}).collect())
|
||||
}).unwrap_or(Vec::new());
|
||||
debug!("expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
|
||||
formal_args, formal_ret,
|
||||
expected_args, expected_ret);
|
||||
expected_args
|
||||
expect_args, expected_ret);
|
||||
expect_args
|
||||
}
|
||||
|
||||
// Checks a method call.
|
||||
|
|
|
@ -174,9 +174,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// trait matching creating lifetime constraints that are too strict.
|
||||
// E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
|
||||
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
|
||||
let lhs_ty = self.check_expr_coercable_to_type_with_needs(lhs_expr,
|
||||
self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)),
|
||||
lhs_needs);
|
||||
let lhs_ty = self.check_expr_with_needs(lhs_expr, lhs_needs);
|
||||
let fresh_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span));
|
||||
let lhs_ty = self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No);
|
||||
let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
|
||||
|
||||
// NB: As we have not yet type-checked the RHS, we don't have the
|
||||
|
|
Loading…
Reference in New Issue