diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs new file mode 100644 index 000000000000..b85573b9c07d --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -0,0 +1,75 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains code to equate the input/output types appearing +//! in the MIR with the expected input/output types from the function +//! signature. This requires a bit of processing, as the expected types +//! are supplied to us before normalization and may contain existential +//! `impl Trait` instances. In contrast, the input/output types found in +//! the MIR (specifically, in the special local variables for the +//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and +//! contain revealed `impl Trait` values). + +use borrow_check::nll::universal_regions::UniversalRegions; +use rustc::ty::Ty; +use rustc::mir::*; + +use rustc_data_structures::indexed_vec::Idx; + +use super::{AtLocation, TypeChecker}; + +impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { + pub(super) fn equate_inputs_and_outputs( + &mut self, + mir: &Mir<'tcx>, + universal_regions: &UniversalRegions<'tcx>, + ) { + let &UniversalRegions { + unnormalized_output_ty, + unnormalized_input_tys, + .. + } = universal_regions; + + let start_position = Location { + block: START_BLOCK, + statement_index: 0, + }; + + // Equate expected input tys with those in the MIR. + let argument_locals = (1..).map(Local::new); + for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) { + let input_ty = self.normalize(&unnormalized_input_ty, start_position); + let mir_input_ty = mir.local_decls[local].ty; + self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty); + } + + // Return types are a bit more complex. They may contain existential `impl Trait` + // types. + + let output_ty = self.normalize(&unnormalized_output_ty, start_position); + let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; + self.equate_normalized_input_or_output(start_position, output_ty, mir_output_ty); + } + + fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) { + debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); + + if let Err(terr) = self.eq_types(a, b, location.at_self()) { + span_mirbug!( + self, + location, + "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", + a, + b, + terr + ); + } + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a56fb0492761..48750b626114 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -36,7 +36,32 @@ use util::liveness::LivenessResults; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; +macro_rules! span_mirbug { + ($context:expr, $elem:expr, $($message:tt)*) => ({ + $crate::borrow_check::nll::type_check::mirbug( + $context.tcx(), + $context.last_span, + &format!( + "broken MIR in {:?} ({:?}): {}", + $context.body_id, + $elem, + format_args!($($message)*), + ), + ) + }) +} + +macro_rules! span_mirbug_and_err { + ($context:expr, $elem:expr, $($message:tt)*) => ({ + { + span_mirbug!($context, $elem, $($message)*); + $context.error() + } + }) +} + mod liveness; +mod input_output; /// Type checks the given `mir` in the context of the inference /// context `infcx`. Returns any region constraints that have yet to @@ -88,18 +113,7 @@ pub(crate) fn type_check<'gcx, 'tcx>( &mut |cx| { liveness::generate(cx, mir, liveness, flow_inits, move_data); - // Equate the input and output tys given by the user with - // the ones found in the MIR. - let &UniversalRegions { - unnormalized_output_ty, - unnormalized_input_tys, - .. - } = universal_regions; - cx.equate_input_or_output(unnormalized_output_ty, mir.local_decls[RETURN_PLACE].ty); - let arg_locals = (1..).map(Local::new); - for (&input_ty, local) in unnormalized_input_tys.iter().zip(arg_locals) { - cx.equate_input_or_output(input_ty, mir.local_decls[local].ty); - } + cx.equate_inputs_and_outputs(mir, universal_regions); }, ) } @@ -136,7 +150,6 @@ fn type_check_internal<'gcx, 'tcx>( checker.constraints } - fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` @@ -144,25 +157,6 @@ fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { tcx.sess.diagnostic().delay_span_bug(span, msg); } -macro_rules! span_mirbug { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - mirbug($context.tcx(), $context.last_span, - &format!("broken MIR in {:?} ({:?}): {}", - $context.body_id, - $elem, - format_args!($($message)*))) - }) -} - -macro_rules! span_mirbug_and_err { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - { - span_mirbug!($context, $elem, $($message)*); - $context.error() - } - }) -} - enum FieldAccessError { OutOfRange { field_count: usize }, } @@ -714,25 +708,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }) } - fn equate_input_or_output(&mut self, unnormalized_a: Ty<'tcx>, b: Ty<'tcx>) { - let start_position = Location { - block: START_BLOCK, - statement_index: 0, - }; - let a = self.normalize(&unnormalized_a, start_position); - if let Err(terr) = self.eq_types(a, b, start_position.at_self()) { - span_mirbug!( - self, - start_position, - "bad input or output {:?} normalized to {:?} should equal {:?} but got error {:?}", - unnormalized_a, - a, - b, - terr - ); - } - } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx }