diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 9d65c3950626..c6f910c4ad7a 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn constrain_opaque_type>( + pub fn constrain_opaque_type>( &self, def_id: DefId, opaque_defn: &OpaqueTypeDecl<'tcx>, diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs index b1e8b974379d..2e018f746f38 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -9,10 +9,12 @@ // except according to those terms. use borrow_check::nll::type_check::Locations; -use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; +use borrow_check::nll::constraints::{ConstraintCategory, ConstraintIndex}; +use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; use rustc::ty::RegionVid; use rustc_data_structures::graph; use rustc_data_structures::indexed_vec::IndexVec; +use syntax_pos::DUMMY_SP; /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 @@ -174,7 +176,8 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { Some(OutlivesConstraint { sup: self.static_region, sub: next_static_idx.into(), - locations: Locations::All, + locations: Locations::All(DUMMY_SP), + category: ConstraintCategory::Internal, }) } else { None diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index 41c846509cdd..76ebc06bfd2f 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -23,6 +23,42 @@ crate struct ConstraintSet { constraints: IndexVec, } +/// Constraints can be categorized to determine whether and why they are +/// interesting. Order of variants indicates sort order of the category, +/// thereby influencing diagnostic output. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub enum ConstraintCategory { + Return, + TypeAnnotation, + Cast, + CallArgument, + + /// A constraint that came from checking the body of a closure. + /// + /// Ideally we would give an explanation that points to the relevant part + /// of the closure's body. + ClosureBounds, + CopyBound, + SizedBound, + Assignment, + OpaqueType, + + /// A "boring" constraint (caused by the given location) is one that + /// the user probably doesn't want to see described in diagnostics, + /// because it is kind of an artifact of the type system setup. + /// Example: `x = Foo { field: y }` technically creates + /// intermediate regions representing the "type of `Foo { field: y + /// }`", and data flows from `y` into those variables, but they + /// are not very interesting. The assignment into `x` on the other + /// hand might be. + Boring, + // Boring and applicable everywhere. + BoringNoLocation, + + /// A constraint that doesn't correspond to anything the user sees. + Internal, +} + impl ConstraintSet { crate fn push(&mut self, constraint: OutlivesConstraint) { debug!( @@ -87,6 +123,9 @@ pub struct OutlivesConstraint { /// Where did this constraint arise? pub locations: Locations, + + /// What caused this constraint? + pub category: ConstraintCategory, } impl fmt::Debug for OutlivesConstraint { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index d3b4f0a0447a..ee900afc44de 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -88,11 +88,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { sup, sub, locations, + category, } = constraint; with_msg(&format!( - "{:?}: {:?} due to {:?}", + "{:?}: {:?} due to {:?} at {:?}", sup, sub, + category, locations, ))?; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index b7000b254a7d..1abc105ac289 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow_check::nll::constraints::OutlivesConstraint; +use borrow_check::nll::constraints::{OutlivesConstraint, ConstraintCategory}; use borrow_check::nll::region_infer::RegionInferenceContext; -use borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::InferCtxt; -use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind}; -use rustc::ty::{self, TyCtxt, RegionVid}; +use rustc::mir::{Location, Mir}; +use rustc::ty::{self, RegionVid}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::{Diagnostic, DiagnosticBuilder}; use std::collections::VecDeque; @@ -28,19 +27,6 @@ mod var_name; use self::region_name::RegionName; -/// Constraints that are considered interesting can be categorized to -/// determine why they are interesting. Order of variants indicates -/// sort order of the category, thereby influencing diagnostic output. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -enum ConstraintCategory { - Cast, - Assignment, - Return, - CallArgument, - Other, - Boring, -} - impl fmt::Display for ConstraintCategory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Must end with a space. Allows for empty names to be provided. @@ -49,7 +35,14 @@ impl fmt::Display for ConstraintCategory { ConstraintCategory::Return => write!(f, "returning this value "), ConstraintCategory::Cast => write!(f, "cast "), ConstraintCategory::CallArgument => write!(f, "argument "), - _ => write!(f, ""), + ConstraintCategory::TypeAnnotation => write!(f, "type annotation "), + ConstraintCategory::ClosureBounds => write!(f, "closure body "), + ConstraintCategory::SizedBound => write!(f, "proving this value is `Sized` "), + ConstraintCategory::CopyBound => write!(f, "copying this value "), + ConstraintCategory::OpaqueType => write!(f, "opaque type "), + ConstraintCategory::Boring + | ConstraintCategory::BoringNoLocation + | ConstraintCategory::Internal => write!(f, ""), } } } @@ -71,7 +64,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn best_blame_constraint( &self, mir: &Mir<'tcx>, - tcx: TyCtxt<'_, '_, 'tcx>, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, ) -> (ConstraintCategory, Span, RegionVid) { @@ -96,7 +88,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Classify each of the constraints along the path. let mut categorized_path: Vec<(ConstraintCategory, Span)> = path .iter() - .map(|&index| self.classify_constraint(index, mir, tcx)) + .map(|constraint| (constraint.category, constraint.locations.span(mir))) .collect(); debug!( "best_blame_constraint: categorized_path={:#?}", @@ -129,12 +121,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); match categorized_path[i].0 { - ConstraintCategory::Boring => false, - ConstraintCategory::Other => { - // other isn't interesting when the two lifetimes - // are unified. - constraint_sup_scc != self.constraint_sccs.scc(constraint.sub) - } + ConstraintCategory::OpaqueType + | ConstraintCategory::Boring + | ConstraintCategory::BoringNoLocation + | ConstraintCategory::Internal => false, _ => constraint_sup_scc != target_scc, } }); @@ -220,106 +210,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { None } - /// This function will return true if a constraint is interesting and false if a constraint - /// is not. It is useful in filtering constraint paths to only interesting points. - fn constraint_is_interesting(&self, constraint: OutlivesConstraint) -> bool { - debug!( - "constraint_is_interesting: locations={:?} constraint={:?}", - constraint.locations, constraint - ); - - match constraint.locations { - Locations::Interesting(_) | Locations::All => true, - _ => false, - } - } - - /// This function classifies a constraint from a location. - fn classify_constraint( - &self, - constraint: OutlivesConstraint, - mir: &Mir<'tcx>, - tcx: TyCtxt<'_, '_, 'tcx>, - ) -> (ConstraintCategory, Span) { - debug!("classify_constraint: constraint={:?}", constraint); - let span = constraint.locations.span(mir); - let location = constraint - .locations - .from_location() - .unwrap_or(Location::START); - - if !self.constraint_is_interesting(constraint) { - return (ConstraintCategory::Boring, span); - } - - let data = &mir[location.block]; - debug!( - "classify_constraint: location={:?} data={:?}", - location, data - ); - let category = if location.statement_index == data.statements.len() { - if let Some(ref terminator) = data.terminator { - debug!("classify_constraint: terminator.kind={:?}", terminator.kind); - match terminator.kind { - TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment, - // Classify calls differently depending on whether or not - // the sub region appears in the destination type (so the - // sup region is in the return type). If the return type - // contains the sub-region, then this is either an - // assignment or a return, depending on whether we are - // writing to the RETURN_PLACE or not. - // - // The idea here is that the region is being propagated - // from an input into the output place, so it's a kind of - // assignment. Otherwise, if the sub-region only appears in - // the argument types, then use the CallArgument - // classification. - TerminatorKind::Call { destination: Some((ref place, _)), .. } => { - if tcx.any_free_region_meets( - &place.ty(mir, tcx).to_ty(tcx), - |region| self.to_region_vid(region) == constraint.sub, - ) { - match place { - Place::Local(mir::RETURN_PLACE) => ConstraintCategory::Return, - _ => ConstraintCategory::Assignment, - } - } else { - ConstraintCategory::CallArgument - } - } - TerminatorKind::Call { destination: None, .. } => { - ConstraintCategory::CallArgument - } - _ => ConstraintCategory::Other, - } - } else { - ConstraintCategory::Other - } - } else { - let statement = &data.statements[location.statement_index]; - debug!("classify_constraint: statement.kind={:?}", statement.kind); - match statement.kind { - StatementKind::Assign(ref place, ref rvalue) => { - debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue); - if *place == Place::Local(mir::RETURN_PLACE) { - ConstraintCategory::Return - } else { - match rvalue { - Rvalue::Cast(..) => ConstraintCategory::Cast, - Rvalue::Use(..) | Rvalue::Aggregate(..) => { - ConstraintCategory::Assignment - } - _ => ConstraintCategory::Other, - } - } - } - _ => ConstraintCategory::Other, - } - }; - - (category, span) - } - /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// @@ -341,7 +231,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { let (category, span, _) = self.best_blame_constraint( mir, - infcx.tcx, fr, |r| r == outlived_fr ); @@ -574,11 +463,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn find_outlives_blame_span( &self, mir: &Mir<'tcx>, - tcx: TyCtxt<'_, '_, 'tcx>, fr1: RegionVid, fr2: RegionVid, ) -> Span { - let (_, span, _) = self.best_blame_constraint(mir, tcx, fr1, |r| r == fr2); + let (_, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2); span } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index d1713a520a79..75f14a6bbdac 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1062,7 +1062,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { longer_fr, shorter_fr, ); - let blame_span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, shorter_fr); + let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr); if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). @@ -1147,7 +1147,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, error_region); + let span = self.find_outlives_blame_span(mir, longer_fr, error_region); // Obviously, this error message is far from satisfactory. // At present, though, it only appears in unit tests -- diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 64a61972a220..430c8d673921 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -9,7 +9,7 @@ // except according to those terms. use borrow_check::location::LocationTable; -use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; +use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::{RegionTest, TypeTest}; use borrow_check::nll::type_check::Locations; @@ -30,6 +30,7 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, + category: ConstraintCategory, outlives_constraints: &'a mut ConstraintSet, type_tests: &'a mut Vec>, all_facts: &'a mut Option, @@ -44,6 +45,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, + category: ConstraintCategory, outlives_constraints: &'a mut ConstraintSet, type_tests: &'a mut Vec>, all_facts: &'a mut Option, @@ -56,6 +58,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { implicit_region_bound, param_env, locations, + category, outlives_constraints, type_tests, all_facts, @@ -183,6 +186,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { self.outlives_constraints.push(OutlivesConstraint { locations: self.locations, + category: self.category, sub, sup, }); diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index e21c490622c0..61c612b3c011 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -14,6 +14,7 @@ use borrow_check::nll::type_check::constraint_conversion; use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints}; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::ToRegionVid; +use borrow_check::nll::constraints::ConstraintCategory; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; @@ -23,6 +24,7 @@ use rustc::traits::query::type_op::{self, TypeOp}; use rustc::ty::{self, RegionVid, Ty}; use rustc_data_structures::transitive_relation::TransitiveRelation; use std::rc::Rc; +use syntax_pos::DUMMY_SP; #[derive(Debug)] crate struct UniversalRegionRelations<'tcx> { @@ -283,7 +285,8 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { &self.region_bound_pairs, self.implicit_region_bound, self.param_env, - Locations::All, + Locations::All(DUMMY_SP), + ConstraintCategory::Internal, &mut self.constraints.outlives_constraints, &mut self.constraints.type_tests, &mut self.all_facts, 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 index 265cd305eb97..6c7e2e9b72e3 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -29,8 +29,9 @@ use rustc::ty::subst::Subst; use rustc::ty::Ty; use rustc_data_structures::indexed_vec::Idx; +use syntax_pos::Span; -use super::{Locations, TypeChecker}; +use super::{ConstraintCategory, Locations, TypeChecker}; impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { pub(super) fn equate_inputs_and_outputs( @@ -56,7 +57,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); let mir_input_ty = mir.local_decls[local].ty; - self.equate_normalized_input_or_output(normalized_input_ty, mir_input_ty); + let mir_input_span = mir.local_decls[local].source_info.span; + self.equate_normalized_input_or_output( + normalized_input_ty, + mir_input_ty, + mir_input_span, + ); } assert!( @@ -65,16 +71,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); if let Some(mir_yield_ty) = mir.yield_ty { let ur_yield_ty = universal_regions.yield_ty.unwrap(); - self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty); + let yield_span = mir.local_decls[RETURN_PLACE].source_info.span; + self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); } // Return types are a bit more complex. They may contain existential `impl Trait` // types. let param_env = self.param_env; let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; + let output_span = mir.local_decls[RETURN_PLACE].source_info.span; let opaque_type_map = self.fully_perform_op( - Locations::All, + Locations::All(output_span), + ConstraintCategory::BoringNoLocation, CustomTypeOp::new( |infcx| { let mut obligations = ObligationAccumulator::default(); @@ -152,26 +161,38 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // prove that `T: Iterator` where `T` is the type we // instantiated it with). if let Some(opaque_type_map) = opaque_type_map { - self.fully_perform_op( - Locations::All, - CustomTypeOp::new( - |_cx| { - infcx.constrain_opaque_types(&opaque_type_map, universal_region_relations); - Ok(InferOk { - value: (), - obligations: vec![], - }) - }, - || "opaque_type_map".to_string(), - ), - ).unwrap(); + for (opaque_def_id, opaque_decl) in opaque_type_map { + self.fully_perform_op( + Locations::All(infcx.tcx.def_span(opaque_def_id)), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |_cx| { + infcx.constrain_opaque_type( + opaque_def_id, + &opaque_decl, + universal_region_relations + ); + Ok(InferOk { + value: (), + obligations: vec![], + }) + }, + || "opaque_type_map".to_string(), + ), + ).unwrap(); + } } } - fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - if let Err(terr) = self.eq_types(a, b, Locations::All) { + if let Err(terr) = self.eq_types( + a, + b, + Locations::All(span), + ConstraintCategory::BoringNoLocation, + ) { span_mirbug!( self, Location::START, diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 47e6ce05cec1..e706c1adaddf 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use borrow_check::nll::constraints::ConstraintCategory; use borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements}; use borrow_check::nll::type_check::liveness::liveness_map::{LiveVar, NllLivenessMap}; use borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap; -use borrow_check::nll::type_check::AtLocation; +use borrow_check::nll::type_check::NormalizeLocation; use borrow_check::nll::type_check::TypeChecker; use dataflow::move_paths::indexes::MovePathIndex; use dataflow::move_paths::MoveData; @@ -487,7 +488,11 @@ impl LivenessContext<'_, '_, '_, '_, 'tcx> { if let Some(data) = &drop_data.region_constraint_data { for &drop_location in drop_locations { self.typeck - .push_region_constraints(drop_location.boring(), data); + .push_region_constraints( + drop_location.to_locations(), + ConstraintCategory::Boring, + data, + ); } } 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 de96539ec30f..c58518011aaf 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -13,7 +13,7 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; -use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint}; +use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint}; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements}; use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; @@ -252,7 +252,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { constant.ty, ty::Variance::Invariant, user_ty, - location.boring(), + location.to_locations(), + ConstraintCategory::Boring, ) { span_mirbug!( self, @@ -281,7 +282,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { local_decl.ty, ty::Variance::Invariant, user_ty, - Locations::All, + Locations::All(local_decl.source_info.span), + ConstraintCategory::TypeAnnotation, ) { span_mirbug!( self, @@ -364,14 +366,19 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); type_checker.normalize_and_prove_instantiated_predicates( instantiated_predicates, - location.boring(), + location.to_locations(), ); } debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty); if let Err(terr) = self.cx - .eq_types(constant.literal.ty, constant.ty, location.boring()) + .eq_types( + constant.literal.ty, + constant.ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { span_mirbug!( self, @@ -417,7 +424,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let sty = self.sanitize_type(place, sty); let ty = self.tcx().type_of(def_id); let ty = self.cx.normalize(ty, location); - if let Err(terr) = self.cx.eq_types(ty, sty, location.boring()) { + if let Err(terr) = self.cx.eq_types( + ty, + sty, + location.to_locations(), + ConstraintCategory::Boring, + ) { span_mirbug!( self, place, @@ -461,7 +473,11 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds // fully apply: in effect, the rule is that if a value of some type could implement // Copy, then it must. - self.cx.prove_trait_ref(trait_ref, location.interesting()); + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); } place_ty } @@ -560,7 +576,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Field(field, fty) => { let fty = self.sanitize_type(place, fty); match self.field_ty(place, base, field, location) { - Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.boring()) { + Ok(ty) => if let Err(terr) = self.cx.eq_types( + ty, + fty, + location.to_locations(), + ConstraintCategory::Boring, + ) { span_mirbug!( self, place, @@ -740,43 +761,32 @@ pub enum Locations { /// user-given type annotations; e.g., if the user wrote `let mut /// x: &'static u32 = ...`, we would ensure that all values /// assigned to `x` are of `'static` lifetime. - All, - - /// A "boring" constraint (caused by the given location) is one that - /// the user probably doesn't want to see described in diagnostics, - /// because it is kind of an artifact of the type system setup. /// - /// Example: `x = Foo { field: y }` technically creates - /// intermediate regions representing the "type of `Foo { field: y - /// }`", and data flows from `y` into those variables, but they - /// are not very interesting. The assignment into `x` on the other - /// hand might be. - Boring(Location), + /// The span points to the place the constraint arose. For example, + /// it points to the type in a user-given type annotation. If + /// there's no sensible span then it's DUMMY_SP. + All(Span), - /// An *important* outlives constraint (caused by the given - /// location) is one that would be useful to highlight in - /// diagnostics, because it represents a point where references - /// flow from one spot to another (e.g., `x = y`) - Interesting(Location), + /// An outlives constraint that only has to hold at a single location, + /// usually it represents a point where references flow from one spot to + /// another (e.g., `x = y`) + Single(Location), } impl Locations { pub fn from_location(&self) -> Option { match self { - Locations::All => None, - Locations::Boring(from_location) | Locations::Interesting(from_location) => { - Some(*from_location) - } + Locations::All(_) => None, + Locations::Single(from_location) => Some(*from_location), } } /// Gets a span representing the location. pub fn span(&self, mir: &Mir<'_>) -> Span { - let span_location = match self { - Locations::All => Location::START, - Locations::Boring(l) | Locations::Interesting(l) => *l, - }; - mir.source_info(span_location).span + match self { + Locations::All(span) => *span, + Locations::Single(l) => mir.source_info(*l).span, + } } } @@ -816,12 +826,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn fully_perform_op( &mut self, locations: Locations, + category: ConstraintCategory, op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>, ) -> Fallible { let (r, opt_data) = op.fully_perform(self.infcx)?; if let Some(data) = &opt_data { - self.push_region_constraints(locations, data); + self.push_region_constraints(locations, category, data); } Ok(r) @@ -830,6 +841,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn push_region_constraints( &mut self, locations: Locations, + category: ConstraintCategory, data: &[QueryRegionConstraint<'tcx>], ) { debug!( @@ -846,6 +858,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.implicit_region_bound, self.param_env, locations, + category, &mut borrowck_context.constraints.outlives_constraints, &mut borrowck_context.constraints.type_tests, &mut borrowck_context.all_facts, @@ -853,22 +866,36 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>, locations: Locations) -> Fallible<()> { + fn sub_types( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { relate_tys::sub_types( self.infcx, sub, sup, locations, + category, self.borrowck_context.as_mut().map(|x| &mut **x), ) } - fn eq_types(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations) -> Fallible<()> { + fn eq_types( + &mut self, + a: Ty<'tcx>, + b: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { relate_tys::eq_types( self.infcx, a, b, locations, + category, self.borrowck_context.as_mut().map(|x| &mut **x), ) } @@ -879,6 +906,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { v: ty::Variance, b: CanonicalTy<'tcx>, locations: Locations, + category: ConstraintCategory, ) -> Fallible<()> { relate_tys::relate_type_and_user_type( self.infcx, @@ -886,6 +914,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { v, b, locations, + category, self.borrowck_context.as_mut().map(|x| &mut **x), ) } @@ -903,21 +932,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting // though. - let is_temp = if let Place::Local(l) = *place { - l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some() - } else { - false - }; - - let locations = if is_temp { - location.boring() - } else { - location.interesting() + let category = match *place { + Place::Local(RETURN_PLACE) => ConstraintCategory::Return, + Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => { + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, }; let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { + if let Err(terr) = self.sub_types( + rv_ty, + place_ty, + location.to_locations(), + category, + ) { span_mirbug!( self, stmt, @@ -933,7 +963,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { rv_ty, ty::Variance::Invariant, user_ty, - location.boring(), + location.to_locations(), + ConstraintCategory::Boring, ) { span_mirbug!( self, @@ -952,7 +983,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { def_id: tcx.lang_items().sized_trait().unwrap(), substs: tcx.mk_substs_trait(place_ty, &[]), }; - self.prove_trait_ref(trait_ref, location.interesting()); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); } } StatementKind::SetDiscriminant { @@ -983,7 +1018,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::AscribeUserType(ref place, variance, c_ty) => { let place_ty = place.ty(mir, tcx).to_ty(tcx); if let Err(terr) = - self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All) + self.relate_type_and_user_type( + place_ty, + variance, + c_ty, + Locations::All(stmt.source_info.span), + ConstraintCategory::TypeAnnotation, + ) { span_mirbug!( self, @@ -1035,8 +1076,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - let locations = term_location.interesting(); - if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) { + let locations = term_location.to_locations(); + if let Err(terr) = self.sub_types( + rv_ty, + place_ty, + locations, + ConstraintCategory::Assignment, + ) { span_mirbug!( self, term, @@ -1053,7 +1099,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .. } => { let discr_ty = discr.ty(mir, tcx); - if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.boring()) { + if let Err(terr) = self.sub_types( + discr_ty, + switch_ty, + term_location.to_locations(), + ConstraintCategory::Assignment, + ) { span_mirbug!( self, term, @@ -1093,7 +1144,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.prove_predicates( sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)), - term_location.boring(), + term_location.to_locations(), + ConstraintCategory::Boring, ); // The ordinary liveness rules will ensure that all @@ -1139,7 +1191,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match mir.yield_ty { None => span_mirbug!(self, term, "yield in non-generator"), Some(ty) => { - if let Err(terr) = self.sub_types(value_ty, ty, term_location.interesting()) + if let Err(terr) = self.sub_types( + value_ty, + ty, + term_location.to_locations(), + ConstraintCategory::Return, + ) { span_mirbug!( self, @@ -1168,19 +1225,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *destination { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - let is_temp = if let Place::Local(l) = *dest { - l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some() - } else { - false + let category = match *dest { + Place::Local(RETURN_PLACE) => ConstraintCategory::Return, + Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => { + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, }; - let locations = if is_temp { - term_location.boring() - } else { - term_location.interesting() - }; + let locations = term_location.to_locations(); - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) { + if let Err(terr) = self.sub_types( + sig.output(), + dest_ty, + locations, + category, + ) { span_mirbug!( self, term, @@ -1221,7 +1281,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); - if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.interesting()) { + if let Err(terr) = self.sub_types( + op_arg_ty, + fn_arg, + term_location.to_locations(), + ConstraintCategory::CallArgument, + ) { span_mirbug!( self, term, @@ -1470,7 +1535,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(operand_ty, &[]), }; - self.prove_trait_ref(trait_ref, location.interesting()); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); }, Rvalue::NullaryOp(_, ty) => { @@ -1485,24 +1554,34 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { substs: tcx.mk_substs_trait(ty, &[]), }; - self.prove_trait_ref(trait_ref, location.interesting()); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); } - Rvalue::Cast(cast_kind, op, ty) => match cast_kind { - CastKind::ReifyFnPointer => { - let fn_sig = op.ty(mir, tcx).fn_sig(tcx); + Rvalue::Cast(cast_kind, op, ty) => { + match cast_kind { + CastKind::ReifyFnPointer => { + let fn_sig = op.ty(mir, tcx).fn_sig(tcx); - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); - let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); + let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { - span_mirbug!( + if let Err(terr) = self.eq_types( + ty_fn_ptr_from, + ty, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( self, rvalue, "equating {:?} with {:?} yields {:?}", @@ -1510,20 +1589,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ty, terr ); - } - } - - CastKind::ClosureFnPointer => { - let sig = match op.ty(mir, tcx).sty { - ty::Closure(def_id, substs) => { - substs.closure_sig_ty(def_id, tcx).fn_sig(tcx) } - _ => bug!(), - }; - let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig); + } - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { - span_mirbug!( + CastKind::ClosureFnPointer => { + let sig = match op.ty(mir, tcx).sty { + ty::Closure(def_id, substs) => { + substs.closure_sig_ty(def_id, tcx).fn_sig(tcx) + } + _ => bug!(), + }; + let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig); + + if let Err(terr) = self.eq_types( + ty_fn_ptr_from, + ty, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( self, rvalue, "equating {:?} with {:?} yields {:?}", @@ -1531,23 +1615,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ty, terr ); + } } - } - CastKind::UnsafeFnPointer => { - let fn_sig = op.ty(mir, tcx).fn_sig(tcx); + CastKind::UnsafeFnPointer => { + let fn_sig = op.ty(mir, tcx).fn_sig(tcx); - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); - let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); + let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); - if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.interesting()) { - span_mirbug!( + if let Err(terr) = self.eq_types( + ty_fn_ptr_from, + ty, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( self, rvalue, "equating {:?} with {:?} yields {:?}", @@ -1555,21 +1644,26 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ty, terr ); + } } + + CastKind::Unsize => { + let &ty = ty; + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), + substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + + CastKind::Misc => {} } - - CastKind::Unsize => { - let &ty = ty; - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), - substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty.into()]), - }; - - self.prove_trait_ref(trait_ref, location.interesting()); - } - - CastKind::Misc => {} - }, + } Rvalue::Ref(region, _borrow_kind, borrowed_place) => { self.add_reborrow_constraint(location, region, borrowed_place); @@ -1644,7 +1738,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; let operand_ty = operand.ty(mir, tcx); - if let Err(terr) = self.sub_types(operand_ty, field_ty, location.boring()) { + if let Err(terr) = self.sub_types( + operand_ty, + field_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { span_mirbug!( self, rvalue, @@ -1723,7 +1822,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.to_region_vid(), sub: borrow_region.to_region_vid(), - locations: location.boring(), + locations: location.to_locations(), + category: ConstraintCategory::Boring, }); if let Some(all_facts) = all_facts { @@ -1839,8 +1939,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { *substs, ); - // Hmm, are these constraints *really* boring? - self.push_region_constraints(location.boring(), &closure_constraints); + self.push_region_constraints( + location.to_locations(), + ConstraintCategory::ClosureBounds, + &closure_constraints, + ); } tcx.predicates_of(*def_id).instantiate(tcx, substs.substs) @@ -1855,16 +1958,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.normalize_and_prove_instantiated_predicates( instantiated_predicates, - location.boring(), + location.to_locations(), ); } - fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations) { + fn prove_trait_ref( + &mut self, + trait_ref: ty::TraitRef<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) { self.prove_predicates( Some(ty::Predicate::Trait( trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), )), locations, + category, ); } @@ -1875,7 +1984,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) { for predicate in instantiated_predicates.predicates { let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations); + self.prove_predicate(predicate, locations, ConstraintCategory::Boring); } } @@ -1883,6 +1992,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, predicates: impl IntoIterator>, locations: Locations, + category: ConstraintCategory, ) { for predicate in predicates { debug!( @@ -1890,11 +2000,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { predicate, locations, ); - self.prove_predicate(predicate, locations); + self.prove_predicate(predicate, locations, category); } } - fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, locations: Locations) { + fn prove_predicate( + &mut self, + predicate: ty::Predicate<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) { debug!( "prove_predicate(predicate={:?}, location={:?})", predicate, locations, @@ -1903,6 +2018,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let param_env = self.param_env; self.fully_perform_op( locations, + category, param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), ).unwrap_or_else(|NoSolution| { span_mirbug!(self, NoSolution, "could not prove {:?}", predicate); @@ -1943,6 +2059,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let param_env = self.param_env; self.fully_perform_op( location.to_locations(), + ConstraintCategory::Boring, param_env.and(type_op::normalize::Normalize::new(value)), ).unwrap_or_else(|NoSolution| { span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value); @@ -1996,26 +2113,6 @@ impl MirPass for TypeckMir { } } -pub trait AtLocation { - /// Indicates a "boring" constraint that the user probably - /// woudln't want to see highlights. - fn boring(self) -> Locations; - - /// Indicates an "interesting" edge, which is of significance only - /// for diagnostics. - fn interesting(self) -> Locations; -} - -impl AtLocation for Location { - fn boring(self) -> Locations { - Locations::Boring(self) - } - - fn interesting(self) -> Locations { - Locations::Interesting(self) - } -} - trait NormalizeLocation: fmt::Debug + Copy { fn to_locations(self) -> Locations; } @@ -2028,6 +2125,6 @@ impl NormalizeLocation for Locations { impl NormalizeLocation for Location { fn to_locations(self) -> Locations { - self.boring() + Locations::Single(self) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 06cb44ac9714..130b4b31d08e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow_check::nll::constraints::OutlivesConstraint; +use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint}; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::ToRegionVid; @@ -28,6 +28,7 @@ pub(super) fn sub_types<'tcx>( a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations, + category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible<()> { debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations); @@ -35,6 +36,7 @@ pub(super) fn sub_types<'tcx>( infcx, ty::Variance::Covariant, locations, + category, borrowck_context, ty::List::empty(), ).relate(&a, &b)?; @@ -47,6 +49,7 @@ pub(super) fn eq_types<'tcx>( a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations, + category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible<()> { debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations); @@ -54,6 +57,7 @@ pub(super) fn eq_types<'tcx>( infcx, ty::Variance::Invariant, locations, + category, borrowck_context, ty::List::empty(), ).relate(&a, &b)?; @@ -69,6 +73,7 @@ pub(super) fn relate_type_and_user_type<'tcx>( v: ty::Variance, b: CanonicalTy<'tcx>, locations: Locations, + category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible<()> { debug!( @@ -89,6 +94,7 @@ pub(super) fn relate_type_and_user_type<'tcx>( infcx, v1, locations, + category, borrowck_context, b_variables, ).relate(&b_value, &a)?; @@ -124,6 +130,8 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> { /// Where (and why) is this relation taking place? locations: Locations, + category: ConstraintCategory, + /// This will be `Some` when we are running the type check as part /// of NLL, and `None` if we are running a "sanity check". borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>, @@ -161,6 +169,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, ambient_variance: ty::Variance, locations: Locations, + category: ConstraintCategory, borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>, canonical_var_infos: CanonicalVarInfos<'tcx>, ) -> Self { @@ -171,6 +180,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> { borrowck_context, locations, canonical_var_values, + category, a_scopes: vec![], b_scopes: vec![], } @@ -264,6 +274,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> { sup, sub, locations: self.locations, + category: self.category, }); // FIXME all facts!