diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/wfcheck.rs')
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 125 |
1 files changed, 81 insertions, 44 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4cccdf30c..53197bc84 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,7 +1,6 @@ use crate::autoderef::Autoderef; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use hir::def::DefKind; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -111,16 +110,13 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); return; } - let outlives_environment = - OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = infcx - .err_ctxt() - .check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { @@ -676,19 +672,13 @@ fn resolve_regions_with_wf_tys<'tcx>( let infcx = tcx.infer_ctxt().build(); let outlives_environment = OutlivesEnvironment::with_bounds( param_env, - Some(&infcx), infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), ); let region_bound_pairs = outlives_environment.region_bound_pairs(); add_constraints(&infcx, region_bound_pairs); - infcx.process_registered_region_obligations( - outlives_environment.region_bound_pairs(), - param_env, - ); let errors = infcx.resolve_regions(&outlives_environment); - debug!(?errors, "errors"); // If we were able to prove that the type outlives the region without @@ -1033,7 +1023,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = tcx.type_of(variant.fields.last().unwrap().did).subst_identity(); + let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); let ty = tcx.erase_regions(ty); if ty.needs_infer() { tcx.sess @@ -1049,7 +1039,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy(); let unsized_len = if all_sized { 0 } else { 1 }; for (idx, field) in - variant.fields[..variant.fields.len() - unsized_len].iter().enumerate() + variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate() { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); @@ -1545,31 +1535,81 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( span: Span, ) { let tcx = wfcx.tcx(); - if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) - && assoc_item.container == ty::AssocItemContainer::TraitContainer - { - for arg in fn_output.walk() { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, proj) = ty.kind() - && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder - && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id() + let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else { + return; + }; + if assoc_item.container != ty::AssocItemContainer::TraitContainer { + return; + } + fn_output.visit_with(&mut ImplTraitInTraitFinder { + wfcx, + fn_def_id, + depth: ty::INNERMOST, + seen: FxHashSet::default(), + }); +} + +// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering +// strategy, we can't just call `check_associated_item` on the new RPITITs, +// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. +// That's because we need to check that the bounds of the RPITIT hold using +// the special substs that we create during opaque type lowering, otherwise we're +// getting a bunch of early bound and free regions mixed up... Haven't looked too +// deep into this, though. +struct ImplTraitInTraitFinder<'a, 'tcx> { + wfcx: &'a WfCheckingCtxt<'a, 'tcx>, + fn_def_id: LocalDefId, + depth: ty::DebruijnIndex, + seen: FxHashSet<DefId>, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> { + let tcx = self.wfcx.tcx(); + if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() + && self.seen.insert(unshifted_opaque_ty.def_id) + && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() + && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && source == self.fn_def_id + { + let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| { + if let ty::ReLateBound(index, bv) = re.kind() { + if depth != ty::INNERMOST { + return tcx.mk_re_error_with_message( + DUMMY_SP, + "we shouldn't walk non-predicate binders with `impl Trait`...", + ); + } + tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) + } else { + re + } + }); + for (bound, bound_span) in tcx + .bound_explicit_item_bounds(opaque_ty.def_id) + .subst_iter_copied(tcx, opaque_ty.substs) { - let span = tcx.def_span(proj.def_id); - let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs); - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); - wfcx.register_obligations(wf_obligations); + let bound = self.wfcx.normalize(bound_span, None, bound); + self.wfcx.register_obligations(traits::wf::predicate_obligations( + self.wfcx.infcx, + self.wfcx.param_env, + self.wfcx.body_def_id, + bound, + bound_span, + )); + // Set the debruijn index back to innermost here, since we already eagerly + // shifted the substs that we use to generate these bounds. This is unfortunately + // subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`, + // but that function doesn't actually need to normalize the bound it's visiting + // (whereas we have to do so here)... + let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST); + bound.visit_with(self); + self.depth = old_depth; } } + ty.super_visit_with(self) } } @@ -1784,7 +1824,7 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id()); + let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id); hir_generics .predicates .iter() @@ -1861,16 +1901,15 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied(); // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); + let implied_obligations = traits::elaborate(tcx, predicates_with_span); - for obligation in implied_obligations { + for (pred, obligation_span) in implied_obligations { // We lower empty bounds like `Vec<dyn Copy>:` as // `WellFormed(Vec<dyn Copy>)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { + if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() { continue; } - let pred = obligation.predicate; // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_vars() { let pred = self.normalize(span, None, pred); @@ -1881,8 +1920,6 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { if let Some(hir::Generics { predicates, .. }) = hir_node.and_then(|node| node.generics()) { - let obligation_span = obligation.cause.span(); - span = predicates .iter() // There seems to be no better way to find out which predicate we are in |