diff options
Diffstat (limited to 'compiler')
41 files changed, 602 insertions, 452 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 942aae3d536..73d1d891bb9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -323,9 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => { - hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) - } + ExprKind::Err => hir::ExprKind::Err(self.dcx().has_errors().unwrap()), ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Paren(_) | ExprKind::ForLoop { .. } => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 933372fae4e..87ed47648c8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1068,7 +1068,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> { match block { Some(block) => self.lower_block_expr(block), - None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")), + None => self.expr_err(span, self.dcx().has_errors().unwrap()), } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 480072ce705..6b5fc014240 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1285,9 +1285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => { - hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered")) - } + TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()), // Lower the anonymous structs or unions in a nested lowering context. // // ``` diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 5ce6a71c4bd..b5c70538c52 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -117,18 +117,14 @@ struct CfgChecker<'a, 'tcx> { impl<'a, 'tcx> CfgChecker<'a, 'tcx> { #[track_caller] fn fail(&self, location: Location, msg: impl AsRef<str>) { - let span = self.body.source_info(location).span; - // We use `span_delayed_bug` as we might see broken MIR when other errors have already - // occurred. - self.tcx.dcx().span_delayed_bug( - span, - format!( - "broken MIR in {:?} ({}) at {:?}:\n{}", - self.body.source.instance, - self.when, - location, - msg.as_ref() - ), + // We might see broken MIR when other errors have already occurred. + assert!( + self.tcx.dcx().has_errors().is_some(), + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.body.source.instance, + self.when, + location, + msg.as_ref(), ); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b738ecb54ff..d876f28040d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1315,6 +1315,9 @@ impl DiagCtxtInner { self.future_breakage_diagnostics.push(diagnostic.clone()); } + // Note that because this comes before the `match` below, + // `-Zeagerly-emit-delayed-bugs` continues to work even after we've + // issued an error and stopped recording new delayed bugs. if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs { diagnostic.level = Error; } @@ -1326,18 +1329,20 @@ impl DiagCtxtInner { diagnostic.level = Bug; } DelayedBug => { - // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `delayed_bugs` - // when an error is first emitted, also), but maybe there's a case - // in which that's not sound? otherwise this is really inefficient. - let backtrace = std::backtrace::Backtrace::capture(); - // This `unchecked_error_guaranteed` is valid. It is where the - // `ErrorGuaranteed` for delayed bugs originates. - #[allow(deprecated)] - let guar = ErrorGuaranteed::unchecked_error_guaranteed(); - self.delayed_bugs - .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar)); - return Some(guar); + // If we have already emitted at least one error, we don't need + // to record the delayed bug, because it'll never be used. + return if let Some(guar) = self.has_errors_or_lint_errors() { + Some(guar) + } else { + let backtrace = std::backtrace::Backtrace::capture(); + // This `unchecked_error_guaranteed` is valid. It is where the + // `ErrorGuaranteed` for delayed bugs originates. + #[allow(deprecated)] + let guar = ErrorGuaranteed::unchecked_error_guaranteed(); + self.delayed_bugs + .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar)); + Some(guar) + }; } Warning if !self.flags.can_emit_warnings => { if diagnostic.has_future_breakage() { @@ -1403,6 +1408,16 @@ impl DiagCtxtInner { } if is_error { + // If we have any delayed bugs recorded, we can discard them + // because they won't be used. (This should only occur if there + // have been no errors previously emitted, because we don't add + // new delayed bugs once the first error is emitted.) + if !self.delayed_bugs.is_empty() { + assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0); + self.delayed_bugs.clear(); + self.delayed_bugs.shrink_to_fit(); + } + // This `unchecked_error_guaranteed` is valid. It is where the // `ErrorGuaranteed` for errors and lint errors originates. #[allow(deprecated)] diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index eec86c36aed..be4b6399e12 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -34,10 +34,10 @@ pub(super) fn failed_to_match_macro<'cx>( if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, // but for that it must have emitted an error already - tracker - .cx - .dcx() - .span_delayed_bug(sp, "Macro matching returned a success on the second try"); + assert!( + tracker.cx.dcx().has_errors().is_some(), + "Macro matching returned a success on the second try" + ); } if let Some(result) = tracker.result { diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index a6ac8ecd950..cee7c84adb2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| { if self_ty.span.can_be_used_for_suggestions() { lint.multipart_suggestion_verbose( - "use `dyn`", + "if this is an object-safe trait, use `dyn`", sugg, Applicability::MachineApplicable, ); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a001044c3e5..98a27c5ed20 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -758,8 +758,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // since we should have emitten an error for them earlier, and they will // not be well-formed! if polarity == ty::ImplPolarity::Negative { - self.tcx().dcx().span_delayed_bug( - binding.span, + assert!( + self.tcx().dcx().has_errors().is_some(), "negative trait bounds should not have bindings", ); continue; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7f674a1e7e4..e7506cee60e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1865,13 +1865,13 @@ fn check_variances_for_type_defn<'tcx>( let hir_param = &hir_generics.params[index]; if ty_param.def_id != hir_param.def_id.into() { - // valid programs always have lifetimes before types in the generic parameter list + // Valid programs always have lifetimes before types in the generic parameter list. // ty_generics are normalized to be in this required order, and variances are built // from ty generics, not from hir generics. but we need hir generics to get - // a span out + // a span out. // - // if they aren't in the same order, then the user has written invalid code, and already - // got an error about it (or I'm wrong about this) + // If they aren't in the same order, then the user has written invalid code, and already + // got an error about it (or I'm wrong about this). tcx.dcx().span_delayed_bug( hir_param.span, "hir generics and ty generics in different order", diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 688760a3912..53a5ada4105 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -85,7 +85,7 @@ pub(super) fn check_item( (_, _, Unsafety::Unsafe, Negative) => { // Reported in AST validation - tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "unsafe negative impl"); + assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl"); Ok(()) } (_, _, Unsafety::Normal, Negative) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index f21de1609cb..9a8f287ec14 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -139,10 +139,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { - let reported = self + let guar = self .dcx() .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?")); - return Err(reported); + return Err(guar); } }) } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d84bce09ecb..b83a0f893f5 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -221,8 +221,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been - // emitted, so we delay an ICE if none have. (#64638) - self.tcx().dcx().span_delayed_bug(e.span, format!("bad base: `{base:?}`")); + // emitted. (#64638) + assert!(self.tcx().dcx().has_errors().is_some(), "bad base: `{base:?}`"); } if let Some(base_ty) = base_ty && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 6137506d4a9..c39d0425f7e 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -802,14 +802,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } // Errors in earlier passes can yield error variables without - // resolution errors here; delay ICE in favor of those errors. - self.tcx().dcx().span_delayed_bug( - self.var_infos[node_idx].origin.span(), - format!( - "collect_error_for_expanding_node() could not find \ - error for var {node_idx:?} in universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \ - upper_bounds={upper_bounds:#?}" - ), + // resolution errors here; ICE if no errors have been emitted yet. + assert!( + self.tcx().dcx().has_errors().is_some(), + "collect_error_for_expanding_node() could not find error for var {node_idx:?} in \ + universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \ + upper_bounds={upper_bounds:#?}", ); } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 7208f17fb34..c0a99e5cc41 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -300,9 +300,9 @@ where self.components_must_outlive(origin, subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be + // Ignore this, we presume it will yield an error later, + // since if a type variable is not resolved by this point + // it never will be. self.tcx.dcx().span_delayed_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 24b351988bf..3ef37bf3466 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -172,13 +172,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { self.bound_from_components(components, visited) } Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be + // Ignore this, we presume it will yield an error later, since + // if a type variable is not resolved by this point it never + // will be. self.tcx .dcx() .delayed_bug(format!("unresolved inference variable in outlives: {v:?}")); - // add a bound that never holds + // Add a bound that never holds. VerifyBound::AnyBound(vec![]) } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 5ae080d4702..0862204d88e 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -431,14 +431,13 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>( // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. for (id, lints) in cx.context.buffered.map { - for early_lint in lints { - sess.dcx().span_delayed_bug( - early_lint.span, - format!( - "failed to process buffered lint here (dummy = {})", - id == ast::DUMMY_NODE_ID - ), + if !lints.is_empty() { + assert!( + sess.dcx().has_errors().is_some(), + "failed to process buffered lint here (dummy = {})", + id == ast::DUMMY_NODE_ID ); + break; } } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 6ffa0819f35..2a6f473cd32 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -207,6 +207,11 @@ pub fn explain_lint_level_source( err: &mut Diagnostic, ) { let name = lint.name_lower(); + if let Level::Allow = level { + // Do not point at `#[allow(compat_lint)]` as the reason for a compatibility lint + // triggering. (#121009) + return; + } match src { LintLevelSource::Default => { err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name)); diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 23771073745..5e4d899f517 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -35,6 +35,16 @@ impl<'tcx> IntoKind for Const<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> { fn ty(self) -> Ty<'tcx> { self.ty() @@ -63,11 +73,13 @@ impl<'tcx> Const<'tcx> { self.0.kind } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn flags(self) -> TypeFlags { self.0.flags } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bd86c1c284e..61e449b8b56 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,7 +28,7 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - Visibility, + TypeVisitable, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -87,7 +87,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; - type Binder<T> = Binder<'tcx, T>; + type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; + type BoundVars = &'tcx List<ty::BoundVariableKind>; + type BoundVar = ty::BoundVariableKind; type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; @@ -151,6 +153,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::Const { Const::new_bound(self, debruijn, var, ty) } + + fn expect_error_or_delayed_bug() { + let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()); + assert!(has_errors.is_some()); + } } type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2d6c6cfbcd1..15bddb2a64f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -504,6 +504,16 @@ impl<'tcx> IntoKind for Ty<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Ty<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl EarlyParamRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 200811940ed..b63f9c6dfa0 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -29,6 +29,16 @@ pub struct Predicate<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, ); +impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl<'tcx> Predicate<'tcx> { /// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`. #[inline] @@ -36,11 +46,13 @@ impl<'tcx> Predicate<'tcx> { self.0.internee } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn flags(self) -> TypeFlags { self.0.flags } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn outer_exclusive_binder(self) -> DebruijnIndex { self.0.outer_exclusive_binder diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 1191d7fca32..b206727f051 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -26,6 +26,19 @@ impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Region<'tcx> { + fn flags(&self) -> TypeFlags { + self.type_flags() + } + + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { + match **self { + ty::ReBound(debruijn, _) => debruijn.shifted_in(1), + _ => ty::INNERMOST, + } + } +} + impl<'tcx> Region<'tcx> { #[inline] pub fn new_early_param( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a3d5f1f1955..ae6544b9dbe 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -942,6 +942,16 @@ where } } +impl<'tcx, T> rustc_type_ir::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { + fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> { + self.bound_vars + } + + fn has_no_bound_vars(&self) -> bool { + self.bound_vars.is_empty() + } +} + impl<'tcx, T> Binder<'tcx, T> { /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about @@ -1808,6 +1818,7 @@ impl<'tcx> Ty<'tcx> { self.0.0 } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn flags(self) -> TypeFlags { self.0.0.flags diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c674a868d9f..09bb06de483 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1320,6 +1320,7 @@ impl<'tcx> Ty<'tcx> { ty } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 7acdb931f1a..59292a281ed 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,140 +1,10 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_errors::ErrorGuaranteed; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use std::ops::ControlFlow; -pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; - -pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { - /// Returns `true` if `self` has any late-bound regions that are either - /// bound by `binder` or bound by some binder outside of `binder`. - /// If `binder` is `ty::INNERMOST`, this indicates whether - /// there are any late-bound regions that appear free. - fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() - } - - /// Returns `true` if this type has any regions that escape `binder` (and - /// hence are not bound by it). - fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { - self.has_vars_bound_at_or_above(binder.shifted_in(1)) - } - - /// Return `true` if this type has regions that are not a part of the type. - /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)` - /// would return `true`. The latter can occur when traversing through the - /// former. - /// - /// See [`HasEscapingVarsVisitor`] for more information. - fn has_escaping_bound_vars(&self) -> bool { - self.has_vars_bound_at_or_above(ty::INNERMOST) - } - - fn has_type_flags(&self, flags: TypeFlags) -> bool { - let res = - self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags); - trace!(?self, ?flags, ?res, "has_type_flags"); - res - } - fn has_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn has_inherent_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INHERENT) - } - fn has_opaque_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) - } - fn has_coroutines(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_COROUTINE) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_ERROR) - } - fn error_reported(&self) -> Result<(), ErrorGuaranteed> { - if self.references_error() { - // We must include lint errors and delayed bugs here. - if let Some(reported) = - ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()) - { - Err(reported) - } else { - bug!("expected some kind of error in `error_reported`"); - } - } else { - Ok(()) - } - } - fn has_non_region_param(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM) - } - fn has_infer_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_INFER) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn has_non_region_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER) - } - fn has_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_INFER) - } - fn has_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PLACEHOLDER) - } - fn has_non_region_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER) - } - fn has_param(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAM) - } - /// "Free" regions in this context means that it has any region - /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - fn has_erased_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_ERASED) - } - - /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - /// Indicates whether this value references only 'global' - /// generic parameters that are the same regardless of what fn we are - /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) - } - - /// True if there are any late-bound regions - fn has_bound_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_BOUND) - } - /// True if there are any late-bound non-region variables - fn has_non_region_bound_vars(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND) - } - /// True if there are any bound variables - fn has_bound_vars(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_BOUND_VARS) - } - - /// Indicates whether this value still has parameters/placeholders/inference variables - /// which could be replaced later, in a way that would change the results of `impl` - /// specialization. - fn still_further_specializable(&self) -> bool { - self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) - } -} - -impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {} +pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; /////////////////////////////////////////////////////////////////////////// // Region folder @@ -370,185 +240,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundEscapingVars; - -/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a -/// bound region or a bound type. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping var" is often just called a "free var". However, -/// we already use the term "free var". It refers to the regions or types that we use to represent -/// bound regions or type params on a fn definition while we are type checking its body. -/// -/// To clarify, conceptually there is no particular difference between -/// an "escaping" var and a "free" var. However, there is a big -/// difference in practice. Basically, when "entering" a binding -/// level, one is generally required to do some sort of processing to -/// a bound var, such as replacing it with a fresh/placeholder -/// var, or making an entry in the environment to represent the -/// scope to which it is attached, etc. An escaping var represents -/// a bound var for which this processing has not yet been done. -struct HasEscapingVarsVisitor { - /// Anything bound by `outer_index` or "above" is escaping. - outer_index: ty::DebruijnIndex, -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor { - type BreakTy = FoundEscapingVars; - - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.outer_index.shift_in(1); - let result = t.super_visit_with(self); - self.outer_index.shift_out(1); - result - } - - #[inline] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `t` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - if t.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the region is bound by `outer_index` or anything outside - // of outer index, then it escapes the binders we have - // visited. - if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `ct` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - if ct.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - if predicate.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundFlags; - -// FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, -} - -impl std::fmt::Debug for HasTypeFlagsVisitor { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.flags.fmt(fmt) - } -} - -// Note: this visitor traverses values down to the level of -// `Ty`/`Const`/`Predicate`, but not within those types. This is because the -// type flags at the outer layer are enough. So it's faster than it first -// looks, particular for `Ty`/`Predicate` where it's just a field access. -// -// N.B. The only case where this isn't totally true is binders, which also -// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that -// are present, regardless of whether those bound variables are used. This -// is important for anonymization of binders in `TyCtxt::erase_regions`. We -// specifically detect this case in `visit_binder`. -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor { - type BreakTy = FoundFlags; - - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - // If we're looking for the HAS_BINDER_VARS flag, check if the - // binder has vars. This won't be present in the binder's bound - // value, so we need to check here too. - if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() { - return ControlFlow::Break(FoundFlags); - } - - t.super_visit_with(self) - } - - #[inline] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - let flags = t.flags(); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call, as usual for `Region`. - let flags = r.type_flags(); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - if c.flags().intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - if predicate.flags().intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } -} - /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8688c589063..241b6c6cb2c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -33,7 +33,7 @@ struct UnsafetyVisitor<'a, 'tcx> { body_target_features: &'tcx [Symbol], /// When inside the LHS of an assignment to a field, this is the type /// of the LHS and the span of the assignment expression. - assignment_info: Option<(Ty<'tcx>, Span)>, + assignment_info: Option<Ty<'tcx>>, in_union_destructure: bool, param_env: ParamEnv<'tcx>, inside_adt: bool, @@ -473,10 +473,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { - if let Some((assigned_ty, assignment_span)) = self.assignment_info { + if let Some(assigned_ty) = self.assignment_info { if assigned_ty.needs_drop(self.tcx, self.param_env) { - // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.dcx().span_delayed_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}")); + // This would be unsafe, but should be outright impossible since we + // reject such unions. + assert!( + self.tcx.dcx().has_errors().is_some(), + "union fields that need dropping should be impossible: \ + {assigned_ty}" + ); } } else { self.requires_unsafe(expr.span, AccessToUnionField); @@ -492,14 +497,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField); } - // Second, check for accesses to union fields - // don't have any special handling for AssignOp since it causes a read *and* write to lhs + // Second, check for accesses to union fields. Don't have any + // special handling for AssignOp since it causes a read *and* + // write to lhs. if matches!(expr.kind, ExprKind::Assign { .. }) { - self.assignment_info = Some((lhs.ty, expr.span)); + self.assignment_info = Some(lhs.ty); visit::walk_expr(self, lhs); self.assignment_info = None; visit::walk_expr(self, &self.thir()[rhs]); - return; // we have already visited everything by now + return; // We have already visited everything by now. } } ExprKind::Borrow { borrow_kind, arg } => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 18a00724c3d..c77c80d9f4b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -153,8 +153,7 @@ impl<'tcx> ConstToPat<'tcx> { // a hard error when we don't have a valtree or when we find something in // the valtree that is not structural; then this can all be made a lot simpler. - let structural = - traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty()); + let structural = traits::search_for_structural_match_violation(self.tcx(), cv.ty()); debug!( "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", cv.ty(), diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index fbb62695383..a0c3de3af58 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -243,10 +243,11 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // old value is being dropped. let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; if assigned_ty.needs_drop(self.tcx, self.param_env) { - // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.dcx().span_delayed_bug( - self.source_info.span, - format!("union fields that need dropping should be impossible: {assigned_ty}") + // This would be unsafe, but should be outright impossible since we reject + // such unions. + assert!( + self.tcx.dcx().has_errors().is_some(), + "union fields that need dropping should be impossible: {assigned_ty}" ); } } else { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8d4afd5b5dc..370f0db72cb 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -561,9 +561,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { .ok()?; dest.into() } - CastKind::FnPtrToPtr - | CastKind::PtrToPtr - | CastKind::PointerCoercion( + CastKind::FnPtrToPtr | CastKind::PtrToPtr => { + let src = self.evaluated[value].as_ref()?; + let src = self.ecx.read_immediate(src).ok()?; + let to = self.ecx.layout_of(to).ok()?; + let ret = self.ecx.ptr_to_ptr(&src, to).ok()?; + ret.into() + } + CastKind::PointerCoercion( ty::adjustment::PointerCoercion::MutToConstPointer | ty::adjustment::PointerCoercion::ArrayToPointer | ty::adjustment::PointerCoercion::UnsafeFnPointer, @@ -571,8 +576,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let src = self.evaluated[value].as_ref()?; let src = self.ecx.read_immediate(src).ok()?; let to = self.ecx.layout_of(to).ok()?; - let ret = self.ecx.ptr_to_ptr(&src, to).ok()?; - ret.into() + ImmTy::from_immediate(*src, to).into() } _ => return None, }, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9f30f2836f1..c11fd5fcc90 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -265,7 +265,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { let body = &tcx.mir_const(def).borrow(); if body.return_ty().references_error() { - tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors"); + assert!(tcx.dcx().has_errors().is_some(), "mir_const_qualif: MIR had errors"); return Default::default(); } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 42edbeaa622..cd434fecce2 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, ConstTy, InferCtxtLike, Interner, IntoKind, PlaceholderLike, @@ -62,8 +63,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc let value = value.fold_with(&mut canonicalizer); // FIXME: Restore these assertions. Should we uplift type flags? - // assert!(!value.has_infer(), "unexpected infer in {value:?}"); - // assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); + assert!(!value.has_infer(), "unexpected infer in {value:?}"); + assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); let (max_universe, variables) = canonicalizer.finalize(); diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 9158ba00901..754757b5de5 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -429,16 +429,16 @@ where let formatter = query.format_value(); if old_hash != new_hash { // We have an inconsistency. This can happen if one of the two - // results is tainted by errors. In this case, delay a bug to - // ensure compilation is doomed. - qcx.dep_context().sess().dcx().delayed_bug(format!( + // results is tainted by errors. + assert!( + qcx.dep_context().sess().dcx().has_errors().is_some(), "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ computed={:#?}\nfed={:#?}", query.dep_kind(), key, formatter(&result), formatter(&cached_result), - )); + ); } } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 522c645253a..1edf6b11fc3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -62,9 +62,10 @@ pub fn is_const_evaluatable<'tcx>( match unexpanded_ct.kind() { ty::ConstKind::Expr(_) => { - // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but - // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it - // is evaluatable or not. For now we just ICE until this is implemented. + // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, + // but currently it is not possible to evaluate `ConstKind::Expr` so we are unable + // to tell if it is evaluatable or not. For now we just ICE until this is + // implemented. Err(NotConstEvaluatable::Error(tcx.dcx().span_delayed_bug( span, "evaluating `ConstKind::Expr` is not currently supported", 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 c7b56aac7e5..335e6ff2822 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3041,7 +3041,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { this = "the implicit `Sized` requirement on this type parameter"; } if let Some(hir::Node::TraitItem(hir::TraitItem { - ident, + generics, kind: hir::TraitItemKind::Type(bounds, None), .. })) = tcx.hir().get_if_local(item_def_id) @@ -3053,7 +3053,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let (span, separator) = if let [.., last] = bounds { (last.span().shrink_to_hi(), " +") } else { - (ident.span.shrink_to_hi(), ":") + (generics.span.shrink_to_hi(), ":") }; err.span_suggestion_verbose( span, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index c5ee0391682..2c8d3fc9de2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -236,9 +236,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - // It could be that we don't report an error because we have seen an `ErrorReported` from another source. - // We should probably be able to fix most of these, but some are delayed bugs that get a proper error - // after this function. + // It could be that we don't report an error because we have seen an `ErrorReported` from + // another source. We should probably be able to fix most of these, but some are delayed + // bugs that get a proper error after this function. reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) } @@ -519,7 +519,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, span, ) { - GetSafeTransmuteErrorAndReason::Silent => return self.dcx().span_delayed_bug(span, "silent safe transmute error"), + GetSafeTransmuteErrorAndReason::Silent => { + return self.dcx().span_delayed_bug( + span, "silent safe transmute error" + ); + } GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, @@ -2990,7 +2994,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { (s, " +") } else { - (span.shrink_to_hi(), ":") + (param.name.ident().span.shrink_to_hi(), ":") }; err.span_suggestion_verbose( span, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 29a4a078fe0..7b715984c2b 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -555,7 +555,7 @@ fn virtual_call_violations_for_method<'tcx>( // NOTE: This check happens last, because it results in a lint, and not a // hard error. - if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| { + if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| { // dyn Trait is okay: // // trait Trait { @@ -594,7 +594,10 @@ fn virtual_call_violations_for_method<'tcx>( // would already have reported an error at the definition of the // auto trait. if pred_trait_ref.args.len() != 1 { - tcx.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters"); + assert!( + tcx.dcx().has_errors().is_some(), + "auto traits cannot have generic parameters" + ); } return false; } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 89459f377dd..e6b42f15d51 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::Span; use std::ops::ControlFlow; /// This method traverses the structure of `ty`, trying to find an @@ -30,19 +29,16 @@ use std::ops::ControlFlow; /// that arose when the requirement was not enforced completely, see /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. pub fn search_for_structural_match_violation<'tcx>( - span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option<Ty<'tcx>> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default() }).break_value() + ty.visit_with(&mut Search { tcx, seen: FxHashSet::default() }).break_value() } /// This implements the traversal over the structure of a given type to try to /// find instances of ADTs (specifically structs or enums) that do not implement /// `StructuralPartialEq`. struct Search<'tcx> { - span: Span, - tcx: TyCtxt<'tcx>, /// Tracks ADTs previously encountered during search, so that @@ -138,7 +134,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { bug!("unexpected type during structural-match checking: {:?}", ty); } ty::Error(_) => { - self.tcx.dcx().span_delayed_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. return ControlFlow::Continue(()); diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs new file mode 100644 index 00000000000..57f961ac97e --- /dev/null +++ b/compiler/rustc_type_ir/src/binder.rs @@ -0,0 +1,7 @@ +use crate::Interner; + +pub trait BoundVars<I: Interner> { + fn bound_vars(&self) -> I::BoundVars; + + fn has_no_bound_vars(&self) -> bool; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 188910ecc52..7728ee0e842 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,9 +2,10 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; +use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ - BoundVar, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind, TyKind, - UniverseIndex, + BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind, + TyKind, UniverseIndex, }; pub trait Interner: Sized { @@ -19,7 +20,10 @@ pub trait Interner: Sized { type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord; type Term: Copy + Debug + Hash + Ord; - type Binder<T>; + type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>; + type BoundVars: IntoIterator<Item = Self::BoundVar>; + type BoundVar; + type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>; // Kinds of tys @@ -28,7 +32,9 @@ pub trait Interner: Sized { + Hash + Ord + Into<Self::GenericArg> - + IntoKind<Kind = TyKind<Self>>; + + IntoKind<Kind = TyKind<Self>> + + TypeSuperVisitable<Self> + + Flags; type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord; type ParamTy: Copy + Debug + Hash + Ord; @@ -48,7 +54,9 @@ pub trait Interner: Sized { + Ord + Into<Self::GenericArg> + IntoKind<Kind = ConstKind<Self>> - + ConstTy<Self>; + + ConstTy<Self> + + TypeSuperVisitable<Self> + + Flags; type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike; type ParamConst: Copy + Debug + Hash + Ord; @@ -62,7 +70,8 @@ pub trait Interner: Sized { + Hash + Ord + Into<Self::GenericArg> - + IntoKind<Kind = RegionKind<Self>>; + + IntoKind<Kind = RegionKind<Self>> + + Flags; type EarlyParamRegion: Copy + Debug + Hash + Ord; type LateParamRegion: Copy + Debug + Hash + Ord; type BoundRegion: Copy + Debug + Hash + Ord; @@ -70,7 +79,7 @@ pub trait Interner: Sized { type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike; // Predicates - type Predicate: Copy + Debug + Hash + Eq; + type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; type TraitPredicate: Copy + Debug + Hash + Eq; type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; @@ -86,6 +95,9 @@ pub trait Interner: Sized { fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty; fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region; fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const; + + /// Assert that an error has been delayed or emitted. + fn expect_error_or_delayed_bug(); } /// Common capabilities of placeholder kinds diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index f498c5531fc..94ccbcbd8a5 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -30,6 +30,7 @@ pub mod visit; #[macro_use] mod macros; +mod binder; mod canonical; mod const_kind; mod debug; @@ -39,6 +40,7 @@ mod interner; mod predicate_kind; mod region_kind; +pub use binder::*; pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 7aa99004667..638fb9f7fa9 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -45,8 +45,7 @@ use rustc_index::{Idx, IndexVec}; use std::fmt; use std::ops::ControlFlow; -use crate::Interner; -use crate::Lrc; +use crate::{self as ty, BoundVars, Interner, IntoKind, Lrc, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -88,38 +87,28 @@ pub trait TypeVisitor<I: Interner>: Sized { #[cfg(not(feature = "nightly"))] type BreakTy; - fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy> - where - I::Binder<T>: TypeSuperVisitable<I>, - { + fn visit_binder<T: TypeVisitable<I>>( + &mut self, + t: &I::Binder<T>, + ) -> ControlFlow<Self::BreakTy> { t.super_visit_with(self) } - fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> - where - I::Ty: TypeSuperVisitable<I>, - { + fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> { t.super_visit_with(self) } // The default region visitor is a no-op because `Region` is non-recursive - // and has no `super_visit_with` method to call. That also explains the - // lack of `I::Region: TypeSuperVisitable<I>` bound. + // and has no `super_visit_with` method to call. fn visit_region(&mut self, _r: I::Region) -> ControlFlow<Self::BreakTy> { ControlFlow::Continue(()) } - fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> - where - I::Const: TypeSuperVisitable<I>, - { + fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy> - where - I::Predicate: TypeSuperVisitable<I>, - { + fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy> { p.super_visit_with(self) } } @@ -200,3 +189,363 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix self.iter().try_for_each(|t| t.visit_with(visitor)) } } + +pub trait Flags { + fn flags(&self) -> TypeFlags; + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex; +} + +pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> { + fn has_type_flags(&self, flags: TypeFlags) -> bool; + + /// Returns `true` if `self` has any late-bound regions that are either + /// bound by `binder` or bound by some binder outside of `binder`. + /// If `binder` is `ty::INNERMOST`, this indicates whether + /// there are any late-bound regions that appear free. + fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool; + + /// Returns `true` if this type has any regions that escape `binder` (and + /// hence are not bound by it). + fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { + self.has_vars_bound_at_or_above(binder.shifted_in(1)) + } + + /// Return `true` if this type has regions that are not a part of the type. + /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)` + /// would return `true`. The latter can occur when traversing through the + /// former. + /// + /// See [`HasEscapingVarsVisitor`] for more information. + fn has_escaping_bound_vars(&self) -> bool { + self.has_vars_bound_at_or_above(ty::INNERMOST) + } + + fn has_projections(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PROJECTION) + } + + fn has_inherent_projections(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INHERENT) + } + + fn has_opaque_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) + } + + fn has_coroutines(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_COROUTINE) + } + + fn references_error(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_ERROR) + } + + fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>; + + fn has_non_region_param(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM) + } + + fn has_infer_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_INFER) + } + + fn has_infer_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER) + } + + fn has_non_region_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER) + } + + fn has_infer(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_INFER) + } + + fn has_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PLACEHOLDER) + } + + fn has_non_region_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER) + } + + fn has_param(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PARAM) + } + + /// "Free" regions in this context means that it has any region + /// that is not (a) erased or (b) late-bound. + fn has_free_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + } + + fn has_erased_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_ERASED) + } + + /// True if there are any un-erased free regions. + fn has_erasable_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + } + + /// Indicates whether this value references only 'global' + /// generic parameters that are the same regardless of what fn we are + /// in. This is used for caching. + fn is_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) + } + + /// True if there are any late-bound regions + fn has_bound_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_BOUND) + } + /// True if there are any late-bound non-region variables + fn has_non_region_bound_vars(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND) + } + /// True if there are any bound variables + fn has_bound_vars(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_BOUND_VARS) + } + + /// Indicates whether this value still has parameters/placeholders/inference variables + /// which could be replaced later, in a way that would change the results of `impl` + /// specialization. + fn still_further_specializable(&self) -> bool { + self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) + } +} + +impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T { + fn has_type_flags(&self, flags: TypeFlags) -> bool { + let res = + self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags); + res + } + + fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { + self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() + } + + fn error_reported(&self) -> Result<(), I::ErrorGuaranteed> { + if self.references_error() { + if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) { + Err(guar) + } else { + panic!("type flags said there was an error, but now there is not") + } + } else { + Ok(()) + } + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundFlags; + +// FIXME: Optimize for checking for infer flags +struct HasTypeFlagsVisitor { + flags: ty::TypeFlags, +} + +impl std::fmt::Debug for HasTypeFlagsVisitor { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.flags.fmt(fmt) + } +} + +// Note: this visitor traverses values down to the level of +// `Ty`/`Const`/`Predicate`, but not within those types. This is because the +// type flags at the outer layer are enough. So it's faster than it first +// looks, particular for `Ty`/`Predicate` where it's just a field access. +// +// N.B. The only case where this isn't totally true is binders, which also +// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that +// are present, regardless of whether those bound variables are used. This +// is important for anonymization of binders in `TyCtxt::erase_regions`. We +// specifically detect this case in `visit_binder`. +impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { + type BreakTy = FoundFlags; + + fn visit_binder<T: TypeVisitable<I>>( + &mut self, + t: &I::Binder<T>, + ) -> ControlFlow<Self::BreakTy> { + // If we're looking for the HAS_BINDER_VARS flag, check if the + // binder has vars. This won't be present in the binder's bound + // value, so we need to check here too. + if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() { + return ControlFlow::Break(FoundFlags); + } + + t.super_visit_with(self) + } + + #[inline] + fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> { + // Note: no `super_visit_with` call. + let flags = t.flags(); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } + + #[inline] + fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> { + // Note: no `super_visit_with` call, as usual for `Region`. + let flags = r.flags(); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } + + #[inline] + fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> { + // Note: no `super_visit_with` call. + if c.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } + + #[inline] + fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> { + // Note: no `super_visit_with` call. + if predicate.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundEscapingVars; + +/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a +/// bound region or a bound type. +/// +/// So, for example, consider a type like the following, which has two binders: +/// +/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope +/// +/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the +/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner +/// fn type*, that type has an escaping region: `'a`. +/// +/// Note that what I'm calling an "escaping var" is often just called a "free var". However, +/// we already use the term "free var". It refers to the regions or types that we use to represent +/// bound regions or type params on a fn definition while we are type checking its body. +/// +/// To clarify, conceptually there is no particular difference between +/// an "escaping" var and a "free" var. However, there is a big +/// difference in practice. Basically, when "entering" a binding +/// level, one is generally required to do some sort of processing to +/// a bound var, such as replacing it with a fresh/placeholder +/// var, or making an entry in the environment to represent the +/// scope to which it is attached, etc. An escaping var represents +/// a bound var for which this processing has not yet been done. +struct HasEscapingVarsVisitor { + /// Anything bound by `outer_index` or "above" is escaping. + outer_index: ty::DebruijnIndex, +} + +impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor { + type BreakTy = FoundEscapingVars; + + fn visit_binder<T: TypeVisitable<I>>( + &mut self, + t: &I::Binder<T>, + ) -> ControlFlow<Self::BreakTy> { + self.outer_index.shift_in(1); + let result = t.super_visit_with(self); + self.outer_index.shift_out(1); + result + } + + #[inline] + fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> { + // If the outer-exclusive-binder is *strictly greater* than + // `outer_index`, that means that `t` contains some content + // bound at `outer_index` or above (because + // `outer_exclusive_binder` is always 1 higher than the + // content in `t`). Therefore, `t` has some escaping vars. + if t.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } + + #[inline] + fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> { + // If the region is bound by `outer_index` or anything outside + // of outer index, then it escapes the binders we have + // visited. + if r.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } + + fn visit_const(&mut self, ct: I::Const) -> ControlFlow<Self::BreakTy> { + // If the outer-exclusive-binder is *strictly greater* than + // `outer_index`, that means that `ct` contains some content + // bound at `outer_index` or above (because + // `outer_exclusive_binder` is always 1 higher than the + // content in `t`). Therefore, `t` has some escaping vars. + if ct.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } + + #[inline] + fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> { + if predicate.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } +} + +struct HasErrorVisitor; + +impl<I: Interner> TypeVisitor<I> for HasErrorVisitor { + type BreakTy = I::ErrorGuaranteed; + + fn visit_ty(&mut self, t: <I as Interner>::Ty) -> ControlFlow<Self::BreakTy> { + if let ty::Error(guar) = t.kind() { + ControlFlow::Break(guar) + } else { + t.super_visit_with(self) + } + } + + fn visit_const(&mut self, c: <I as Interner>::Const) -> ControlFlow<Self::BreakTy> { + if let ty::ConstKind::Error(guar) = c.kind() { + ControlFlow::Break(guar) + } else { + c.super_visit_with(self) + } + } + + fn visit_region(&mut self, r: <I as Interner>::Region) -> ControlFlow<Self::BreakTy> { + if let ty::ReError(guar) = r.kind() { + ControlFlow::Break(guar) + } else { + ControlFlow::Continue(()) + } + } +} |
