Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve type variables after checking casts #88266

Merged
merged 6 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_trait_selection::traits::{
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub fn check_match(
&self,
expr: &'tcx hir::Expr<'tcx>,
Expand All @@ -26,6 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

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() {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;

/// 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>,
Expand Down Expand Up @@ -603,12 +604,11 @@ impl<'a, 'tcx> CastCheck<'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() {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
/// 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>,
Expand Down
23 changes: 21 additions & 2 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// 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
Expand Down Expand Up @@ -1039,7 +1054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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() {
Expand All @@ -1049,6 +1064,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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
}
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_typeck/src/check/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use rustc_infer::infer::type_variable::Diverging;
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;
Expand Down Expand Up @@ -50,6 +52,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {

// 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.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use std::slice;
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);
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_typeck/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}

#[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(&param.pat));
debug!("consume_body: param_ty = {:?}", param_ty);
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/issue_88118.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions src/test/ui/closures/issue-87814-1.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/test/ui/closures/issue-87814-2.rs
Original file line number Diff line number Diff line change
@@ -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(_) => (),
};
}