Skip to content

Commit

Permalink
Simplify code around expected argument types.
Browse files Browse the repository at this point in the history
  • Loading branch information
leoyvens committed Apr 3, 2018
1 parent ba5a5cf commit 0a3eb5c
Showing 1 changed file with 50 additions and 49 deletions.
99 changes: 50 additions & 49 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -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,
Expand All @@ -2528,7 +2528,6 @@ 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();

let param_count_error = |expected_count: usize,
Expand Down Expand Up @@ -2615,6 +2614,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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>>());
Expand Down Expand Up @@ -2666,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);
}
}

Expand Down Expand Up @@ -2834,6 +2832,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expr: &'gcx hir::Expr,
expected: Ty<'tcx>) -> Ty<'tcx> {
let ty = self.check_expr_with_hint(expr, expected);
// checks don't need two phase
self.demand_coerce(expr, ty, expected, AllowTwoPhase::No)
}

Expand Down Expand Up @@ -2882,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);

// 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(()),
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(()),
}

// 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.
Expand Down

0 comments on commit 0a3eb5c

Please sign in to comment.