Skip to content

Commit 555119f

Browse files
committed
Introduce demand_compatible
1 parent 45341a6 commit 555119f

File tree

1 file changed

+50
-41
lines changed
  • compiler/rustc_typeck/src/check/fn_ctxt

1 file changed

+50
-41
lines changed

compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

+50-41
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
321321

322322
let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
323323

324+
// We introduce a helper function to demand that a given argument satisfy a given input
325+
// This is more complicated than just checking type equality, as arguments could be coerced
326+
// This version writes those types back so further type checking uses the narrowed types
327+
let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
328+
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
329+
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
330+
let provided_arg = &provided_args[idx];
331+
332+
debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
333+
334+
// The special-cased logic below has three functions:
335+
// 1. Provide as good of an expected type as possible.
336+
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
337+
338+
let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
339+
340+
// 2. Coerce to the most detailed type that could be coerced
341+
// to, which is `expected_ty` if `rvalue_hint` returns an
342+
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
343+
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
344+
345+
// Keep track of these for below
346+
final_arg_types.push((idx, checked_ty, coerced_ty));
347+
348+
// Cause selection errors caused by resolving a single argument to point at the
349+
// argument and not the call. This is otherwise redundant with the `demand_coerce`
350+
// call immediately after, but it lets us customize the span pointed to in the
351+
// fulfillment error to be more accurate.
352+
let _ =
353+
self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
354+
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
355+
self.point_at_arg_instead_of_call_if_possible(
356+
errors,
357+
&final_arg_types,
358+
call_expr,
359+
call_span,
360+
provided_args,
361+
);
362+
});
363+
364+
// We're processing function arguments so we definitely want to use
365+
// two-phase borrows.
366+
self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
367+
368+
// 3. Relate the expected type and the formal one,
369+
// if the expected type was used for the coercion.
370+
self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
371+
};
372+
324373
// Check the arguments.
325374
// We do this in a pretty awful way: first we type-check any arguments
326375
// that are not closures, then we type-check the closures. This is so
@@ -369,47 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
369418
continue;
370419
}
371420

372-
let formal_ty = formal_input_tys[i];
373-
debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
374-
375-
// The special-cased logic below has three functions:
376-
// 1. Provide as good of an expected type as possible.
377-
let expected = Expectation::rvalue_hint(self, expected_input_tys[i]);
378-
379-
let checked_ty = self.check_expr_with_expectation(&arg, expected);
380-
381-
// 2. Coerce to the most detailed type that could be coerced
382-
// to, which is `expected_ty` if `rvalue_hint` returns an
383-
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
384-
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
385-
386-
final_arg_types.push((i, checked_ty, coerce_ty));
387-
388-
// Cause selection errors caused by resolving a single argument to point at the
389-
// argument and not the call. This is otherwise redundant with the `demand_coerce`
390-
// call immediately after, but it lets us customize the span pointed to in the
391-
// fulfillment error to be more accurate.
392-
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
393-
coerce_ty,
394-
|errors| {
395-
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
396-
self.point_at_arg_instead_of_call_if_possible(
397-
errors,
398-
&final_arg_types,
399-
call_expr,
400-
call_span,
401-
provided_args,
402-
);
403-
},
404-
);
405-
406-
// We're processing function arguments so we definitely want to use
407-
// two-phase borrows.
408-
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
409-
410-
// 3. Relate the expected type and the formal one,
411-
// if the expected type was used for the coercion.
412-
self.demand_suptype(arg.span, formal_ty, coerce_ty);
421+
demand_compatible(i, &mut final_arg_types);
413422
}
414423
}
415424

0 commit comments

Comments
 (0)