From 0a3eb5c508bce50873401ca942e3cb1d4a0ce21f Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 27 Mar 2018 11:27:02 -0300 Subject: [PATCH] Simplify code around expected argument types. --- src/librustc_typeck/check/mod.rs | 99 ++++++++++++++++---------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bfe92fc5be802..5ca8d1b06e127 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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,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, @@ -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::>()); @@ -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); } } @@ -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) } @@ -2882,45 +2881,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { formal_args: &[Ty<'tcx>]) -> Vec> { 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.