From 4eee55691aeb345cbac0ad558003d5f2ed72b478 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 8 Aug 2025 19:18:17 +0200 Subject: borrowck: defer opaque type errors --- compiler/rustc_borrowck/src/diagnostics/mod.rs | 2 +- .../src/diagnostics/opaque_suggestions.rs | 243 ------------------- .../rustc_borrowck/src/diagnostics/opaque_types.rs | 262 +++++++++++++++++++++ .../src/diagnostics/region_errors.rs | 3 - compiler/rustc_borrowck/src/lib.rs | 8 +- compiler/rustc_borrowck/src/nll.rs | 5 - compiler/rustc_borrowck/src/region_infer/mod.rs | 2 +- .../src/region_infer/opaque_types.rs | 78 +++--- 8 files changed, 313 insertions(+), 290 deletions(-) delete mode 100644 compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs create mode 100644 compiler/rustc_borrowck/src/diagnostics/opaque_types.rs (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 34bed375cb9..b67dba3af96 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -51,7 +51,7 @@ mod conflict_errors; mod explain_borrow; mod move_errors; mod mutability_errors; -mod opaque_suggestions; +mod opaque_types; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs deleted file mode 100644 index 7192a889adc..00000000000 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs +++ /dev/null @@ -1,243 +0,0 @@ -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use std::ops::ControlFlow; - -use either::Either; -use itertools::Itertools as _; -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Diag, Subdiagnostic}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::{self, ConstraintCategory, Location}; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, -}; -use rustc_trait_selection::errors::impl_trait_overcapture_suggestion; - -use crate::MirBorrowckCtxt; -use crate::borrow_set::BorrowData; -use crate::consumers::RegionInferenceContext; -use crate::type_check::Locations; - -impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { - /// Try to note when an opaque is involved in a borrowck error and that - /// opaque captures lifetimes due to edition 2024. - // FIXME: This code is otherwise somewhat general, and could easily be adapted - // to explain why other things overcapture... like async fn and RPITITs. - pub(crate) fn note_due_to_edition_2024_opaque_capture_rules( - &self, - borrow: &BorrowData<'tcx>, - diag: &mut Diag<'_>, - ) { - // We look at all the locals. Why locals? Because it's the best thing - // I could think of that's correlated with the *instantiated* higher-ranked - // binder for calls, since we don't really store those anywhere else. - for ty in self.body.local_decls.iter().map(|local| local.ty) { - if !ty.has_opaque_types() { - continue; - } - - let tcx = self.infcx.tcx; - let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty - .visit_with(&mut FindOpaqueRegion { - regioncx: &self.regioncx, - tcx, - borrow_region: borrow.region, - }) - else { - continue; - }; - - // If an opaque explicitly captures a lifetime, then no need to point it out. - // FIXME: We should be using a better heuristic for `use<>`. - if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() { - continue; - } - - // If one of the opaque's bounds mentions the region, then no need to - // point it out, since it would've been captured on edition 2021 as well. - // - // Also, while we're at it, collect all the lifetimes that the opaque - // *does* mention. We'll use that for the `+ use<'a>` suggestion below. - let mut visitor = CheckExplicitRegionMentionAndCollectGenerics { - tcx, - generics: tcx.generics_of(opaque_def_id), - offending_region_idx, - seen_opaques: [opaque_def_id].into_iter().collect(), - seen_lifetimes: Default::default(), - }; - if tcx - .explicit_item_bounds(opaque_def_id) - .skip_binder() - .visit_with(&mut visitor) - .is_break() - { - continue; - } - - // If we successfully located a terminator, then point it out - // and provide a suggestion if it's local. - match self.body.stmt_at(location) { - Either::Right(mir::Terminator { source_info, .. }) => { - diag.span_note( - source_info.span, - "this call may capture more lifetimes than intended, \ - because Rust 2024 has adjusted the `impl Trait` lifetime capture rules", - ); - let mut captured_args = visitor.seen_lifetimes; - // Add in all of the type and const params, too. - // Ordering here is kinda strange b/c we're walking backwards, - // but we're trying to provide *a* suggestion, not a nice one. - let mut next_generics = Some(visitor.generics); - let mut any_synthetic = false; - while let Some(generics) = next_generics { - for param in &generics.own_params { - if param.kind.is_ty_or_const() { - captured_args.insert(param.def_id); - } - if param.kind.is_synthetic() { - any_synthetic = true; - } - } - next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id)); - } - - if let Some(opaque_def_id) = opaque_def_id.as_local() - && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = - tcx.hir_expect_opaque_ty(opaque_def_id).origin - { - if let Some(sugg) = impl_trait_overcapture_suggestion( - tcx, - opaque_def_id, - parent, - captured_args, - ) { - sugg.add_to_diag(diag); - } - } else { - diag.span_help( - tcx.def_span(opaque_def_id), - format!( - "if you can modify this crate, add a precise \ - capturing bound to avoid overcapturing: `+ use<{}>`", - if any_synthetic { - "/* Args */".to_string() - } else { - captured_args - .into_iter() - .map(|def_id| tcx.item_name(def_id)) - .join(", ") - } - ), - ); - } - return; - } - Either::Left(_) => {} - } - } - } -} - -/// This visitor contains the bulk of the logic for this lint. -struct FindOpaqueRegion<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - regioncx: &'a RegionInferenceContext<'tcx>, - borrow_region: ty::RegionVid, -} - -impl<'tcx> TypeVisitor> for FindOpaqueRegion<'_, 'tcx> { - type Result = ControlFlow<(DefId, usize, Location), ()>; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - // If we find an opaque in a local ty, then for each of its captured regions, - // try to find a path between that captured regions and our borrow region... - if let ty::Alias(ty::Opaque, opaque) = *ty.kind() - && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } = - self.tcx.opaque_ty_origin(opaque.def_id) - { - let variances = self.tcx.variances_of(opaque.def_id); - for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() { - // Skip uncaptured args. - if *variance == ty::Bivariant { - continue; - } - // We only care about regions. - let Some(opaque_region) = arg.as_region() else { - continue; - }; - // Don't try to convert a late-bound region, which shouldn't exist anyways (yet). - if opaque_region.is_bound() { - continue; - } - let opaque_region_vid = self.regioncx.to_region_vid(opaque_region); - - // Find a path between the borrow region and our opaque capture. - if let Some((path, _)) = - self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| { - r == opaque_region_vid - }) - { - for constraint in path { - // If we find a call in this path, then check if it defines the opaque. - if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category - && let ty::FnDef(call_def_id, _) = *call_ty.kind() - // This function defines the opaque :D - && call_def_id == parent - && let Locations::Single(location) = constraint.locations - { - return ControlFlow::Break((opaque.def_id, idx, location)); - } - } - } - } - } - - ty.super_visit_with(self) - } -} - -struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> { - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - offending_region_idx: usize, - seen_opaques: FxIndexSet, - seen_lifetimes: FxIndexSet, -} - -impl<'tcx> TypeVisitor> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> { - type Result = ControlFlow<(), ()>; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - match *ty.kind() { - ty::Alias(ty::Opaque, opaque) => { - if self.seen_opaques.insert(opaque.def_id) { - for (bound, _) in self - .tcx - .explicit_item_bounds(opaque.def_id) - .iter_instantiated_copied(self.tcx, opaque.args) - { - bound.visit_with(self)?; - } - } - ControlFlow::Continue(()) - } - _ => ty.super_visit_with(self), - } - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { - match r.kind() { - ty::ReEarlyParam(param) => { - if param.index as usize == self.offending_region_idx { - ControlFlow::Break(()) - } else { - self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id); - ControlFlow::Continue(()) - } - } - _ => ControlFlow::Continue(()), - } - } -} diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs new file mode 100644 index 00000000000..83fe4a9f98f --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs @@ -0,0 +1,262 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + +use std::ops::ControlFlow; + +use either::Either; +use itertools::Itertools as _; +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Diag, Subdiagnostic}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::{self, ConstraintCategory, Location}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; +use rustc_trait_selection::errors::impl_trait_overcapture_suggestion; + +use crate::MirBorrowckCtxt; +use crate::borrow_set::BorrowData; +use crate::consumers::RegionInferenceContext; +use crate::region_infer::opaque_types::DeferredOpaqueTypeError; +use crate::type_check::Locations; + +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { + pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec>) { + if errors.is_empty() { + return; + } + let mut guar = None; + for error in errors { + guar = Some(match error { + DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx), + DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => { + self.infcx.dcx().emit_err(err) + } + }); + } + let guar = guar.unwrap(); + self.root_cx.set_tainted_by_errors(guar); + self.infcx.set_tainted_by_errors(guar); + } + + /// Try to note when an opaque is involved in a borrowck error and that + /// opaque captures lifetimes due to edition 2024. + // FIXME: This code is otherwise somewhat general, and could easily be adapted + // to explain why other things overcapture... like async fn and RPITITs. + pub(crate) fn note_due_to_edition_2024_opaque_capture_rules( + &self, + borrow: &BorrowData<'tcx>, + diag: &mut Diag<'_>, + ) { + // We look at all the locals. Why locals? Because it's the best thing + // I could think of that's correlated with the *instantiated* higher-ranked + // binder for calls, since we don't really store those anywhere else. + for ty in self.body.local_decls.iter().map(|local| local.ty) { + if !ty.has_opaque_types() { + continue; + } + + let tcx = self.infcx.tcx; + let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty + .visit_with(&mut FindOpaqueRegion { + regioncx: &self.regioncx, + tcx, + borrow_region: borrow.region, + }) + else { + continue; + }; + + // If an opaque explicitly captures a lifetime, then no need to point it out. + // FIXME: We should be using a better heuristic for `use<>`. + if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() { + continue; + } + + // If one of the opaque's bounds mentions the region, then no need to + // point it out, since it would've been captured on edition 2021 as well. + // + // Also, while we're at it, collect all the lifetimes that the opaque + // *does* mention. We'll use that for the `+ use<'a>` suggestion below. + let mut visitor = CheckExplicitRegionMentionAndCollectGenerics { + tcx, + generics: tcx.generics_of(opaque_def_id), + offending_region_idx, + seen_opaques: [opaque_def_id].into_iter().collect(), + seen_lifetimes: Default::default(), + }; + if tcx + .explicit_item_bounds(opaque_def_id) + .skip_binder() + .visit_with(&mut visitor) + .is_break() + { + continue; + } + + // If we successfully located a terminator, then point it out + // and provide a suggestion if it's local. + match self.body.stmt_at(location) { + Either::Right(mir::Terminator { source_info, .. }) => { + diag.span_note( + source_info.span, + "this call may capture more lifetimes than intended, \ + because Rust 2024 has adjusted the `impl Trait` lifetime capture rules", + ); + let mut captured_args = visitor.seen_lifetimes; + // Add in all of the type and const params, too. + // Ordering here is kinda strange b/c we're walking backwards, + // but we're trying to provide *a* suggestion, not a nice one. + let mut next_generics = Some(visitor.generics); + let mut any_synthetic = false; + while let Some(generics) = next_generics { + for param in &generics.own_params { + if param.kind.is_ty_or_const() { + captured_args.insert(param.def_id); + } + if param.kind.is_synthetic() { + any_synthetic = true; + } + } + next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id)); + } + + if let Some(opaque_def_id) = opaque_def_id.as_local() + && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = + tcx.hir_expect_opaque_ty(opaque_def_id).origin + { + if let Some(sugg) = impl_trait_overcapture_suggestion( + tcx, + opaque_def_id, + parent, + captured_args, + ) { + sugg.add_to_diag(diag); + } + } else { + diag.span_help( + tcx.def_span(opaque_def_id), + format!( + "if you can modify this crate, add a precise \ + capturing bound to avoid overcapturing: `+ use<{}>`", + if any_synthetic { + "/* Args */".to_string() + } else { + captured_args + .into_iter() + .map(|def_id| tcx.item_name(def_id)) + .join(", ") + } + ), + ); + } + return; + } + Either::Left(_) => {} + } + } + } +} + +/// This visitor contains the bulk of the logic for this lint. +struct FindOpaqueRegion<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, + borrow_region: ty::RegionVid, +} + +impl<'tcx> TypeVisitor> for FindOpaqueRegion<'_, 'tcx> { + type Result = ControlFlow<(DefId, usize, Location), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + // If we find an opaque in a local ty, then for each of its captured regions, + // try to find a path between that captured regions and our borrow region... + if let ty::Alias(ty::Opaque, opaque) = *ty.kind() + && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } = + self.tcx.opaque_ty_origin(opaque.def_id) + { + let variances = self.tcx.variances_of(opaque.def_id); + for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() { + // Skip uncaptured args. + if *variance == ty::Bivariant { + continue; + } + // We only care about regions. + let Some(opaque_region) = arg.as_region() else { + continue; + }; + // Don't try to convert a late-bound region, which shouldn't exist anyways (yet). + if opaque_region.is_bound() { + continue; + } + let opaque_region_vid = self.regioncx.to_region_vid(opaque_region); + + // Find a path between the borrow region and our opaque capture. + if let Some((path, _)) = + self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| { + r == opaque_region_vid + }) + { + for constraint in path { + // If we find a call in this path, then check if it defines the opaque. + if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category + && let ty::FnDef(call_def_id, _) = *call_ty.kind() + // This function defines the opaque :D + && call_def_id == parent + && let Locations::Single(location) = constraint.locations + { + return ControlFlow::Break((opaque.def_id, idx, location)); + } + } + } + } + } + + ty.super_visit_with(self) + } +} + +struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + offending_region_idx: usize, + seen_opaques: FxIndexSet, + seen_lifetimes: FxIndexSet, +} + +impl<'tcx> TypeVisitor> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + type Result = ControlFlow<(), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match *ty.kind() { + ty::Alias(ty::Opaque, opaque) => { + if self.seen_opaques.insert(opaque.def_id) { + for (bound, _) in self + .tcx + .explicit_item_bounds(opaque.def_id) + .iter_instantiated_copied(self.tcx, opaque.args) + { + bound.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } + _ => ty.super_visit_with(self), + } + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { + match r.kind() { + ty::ReEarlyParam(param) => { + if param.index as usize == self.offending_region_idx { + ControlFlow::Break(()) + } else { + self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id); + ControlFlow::Continue(()) + } + } + _ => ControlFlow::Continue(()), + } + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b130cf8ed27..2b74f1a48f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -92,9 +92,6 @@ impl<'tcx> RegionErrors<'tcx> { ) -> impl Iterator, ErrorGuaranteed)> { self.0.into_iter() } - pub(crate) fn has_errors(&self) -> Option { - self.0.get(0).map(|x| x.1) - } } impl std::fmt::Debug for RegionErrors<'_> { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 752ff8e6f58..d76d6a04e6e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -375,7 +375,7 @@ fn do_mir_borrowck<'tcx>( polonius_context, ); - regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values); + let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values); // Dump MIR results into a file, if that is enabled. This lets us // write unit-tests, as well as helping with debugging. @@ -471,7 +471,11 @@ fn do_mir_borrowck<'tcx>( }; // Compute and report region errors, if any. - mbcx.report_region_errors(nll_errors); + if nll_errors.is_empty() { + mbcx.report_opaque_type_errors(opaque_type_errors); + } else { + mbcx.report_region_errors(nll_errors); + } let (mut flow_analysis, flow_entry_states) = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index ca6092e70d2..8608a8a3a66 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -148,11 +148,6 @@ pub(crate) fn compute_regions<'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, body, polonius_output.clone()); - if let Some(guar) = nll_errors.has_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(guar); - } - NllOutput { regioncx, polonius_input: polonius_facts.map(Box::new), diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f1320048533..f4dc9627b35 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -44,7 +44,7 @@ use crate::{ mod dump_mir; mod graphviz; -mod opaque_types; +pub(crate) mod opaque_types; mod reverse_sccs; pub(crate) mod values; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 6270e6d9a60..23c4554aa15 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -6,7 +6,9 @@ use rustc_middle::ty::{ TypeVisitableExt, fold_regions, }; use rustc_span::Span; -use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid; +use rustc_trait_selection::opaque_types::{ + InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid, +}; use tracing::{debug, instrument}; use super::RegionInferenceContext; @@ -14,6 +16,11 @@ use crate::BorrowCheckRootCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::universal_regions::RegionClassification; +pub(crate) enum DeferredOpaqueTypeError<'tcx> { + InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>), + LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. @@ -58,13 +65,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html - #[instrument(level = "debug", skip(self, root_cx, infcx), ret)] + #[instrument(level = "debug", skip(self, root_cx, infcx))] pub(crate) fn infer_opaque_types( &self, root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, - ) { + ) -> Vec> { + let mut errors = Vec::new(); let mut decls_modulo_regions: FxIndexMap, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); @@ -124,8 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); debug!(?concrete_type); - let ty = - infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); + let ty = match infcx + .infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type) + { + Ok(ty) => ty, + Err(err) => { + errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err)); + continue; + } + }; // Sometimes, when the hidden type is an inference variable, it can happen that // the hidden type becomes the opaque type itself. In this case, this was an opaque @@ -149,25 +164,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { // non-region parameters. This is necessary because within the new solver we perform // various query operations modulo regions, and thus could unsoundly select some impls // that don't hold. - if !ty.references_error() - && let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - infcx.tcx.erase_regions(opaque_type_key), - (opaque_type_key, concrete_type.span), - ) - && let Some((arg1, arg2)) = std::iter::zip( - prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - ) - .find(|(arg1, arg2)| arg1 != arg2) + if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( + infcx.tcx.erase_regions(opaque_type_key), + (opaque_type_key, concrete_type.span), + ) && let Some((arg1, arg2)) = std::iter::zip( + prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + ) + .find(|(arg1, arg2)| arg1 != arg2) { - infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { - arg: arg1, - prev: arg2, - span: prev_span, - prev_span: concrete_type.span, - }); + errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam( + LifetimeMismatchOpaqueParam { + arg: arg1, + prev: arg2, + span: prev_span, + prev_span: concrete_type.span, + }, + )); } } + + errors } /// Map the regions in the type to named regions. This is similar to what @@ -260,19 +277,13 @@ impl<'tcx> InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx> { - if let Some(e) = self.tainted_by_errors() { - return Ty::new_error(self.tcx, e); - } - - if let Err(err) = check_opaque_type_parameter_valid( + ) -> Result, InvalidOpaqueTypeArgs<'tcx>> { + check_opaque_type_parameter_valid( self, opaque_type_key, instantiated_ty.span, DefiningScopeKind::MirBorrowck, - ) { - return Ty::new_error(self.tcx, err.report(self)); - } + )?; let definition_ty = instantiated_ty .remap_generic_params_to_declaration_params( @@ -282,10 +293,7 @@ impl<'tcx> InferCtxt<'tcx> { ) .ty; - if let Err(e) = definition_ty.error_reported() { - return Ty::new_error(self.tcx, e); - } - - definition_ty + definition_ty.error_reported()?; + Ok(definition_ty) } } -- cgit 1.4.1-3-g733a5