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 | |
| 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')
77 files changed, 1327 insertions, 875 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()); } }); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 223b3ad0cf9..8790baa010c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; +use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; @@ -47,7 +47,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { location: Location, ) -> bool { let ty = ccx.body.local_decls[local].ty; - if !NeedsDrop::in_any_value_of_ty(ccx, ty) { + // Peeking into opaque types causes cycles if the current function declares said opaque + // type. Thus we avoid short circuiting on the type and instead run the more expensive + // analysis that looks at the actual usage within this function + if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) { return false; } @@ -101,7 +104,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { location: Location, ) -> bool { let ty = ccx.body.local_decls[local].ty; - if !HasMutInterior::in_any_value_of_ty(ccx, ty) { + // Peeking into opaque types causes cycles if the current function declares said opaque + // type. Thus we avoid short circuiting on the type and instead run the more expensive + // analysis that looks at the actual usage within this function + if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) { return false; } @@ -148,7 +154,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { // If we know that all values of the return type are structurally matchable, there's no // need to run dataflow. - _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false, + // Opaque types do not participate in const generics or pattern matching, so we can safely count them out. + _ if ccx.body.return_ty().has_opaque_types() + || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => + { + false + } hir::ConstContext::Const | hir::ConstContext::Static(_) => { let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index deeca78b75d..e68e1a055d9 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -79,7 +79,6 @@ pub fn equal_up_to_regions<'tcx>( } // Normalize lifetimes away on both sides, then compare. - let param_env = param_env.with_reveal_all_normalized(tcx); let normalize = |ty: Ty<'tcx>| { tcx.normalize_erasing_regions( param_env, @@ -171,9 +170,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } // Normalize projections and things like that. - // FIXME: We need to reveal_all, as some optimizations change types in ways - // that require unfolding opaque types. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); + let param_env = self.param_env; let src = self.tcx.normalize_erasing_regions(param_env, src); let dest = self.tcx.normalize_erasing_regions(param_env, dest); diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index cc7ec9432fa..2f4b3844430 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -30,6 +30,11 @@ where } } + /// Removes the entry from the map and returns the removed value + pub fn remove(&mut self, k: &K) -> Option<V> { + self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1) + } + /// Gets a reference to the value in the entry. pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where @@ -39,6 +44,15 @@ where self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) } + /// Gets a mutable reference to the value in the entry. + pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow<Q>, + Q: Eq, + { + self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1) + } + /// Returns the any value corresponding to the supplied predicate filter. /// /// The supplied predicate will be applied to each (key, value) pair and it will return a @@ -58,7 +72,7 @@ where // This should return just one element, otherwise it's a bug assert!( filter.next().is_none(), - "Collection {:?} should have just one matching element", + "Collection {:#?} should have just one matching element", self ); Some(value) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index ff8082840e1..71ee4f1e76d 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -34,6 +34,12 @@ pub struct At<'a, 'tcx> { pub infcx: &'a InferCtxt<'a, 'tcx>, pub cause: &'a ObligationCause<'tcx>, pub param_env: ty::ParamEnv<'tcx>, + /// Whether we should define opaque types + /// or just treat them opaquely. + /// Currently only used to prevent predicate + /// matching from matching anything against opaque + /// types. + pub define_opaque_types: bool, } pub struct Trace<'a, 'tcx> { @@ -49,7 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> At<'a, 'tcx> { - At { infcx: self, cause, param_env } + At { infcx: self, cause, param_env, define_opaque_types: true } } /// Forks the inference context, creating a new inference context with the same inference @@ -59,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Self { tcx: self.tcx.clone(), defining_use_anchor: self.defining_use_anchor.clone(), + reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(), in_progress_typeck_results: self.in_progress_typeck_results.clone(), inner: self.inner.clone(), skip_leak_check: self.skip_leak_check.clone(), @@ -86,6 +93,10 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { } impl<'a, 'tcx> At<'a, 'tcx> { + pub fn define_opaque_types(self, define_opaque_types: bool) -> Self { + Self { define_opaque_types, ..self } + } + /// Hacky routine for equating two impl headers in coherence. pub fn eq_impl_headers( self, @@ -216,7 +227,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); + let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); fields .sub(a_is_expected) .relate(a, b) @@ -233,7 +244,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); + let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); fields .equate(a_is_expected) .relate(a, b) @@ -248,7 +259,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); + let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); fields .lub(a_is_expected) .relate(a, b) @@ -263,7 +274,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { { let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); + let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types); fields .glb(a_is_expected) .relate(a, b) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 48d5c21f9eb..20f65962db4 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -26,6 +26,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt}; +use rustc_span::Span; use std::fmt::Debug; use std::iter; @@ -89,6 +90,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, // Ambiguities are OK! + opaque_types: vec![], value: answer, }) } @@ -133,14 +135,27 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let certainty = if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; + let opaque_types = self.take_opaque_types_for_query_response(); + Ok(QueryResponse { var_values: inference_vars, region_constraints, certainty, value: answer, + opaque_types, }) } + fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + self.inner + .borrow_mut() + .opaque_type_storage + .take_opaque_types() + .into_iter() + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty)) + .collect() + } + /// Given the (canonicalized) result to a canonical query, /// instantiates the result so it can be used, plugging in the /// values from the canonical query. (Note that the result may @@ -223,13 +238,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { where R: Debug + TypeFoldable<'tcx>, { - let result_subst = - self.query_response_substitution_guess(cause, original_values, query_response); + let InferOk { value: result_subst, mut obligations } = self + .query_response_substitution_guess(cause, param_env, original_values, query_response)?; // Compute `QueryOutlivesConstraint` values that unify each of // the original values `v_o` that was canonicalized into a // variable... - let mut obligations = vec![]; for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. @@ -343,20 +357,25 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { original_values, query_response, ); - let result_subst = - self.query_response_substitution_guess(cause, original_values, query_response); + let mut value = self.query_response_substitution_guess( + cause, + param_env, + original_values, + query_response, + )?; - let obligations = self - .unify_query_response_substitution_guess( + value.obligations.extend( + self.unify_query_response_substitution_guess( cause, param_env, original_values, - &result_subst, + &value.value, query_response, )? - .into_obligations(); + .into_obligations(), + ); - Ok(InferOk { value: result_subst, obligations }) + Ok(value) } /// Given the original values and the (canonicalized) result from @@ -371,9 +390,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { fn query_response_substitution_guess<R>( &self, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, original_values: &OriginalQueryValues<'tcx>, query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - ) -> CanonicalVarValues<'tcx> + ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> where R: Debug + TypeFoldable<'tcx>, { @@ -473,7 +493,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { .collect(), }; - result_subst + let mut obligations = vec![]; + + // Carry all newly resolved opaque types to the caller's scope + for &(a, b) in &query_response.value.opaque_types { + let a = substitute_value(self.tcx, &result_subst, a); + let b = substitute_value(self.tcx, &result_subst, b); + obligations.extend(self.handle_opaque_type(a, b, cause, param_env)?.obligations); + } + + Ok(InferOk { value: result_subst, obligations }) } /// Given a "guess" at the values for the canonical variables in @@ -629,6 +658,10 @@ struct QueryTypeRelatingDelegate<'a, 'tcx> { } impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { + fn span(&self) -> Span { + self.cause.span + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -684,4 +717,14 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { fn forbid_inference_vars() -> bool { true } + + fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) { + self.obligations.push(self.infcx.opaque_ty_obligation( + a, + b, + a_is_expected, + self.param_env, + self.cause.clone(), + )); + } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index e1b5d04ccfb..41995ca509e 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -51,6 +51,12 @@ pub struct CombineFields<'infcx, 'tcx> { pub cause: Option<ty::relate::Cause>, pub param_env: ty::ParamEnv<'tcx>, pub obligations: PredicateObligations<'tcx>, + /// Whether we should define opaque types + /// or just treat them opaquely. + /// Currently only used to prevent predicate + /// matching from matching anything against opaque + /// types. + pub define_opaque_types: bool, } #[derive(Copy, Clone, Debug)] @@ -322,6 +328,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { /// will first instantiate `b_vid` with a *generalized* version /// of `a_ty`. Generalization introduces other inference /// variables wherever subtyping could occur. + #[instrument(skip(self), level = "debug")] pub fn instantiate( &mut self, a_ty: Ty<'tcx>, @@ -334,8 +341,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // Get the actual variable that b_vid has been inferred to debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); - // Generalize type of `a_ty` appropriately depending on the // direction. As an example, assume: // @@ -348,10 +353,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // variables. (Down below, we will relate `a_ty <: b_ty`, // adding constraints like `'x: '?2` and `?1 <: ?3`.) let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; - debug!( - "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", - a_ty, dir, b_vid, b_ty - ); + debug!(?b_ty); self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); if needs_wf { @@ -392,13 +394,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { /// Preconditions: /// /// - `for_vid` is a "root vid" + #[instrument(skip(self), level = "trace")] fn generalize( &self, ty: Ty<'tcx>, for_vid: ty::TyVid, dir: RelationDir, ) -> RelateResult<'tcx, Generalization<'tcx>> { - debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir); // Determine the ambient variance within which `ty` appears. // The surrounding equation is: // @@ -412,7 +414,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { RelationDir::SupertypeOf => ty::Contravariant, }; - debug!("generalize: ambient_variance = {:?}", ambient_variance); + trace!(?ambient_variance); let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { v @ TypeVariableValue::Known { .. } => { @@ -421,8 +423,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { TypeVariableValue::Unknown { universe } => universe, }; - debug!("generalize: for_universe = {:?}", for_universe); - debug!("generalize: trace = {:?}", self.trace); + trace!(?for_universe); + trace!(?self.trace); let mut generalize = Generalizer { infcx: self.infcx, @@ -439,12 +441,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let ty = match generalize.relate(ty, ty) { Ok(ty) => ty, Err(e) => { - debug!("generalize: failure {:?}", e); + debug!(?e, "failure"); return Err(e); } }; let needs_wf = generalize.needs_wf; - debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf); + trace!(?ty, ?needs_wf, "success"); Ok(Generalization { ty, needs_wf }) } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 5ac9ad6850c..c1c075e9a4c 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -66,18 +66,19 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.relate(a, b) } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } + trace!(a = ?a.kind(), b = ?b.kind()); + let infcx = self.fields.infcx; + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); - debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); - match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); @@ -91,6 +92,21 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; } + (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + self.fields.infcx.super_combine_tys(self, a, b)?; + } + (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) + if self.fields.define_opaque_types && did.is_local() => + { + self.fields.obligations.push(infcx.opaque_ty_obligation( + a, + b, + self.a_is_expected(), + self.param_env(), + self.fields.trace.cause.clone(), + )); + } + _ => { self.fields.infcx.super_combine_tys(self, a, b)?; } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index e98f33ea86e..0d38b94965a 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -6,7 +6,7 @@ use super::InferCtxt; use super::Subtype; use crate::infer::combine::ConstEquateRelation; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, PredicateObligation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -113,12 +113,20 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, &self.fields.trace.cause } + fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) { + self.fields.obligations.extend(obligations) + } + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(v, a)?; sub.relate(v, b)?; Ok(()) } + + fn define_opaque_types(&self) -> bool { + self.fields.define_opaque_types + } } impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 32affd6a14e..f4c749492d3 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -20,7 +20,7 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::InferCtxt; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, PredicateObligation}; use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty}; @@ -35,6 +35,10 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> { fn cause(&self) -> &ObligationCause<'tcx>; + fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>); + + fn define_opaque_types(&self) -> bool; + // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. // @@ -45,6 +49,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> { } /// Relates two types using a given lattice. +#[instrument(skip(this), level = "debug")] pub fn super_lattice_tys<'a, 'tcx: 'a, L>( this: &mut L, a: Ty<'tcx>, @@ -53,15 +58,17 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>( where L: LatticeDir<'a, 'tcx>, { - debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b); + debug!("{}", this.tag()); if a == b { return Ok(a); } let infcx = this.infcx(); + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); + match (a.kind(), b.kind()) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to @@ -98,6 +105,22 @@ where Ok(v) } + (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + infcx.super_combine_tys(this, a, b) + } + (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) + if this.define_opaque_types() && did.is_local() => + { + this.add_obligations(vec![infcx.opaque_ty_obligation( + a, + b, + this.a_is_expected(), + this.param_env(), + this.cause().clone(), + )]); + Ok(a) + } + _ => infcx.super_combine_tys(this, a, b), } } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index bc85a4ac609..498c1e907c4 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -6,7 +6,7 @@ use super::InferCtxt; use super::Subtype; use crate::infer::combine::ConstEquateRelation; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, PredicateObligation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -119,10 +119,18 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, &self.fields.trace.cause } + fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) { + self.fields.obligations.extend(obligations) + } + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); sub.relate(a, v)?; sub.relate(b, v)?; Ok(()) } + + fn define_opaque_types(&self) -> bool { + self.fields.define_opaque_types + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 83ba9c96978..63ffb5bde38 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -5,7 +5,7 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; -use self::opaque_types::OpaqueTypeMap; +use self::opaque_types::OpaqueTypeStorage; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; @@ -191,18 +191,8 @@ pub struct InferCtxtInner<'tcx> { undo_log: InferCtxtUndoLogs<'tcx>, - // Opaque types found in explicit return types and their - // associated fresh inference variable. Writeback resolves these - // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl outside of type inference. - pub opaque_types: OpaqueTypeMap<'tcx>, - - /// A map from inference variables created from opaque - /// type instantiations (`ty::Infer`) to the actual opaque - /// type (`ty::Opaque`). Used during fallback to map unconstrained - /// opaque type inference variables to their corresponding - /// opaque type. - pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>, + /// Caches for opaque type inference. + pub opaque_type_storage: OpaqueTypeStorage<'tcx>, } impl<'tcx> InferCtxtInner<'tcx> { @@ -216,8 +206,7 @@ impl<'tcx> InferCtxtInner<'tcx> { float_unification_storage: ut::UnificationTableStorage::new(), region_constraint_storage: Some(RegionConstraintStorage::new()), region_obligations: vec![], - opaque_types: Default::default(), - opaque_types_vars: Default::default(), + opaque_type_storage: Default::default(), } } @@ -237,6 +226,11 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] + pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { + self.opaque_type_storage.with_log(&mut self.undo_log) + } + + #[inline] fn int_unification_table( &mut self, ) -> ut::UnificationTable< @@ -296,6 +290,10 @@ pub struct InferCtxt<'a, 'tcx> { /// to the outside until the end up in an `InferCtxt` for typeck or borrowck. pub defining_use_anchor: Option<LocalDefId>, + /// Used by WF-checking to not have to figure out hidden types itself, but + /// to just invoke type_of to get the already computed hidden type from typeck. + pub reveal_defining_opaque_types: bool, + /// During type-checking/inference of a body, `in_progress_typeck_results` /// contains a reference to the typeck results being built up, which are /// used for reading closure kinds/signatures as they are inferred, @@ -571,6 +569,7 @@ pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>, defining_use_anchor: Option<LocalDefId>, + reveal_defining_opaque_types: bool, } pub trait TyCtxtInferExt<'tcx> { @@ -579,7 +578,12 @@ pub trait TyCtxtInferExt<'tcx> { impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { - InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None } + InferCtxtBuilder { + tcx: self, + defining_use_anchor: None, + fresh_typeck_results: None, + reveal_defining_opaque_types: false, + } } } @@ -603,6 +607,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + /// WF-checking doesn't need to recompute opaque types and can instead use + /// the type_of query to get them from typeck. + pub fn reveal_defining_opaque_types(mut self) -> Self { + self.reveal_defining_opaque_types = true; + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -627,11 +638,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self; + let InferCtxtBuilder { + tcx, + defining_use_anchor, + reveal_defining_opaque_types, + ref fresh_typeck_results, + } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { tcx, defining_use_anchor, + reveal_defining_opaque_types, in_progress_typeck_results, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), @@ -766,6 +783,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, + define_opaque_types: bool, ) -> CombineFields<'a, 'tcx> { CombineFields { infcx: self, @@ -773,6 +791,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: None, param_env, obligations: PredicateObligations::new(), + define_opaque_types, } } @@ -1088,12 +1107,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } + pub fn next_ty_var_id_in_universe( + &self, + origin: TypeVariableOrigin, + universe: ty::UniverseIndex, + ) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(universe, origin) + } + pub fn next_ty_var_in_universe( &self, origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); + let vid = self.next_ty_var_id_in_universe(origin, universe); self.tcx.mk_ty_var(vid) } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 69db6509b79..2c7f3adafdc 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -24,11 +24,13 @@ use crate::infer::combine::ConstEquateRelation; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; +use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_span::Span; use std::fmt::Debug; use std::ops::ControlFlow; @@ -75,6 +77,7 @@ where pub trait TypeRelatingDelegate<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx>; + fn span(&self) -> Span; /// Push a constraint `sup: sub` -- this constraint must be /// satisfied for the two types to be related. `sub` and `sup` may @@ -88,6 +91,7 @@ pub trait TypeRelatingDelegate<'tcx> { ); fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); + fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool); /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -277,7 +281,6 @@ where projection_ty: ty::ProjectionTy<'tcx>, value_ty: Ty<'tcx>, ) -> Ty<'tcx> { - use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::DUMMY_SP; match *value_ty.kind() { @@ -286,6 +289,8 @@ where kind: TypeVariableOriginKind::MiscVariable, span: DUMMY_SP, }); + // FIXME(lazy-normalization): This will always ICE, because the recursive + // call will end up in the _ arm below. self.relate_projection_ty(projection_ty, var); self.relate_projection_ty(other_projection_ty, var); var @@ -531,6 +536,8 @@ where #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let infcx = self.infcx; + let a = self.infcx.shallow_resolve(a); if !D::forbid_inference_vars() { @@ -559,6 +566,35 @@ where (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), + (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + self.infcx.super_combine_tys(self, a, b) + } + (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => { + let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; + let mut generalize = |ty, ty_is_expected| { + let var = infcx.next_ty_var_id_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.delegate.span(), + }, + ty::UniverseIndex::ROOT, + ); + if ty_is_expected { + self.relate_ty_var((ty, var)) + } else { + self.relate_ty_var((var, ty)) + } + }; + let (a, b) = match (a.kind(), b.kind()) { + (&ty::Opaque(..), _) => (a, generalize(b, false)?), + (_, &ty::Opaque(..)) => (generalize(a, true)?, b), + _ => unreachable!(), + }; + self.delegate.register_opaque_type(a, b, true); + trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); + Ok(a) + } + (&ty::Projection(projection_ty), _) if D::normalization() == NormalizationStrategy::Lazy => { diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index e7dca94806c..46420fbe0c3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,10 +1,11 @@ -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk}; -use crate::traits; +use crate::traits::{self, PredicateObligation}; +use hir::def_id::{DefId, LocalDefId}; +use hir::OpaqueTyOrigin; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor}; @@ -14,14 +15,28 @@ use std::ops::ControlFlow; pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; +mod table; + +pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; + +use super::InferResult; + /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that /// appear in the return type). -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct OpaqueTypeDecl<'tcx> { - /// The opaque type (`ty::Opaque`) for this declaration. - pub opaque_type: Ty<'tcx>, + /// The hidden types that have been inferred for this opaque type. + /// There can be multiple, but they are all `lub`ed together at the end + /// to obtain the canonical hidden type. + pub hidden_type: OpaqueHiddenType<'tcx>, + + /// The origin of the opaque type. + pub origin: hir::OpaqueTyOrigin, +} +#[derive(Copy, Clone, Debug, TypeFoldable)] +pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So /// for example: /// @@ -35,7 +50,7 @@ pub struct OpaqueTypeDecl<'tcx> { /// In cases where the fn returns `(impl Trait, impl Trait)` or /// other such combinations, the result is currently /// over-approximated, but better than nothing. - pub definition_span: Span, + pub span: Span, /// The type variable that represents the value of the opaque type /// that we require. In other words, after we compile this function, @@ -49,54 +64,132 @@ pub struct OpaqueTypeDecl<'tcx> { /// those that are arguments to `Foo` in the constraint above. (In /// other words, `?C` should not include `'b`, even though it's a /// lifetime parameter on `foo`.) - pub concrete_ty: Ty<'tcx>, - - /// The origin of the opaque type. - pub origin: hir::OpaqueTyOrigin, + pub ty: Ty<'tcx>, } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Replaces all opaque types in `value` with fresh inference variables - /// and creates appropriate obligations. For example, given the input: - /// - /// impl Iterator<Item = impl Debug> - /// - /// this method would create two type variables, `?0` and `?1`. It would - /// return the type `?0` but also the obligations: - /// - /// ?0: Iterator<Item = ?1> - /// ?1: Debug - /// - /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to - /// info about the `impl Iterator<..>` type and `?1` to info about - /// the `impl Debug` type. - /// - /// # Parameters - /// - /// - `parent_def_id` -- the `DefId` of the function in which the opaque type - /// is defined - /// - `body_id` -- the body-id with which the resulting obligations should - /// be associated - /// - `param_env` -- the in-scope parameter environment to be used for - /// obligations - /// - `value` -- the value within which we are instantiating opaque types - /// - `value_span` -- the span where the value came from, used in error reporting - pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>( + pub fn handle_opaque_type( &self, - body_id: hir::HirId, + a: Ty<'tcx>, + b: Ty<'tcx>, + cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: T, - value_span: Span, - ) -> InferOk<'tcx, T> { - debug!( - "instantiate_opaque_types(value={:?}, body_id={:?}, \ - param_env={:?}, value_span={:?})", - value, body_id, param_env, value_span, - ); - let mut instantiator = - Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] }; - let value = instantiator.instantiate_opaque_types_in_map(value); - InferOk { value, obligations: instantiator.obligations } + ) -> InferResult<'tcx, ()> { + if a.references_error() || b.references_error() { + return Ok(InferOk { value: (), obligations: vec![] }); + } + if self.defining_use_anchor.is_some() { + let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { + ty::Opaque(def_id, substs) => { + if let ty::Opaque(did2, _) = *b.kind() { + // We could accept this, but there are various ways to handle this situation, and we don't + // want to make a decision on it right now. Likely this case is so super rare anyway, that + // no one encounters it in practice. + // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, + // where it is of no concern, so we only check for TAITs. + if let Some(OpaqueTyOrigin::TyAlias) = + self.opaque_type_origin(did2, cause.span) + { + self.tcx + .sess + .struct_span_err( + cause.span, + "opaque type's hidden type cannot be another opaque type from the same scope", + ) + .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope") + .span_note( + self.tcx.def_span(def_id), + "opaque type whose hidden type is being assigned", + ) + .span_note( + self.tcx.def_span(did2), + "opaque type being used as hidden type", + ) + .emit(); + } + } + Some(self.register_hidden_type( + OpaqueTypeKey { def_id, substs }, + cause.clone(), + param_env, + b, + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references an + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + self.opaque_type_origin(def_id, cause.span)?, + )) + } + _ => None, + }; + if let Some(res) = process(a, b) { + res + } else if let Some(res) = process(b, a) { + res + } else { + // Rerun equality check, but this time error out due to + // different types. + match self.at(cause, param_env).define_opaque_types(false).eq(a, b) { + Ok(_) => span_bug!( + cause.span, + "opaque types are never equal to anything but themselves: {:#?}", + (a, b) + ), + Err(e) => Err(e), + } + } + } else { + let (opaque_type, hidden_ty) = match (a.kind(), b.kind()) { + (ty::Opaque(..), _) => (a, b), + (_, ty::Opaque(..)) => (b, a), + types => span_bug!( + cause.span, + "opaque type obligations only work for opaque types: {:#?}", + types + ), + }; + let key = opaque_type.expect_opaque_type(); + let origin = self.opaque_ty_origin_unchecked(key.def_id, cause.span); + let prev = self.inner.borrow_mut().opaque_types().register( + key, + OpaqueHiddenType { ty: hidden_ty, span: cause.span }, + origin, + ); + match prev { + Some(prev) => self.at(cause, param_env).eq(prev, hidden_ty), + None => Ok(InferOk { value: (), obligations: vec![] }), + } + } } /// Given the map `opaque_types` containing the opaque @@ -231,51 +324,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// but this is not necessary, because the opaque type we /// create will be allowed to reference `T`. So we only generate a /// constraint that `'0: 'a`. - /// - /// # The `free_region_relations` parameter - /// - /// The `free_region_relations` argument is used to find the - /// "minimum" of the regions supplied to a given opaque type. - /// It must be a relation that can answer whether `'a <= 'b`, - /// where `'a` and `'b` are regions that appear in the "substs" - /// for the opaque type references (the `<'a>` in `Foo1<'a>`). - /// - /// Note that we do not impose the constraints based on the - /// generic regions from the `Foo1` definition (e.g., `'x`). This - /// is because the constraints we are imposing here is basically - /// the concern of the one generating the constraining type C1, - /// which is the current function. It also means that we can - /// take "implied bounds" into account in some cases: - /// - /// ```text - /// trait SomeTrait<'a, 'b> { } - /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. } - /// ``` - /// - /// Here, the fact that `'b: 'a` is known only because of the - /// implied bounds from the `&'a &'b u32` parameter, and is not - /// "inherent" to the opaque type definition. - /// - /// # Parameters - /// - /// - `opaque_types` -- the map produced by `instantiate_opaque_types` - /// - `free_region_relations` -- something that can be used to relate - /// the free regions (`'a`) that appear in the impl trait. #[instrument(level = "debug", skip(self))] - pub fn constrain_opaque_type( + pub fn register_member_constraints( &self, + param_env: ty::ParamEnv<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, - opaque_defn: &OpaqueTypeDecl<'tcx>, + concrete_ty: Ty<'tcx>, + span: Span, ) { let def_id = opaque_type_key.def_id; let tcx = self.tcx; - let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); + let concrete_ty = self.resolve_vars_if_possible(concrete_ty); debug!(?concrete_ty); - let first_own_region = match opaque_defn.origin { + let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) { hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { // We lower // @@ -319,7 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { op: |r| { self.member_constraint( opaque_type_key.def_id, - opaque_defn.definition_span, + span, concrete_ty, r, &choice_regions, @@ -328,15 +393,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }); } - fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> { - let tcx = self.tcx; - let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + pub fn opaque_ty_obligation( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + a_is_expected: bool, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + ) -> PredicateObligation<'tcx> { + let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; + PredicateObligation::new( + cause, + param_env, + self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::OpaqueType(a, b))), + ) + } + + #[instrument(skip(self), level = "trace")] + pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> { + let def_id = opaque_def_id.as_local()?; + let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = self.defining_use_anchor?; - let item_kind = &tcx.hir().expect_item(def_id).kind; + let item_kind = &self.tcx.hir().expect_item(def_id).kind; + let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else { span_bug!( - tcx.def_span(def_id), - "weird opaque type: {:#?}", + span, + "weird opaque type: {:#?}, {:#?}", + opaque_def_id, item_kind ) }; @@ -347,11 +431,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, // Named `type Foo = impl Bar;` hir::OpaqueTyOrigin::TyAlias => { - may_define_opaque_type(tcx, parent_def_id, opaque_hir_id) + may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) } }; + trace!(?origin); in_definition_scope.then_some(*origin) } + + #[instrument(skip(self), level = "trace")] + fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin { + let def_id = opaque_def_id.as_local().unwrap(); + let origin = match self.tcx.hir().expect_item(def_id).kind { + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, + ref itemkind => { + span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind) + } + }; + trace!(?origin); + origin + } + + pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> { + self.inner.borrow().opaque_type_storage.opaque_types() + } } // Visitor that requires that (almost) all regions in the type visited outlive @@ -426,180 +528,93 @@ where } } -struct Instantiator<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value_span: Span, - obligations: Vec<traits::PredicateObligation<'tcx>>, +pub enum UseKind { + DefiningUse, + OpaqueUse, } -impl<'a, 'tcx> Instantiator<'a, 'tcx> { - fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { - let tcx = self.infcx.tcx; - value.fold_with(&mut BottomUpFolder { - tcx, - ty_op: |ty| { - if ty.references_error() { - return tcx.ty_error(); - } else if let ty::Opaque(def_id, substs) = ty.kind() { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references an - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - if let Some(def_id) = def_id.as_local() { - if let Some(origin) = self.infcx.opaque_type_origin(def_id) { - let opaque_type_key = - OpaqueTypeKey { def_id: def_id.to_def_id(), substs }; - return self.fold_opaque_ty(ty, opaque_type_key, origin); - } - - debug!( - "instantiate_opaque_types_in_map: \ - encountered opaque outside its definition scope \ - def_id={:?}", - def_id, - ); - } - } - - ty - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }) +impl UseKind { + pub fn is_defining(self) -> bool { + match self { + UseKind::DefiningUse => true, + UseKind::OpaqueUse => false, + } } +} +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] - fn fold_opaque_ty( - &mut self, - ty: Ty<'tcx>, + fn register_hidden_type( + &self, opaque_type_key: OpaqueTypeKey<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, origin: hir::OpaqueTyOrigin, - ) -> Ty<'tcx> { - let infcx = self.infcx; - let tcx = infcx.tcx; + ) -> InferResult<'tcx, ()> { + let tcx = self.tcx; let OpaqueTypeKey { def_id, substs } = opaque_type_key; - // Use the same type variable if the exact same opaque type appears more - // than once in the return type (e.g., if it's passed to a type alias). - if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) { - debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind()); - return opaque_defn.concrete_ty; - } - - let ty_var = infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: self.value_span, - }); - // Ideally, we'd get the span where *this specific `ty` came // from*, but right now we just use the span from the overall // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. - let definition_span = self.value_span; + let span = cause.span; - { - let mut infcx = self.infcx.inner.borrow_mut(); - infcx.opaque_types.insert( - OpaqueTypeKey { def_id, substs }, - OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin }, - ); - infcx.opaque_types_vars.insert(ty_var, ty); + let mut obligations = vec![]; + let prev = self.inner.borrow_mut().opaque_types().register( + OpaqueTypeKey { def_id, substs }, + OpaqueHiddenType { ty: hidden_ty, span }, + origin, + ); + if let Some(prev) = prev { + obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations; } - debug!("generated new type inference var {:?}", ty_var.kind()); - let item_bounds = tcx.explicit_item_bounds(def_id); - self.obligations.reserve(item_bounds.len()); for (predicate, _) in item_bounds { debug!(?predicate); let predicate = predicate.subst(tcx, substs); - debug!(?predicate); let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match *ty.kind() { - // Replace all other mentions of the same opaque type with the hidden type, - // as the bounds must hold on the hidden type after all. - ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { - ty_var - } - // Instantiate nested instances of `impl Trait`. - ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty), - _ => ty, - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }); - - // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them. - let predicate = predicate.fold_with(&mut BottomUpFolder { - tcx, - ty_op: |ty| match ty.kind() { + // We can't normalize associated types from `rustc_infer`, + // but we can eagerly register inference variables for them. ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => { - infcx.infer_projection( - self.param_env, - *projection_ty, - traits::ObligationCause::misc(self.value_span, self.body_id), + self.infer_projection( + param_env, + projection_ty, + cause.clone(), 0, - &mut self.obligations, + &mut obligations, ) } + // Replace all other mentions of the same opaque type with the hidden type, + // as the bounds must hold on the hidden type after all. + ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { + hidden_ty + } _ => ty, }, lt_op: |lt| lt, ct_op: |ct| ct, }); - debug!(?predicate); if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if projection.term.references_error() { - return tcx.ty_error(); + // No point on adding these obligations since there's a type error involved. + return Ok(InferOk { value: (), obligations: vec![] }); } + trace!("{:#?}", projection.term); } - - let cause = - traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType); - // Require that the predicate holds for the concrete type. debug!(?predicate); - self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate)); + obligations.push(traits::Obligation::new(cause.clone(), param_env, predicate)); } - - ty_var + Ok(InferOk { value: (), obligations }) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs new file mode 100644 index 00000000000..202afea559c --- /dev/null +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -0,0 +1,88 @@ +use rustc_data_structures::undo_log::UndoLogs; +use rustc_hir::OpaqueTyOrigin; +use rustc_middle::ty::{self, OpaqueTypeKey, Ty}; +use rustc_span::DUMMY_SP; + +use crate::infer::{InferCtxtUndoLogs, UndoLog}; + +use super::{OpaqueHiddenType, OpaqueTypeDecl, OpaqueTypeMap}; + +#[derive(Default, Debug, Clone)] +pub struct OpaqueTypeStorage<'tcx> { + // Opaque types found in explicit return types and their + // associated fresh inference variable. Writeback resolves these + // variables to get the concrete type, which can be used to + // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + pub opaque_types: OpaqueTypeMap<'tcx>, +} + +impl<'tcx> OpaqueTypeStorage<'tcx> { + #[instrument(level = "debug")] + pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) { + if let Some(idx) = idx { + self.opaque_types.get_mut(&key).unwrap().hidden_type = idx; + } else { + match self.opaque_types.remove(&key) { + None => bug!("reverted opaque type inference that was never registered: {:?}", key), + Some(_) => {} + } + } + } + + pub fn get_decl(&self, key: &OpaqueTypeKey<'tcx>) -> Option<&OpaqueTypeDecl<'tcx>> { + self.opaque_types.get(key) + } + + pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> { + self.opaque_types.clone() + } + + #[instrument(level = "debug")] + pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { + std::mem::take(&mut self.opaque_types) + } + + #[inline] + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, + ) -> OpaqueTypeTable<'a, 'tcx> { + OpaqueTypeTable { storage: self, undo_log } + } +} + +impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { + fn drop(&mut self) { + if !self.opaque_types.is_empty() { + ty::tls::with(|tcx| { + tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types)) + }); + } + } +} + +pub struct OpaqueTypeTable<'a, 'tcx> { + storage: &'a mut OpaqueTypeStorage<'tcx>, + + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, +} + +impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] + pub fn register( + &mut self, + key: OpaqueTypeKey<'tcx>, + hidden_type: OpaqueHiddenType<'tcx>, + origin: OpaqueTyOrigin, + ) -> Option<Ty<'tcx>> { + if let Some(decl) = self.storage.opaque_types.get_mut(&key) { + let prev = std::mem::replace(&mut decl.hidden_type, hidden_type); + self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev))); + return Some(prev.ty); + } + let decl = OpaqueTypeDecl { hidden_type, origin }; + self.storage.opaque_types.insert(key, decl); + self.undo_log.push(UndoLog::OpaqueTypes(key, None)); + None + } +} diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 03d6c45a653..b60ffc1878b 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -28,6 +28,7 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { Some(OutlivesBound::RegionSubRegion(r_b, r_a)) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 5d8cc94e05c..45aa2bcba86 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -153,6 +153,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// This function may have to perform normalizations, and hence it /// returns an `InferOk` with subobligations that must be /// processed. + #[instrument(level = "debug", skip(self, region_bound_pairs_map))] pub fn process_registered_region_obligations( &self, region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, @@ -164,8 +165,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { "cannot process registered region obligations in a snapshot" ); - debug!(?param_env, "process_registered_region_obligations()"); - let my_region_obligations = self.take_registered_region_obligations(); for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 9ec1b3390d0..85bae8b823b 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -2,6 +2,7 @@ use super::combine::{CombineFields, RelationDir}; use super::SubregionOrigin; use crate::infer::combine::ConstEquateRelation; +use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::Obligation; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; @@ -74,9 +75,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); - if a == b { return Ok(a); } @@ -84,6 +84,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { let infcx = self.fields.infcx; let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => { // Shouldn't have any LBR here, so we can safely put @@ -121,6 +122,40 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(self.tcx().ty_error()) } + (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { + self.fields.infcx.super_combine_tys(self, a, b)?; + Ok(a) + } + (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) + if self.fields.define_opaque_types && did.is_local() => + { + let mut generalize = |ty, ty_is_expected| { + let var = infcx.next_ty_var_id_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.fields.trace.cause.span, + }, + ty::UniverseIndex::ROOT, + ); + self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?; + Ok(infcx.tcx.mk_ty_var(var)) + }; + let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) }; + let (a, b) = match (a.kind(), b.kind()) { + (&ty::Opaque(..), _) => (a, generalize(b, true)?), + (_, &ty::Opaque(..)) => (generalize(a, false)?, b), + _ => unreachable!(), + }; + self.fields.obligations.push(infcx.opaque_ty_obligation( + a, + b, + true, + self.param_env(), + self.fields.trace.cause.clone(), + )); + Ok(a) + } + _ => { self.fields.infcx.super_combine_tys(self, a, b)?; Ok(a) diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index ecd886b5478..49bef4face3 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -4,13 +4,15 @@ use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; use rustc_middle::infer::unify_key::RegionVidKey; -use rustc_middle::ty; +use rustc_middle::ty::{self, OpaqueTypeKey}; use crate::{ infer::{region_constraints, type_variable, InferCtxtInner}, traits, }; +use super::opaque_types::OpaqueHiddenType; + pub struct Snapshot<'tcx> { pub(crate) undo_len: usize, _marker: PhantomData<&'tcx ()>, @@ -19,6 +21,7 @@ pub struct Snapshot<'tcx> { /// Records the "undo" data for a single operation that affects some form of inference variable. #[derive(Clone)] pub(crate) enum UndoLog<'tcx> { + OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), @@ -65,6 +68,7 @@ impl_from! { impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { + UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 674c75fdee5..6600d5e4d02 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -167,6 +167,9 @@ impl<'tcx> Elaborator<'tcx> { // Currently, we do not elaborate WF predicates, // although we easily could. } + ty::PredicateKind::OpaqueType(..) => { + todo!("{:#?}", obligation) + } ty::PredicateKind::ObjectSafe(..) => { // Currently, we do not elaborate object-safe // predicates. diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 50a3df21a3b..cec32823ee2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1675,6 +1675,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { Coerce(..) | ConstEvaluatable(..) | ConstEquate(..) | + OpaqueType(..) | TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 419ed429246..f3ea83a32b5 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -178,6 +178,12 @@ pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, pub certainty: Certainty, + /// List of opaque types which we tried to compare to another type. + /// Inside the query we don't know yet whether the opaque type actually + /// should get its hidden type inferred. So we bubble the opaque type + /// and the type it was compared against upwards and let the query caller + /// handle it. + pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, pub value: R, } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 738c48dbb5c..3243ef28ff0 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -53,17 +53,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { self.relate(a, b) } + #[instrument(skip(self), level = "debug")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); Ok(a) } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f51e6c2bc1f..ac9f04ee055 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -33,6 +33,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -485,9 +486,13 @@ pub struct TypeckResults<'tcx> { /// this field will be set to `Some(ErrorGuaranteed)`. pub tainted_by_errors: Option<ErrorGuaranteed>, - /// All the opaque types that are restricted to concrete types - /// by this function. - pub concrete_opaque_types: FxHashSet<DefId>, + /// All the opaque types that have hidden types set + /// by this function. For return-position-impl-trait we also store the + /// type here, so that mir-borrowck can figure out hidden types, + /// even if they are only set in dead code (which doesn't show up in MIR). + /// For type-alias-impl-trait, this map is only used to prevent query cycles, + /// so the hidden types are all `None`. + pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 7a3d615862c..06ac21e5d57 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -265,6 +265,10 @@ impl FlagComputation { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { self.add_ty(ty); } + ty::PredicateKind::OpaqueType(opaque, ty) => { + self.add_ty(opaque); + self.add_ty(ty); + } } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 780d380da36..388109e6512 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1243,15 +1243,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; #[inline] - #[instrument(level = "trace")] - fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { - debug!( - "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", - t, - t.flags(), - self.flags - ); - if t.flags().intersects(self.flags) { + #[instrument(skip(self), level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + let flags = t.flags(); + trace!(t.flags=?t.flags()); + if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 31db66dc242..4208ef1a7f4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -632,6 +632,11 @@ pub enum PredicateKind<'tcx> { /// /// Only used for Chalk. TypeWellFormedFromEnv(Ty<'tcx>), + + /// Represents a hidden type assignment for an opaque type. + /// Such obligations get processed by checking whether the item currently being + /// type-checked may acually define it. + OpaqueType(Ty<'tcx>, Ty<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -999,6 +1004,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::OpaqueType(..) | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1017,6 +1023,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::OpaqueType(..) | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1057,7 +1064,18 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)] +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + HashStable, + TyEncodable, + TyDecodable, + TypeFoldable, + Lift +)] pub struct OpaqueTypeKey<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5cfd9a5edfb..d5f5a1572b8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -647,20 +647,23 @@ pub trait PrettyPrinter<'tcx>: return Ok(self); } - return with_no_queries!({ - let def_key = self.tcx().def_key(def_id); - if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { - p!(write("{}", name)); - // FIXME(eddyb) print this with `print_def_path`. - if !substs.is_empty() { - p!("::"); - p!(generic_delimiters(|cx| cx.comma_sep(substs.iter()))); + let parent = self.tcx().parent(def_id).expect("opaque types always have a parent"); + match self.tcx().def_kind(parent) { + DefKind::TyAlias | DefKind::AssocTy => { + if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() { + if d == def_id { + // If the type alias directly starts with the `impl` of the + // opaque type we're printing, then skip the `::{opaque#1}`. + p!(print_def_path(parent, substs)); + return Ok(self); + } } + // Complex opaque type, e.g. `type Foo = (i32, impl Debug);` + p!(print_def_path(def_id, substs)); return Ok(self); } - - self.pretty_print_opaque_impl_type(def_id, substs) - }); + _ => return self.pretty_print_opaque_impl_type(def_id, substs), + } } ty::Str => p!("str"), ty::Generator(did, substs, movability) => { @@ -2651,6 +2654,9 @@ define_print_and_forward_display! { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { p!("the type `", print(ty), "` is found in the environment") } + ty::PredicateKind::OpaqueType(a, b) => { + p!("opaque type assigment with `", print(a), "` == `", print(b) ,"`") + } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 5c7910db362..576f4121c42 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -198,6 +198,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { write!(f, "TypeWellFormedFromEnv({:?})", ty) } + ty::PredicateKind::OpaqueType(a, b) => { + write!(f, "OpaqueType({:?}, {:?})", a.kind(), b.kind()) + } } } } @@ -471,6 +474,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv) } + ty::PredicateKind::OpaqueType(opaque, ty) => { + Some(ty::PredicateKind::OpaqueType(tcx.lift(opaque)?, tcx.lift(ty)?)) + } } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index dc16460ca43..335ddeb66db 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1925,6 +1925,13 @@ impl<'tcx> Ty<'tcx> { } } + pub fn expect_opaque_type(self) -> ty::OpaqueTypeKey<'tcx> { + match *self.kind() { + Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs }, + _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self), + } + } + pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index f98025f7953..679043bdc30 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,8 +1,8 @@ use crate::build::matches::ArmHasGuard; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; -use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::{mir::*, ty}; use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -190,7 +190,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This return type is usually `()`, unless the block is diverging, in which case the // return type is `!`. For the unit type, we need to actually return the unit, but in // the case of `!`, no return value is required, as the block will never return. - if destination_ty.is_unit() { + // Opaque types of empty bodies also need this unit assignment, in order to infer that their + // type is actually unit. Otherwise there will be no defining use found in the MIR. + if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) { // We only want to assign an implicit `()` as the return value of the block if the // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.) this.cfg.push_assign_unit(block, source_info, destination, this.tcx); diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 9778f77384c..7fd20b45e77 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -181,7 +181,6 @@ impl<K: DepKind> EncoderState<K> { } } - #[instrument(level = "debug", skip(self, record_graph))] fn encode_node( &mut self, node: &NodeInfo<K>, @@ -208,7 +207,6 @@ impl<K: DepKind> EncoderState<K> { stat.edge_counter += edge_count as u64; } - debug!(?index, ?node); let encoder = &mut self.encoder; if self.result.is_ok() { self.result = node.encode(encoder); diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c93ff0aa6e2..c5531222fef 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -33,7 +33,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// purpose of this function is to do that translation. /// /// (*) C1 and C2 were introduced in the comments on - /// `constrain_opaque_type`. Read that comment for more context. + /// `register_member_constraints`. Read that comment for more context. /// /// # Parameters /// @@ -48,6 +48,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { instantiated_ty: Ty<'tcx>, span: Span, ) -> Ty<'tcx> { + if self.is_tainted_by_errors() { + return self.tcx.ty_error(); + } + let OpaqueTypeKey { def_id, substs } = opaque_type_key; // Use substs to build up a reverse map from regions to their @@ -67,7 +71,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // after producing an error for each of them. let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new( self.tcx, - self.is_tainted_by_errors(), def_id, map, instantiated_ty, @@ -82,10 +85,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, - /// If errors have already been reported in this fn, we suppress - /// our own errors because they are sometimes derivative. - tainted_by_errors: bool, - opaque_type_def_id: DefId, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, map_missing_regions_to_empty: bool, @@ -100,7 +99,6 @@ struct ReverseMapper<'tcx> { impl<'tcx> ReverseMapper<'tcx> { fn new( tcx: TyCtxt<'tcx>, - tainted_by_errors: bool, opaque_type_def_id: DefId, map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, hidden_ty: Ty<'tcx>, @@ -108,7 +106,6 @@ impl<'tcx> ReverseMapper<'tcx> { ) -> Self { Self { tcx, - tainted_by_errors, opaque_type_def_id, map, map_missing_regions_to_empty: false, @@ -167,9 +164,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&r.into()).map(|k| k.unpack()) { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty || self.tainted_by_errors => { - self.tcx.lifetimes.re_root_empty - } + None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, None if generics.parent.is_some() => { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( @@ -359,6 +354,7 @@ crate fn required_region_bounds<'tcx>( | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { // Search for a bound of the form `erased_self_ty diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index ee9983ee8b8..ee8b3a62453 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -865,6 +865,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} }; } diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index a607fb6c1b8..22182faa0c6 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -92,6 +92,11 @@ pub fn codegen_fulfill_obligation<'tcx>( }); let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); + // We may constrain the hidden types of opaque types in this query, but this is + // not information our callers need, as all that information is handled by borrowck + // and typeck. + drop(infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types()); + debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source); Ok(&*tcx.arena.alloc(impl_source)) }) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 468c7a3c55b..218abdd573d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -797,6 +797,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, "TypeWellFormedFromEnv predicate should only exist in the environment" ), + + ty::PredicateKind::OpaqueType(..) => { + todo!("{:#?}", obligation); + } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d65b390af34..39da99ac252 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1294,6 +1294,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Generator(..) => "generator", _ => "function", }; + let span = self.tcx.sess.source_map().guess_head_span(span); let mut err = struct_span_err!( self.tcx.sess, span, @@ -1673,6 +1674,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )); let original_span = err.span.primary_span().unwrap(); + let original_span = self.tcx.sess.source_map().guess_head_span(original_span); let mut span = MultiSpan::from_span(original_span); let message = outer_generator diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1b862834467..d55d06ebbf4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -413,6 +413,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } + ty::PredicateKind::OpaqueType(..) => { + todo!("{:#?}", obligation); + } }, Some(pred) => match pred { ty::PredicateKind::Trait(data) => { @@ -662,6 +665,20 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } + ty::PredicateKind::OpaqueType(a, b) => { + match self.selcx.infcx().handle_opaque_type( + a, + b, + &obligation.cause, + obligation.param_env, + ) { + Ok(value) => ProcessResult::Changed(mk_pending(value.obligations)), + Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( + ExpectedFound::new(true, a, b), + err, + )), + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 6cceec86213..eab207600ab 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -313,6 +313,7 @@ fn predicate_references_self<'tcx>( | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -344,6 +345,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } }) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 0a85676f431..605c9ace5ed 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -3,7 +3,8 @@ use crate::infer::{InferCtxt, InferOk}; use crate::traits::engine::TraitEngineExt as _; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; -use crate::traits::{ObligationCause, TraitEngine}; +use crate::traits::TraitEngine; +use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; @@ -31,6 +32,9 @@ where G: Fn() -> String, { type Output = R; + /// We can't do any custom error reporting for `CustomTypeOp`, so + /// we can use `!` to enforce that the implementation never provides it. + type ErrorInfo = !; /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints @@ -40,7 +44,7 @@ where info!("fully_perform({:?})", self); } - scrape_region_constraints(infcx, || (self.closure)(infcx)) + Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) } } @@ -55,12 +59,11 @@ where /// Executes `op` and then scrapes out all the "old style" region /// constraints that result, creating query-region-constraints. -fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( +pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'_, 'tcx>, op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, -) -> Fallible<TypeOpOutput<'tcx, Op>> { +) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - let dummy_body_id = ObligationCause::dummy().body_id; // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the @@ -75,7 +78,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); fulfill_cx.register_predicate_obligations(infcx, obligations); let errors = fulfill_cx.select_all_or_error(infcx); if !errors.is_empty() { @@ -99,12 +101,18 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); if region_constraints.is_empty() { - Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None }) + Ok(( + TypeOpOutput { output: value, constraints: None, error_info: None }, + region_constraint_data, + )) } else { - Ok(TypeOpOutput { - output: value, - constraints: Some(Rc::new(region_constraints)), - canonicalized_query: None, - }) + Ok(( + TypeOpOutput { + output: value, + constraints: Some(Rc::new(region_constraints)), + error_info: None, + }, + region_constraint_data, + )) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index d662f61e2cf..1e72dd69339 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -28,6 +28,7 @@ pub use rustc_middle::traits::query::type_op::*; /// cannot be completed). pub trait TypeOp<'tcx>: Sized + fmt::Debug { type Output; + type ErrorInfo; /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints @@ -41,9 +42,8 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> { pub output: Op::Output, /// Any region constraints from performing the type op. pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>, - /// The canonicalized form of the query. - /// This for error reporting to be able to rerun the query. - pub canonicalized_query: Option<Canonical<'tcx, Op>>, + /// Used for error reporting to be able to rerun the query + pub error_info: Option<Op::ErrorInfo>, } /// "Query type ops" are type ops that are implemented using a @@ -119,10 +119,11 @@ where Q: QueryTypeOp<'tcx>, { type Output = Q::QueryResponse; + type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { let mut region_constraints = QueryRegionConstraints::default(); - let (output, canonicalized_query, mut obligations, _) = + let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; // Typically, instantiating NLL query results does not @@ -160,6 +161,6 @@ where let region_constraints = if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; - Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query }) + Ok(TypeOpOutput { output, constraints: region_constraints, error_info }) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3e7a2252318..cf472813e9e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -256,6 +256,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; if obligation.predicate.skip_binder().self_ty().is_ty_var() { + debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type"); // Self is a type variable (e.g., `_: AsRef<str>`). // // This is somewhat problematic, as the current scheme can't really diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 72d156067a1..9b8a49e512b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -33,6 +33,7 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject::{self, TreatParams}; +use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; @@ -672,6 +673,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } + ty::PredicateKind::OpaqueType(a, b) => { + match self.infcx().handle_opaque_type( + a, + b, + &obligation.cause, + obligation.param_env, + ) { + Ok(res) => { + self.evaluate_predicates_recursively(previous_stack, res.obligations) + } + Err(_) => Ok(EvaluatedToErr), + } + } } }); @@ -1313,6 +1327,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")] fn insert_candidate_cache( &mut self, mut param_env: ty::ParamEnv<'tcx>, @@ -1353,6 +1368,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// a projection, look at the bounds of `T::Bar`, see if we can find a /// `Baz` bound. We return indexes into the list returned by /// `tcx.item_bounds` for any applicable bounds. + #[instrument(level = "debug", skip(self))] fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, @@ -1360,10 +1376,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); - debug!( - ?placeholder_trait_predicate, - "match_projection_obligation_against_definition_bounds" - ); + debug!(?placeholder_trait_predicate); let tcx = self.infcx.tcx; let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { @@ -1414,7 +1427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .collect(); - debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds"); + debug!(?matching_bounds); matching_bounds } @@ -1444,6 +1457,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); self.infcx .at(&obligation.cause, obligation.param_env) + .define_opaque_types(false) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .map(|InferOk { obligations: _, value: () }| { // This method is called within a probe, so we can't have @@ -1506,6 +1520,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let is_match = self .infcx .at(&obligation.cause, obligation.param_env) + .define_opaque_types(false) .sup(obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( @@ -2081,11 +2096,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.match_impl(impl_def_id, obligation) { Ok(substs) => substs, Err(()) => { - bug!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, - obligation + self.infcx.tcx.sess.delay_span_bug( + obligation.cause.span, + &format!( + "Impl {:?} was matchable against {:?} but now is not", + impl_def_id, obligation + ), ); + let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + let err = self.tcx().ty_error(); + let value = value.fold_with(&mut BottomUpFolder { + tcx: self.tcx(), + ty_op: |_| err, + lt_op: |l| l, + ct_op: |c| c, + }); + Normalized { value, obligations: vec![] } } } } @@ -2220,6 +2246,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { self.infcx .at(&obligation.cause, obligation.param_env) + // We don't want predicates for opaque types to just match all other types, + // if there is an obligation on the opaque type, then that obligation must be met + // opaquely. Otherwise we'd match any obligation to the opaque type and then error + // out later. + .define_opaque_types(false) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| ()) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b4ed5b95b10..2ac68cea544 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -148,6 +148,10 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateKind::OpaqueType(opaque, ty) => { + wf.compute(opaque.into()); + wf.compute(ty.into()); + } ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e3c865ce9e6..1d5b5c6c3cd 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -110,6 +110,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate), }; @@ -202,6 +203,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } @@ -621,6 +623,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } @@ -750,6 +753,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index 3c2a266dab9..4e19479da87 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -134,6 +134,7 @@ crate fn evaluate_goal<'tcx>( var_values: CanonicalVarValues { var_values }, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, + opaque_types: vec![], value: (), }, }; @@ -162,6 +163,7 @@ crate fn evaluate_goal<'tcx>( .make_identity(tcx), region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Ambiguous, + opaque_types: vec![], value: (), }, }; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 90c698db8fb..1535a46a01b 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -105,6 +105,7 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![], ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index a4aa965ec95..1d26f6a12a3 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -69,6 +69,7 @@ fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => true, } } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e26f0033156..b015e40b683 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -61,6 +61,14 @@ bitflags! { | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits + // The `evaluate_obligation` query does not return further + // obligations. If it evaluates an obligation with an opaque + // type, that opaque type may get compared to another type, + // constraining it. We would lose this information. + // FIXME: differentiate between crate-local opaque types + // and opaque types from other crates, as only opaque types + // from the local crate can possibly be a local name + | TypeFlags::HAS_TY_OPAQUE.bits // We consider 'freshened' types and constants // to depend on a particular fn. // The freshening process throws away information, diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 9529e1528a8..79be8bde55a 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; -use rustc_middle::ty::{self, ToPredicate, Ty}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; use rustc_span::{MultiSpan, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ @@ -98,8 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - let opt_suggest_box_span = - self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected); + let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected); let (arm_span, semi_span) = self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty); @@ -504,20 +503,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // provide a structured suggestion in that case. pub(crate) fn opt_suggest_box_span( &self, - span: Span, outer_ty: Ty<'tcx>, orig_expected: Expectation<'tcx>, ) -> Option<Span> { - match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) { - (Expectation::ExpectHasType(expected), Some((_id, ty))) - if self.in_tail_expr && self.can_coerce(outer_ty, expected) => + match orig_expected { + Expectation::ExpectHasType(expected) + if self.in_tail_expr + && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types() + && self.can_coerce(outer_ty, expected) => { - let impl_trait_ret_ty = - self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span); - assert!( - impl_trait_ret_ty.obligations.is_empty(), - "we should never get new obligations here" - ); let obligations = self.fulfillment_cx.borrow().pending_obligations(); let mut suggest_box = !obligations.is_empty(); for o in obligations { diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index d5187c109e3..2a5cf03e9d0 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -538,7 +538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, fn_sig: ty::FnSig<'tcx>, ) -> Ty<'tcx> { - // `fn_sig` is the *signature* of the cosure being called. We + // `fn_sig` is the *signature* of the closure being called. We // don't know the full details yet (`Fn` vs `FnMut` etc), but we // do know the types expected for each argument and the return // type. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e57d55fdc23..1a5f118ea50 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; @@ -83,8 +83,6 @@ pub(super) fn check_fn<'a, 'tcx>( can_be_generator: Option<hir::Movability>, return_type_pre_known: bool, ) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) { - let mut fn_sig = fn_sig; - // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); @@ -97,21 +95,8 @@ pub(super) fn check_fn<'a, 'tcx>( let declared_ret_ty = fn_sig.output(); - let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span()); - debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(declared_ret_ty))); fcx.ret_type_span = Some(decl.output.span()); - if let ty::Opaque(..) = declared_ret_ty.kind() { - fcx.ret_coercion_impl_trait = Some(declared_ret_ty); - } - fn_sig = tcx.mk_fn_sig( - fn_sig.inputs().iter().cloned(), - revealed_ret_ty, - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - ); let span = body.value.span; @@ -253,7 +238,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); debug!("actual_return_ty replaced with {:?}", actual_return_ty); } - fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); + fcx.demand_suptype(span, declared_ret_ty, actual_return_ty); // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { @@ -656,6 +641,8 @@ fn check_opaque_meets_bounds<'tcx>( span: Span, origin: &hir::OpaqueTyOrigin, ) { + let hidden_type = tcx.type_of(def_id).subst(tcx, substs); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, @@ -670,25 +657,13 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); - let _ = inh.register_infer_ok_obligations( - infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span), - ); - - let opaque_type_map = infcx.inner.borrow().opaque_types.clone(); - for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map { - let hidden_type = tcx.type_of(def_id).subst(tcx, substs); - trace!(?hidden_type); - match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) { - Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), - Err(ty_err) => { - tcx.sess.delay_span_bug( - span, - &format!( - "could not check bounds on revealed type `{}`:\n{}", - hidden_type, ty_err, - ), - ); - } + match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { + Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), + Err(ty_err) => { + tcx.sess.delay_span_bug( + span, + &format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,), + ); } } @@ -701,7 +676,7 @@ fn check_opaque_meets_bounds<'tcx>( match origin { // Checked when type checking the function containing them. - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return, + hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { // Finally, resolve all regions. This catches wily misuses of @@ -710,6 +685,9 @@ fn check_opaque_meets_bounds<'tcx>( fcx.regionck_item(hir_id, span, FxHashSet::default()); } } + + // Clean up after ourselves + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); }); } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 59c8febdc30..83ef76a48cd 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -3,16 +3,20 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use crate::astconv::AstConv; +use crate::rustc_middle::ty::subst::Subst; +use hir::OpaqueTyOrigin; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; +use rustc_infer::traits::ObligationCause; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; +use rustc_span::DUMMY_SP; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -172,6 +176,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { match *expected_ty.kind() { + ty::Opaque(def_id, substs) => { + let bounds = self.tcx.explicit_item_bounds(def_id); + let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() { + ty::PredicateKind::Projection(proj_predicate) => self + .deduce_sig_from_projection( + Some(*span), + pred.kind().rebind(proj_predicate.subst(self.tcx, substs)), + ), + _ => None, + }); + + let kind = bounds + .iter() + .filter_map(|(pred, _)| match pred.kind().skip_binder() { + ty::PredicateKind::Trait(tp) => { + self.tcx.fn_trait_kind_from_lang_item(tp.def_id()) + } + _ => None, + }) + .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); + trace!(?sig, ?kind); + (sig, kind) + } ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); @@ -197,10 +224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { let expected_sig = self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| { - debug!( - "deduce_expectations_from_obligations: obligation.predicate={:?}", - obligation.predicate - ); + debug!(?obligation.predicate); let bound_predicate = obligation.predicate.kind(); if let ty::PredicateKind::Projection(proj_predicate) = @@ -235,6 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// The `cause_span` should be the span that caused us to /// have this expected signature, or `None` if we can't readily /// know that. + #[instrument(level = "debug", skip(self, cause_span))] fn deduce_sig_from_projection( &self, cause_span: Option<Span>, @@ -242,15 +267,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<ExpectedSig<'tcx>> { let tcx = self.tcx; - debug!("deduce_sig_from_projection({:?})", projection); - let trait_def_id = projection.trait_def_id(tcx); let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some(); let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span); let is_gen = gen_trait == trait_def_id; if !is_fn && !is_gen { - debug!("deduce_sig_from_projection: not fn or generator"); + debug!("not fn or generator"); return None; } @@ -259,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // associated item and not yield. let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1]; if return_assoc_item != projection.projection_def_id() { - debug!("deduce_sig_from_projection: not return assoc item of generator"); + debug!("not return assoc item of generator"); return None; } } @@ -267,7 +290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let input_tys = if is_fn { let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); - debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); + debug!(?arg_param_ty); match arg_param_ty.kind() { &ty::Tuple(tys) => tys, @@ -282,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Since this is a return parameter type it is safe to unwrap. let ret_param_ty = projection.skip_binder().term.ty().unwrap(); let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); - debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); + debug!(?ret_param_ty); let sig = projection.rebind(self.tcx.mk_fn_sig( input_tys.iter(), @@ -291,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Unsafety::Normal, Abi::Rust, )); - debug!("deduce_sig_from_projection: sig={:?}", sig); + debug!(?sig); Some(ExpectedSig { cause_span, sig }) } @@ -401,9 +424,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in this binder we are creating. assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); let bound_sig = expected_sig.sig.map_bound(|sig| { + let output = self.hide_parent_opaque_types( + sig.output(), + expected_sig.cause_span.unwrap_or(DUMMY_SP), + body.id().hir_id, + ); self.tcx.mk_fn_sig( sig.inputs().iter().cloned(), - sig.output(), + output, sig.c_variadic, hir::Unsafety::Normal, Abi::RustCall, @@ -590,6 +618,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => astconv.ty_infer(None, decl.output.span()), }, }; + let supplied_return = + self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id); let result = ty::Binder::bind_with_vars( self.tcx.mk_fn_sig( @@ -610,27 +640,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } + fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> { + ty.fold_with(&mut ty::fold::BottomUpFolder { + tcx: self.infcx.tcx, + lt_op: |lt| lt, + ct_op: |ct| ct, + ty_op: |ty| match *ty.kind() { + // Closures can't create hidden types for opaque types of their parent, as they + // do not have all the outlives information available. Also `type_of` looks for + // hidden types in the owner (so the closure's parent), so it would not find these + // definitions. + ty::Opaque(def_id, _substs) + if matches!( + self.infcx.opaque_type_origin(def_id, DUMMY_SP), + Some(OpaqueTyOrigin::FnReturn(..)) + ) => + { + let ty_var = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + let cause = ObligationCause::misc(span, body_id); + self.register_predicates(vec![self.infcx.opaque_ty_obligation( + ty, + ty_var, + true, + self.param_env, + cause, + )]); + ty_var + } + _ => ty, + }, + }) + } + /// Invoked when we are translating the generator that results /// from desugaring an `async fn`. Returns the "sugared" return /// type of the `async fn` -- that is, the return type that the /// user specified. The "desugared" return type is an `impl /// Future<Output = T>`, so we do this by searching through the /// obligations to extract the `T`. + #[instrument(skip(self), level = "debug")] fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> { - debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id); - let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") }); - // In practice, the return type of the surrounding function is - // always a (not yet resolved) inference variable, because it - // is the hidden type for an `impl Trait` that we are going to - // be inferring. let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); - let ret_vid = match *ret_ty.kind() { - ty::Infer(ty::TyVar(ret_vid)) => ret_vid, + let (def_id, substs) = match *ret_ty.kind() { + ty::Opaque(def_id, substs) => (def_id, substs), ty::Error(_) => return None, _ => span_bug!( self.tcx.def_span(expr_def_id), @@ -638,17 +698,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), }; + let item_bounds = self.tcx.explicit_item_bounds(def_id); + // Search for a pending obligation like // // `<R as Future>::Output = T` // // where R is the return type we are expecting. This type `T` // will be our output. - let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - let bound_predicate = obligation.predicate.kind(); + let output_ty = item_bounds.iter().find_map(|&(predicate, span)| { + let bound_predicate = predicate.subst(self.tcx, substs).kind(); if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() { self.deduce_future_output_from_projection( - obligation.cause.span, + span, bound_predicate.rebind(proj_predicate), ) } else { diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index c0eda02a999..2f973a54f88 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1272,7 +1272,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { /// Returns the current "merged type", representing our best-guess /// at the LUB of the expressions we've seen so far (if any). This - /// isn't *final* until you call `self.final()`, which will return + /// isn't *final* until you call `self.complete()`, which will return /// the merged type. pub fn merged_ty(&self) -> Ty<'tcx> { self.final_ty.unwrap_or(self.expected_ty) diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs index e9e81034477..9e1a70b7dfb 100644 --- a/compiler/rustc_typeck/src/check/expectation.rs +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -1,5 +1,6 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::{self, Ty}; +use rustc_span::DUMMY_SP; use rustc_span::{self, Span}; use super::Expectation::*; @@ -43,7 +44,7 @@ impl<'a, 'tcx> Expectation<'tcx> { // when checking the 'then' block which are incompatible with the // 'else' branch. pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match *self { + match self.strip_opaque(fcx) { ExpectHasType(ety) => { let ety = fcx.shallow_resolve(ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } @@ -104,14 +105,35 @@ impl<'a, 'tcx> Expectation<'tcx> { /// for the program to type-check). `only_has_type` will return /// such a constraint, if it exists. pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> { - match self { - ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), + match self.strip_opaque(fcx) { + ExpectHasType(ty) => Some(ty), NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { None } } } + /// We must not treat opaque types as expected types in their defining scope, as that + /// will break `fn foo() -> impl Trait { if cond { a } else { b } }` if `a` and `b` are + /// only "equal" if they coerce to a common target, like two different function items + /// coercing to a function pointer if they have the same signature. + fn strip_opaque(self, fcx: &FnCtxt<'a, 'tcx>) -> Self { + match self { + ExpectHasType(ty) => { + let ty = fcx.resolve_vars_if_possible(ty); + match *ty.kind() { + ty::Opaque(def_id, _) + if fcx.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() => + { + NoExpectation + } + _ => self, + } + } + _ => self, + } + } + /// Like `only_has_type`, but instead of returning `None` if no /// hard constraint exists, creates a fresh type variable. pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e5784259ce8..81cebaef3aa 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -965,8 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let else_diverges = self.diverges.get(); - let opt_suggest_box_span = - self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected); + let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); let if_cause = self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 7214cdf3312..85132317824 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -24,7 +24,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); - // Check if we have any unsolved varibales. If not, no need for fallback. + // Check if we have any unsolved variables. If not, no need for fallback. let unsolved_variables = self.unsolved_variables(); if unsolved_variables.is_empty() { return false; @@ -66,16 +66,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // refer to opaque types. self.select_obligations_where_possible(fallback_has_occurred, |_| {}); - // We now run fallback again, but this time we allow it to replace - // unconstrained opaque type variables, in addition to performing - // other kinds of fallback. - for ty in &self.unsolved_variables() { - fallback_has_occurred |= self.fallback_opaque_type_vars(*ty); - } - - // See if we can make any more progress. - self.select_obligations_where_possible(fallback_has_occurred, |_| {}); - fallback_has_occurred } @@ -136,59 +126,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { true } - /// Second round of fallback: Unconstrained type variables created - /// from the instantiation of an opaque type fall back to the - /// opaque type itself. This is a somewhat incomplete attempt to - /// manage "identity passthrough" for `impl Trait` types. - /// - /// For example, in this code: - /// - ///``` - /// type MyType = impl Copy; - /// fn defining_use() -> MyType { true } - /// fn other_use() -> MyType { defining_use() } - /// ``` - /// - /// `defining_use` will constrain the instantiated inference - /// variable to `bool`, while `other_use` will constrain - /// the instantiated inference variable to `MyType`. - /// - /// When we process opaque types during writeback, we - /// will handle cases like `other_use`, and not count - /// them as defining usages - /// - /// However, we also need to handle cases like this: - /// - /// ```rust - /// pub type Foo = impl Copy; - /// fn produce() -> Option<Foo> { - /// None - /// } - /// ``` - /// - /// In the above snippet, the inference variable created by - /// instantiating `Option<Foo>` will be completely unconstrained. - /// We treat this as a non-defining use by making the inference - /// variable fall back to the opaque type itself. - fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool { - let span = self - .infcx - .type_var_origin(ty) - .map(|origin| origin.span) - .unwrap_or(rustc_span::DUMMY_SP); - let oty = self.inner.borrow().opaque_types_vars.get(&ty).copied(); - if let Some(opaque_ty) = oty { - debug!( - "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}", - ty, opaque_ty - ); - self.demand_eqtype(span, ty, opaque_ty); - true - } else { - return false; - } - } - /// The "diverging fallback" system is rather complicated. This is /// a result of our need to balance 'do the right thing' with /// backwards compatibility. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e3439a6f1d9..83587951f25 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -372,23 +372,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result, spans) } - /// Replaces the opaque types from the given value with type variables, - /// and records the `OpaqueTypeMap` for later use during writeback. See - /// `InferCtxt::instantiate_opaque_types` for more details. - #[instrument(skip(self, value_span), level = "debug")] - pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( - &self, - value: T, - value_span: Span, - ) -> T { - self.register_infer_ok_obligations(self.instantiate_opaque_types( - self.body_id, - self.param_env, - value, - value_span, - )) - } - /// Convenience method which tracks extra diagnostic information for normalization /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item /// whose type is being wf-checked - this is used to construct a more precise span if @@ -749,6 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inference variable. ty::PredicateKind::ClosureKind(..) => None, ty::PredicateKind::TypeWellFormedFromEnv(..) => None, + ty::PredicateKind::OpaqueType(..) => None, } }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) @@ -775,6 +759,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Vec<Ty<'tcx>> { let formal_ret = self.resolve_vars_with_obligations(formal_ret); let Some(ret_ty) = expected_ret.only_has_type(self) else { return Vec::new() }; + + // HACK(oli-obk): This is a backwards compatibility hack. Without it, the inference + // variable will get instantiated with the opaque type. The inference variable often + // has various helpful obligations registered for it that help closures figure out their + // signature. If we infer the inference var to the opaque type, the closure won't be able + // to find those obligations anymore, and it can't necessarily find them from the opaque + // type itself. We could be more powerful with inference if we *combined* the obligations + // so that we got both the obligations from the opaque type and the ones from the inference + // variable. That will accept more code than we do right now, so we need to carefully consider + // the implications. + // Note: this check is pessimistic, as the inference type could be matched with something other + // than the opaque type, but then we need a new `TypeRelation` just for this specific case and + // can't re-use `sup` below. + if formal_ret.has_infer_types() { + for ty in ret_ty.walk() { + if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() { + if let ty::Opaque(def_id, _) = *ty.kind() { + if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { + return Vec::new(); + } + } + } + } + } + let expect_args = self .fudge_inference_if_ok(|| { // Attempt to apply a subtyping relationship between the formal diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 222c14d0d47..6c55f821294 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -57,8 +57,6 @@ pub struct FnCtxt<'a, 'tcx> { /// any). pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, - pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, - pub(super) ret_type_span: Option<Span>, /// Used exclusively to reduce cost of advanced evaluation used for @@ -130,7 +128,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, - ret_coercion_impl_trait: None, ret_type_span: None, in_tail_expr: false, ret_coercion_span: Cell::new(None), diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index beb6b371b2b..b775f24f8ef 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -95,6 +95,13 @@ impl<'tcx> InheritedBuilder<'tcx> { let def_id = self.def_id; self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) } + + /// WF-checking doesn't need to recompute opaque types and can instead use + /// the type_of query to get them from typeck. + pub fn reveal_defining_opaque_types(mut self) -> Self { + self.infcx = self.infcx.reveal_defining_opaque_types(); + self + } } impl<'a, 'tcx> Inherited<'a, 'tcx> { @@ -119,8 +126,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { - debug!("register_predicate({:?})", obligation); if obligation.has_escaping_bound_vars() { span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 704866c2cc2..26119e5a064 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -858,6 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } }); @@ -1476,6 +1477,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { TraitCandidate(trait_ref) => self.probe(|_| { let _ = self .at(&ObligationCause::dummy(), self.param_env) + .define_opaque_types(false) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { @@ -1505,6 +1507,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // First check that the self type can be related. let sub_obligations = match self .at(&ObligationCause::dummy(), self.param_env) + .define_opaque_types(false) .sup(probe.xform_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => obligations, @@ -1655,6 +1658,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); if self .at(&ObligationCause::dummy(), self.param_env) + .define_opaque_types(false) .sup(return_ty, xform_ret_ty) .is_err() { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 31cc3fa2ac6..b6111793678 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -343,6 +343,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T typeck_with_fallback(tcx, def_id, fallback) } +#[instrument(skip(tcx, fallback))] fn typeck_with_fallback<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 7106f8f9d7a..70bc46c5123 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -335,11 +335,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Returns a list of `Ty`s for each upvar. fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> { - // Presently an unboxed closure type cannot "escape" out of a - // function, so we will only encounter ones that originated in the - // local crate or were inlined into it along with some function. - // This may change if abstract return types of some sort are - // implemented. self.typeck_results .borrow() .closure_min_captures_flattened(closure_id) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index d6eeef3323c..250576bff04 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -968,7 +968,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder< fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { CheckWfFcxBuilder { - inherited: Inherited::build(tcx, def_id), + inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(), id: hir::HirId::make_owner(def_id), span, param_env: tcx.param_env(def_id), diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index c1cb9a1a8d1..35f1ddb65aa 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_trait_selection::opaque_types::InferCtxtExt; use std::mem; @@ -65,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); - wbcx.visit_opaque_types(body.value.span); + wbcx.visit_opaque_types(); wbcx.visit_coercion_casts(); wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); @@ -497,64 +496,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.generator_interior_types.clone(); } - #[instrument(skip(self, span), level = "debug")] - fn visit_opaque_types(&mut self, span: Span) { - let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone(); - for (opaque_type_key, opaque_defn) in opaque_types { - let hir_id = - self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local()); - let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id); - - debug_assert!(!instantiated_ty.has_escaping_bound_vars()); - - let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap(); - - // Prevent: - // * `fn foo<T>() -> Foo<T>` - // * `fn foo<T: Bound + Other>() -> Foo<T>` - // from being defining. - - // Also replace all generic params with the ones from the opaque type - // definition so that - // ```rust - // type Foo<T> = impl Baz + 'static; - // fn foo<U>() -> Foo<U> { .. } - // ``` - // figures out the concrete type with `U`, but the stored type is with `T`. - - // FIXME: why are we calling this here? This seems too early, and duplicated. - let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( - opaque_type_key, - instantiated_ty, - span, - ); - - let mut skip_add = false; - - if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() { - if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias { - if opaque_type_key.def_id == definition_ty_def_id { - debug!( - "skipping adding concrete definition for opaque type {:?} {:?}", - opaque_defn, opaque_type_key.def_id - ); - skip_add = true; - } + #[instrument(skip(self), level = "debug")] + fn visit_opaque_types(&mut self) { + let opaque_types = + self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + for (opaque_type_key, decl) in opaque_types { + let hidden_type = match decl.origin { + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { + Some(self.resolve(decl.hidden_type.ty, &decl.hidden_type.span)) } - } - - if opaque_type_key.substs.needs_infer() { - span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs) - } - - // We only want to add an entry into `concrete_opaque_types` - // if we actually found a defining usage of this opaque type. - // Otherwise, we do nothing - we'll either find a defining usage - // in some other location, or we'll end up emitting an error due - // to the lack of defining usage - if !skip_add { - self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id); - } + hir::OpaqueTyOrigin::TyAlias => None, + }; + self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index d422f355ad3..885713cd2f3 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -359,28 +359,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) .copied() .unwrap_or_else(|| { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "owner {:?} has no opaque type for {:?} in its typeck results", - owner, def_id, - ), - ); - if let Some(_) = - tcx.typeck(owner).tainted_by_errors - { + let table = tcx.typeck(owner); + if let Some(_) = table.tainted_by_errors { // Some error in the // owner fn prevented us from populating // the `concrete_opaque_types` table. tcx.ty_error() } else { - // We failed to resolve the opaque type or it - // resolves to itself. Return the non-revealed - // type, which should result in E0720. - tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ) + table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| { + // We failed to resolve the opaque type or it + // resolves to itself. We interpret this as the + // no values of the hidden type ever being constructed, + // so we can just make the hidden type be `!`. + // For backwards compatibility reasons, we fall back to + // `()` until we the diverging default is changed. + Some(tcx.mk_diverging_default()) + }).expect("RPIT always have a hidden type from typeck") } }); debug!("concrete_ty = {:?}", concrete_ty); @@ -575,7 +569,21 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } // Calling `mir_borrowck` can lead to cycle errors through // const-checking, avoid calling it if we don't have to. - if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) { + // ```rust + // type Foo = impl Fn() -> usize; // when computing type for this + // const fn bar() -> Foo { + // || 0usize + // } + // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles + // // because we again need to reveal `Foo` so we can check whether the + // // constant does not contain interior mutability. + // ``` + let tables = self.tcx.typeck(def_id); + if let Some(_) = tables.tainted_by_errors { + self.found = Some((DUMMY_SP, self.tcx.ty_error())); + return; + } + if tables.concrete_opaque_types.get(&self.def_id).is_none() { debug!("no constraints in typeck results"); return; } @@ -629,7 +637,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); + trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. if it.def_id.to_def_id() != self.def_id { self.check(it.def_id); @@ -637,7 +645,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } } fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); + trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. if it.def_id.to_def_id() != self.def_id { self.check(it.def_id); @@ -645,7 +653,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); + trace!(?it.def_id); self.check(it.def_id); intravisit::walk_trait_item(self, it); } @@ -655,12 +663,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { let scope = tcx.hir().get_defining_scope(hir_id); let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None }; - debug!("find_opaque_ty_constraints: scope={:?}", scope); + debug!(?scope); if scope == hir::CRATE_HIR_ID { tcx.hir().walk_toplevel_module(&mut locator); } else { - debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); + trace!("scope={:#?}", tcx.hir().get(scope)); match tcx.hir().get(scope) { // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods // This allows our visitor to process the defining item itself, causing @@ -687,7 +695,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { Some((_, ty)) => ty, None => { let span = tcx.def_span(def_id); - tcx.sess.span_err(span, "could not find defining uses"); + let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap()); + let label = format!( + "`{}` must be used in combination with a concrete type within the same module", + name + ); + tcx.sess.struct_span_err(span, "unconstrained opaque type").note(&label).emit(); tcx.ty_error() } } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 6cef3e9d940..737e6002005 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -425,6 +425,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } } diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index bbf31de527e..7839ce5e4ff 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -59,6 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::OpaqueType(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => (), } } |
