diff options
| author | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2022-02-14 16:10:22 +0000 |
|---|---|---|
| committer | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2022-03-28 16:27:14 +0000 |
| commit | 264cd05b16198c2838ec6cd585bd122491e3f7a9 (patch) | |
| tree | 133ca794d093e515a783cd92db831ff51e197820 /compiler/rustc_borrowck | |
| parent | 0e4524e5b4a9c5656fef69f532f96eb9959a1803 (diff) | |
| download | rust-264cd05b16198c2838ec6cd585bd122491e3f7a9.tar.gz rust-264cd05b16198c2838ec6cd585bd122491e3f7a9.zip | |
Revert "Auto merge of #93893 - oli-obk:sad_revert, r=oli-obk"
This reverts commit 6499c5e7fc173a3f55b7a3bd1e6a50e9edef782d, reversing changes made to 78450d2d602b06d9b94349aaf8cece1a4acaf3a8.
Diffstat (limited to 'compiler/rustc_borrowck')
10 files changed, 261 insertions, 260 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 7507ea76ed0..8601fbe27f3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -2,9 +2,13 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; +use rustc_infer::infer::region_constraints::RegionConstraintData; +use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::RegionVid; +use rustc_middle::ty::UniverseIndex; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; @@ -76,6 +80,15 @@ crate trait ToUniverseInfo<'tcx> { fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; } +impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { + fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType { + base_universe: Some(base_universe), + ..self + }))) + } +} + impl<'tcx> ToUniverseInfo<'tcx> for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> { @@ -116,6 +129,12 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo } } +impl<'tcx> ToUniverseInfo<'tcx> for ! { + fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + self + } +} + #[allow(unused_lifetimes)] trait TypeOpInfo<'tcx> { /// Returns an error to be reported if rerunning the type op fails to @@ -130,7 +149,7 @@ trait TypeOpInfo<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, @@ -175,7 +194,7 @@ trait TypeOpInfo<'tcx> { debug!(?placeholder_region); let span = cause.span; - let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); + let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); if let Some(nice_error) = nice_error { mbcx.buffer_error(nice_error); @@ -208,16 +227,16 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); try_extract_error_from_fulfill_cx( fulfill_cx, @@ -255,16 +274,16 @@ where fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let mut selcx = SelectionContext::new(infcx); @@ -316,16 +335,16 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error( &self, - tcx: TyCtxt<'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - tcx.infer_ctxt().enter_with_canonical( + mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) .ok()?; try_extract_error_from_fulfill_cx( @@ -339,6 +358,43 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { } } +impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { + fn fallback_error( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, + // and is only the fallback when the nice error fails. Consider improving this some more. + tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!") + } + + fn base_universe(&self) -> ty::UniverseIndex { + self.base_universe.unwrap() + } + + fn nice_error( + &self, + mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, + _cause: ObligationCause<'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option<ty::Region<'tcx>>, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { + try_extract_error_from_region_constraints( + mbcx.infcx, + placeholder_region, + error_region, + self.region_constraints.as_ref().unwrap(), + // We're using the original `InferCtxt` that we + // started MIR borrowchecking with, so the region + // constraints have already been taken. Use the data from + // our `mbcx` instead. + |vid| mbcx.regioncx.var_infos[vid].origin, + |vid| mbcx.regioncx.var_infos[vid].universe, + ) + } +} + #[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>, @@ -346,15 +402,30 @@ fn try_extract_error_from_fulfill_cx<'tcx>( placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - let tcx = infcx.tcx; - // We generally shouldn't have errors here because the query was // already run, but there's no point using `delay_span_bug` // when we're going to emit an error here anyway. let _errors = fulfill_cx.select_all_or_error(infcx); + let region_constraints = infcx.with_region_constraints(|r| r.clone()); + try_extract_error_from_region_constraints( + infcx, + placeholder_region, + error_region, + ®ion_constraints, + |vid| infcx.region_var_origin(vid), + |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))), + ) +} - let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { - debug!("{:#?}", region_constraints); +fn try_extract_error_from_region_constraints<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + placeholder_region: ty::Region<'tcx>, + error_region: Option<ty::Region<'tcx>>, + region_constraints: &RegionConstraintData<'tcx>, + mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, + mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, +) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { + let (sub_region, cause) = region_constraints.constraints.iter().find_map(|(constraint, cause)| { match *constraint { Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { @@ -362,12 +433,11 @@ fn try_extract_error_from_fulfill_cx<'tcx>( } // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((tcx.mk_region(ty::ReVar(vid)), cause.clone())) + Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone())) } _ => None, } - }) - })?; + })?; debug!(?sub_region, "cause = {:#?}", cause); let nice_error = match (error_region, *sub_region) { @@ -375,7 +445,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( infcx, RegionResolutionError::SubSupConflict( vid, - infcx.region_var_origin(vid), + region_var_origin(vid), cause.clone(), error_region, cause.clone(), @@ -392,8 +462,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>( infcx, RegionResolutionError::UpperBoundUniverseConflict( vid, - infcx.region_var_origin(vid), - infcx.universe_of_region(sub_region), + region_var_origin(vid), + universe_of_region(vid), cause.clone(), placeholder_region, ), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 6f78c816093..58b246ec873 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -7,6 +7,7 @@ #![feature(let_chains)] #![feature(let_else)] #![feature(min_specialization)] +#![feature(never_type)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![feature(try_blocks)] @@ -125,8 +126,9 @@ fn mir_borrowck<'tcx>( ) -> &'tcx BorrowCheckResult<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); + let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner; - let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { + let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow(); do_mir_borrowck(&infcx, input_body, promoted, false).0 @@ -141,7 +143,7 @@ fn mir_borrowck<'tcx>( /// If `return_body_with_facts` is true, then return the body with non-erased /// region ids on which the borrow checking was performed together with Polonius /// facts. -#[instrument(skip(infcx, input_body, input_promoted), level = "debug")] +#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")] fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 20f54d04777..1f81f7dda13 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -45,6 +45,7 @@ mod reverse_sccs; pub mod values; pub struct RegionInferenceContext<'tcx> { + pub var_infos: VarInfos, /// Contains the definition for every region variable. Region /// variables are identified by their index (`RegionVid`). The /// definition contains information about where the region came @@ -267,7 +268,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Self { // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos - .into_iter() + .iter() .map(|info| RegionDefinition::new(info.universe, info.origin)) .collect(); @@ -292,6 +293,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { + var_infos, definitions, liveness_constraints, constraints, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 60c48d8a764..a2378802802 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; @@ -54,27 +53,44 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>, + opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>, span: Span, ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> { opaque_ty_decls .into_iter() - .filter_map(|(opaque_type_key, decl)| { + .map(|(opaque_type_key, (concrete_type, decl_span, origin))| { let substs = opaque_type_key.substs; - let concrete_type = decl.concrete_ty; + // FIXME: why are the spans in decl_span often DUMMY_SP? + let span = decl_span.substitute_dummy(span); debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { - let vid = self.universal_regions.to_region_vid(region); - subst_regions.push(vid); - self.definitions[vid].external_name.unwrap_or_else(|| { - infcx - .tcx - .sess - .delay_span_bug(span, "opaque type with non-universal region substs"); - infcx.tcx.lifetimes.re_static - }) + if let ty::RePlaceholder(..) = region.kind() { + // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. + return region; + } + let vid = self.to_region_vid(region); + trace!(?vid); + let scc = self.constraint_sccs.scc(vid); + trace!(?scc); + match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { + self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?) + }) { + Some(region) => { + let vid = self.universal_regions.to_region_vid(region); + subst_regions.push(vid); + region + } + None => { + subst_regions.push(vid); + infcx.tcx.sess.delay_span_bug( + span, + "opaque type with non-universal region substs", + ); + infcx.tcx.lifetimes.re_static + } + } }); subst_regions.sort(); @@ -100,12 +116,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { span, ); - check_opaque_type_parameter_valid( - infcx.tcx, + ( opaque_type_key, - OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, + if check_opaque_type_parameter_valid(infcx.tcx, opaque_type_key, origin, span) { + remapped_type + } else { + infcx.tcx.ty_error() + }, ) - .then_some((opaque_type_key, remapped_type)) }) .collect() } @@ -149,9 +167,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_opaque_type_parameter_valid( tcx: TyCtxt<'_>, opaque_type_key: OpaqueTypeKey<'_>, - decl: OpaqueTypeDecl<'_>, + origin: OpaqueTyOrigin, + span: Span, ) -> bool { - match decl.origin { + match origin { // No need to check return position impl trait (RPIT) // because for type and const parameters they are correct // by construction: we convert @@ -177,7 +196,6 @@ fn check_opaque_type_parameter_valid( // Check these OpaqueTyOrigin::TyAlias => {} } - let span = decl.definition_span; let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); for (i, arg) in opaque_type_key.substs.iter().enumerate() { diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 0fa72ed8241..3856b7f4a4b 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -33,12 +33,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) -> Fallible<R> where Op: type_op::TypeOp<'tcx, Output = R>, - Canonical<'tcx, Op>: ToUniverseInfo<'tcx>, + Op::ErrorInfo: ToUniverseInfo<'tcx>, { let old_universe = self.infcx.universe(); - let TypeOpOutput { output, constraints, canonicalized_query } = - op.fully_perform(self.infcx)?; + let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; if let Some(data) = &constraints { self.push_region_constraints(locations, category, data); @@ -47,8 +46,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let universe = self.infcx.universe(); if old_universe != universe { - let universe_info = match canonicalized_query { - Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe), + let universe_info = match error_info { + Some(error_info) => error_info.to_universe_info(old_universe), None => UniverseInfo::other(), }; for u in old_universe..universe { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 2e7798beb64..0b9d0a0e922 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -267,7 +267,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { TypeOpOutput { output: self.infcx.tcx.ty_error(), constraints: None, - canonicalized_query: None, + error_info: None, } }); // Note: we need this in examples like diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index bc740de5150..83c8ecba1f1 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -147,9 +147,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Return types are a bit more complex. They may contain opaque `impl Trait` types. let mir_output_ty = body.local_decls[RETURN_PLACE].ty; let output_span = body.local_decls[RETURN_PLACE].source_info.span; - if let Err(terr) = self.eq_opaque_type_and_type( - mir_output_ty, + if let Err(terr) = self.eq_types( normalized_output_ty, + mir_output_ty, Locations::All(output_span), ConstraintCategory::BoringNoLocation, ) { @@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let user_provided_output_ty = user_provided_sig.output(); let user_provided_output_ty = self.normalize(user_provided_output_ty, Locations::All(output_span)); - if let Err(err) = self.eq_opaque_type_and_type( - mir_output_ty, + if let Err(err) = self.eq_types( user_provided_output_ty, + mir_output_ty, Locations::All(output_span), ConstraintCategory::BoringNoLocation, ) { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a7cf25d43d2..2d4bb272df5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -5,6 +5,7 @@ use std::{fmt, iter, mem}; use either::Either; +use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::vec_map::VecMap; @@ -15,8 +16,8 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, @@ -39,9 +40,11 @@ use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use rustc_const_eval::transform::{ check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression, @@ -75,7 +78,7 @@ macro_rules! span_mirbug { $context.last_span, &format!( "broken MIR in {:?} ({:?}): {}", - $context.body.source.def_id(), + $context.body().source.def_id(), $elem, format_args!($($message)*), ), @@ -199,59 +202,44 @@ pub(crate) fn type_check<'mir, 'tcx>( ); translate_outlives_facts(&mut cx); - let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types); + let opaque_type_values = + infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); opaque_type_values .into_iter() - .filter_map(|(opaque_type_key, mut decl)| { - decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + .map(|(opaque_type_key, decl)| { + cx.fully_perform_op( + Locations::All(body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.register_member_constraints( + param_env, + opaque_type_key, + decl.hidden_type.ty, + decl.hidden_type.span, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + ) + .unwrap(); + let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type.ty); trace!( "finalized opaque type {:?} to {:#?}", opaque_type_key, - decl.concrete_ty.kind() + hidden_type.kind() ); - if decl.concrete_ty.has_infer_types_or_consts() { + if hidden_type.has_infer_types_or_consts() { infcx.tcx.sess.delay_span_bug( - body.span, - &format!("could not resolve {:#?}", decl.concrete_ty.kind()), + decl.hidden_type.span, + &format!("could not resolve {:#?}", hidden_type.kind()), ); - decl.concrete_ty = infcx.tcx.ty_error(); + hidden_type = infcx.tcx.ty_error(); } - let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind() - { - *def_id == opaque_type_key.def_id - } else { - false - }; - if concrete_is_opaque { - // We're using an opaque `impl Trait` type without - // 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - debug!( - "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_type_key.def_id, - ); - None - } else { - Some((opaque_type_key, decl)) - } + (opaque_type_key, (hidden_type, decl.hidden_type.span, decl.origin)) }) .collect() }, @@ -283,7 +271,7 @@ fn type_check_internal<'a, 'tcx, R>( borrowck_context, ); let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, body, promoted); + let mut verifier = TypeVerifier::new(&mut checker, promoted); verifier.visit_body(&body); verifier.errors_reported }; @@ -340,7 +328,6 @@ enum FieldAccessError { /// is a problem. struct TypeVerifier<'a, 'b, 'tcx> { cx: &'a mut TypeChecker<'b, 'tcx>, - body: &'b Body<'tcx>, promoted: &'b IndexVec<Promoted, Body<'tcx>>, last_span: Span, errors_reported: bool, @@ -476,7 +463,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - let rval_ty = rvalue.ty(self.body, self.tcx()); + let rval_ty = rvalue.ty(self.body(), self.tcx()); self.sanitize_type(rvalue, rval_ty); } @@ -535,10 +522,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn new( cx: &'a mut TypeChecker<'b, 'tcx>, - body: &'b Body<'tcx>, promoted: &'b IndexVec<Promoted, Body<'tcx>>, ) -> Self { - TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false } + TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false } + } + + fn body(&self) -> &Body<'tcx> { + self.cx.body } fn tcx(&self) -> TyCtxt<'tcx> { @@ -563,7 +553,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); - let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); + let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty); for elem in place.projection.iter() { if place_ty.variant_index.is_none() { @@ -608,7 +598,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_body = mem::replace(&mut self.body, promoted_body); + let parent_body = mem::replace(&mut self.cx.body, promoted_body); // Use new sets of constraints and closure bounds so that we can // modify their locations. @@ -644,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { self.cx.typeck_mir(promoted_body); } - self.body = parent_body; + self.cx.body = parent_body; // Merge the outlives constraints back in, at the given location. swap_constraints(self); @@ -706,7 +696,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { })) } ProjectionElem::Index(i) => { - let index_ty = Place::from(i).ty(self.body, tcx).ty; + let index_ty = Place::from(i).ty(self.body(), tcx).ty; if index_ty != tcx.types.usize { PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) } else { @@ -915,7 +905,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>, + crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>, } /// A collection of region constraints that must be satisfied for the @@ -1065,17 +1055,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { checker } + fn body(&self) -> &Body<'tcx> { + self.body + } + fn unsized_feature_enabled(&self) -> bool { let features = self.tcx().features(); features.unsized_locals || features.unsized_fn_params } /// Equate the inferred type and the annotated type for user type annotations + #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { - debug!( - "check_user_type_annotations: user_type_annotations={:?}", - self.user_type_annotations - ); + debug!(?self.user_type_annotations); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); @@ -1216,131 +1208,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ok(()) } - /// Equates a type `anon_ty` that may contain opaque types whose - /// values are to be inferred by the MIR. - /// - /// The type `revealed_ty` contains the same type as `anon_ty`, but with the - /// hidden types for impl traits revealed. - /// - /// # Example - /// - /// Consider a piece of code like - /// - /// ```rust - /// type Foo<U> = impl Debug; - /// - /// fn foo<T: Debug>(t: T) -> Box<Foo<T>> { - /// Box::new((t, 22_u32)) - /// } - /// ``` - /// - /// Here, the function signature would be something like - /// `fn(T) -> Box<impl Debug>`. The MIR return slot would have - /// the type with the opaque type revealed, so `Box<(T, u32)>`. - /// - /// In terms of our function parameters: - /// - /// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type - /// scoped to this function (note that it is parameterized by the - /// generics of `foo`). Note that `anon_ty` is not just the opaque type, - /// but the entire return type (which may contain opaque types within it). - /// * `revealed_ty` would be `Box<(T, u32)>` - #[instrument(skip(self), level = "debug")] - fn eq_opaque_type_and_type( - &mut self, - revealed_ty: Ty<'tcx>, - anon_ty: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - // Fast path for the common case. - if !anon_ty.has_opaque_types() { - if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { - span_mirbug!( - self, - locations, - "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", - revealed_ty, - anon_ty, - terr - ); - } - return Ok(()); - } - - let param_env = self.param_env; - let body = self.body; - let mir_def_id = body.source.def_id().expect_local(); - - debug!(?mir_def_id); - self.fully_perform_op( - locations, - category, - CustomTypeOp::new( - |infcx| { - let mut obligations = ObligationAccumulator::default(); - - let dummy_body_id = hir::CRATE_HIR_ID; - - // Replace the opaque types defined by this function with - // inference variables, creating a map. In our example above, - // this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type) - // to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`. - // (Note that the key of the map is both the def-id of `Foo` along with - // any generic parameters.) - let output_ty = obligations.add(infcx.instantiate_opaque_types( - dummy_body_id, - param_env, - anon_ty, - locations.span(body), - )); - debug!(?output_ty, ?revealed_ty); - - // Make sure that the inferred types are well-formed. I'm - // not entirely sure this is needed (the HIR type check - // didn't do this) but it seems sensible to prevent opaque - // types hiding ill-formed types. - obligations.obligations.push(traits::Obligation::new( - ObligationCause::dummy(), - param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into())) - .to_predicate(infcx.tcx), - )); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(output_ty, revealed_ty)?, - ); - - debug!("equated"); - - Ok(InferOk { value: (), obligations: obligations.into_vec() }) - }, - || "input_output".to_string(), - ), - )?; - - // Finally, if we instantiated the anon types successfully, we - // have to solve any bounds (e.g., `-> impl Iterator` needs to - // prove that `T: Iterator` where `T` is the type we - // instantiated it with). - let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone(); - for (opaque_type_key, opaque_decl) in opaque_type_map { - self.fully_perform_op( - locations, - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.constrain_opaque_type(opaque_type_key, &opaque_decl); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - )?; - } - Ok(()) - } - fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -2772,19 +2639,31 @@ impl NormalizeLocation for Location { } } -#[derive(Debug, Default)] -struct ObligationAccumulator<'tcx> { - obligations: PredicateObligations<'tcx>, +/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s, +/// this is not canonicalized - it directly affects the main `InferCtxt` +/// that we use during MIR borrowchecking. +#[derive(Debug)] +pub(super) struct InstantiateOpaqueType<'tcx> { + pub base_universe: Option<ty::UniverseIndex>, + pub region_constraints: Option<RegionConstraintData<'tcx>>, + pub obligation: PredicateObligation<'tcx>, } -impl<'tcx> ObligationAccumulator<'tcx> { - fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T { - let InferOk { value, obligations } = value; - self.obligations.extend(obligations); - value - } - - fn into_vec(self) -> PredicateObligations<'tcx> { - self.obligations +impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { + type Output = (); + /// We use this type itself to store the information used + /// when reporting errors. Since this is not a query, we don't + /// re-run anything during error reporting - we just use the information + /// we saved to help extract an error from the already-existing region + /// constraints in our `InferCtxt` + type ErrorInfo = InstantiateOpaqueType<'tcx>; + + fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + let (mut output, region_constraints) = scrape_region_constraints(infcx, || { + Ok(InferOk { value: (), obligations: vec![self.obligation.clone()] }) + })?; + self.region_constraints = Some(region_constraints); + output.error_info = Some(self); + Ok(output) } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 590a7a91641..a032095bf98 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,13 +1,15 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Const, Ty}; +use rustc_span::Span; use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; -use crate::type_check::{Locations, TypeChecker}; +use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: @@ -63,6 +65,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { } impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.locations.span(self.type_checker.body) + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.type_checker.param_env } @@ -117,6 +123,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> // We don't have to worry about the equality of consts during borrow checking // as consts always have a static lifetime. + // FIXME(oli-obk): is this really true? We can at least have HKL and with + // inline consts we may have further lifetimes that may be unsound to treat as + // 'static. fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {} fn normalization() -> NormalizationStrategy { @@ -126,4 +135,30 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> fn forbid_inference_vars() -> bool { true } + + fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) { + let param_env = self.param_env(); + let span = self.span(); + let def_id = self.type_checker.body.source.def_id().expect_local(); + let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id); + let cause = ObligationCause::misc(span, body_id); + self.type_checker + .fully_perform_op( + self.locations, + self.category, + InstantiateOpaqueType { + obligation: self.type_checker.infcx.opaque_ty_obligation( + a, + b, + a_is_expected, + param_env, + cause, + ), + // These fields are filled in during exectuion of the operation + base_universe: None, + region_constraints: None, + }, + ) + .unwrap(); + } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 478dbe31fba..e9c64049817 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -725,6 +725,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin)) } + #[instrument(level = "debug", skip(self, indices))] fn replace_bound_regions_with_nll_infer_vars<T>( &self, origin: NllRegionVariableOrigin, @@ -735,22 +736,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { where T: TypeFoldable<'tcx>, { - debug!( - "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})", - value, all_outlive_scope, - ); let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { - debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br); + debug!(?br); let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope.to_def_id(), bound_region: br.kind, })); let region_vid = self.next_nll_region_var(origin); indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); - debug!( - "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}", - liberated_region, region_vid - ); + debug!(?liberated_region, ?region_vid); region_vid }); value @@ -765,6 +759,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// entries for them and store them in the indices map. This code iterates over the complete /// set of late-bound regions and checks for any that we have not yet seen, adding them to the /// inputs vector. + #[instrument(skip(self, indices))] fn replace_late_bound_regions_with_nll_infer_vars( &self, mir_def_id: LocalDefId, @@ -776,6 +771,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } }); |
