Auto merge of #88266 - nikomatsakis:issue-87879, r=jackh726
resolve type variables after checking casts r? `@jackh726` Fixes #87814 Fixes #88118 Supercedes #87879 (cc `@ldm0)`
This commit is contained in:
commit
b03ccace57
@ -14,6 +14,7 @@
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn check_match(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -26,6 +27,7 @@ pub fn check_match(
|
||||
|
||||
let acrb = arms_contain_ref_bindings(arms);
|
||||
let scrutinee_ty = self.demand_scrutinee_type(scrut, acrb, arms.is_empty());
|
||||
debug!(?scrutinee_ty);
|
||||
|
||||
// If there are no arms, that is a diverging match; a special case.
|
||||
if arms.is_empty() {
|
||||
|
@ -51,6 +51,7 @@
|
||||
|
||||
/// Reifies a cast check to be checked once we have full type information for
|
||||
/// a function context.
|
||||
#[derive(Debug)]
|
||||
pub struct CastCheck<'tcx> {
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
@ -603,12 +604,11 @@ fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
});
|
||||
}
|
||||
|
||||
#[instrument(skip(fcx), level = "debug")]
|
||||
pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
|
||||
self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
|
||||
|
||||
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
|
||||
|
||||
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
|
||||
self.report_cast_to_unsized_type(fcx);
|
||||
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
|
||||
|
@ -1328,6 +1328,7 @@ pub fn coerce_forced_unit<'a>(
|
||||
/// The inner coercion "engine". If `expression` is `None`, this
|
||||
/// is a forced-unit case, and hence `expression_ty` must be
|
||||
/// `Nil`.
|
||||
#[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")]
|
||||
crate fn coerce_inner<'a>(
|
||||
&mut self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
@ -156,12 +156,27 @@ pub(super) fn check_expr_with_needs(
|
||||
/// Note that inspecting a type's structure *directly* may expose the fact
|
||||
/// that there are actually multiple representations for `Error`, so avoid
|
||||
/// that when err needs to be handled differently.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn check_expr_with_expectation(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
debug!(">> type-checking: expected={:?}, expr={:?} ", expected, expr);
|
||||
if self.tcx().sess.verbose() {
|
||||
// make this code only run with -Zverbose because it is probably slow
|
||||
if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
|
||||
if !lint_str.contains("\n") {
|
||||
debug!("expr text: {}", lint_str);
|
||||
} else {
|
||||
let mut lines = lint_str.lines();
|
||||
if let Some(line0) = lines.next() {
|
||||
let remaining_lines = lines.count();
|
||||
debug!("expr text: {}", line0);
|
||||
debug!("expr text: ...(and {} more lines)", remaining_lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block
|
||||
// without the final expr (e.g. `try { return; }`). We don't want to generate an
|
||||
@ -1039,7 +1054,7 @@ fn check_expr_cast(
|
||||
let t_cast = self.to_ty_saving_user_provided_ty(t);
|
||||
let t_cast = self.resolve_vars_if_possible(t_cast);
|
||||
let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
|
||||
let t_cast = self.resolve_vars_if_possible(t_cast);
|
||||
let t_expr = self.resolve_vars_if_possible(t_expr);
|
||||
|
||||
// Eagerly check for some obvious errors.
|
||||
if t_expr.references_error() || t_cast.references_error() {
|
||||
@ -1049,6 +1064,10 @@ fn check_expr_cast(
|
||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||
Ok(cast_check) => {
|
||||
debug!(
|
||||
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
||||
t_cast, t_expr, cast_check,
|
||||
);
|
||||
deferred_cast_checks.push(cast_check);
|
||||
t_cast
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
pub(super) fn type_inference_fallback(&self) {
|
||||
/// Performs type inference fallback, returning true if any fallback
|
||||
/// occurs.
|
||||
pub(super) fn type_inference_fallback(&self) -> bool {
|
||||
// All type checking constraints were added, try to fallback unsolved variables.
|
||||
self.select_obligations_where_possible(false, |_| {});
|
||||
let mut fallback_has_occurred = false;
|
||||
@ -50,6 +52,8 @@ pub(super) fn type_inference_fallback(&self) {
|
||||
|
||||
// See if we can make any more progress.
|
||||
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
fallback_has_occurred
|
||||
}
|
||||
|
||||
// Tries to apply a fallback to `ty` if it is an unsolved variable.
|
||||
|
@ -29,6 +29,7 @@
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn check_casts(&self) {
|
||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||
debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
|
||||
for cast in deferred_cast_checks.drain(..) {
|
||||
cast.check(self);
|
||||
}
|
||||
|
@ -446,11 +446,12 @@ fn typeck_with_fallback<'tcx>(
|
||||
fcx
|
||||
};
|
||||
|
||||
fcx.type_inference_fallback();
|
||||
let fallback_has_occurred = fcx.type_inference_fallback();
|
||||
|
||||
// Even though coercion casts provide type hints, we check casts after fallback for
|
||||
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
|
||||
fcx.check_casts();
|
||||
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
// Closure and generator analysis may run after fallback
|
||||
// because they don't constrain other type variables.
|
||||
|
@ -120,9 +120,8 @@ pub fn new(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn consume_body(&mut self, body: &hir::Body<'_>) {
|
||||
debug!("consume_body(body={:?})", body);
|
||||
|
||||
for param in body.params {
|
||||
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat));
|
||||
debug!("consume_body: param_ty = {:?}", param_ty);
|
||||
|
15
src/test/ui/closures/2229_closure_analysis/issue_88118.rs
Normal file
15
src/test/ui/closures/2229_closure_analysis/issue_88118.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Regression test for #88118. Used to ICE.
|
||||
//
|
||||
// check-pass
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(capture_disjoint_fields)]
|
||||
|
||||
fn foo<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
|
||||
Box::new(move |value| {
|
||||
(|_| handler.clone()())(value);
|
||||
None
|
||||
}) as Box<dyn Fn(i32) -> Option<i32>>;
|
||||
}
|
||||
|
||||
fn main() {}
|
8
src/test/ui/closures/issue-87814-1.rs
Normal file
8
src/test/ui/closures/issue-87814-1.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// check-pass
|
||||
fn main() {
|
||||
let mut schema_all = vec![];
|
||||
(0..42).for_each(|_x| match Err(()) as Result<(), _> {
|
||||
Ok(()) => schema_all.push(()),
|
||||
Err(_) => (),
|
||||
});
|
||||
}
|
11
src/test/ui/closures/issue-87814-2.rs
Normal file
11
src/test/ui/closures/issue-87814-2.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
#![feature(try_reserve)]
|
||||
|
||||
fn main() {
|
||||
let mut schema_all: (Vec<String>, Vec<String>) = (vec![], vec![]);
|
||||
|
||||
let _c = || match schema_all.0.try_reserve(1) as Result<(), _> {
|
||||
Ok(()) => (),
|
||||
Err(_) => (),
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user