From 946462a12cac408bb5bc1541a41bbebc5f7b2fd9 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 31 Oct 2020 16:12:23 +0100 Subject: [PATCH 1/2] Use `ControlFlow` in `Visitor` --- chalk-derive/src/lib.rs | 14 +- chalk-engine/src/lib.rs | 2 +- chalk-ir/src/lib.rs | 2 +- chalk-ir/src/visit.rs | 274 +++++++++--------- chalk-ir/src/visit/binder_impls.rs | 20 +- chalk-ir/src/visit/boring_impls.rs | 137 +++++---- chalk-ir/src/visit/visitors.rs | 44 +-- .../src/clauses/builtin_traits/unsize.rs | 33 +-- chalk-solve/src/clauses/env_elaborator.rs | 18 +- chalk-solve/src/infer/ucanonicalize.rs | 13 +- chalk-solve/src/logging_db/id_collector.rs | 11 +- chalk-solve/src/rust_ir.rs | 34 +-- chalk-solve/src/solve/truncate.rs | 11 +- chalk-solve/src/wf.rs | 63 ++-- 14 files changed, 318 insertions(+), 358 deletions(-) diff --git a/chalk-derive/src/lib.rs b/chalk-derive/src/lib.rs index 3bc1573e265..53c8e365944 100644 --- a/chalk-derive/src/lib.rs +++ b/chalk-derive/src/lib.rs @@ -162,10 +162,7 @@ fn derive_any_visit( let body = s.each(|bi| { quote! { - result = result.combine(::chalk_ir::visit::Visit::visit_with(#bi, visitor, outer_binder)); - if result.return_early() { - return result; - } + ::chalk_ir::try_break!(::chalk_ir::visit::Visit::visit_with(#bi, visitor, outer_binder)); } }); @@ -178,19 +175,18 @@ fn derive_any_visit( s.bound_impl( quote!(::chalk_ir::visit:: #trait_name <#interner>), quote! { - fn #method_name <'i, R: ::chalk_ir::visit::VisitResult>( + fn #method_name <'i>( &self, - visitor: &mut dyn ::chalk_ir::visit::Visitor < 'i, #interner, Result = R >, + visitor: &mut dyn ::chalk_ir::visit::Visitor < 'i, #interner >, outer_binder: ::chalk_ir::DebruijnIndex, - ) -> R + ) -> ::chalk_ir::visit::ControlFlow<()> where #interner: 'i { - let mut result = R::new(); match *self { #body } - return result; + ::chalk_ir::visit::ControlFlow::CONTINUE } }, ) diff --git a/chalk-engine/src/lib.rs b/chalk-engine/src/lib.rs index f9ef26bebbf..aef14f32ba7 100644 --- a/chalk-engine/src/lib.rs +++ b/chalk-engine/src/lib.rs @@ -58,7 +58,7 @@ use std::usize; use chalk_derive::{Fold, HasInterner, Visit}; use chalk_ir::interner::Interner; -use chalk_ir::visit::VisitResult; +use chalk_ir::visit::ControlFlow; use chalk_ir::{ AnswerSubst, Canonical, ConstrainedSubst, Constraint, DebruijnIndex, Goal, InEnvironment, Substitution, diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 3dfe315a5e5..78d80f83832 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -9,7 +9,7 @@ extern crate self as chalk_ir; use crate::cast::{Cast, CastTo, Caster}; use crate::fold::shift::Shift; use crate::fold::{Fold, Folder, Subst, SuperFold}; -use crate::visit::{SuperVisit, Visit, VisitExt, VisitResult, Visitor}; +use crate::visit::{ControlFlow, SuperVisit, Visit, VisitExt, Visitor}; use chalk_derive::{Fold, HasInterner, SuperVisit, Visit, Zip}; use std::marker::PhantomData; diff --git a/chalk-ir/src/visit.rs b/chalk-ir/src/visit.rs index 5a1ce0f18ba..6406695c981 100644 --- a/chalk-ir/src/visit.rs +++ b/chalk-ir/src/visit.rs @@ -12,53 +12,48 @@ pub mod visitors; pub use visitors::VisitExt; -/// A "result type" that can be returned from a visitor. Visitors pick -/// an appropriate result type depending on what sort of operation they -/// are doing. A common choice is `FindAny`, which indicates that the visitor -/// is searching for something and that the visitor should stop once it is found. -pub trait VisitResult: Sized { - /// Creates a new visitor result. - fn new() -> Self; - - /// Returns true if this result is "complete" and we can stop visiting any - /// further parts of the term. This is used by `FindAny`, for example, to - /// stop the search after a match has been found. - fn return_early(&self) -> bool; - - /// Combines two visitor results. - fn combine(self, other: Self) -> Self; - - /// Convenience helper for use in writing `Visitor` impls. Returns `self` - /// if `return_early()` is true, but otherwise combines `self` with the - /// result of invoking `op`. - /// - /// If you have a struct with two fields, `foo` and `bar`, you can - /// thus write code like - /// - /// ```rust,ignore - /// self.foo.visit_with(visitor, outer_binder) - /// .and_then(|| self.bar.visit_with(visitor, outer_binder)) - /// ``` - /// - /// and `bar` will only be visited if necessary. - fn and_then(self, op: impl FnOnce() -> Self) -> Self { - if self.return_early() { - self - } else { - self.combine(op()) +/// An copy of the unstable `std::ops::ControlFlow` for use in Chalk visitors. +pub enum ControlFlow { + Continue(C), + Break(B), +} + +impl ControlFlow { + #[inline] + pub fn is_break(&self) -> bool { + matches!(*self, ControlFlow::Break(_)) + } + + #[inline] + pub fn is_continue(&self) -> bool { + matches!(*self, ControlFlow::Continue(_)) + } + + #[inline] + pub fn break_value(self) -> Option { + match self { + ControlFlow::Continue(..) => None, + ControlFlow::Break(x) => Some(x), } } } -/// Unit type for a visitor indicates a "side-effecting" visitor that -/// should visit an entire term. -impl VisitResult for () { - fn new() -> Self {} +impl ControlFlow { + pub const CONTINUE: Self = ControlFlow::Continue(()); +} - fn return_early(&self) -> bool { - false - } - fn combine(self, _other: Self) {} +impl ControlFlow<(), C> { + pub const BREAK: Self = ControlFlow::Break(()); +} + +#[macro_export] +macro_rules! try_break { + ($expr:expr) => { + match $expr { + $crate::visit::ControlFlow::Continue(c) => c, + $crate::visit::ControlFlow::Break(b) => return $crate::visit::ControlFlow::Break(b), + } + }; } /// A "visitor" recursively folds some term -- that is, some bit of IR, @@ -74,9 +69,6 @@ pub trait Visitor<'i, I: Interner> where I: 'i, { - /// The type of result that this visitor produces. - type Result: VisitResult; - /// Creates a `dyn` value from this visitor. Unfortunately, this /// must be added manually to each impl of visitor; it permits the /// default implements below to create a `&mut dyn Visitor` from @@ -84,13 +76,13 @@ where /// method). Effectively, this limits impls of `visitor` to types /// for which we are able to create a dyn value (i.e., not `[T]` /// types). - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result>; + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I>; /// Top-level callback: invoked for each `Ty` that is /// encountered when visiting. By default, invokes /// `super_visit_with`, which will in turn invoke the more /// specialized visiting methods below, like `visit_free_var`. - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<()> { ty.super_visit_with(self.as_dyn(), outer_binder) } @@ -102,7 +94,7 @@ where &mut self, lifetime: &Lifetime, outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { lifetime.super_visit_with(self.as_dyn(), outer_binder) } @@ -110,7 +102,7 @@ where /// encountered when visiting. By default, invokes /// `super_visit_with`, which will in turn invoke the more /// specialized visiting methods below, like `visit_free_var`. - fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> ControlFlow<()> { constant.super_visit_with(self.as_dyn(), outer_binder) } @@ -119,12 +111,12 @@ where &mut self, clause: &ProgramClause, outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { clause.super_visit_with(self.as_dyn(), outer_binder) } /// Invoked for every goal. By default, recursively visits the goals contents. - fn visit_goal(&mut self, goal: &Goal, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_goal(&mut self, goal: &Goal, outer_binder: DebruijnIndex) -> ControlFlow<()> { goal.super_visit_with(self.as_dyn(), outer_binder) } @@ -133,7 +125,7 @@ where &mut self, domain_goal: &DomainGoal, outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { domain_goal.super_visit_with(self.as_dyn(), outer_binder) } @@ -146,14 +138,18 @@ where /// Invoked for `BoundVar` instances that are not bound /// within the type being visited over: - fn visit_free_var(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_free_var( + &mut self, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { if self.forbid_free_vars() { panic!( "unexpected free variable `{:?}` with outer binder {:?}", bound_var, outer_binder ) } else { - Self::Result::new() + ControlFlow::CONTINUE } } @@ -169,11 +165,11 @@ where &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { if self.forbid_free_placeholders() { panic!("unexpected placeholder type `{:?}`", universe) } else { - Self::Result::new() + ControlFlow::CONTINUE } } @@ -182,7 +178,7 @@ where &mut self, where_clause: &WhereClause, outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { where_clause.super_visit_with(self.as_dyn(), outer_binder) } @@ -199,11 +195,11 @@ where &mut self, var: InferenceVar, _outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { if self.forbid_inference_vars() { panic!("unexpected inference type `{:?}`", var) } else { - Self::Result::new() + ControlFlow::CONTINUE } } @@ -219,11 +215,11 @@ pub trait Visit: Debug { /// visitor. Typically `binders` starts as 0, but is adjusted when /// we encounter `Binders` in the IR or other similar /// constructs. - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i; } @@ -233,11 +229,11 @@ pub trait Visit: Debug { /// the contents of the type. pub trait SuperVisit: Visit { /// Recursively visits the type contents. - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i; } @@ -246,11 +242,11 @@ pub trait SuperVisit: Visit { /// usually (in turn) invokes `super_visit_ty` to visit the individual /// parts. impl Visit for Ty { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -258,16 +254,16 @@ impl Visit for Ty { } } -/// "Super visit" for a type invokes te more detailed callbacks on the type +/// "Super visit" for a type invokes the more detailed callbacks on the type impl SuperVisit for Ty where I: Interner, { - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -277,7 +273,7 @@ where if let Some(_) = bound_var.shifted_out_to(outer_binder) { visitor.visit_free_var(*bound_var, outer_binder) } else { - R::new() + ControlFlow::CONTINUE } } TyKind::Dyn(clauses) => clauses.visit_with(visitor, outer_binder), @@ -290,52 +286,58 @@ where substitution.visit_with(visitor, outer_binder) } TyKind::Scalar(scalar) => scalar.visit_with(visitor, outer_binder), - TyKind::Str => R::new(), - TyKind::Tuple(arity, substitution) => arity - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), - TyKind::OpaqueType(opaque_ty, substitution) => opaque_ty - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), + TyKind::Str => ControlFlow::CONTINUE, + TyKind::Tuple(arity, substitution) => { + try_break!(arity.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::OpaqueType(opaque_ty, substitution) => { + try_break!(opaque_ty.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } TyKind::Slice(substitution) => substitution.visit_with(visitor, outer_binder), - TyKind::FnDef(fn_def, substitution) => fn_def - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), + TyKind::FnDef(fn_def, substitution) => { + try_break!(fn_def.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } TyKind::Ref(mutability, lifetime, ty) => { - mutability.visit_with(visitor, outer_binder).combine( - lifetime - .visit_with(visitor, outer_binder) - .combine(ty.visit_with(visitor, outer_binder)), - ) + try_break!(mutability.visit_with(visitor, outer_binder)); + try_break!(lifetime.visit_with(visitor, outer_binder)); + ty.visit_with(visitor, outer_binder) + } + TyKind::Raw(mutability, ty) => { + try_break!(mutability.visit_with(visitor, outer_binder)); + ty.visit_with(visitor, outer_binder) + } + TyKind::Never => ControlFlow::CONTINUE, + TyKind::Array(ty, const_) => { + try_break!(ty.visit_with(visitor, outer_binder)); + const_.visit_with(visitor, outer_binder) + } + TyKind::Closure(id, substitution) => { + try_break!(id.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::Generator(generator, substitution) => { + try_break!(generator.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) + } + TyKind::GeneratorWitness(witness, substitution) => { + try_break!(witness.visit_with(visitor, outer_binder)); + substitution.visit_with(visitor, outer_binder) } - TyKind::Raw(mutability, ty) => mutability - .visit_with(visitor, outer_binder) - .combine(ty.visit_with(visitor, outer_binder)), - TyKind::Never => R::new(), - TyKind::Array(ty, const_) => ty - .visit_with(visitor, outer_binder) - .combine(const_.visit_with(visitor, outer_binder)), - TyKind::Closure(id, substitution) => id - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), - TyKind::Generator(generator, substitution) => generator - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), - TyKind::GeneratorWitness(witness, substitution) => witness - .visit_with(visitor, outer_binder) - .combine(substitution.visit_with(visitor, outer_binder)), TyKind::Foreign(foreign_ty) => foreign_ty.visit_with(visitor, outer_binder), - TyKind::Error => R::new(), + TyKind::Error => ControlFlow::CONTINUE, } } } impl Visit for Lifetime { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -344,11 +346,11 @@ impl Visit for Lifetime { } impl SuperVisit for Lifetime { - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -358,25 +360,25 @@ impl SuperVisit for Lifetime { if let Some(_) = bound_var.shifted_out_to(outer_binder) { visitor.visit_free_var(*bound_var, outer_binder) } else { - R::new() + ControlFlow::CONTINUE } } LifetimeData::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder), LifetimeData::Placeholder(universe) => { visitor.visit_free_placeholder(*universe, outer_binder) } - LifetimeData::Static => R::new(), + LifetimeData::Static => ControlFlow::CONTINUE, LifetimeData::Phantom(..) => unreachable!(), } } } impl Visit for Const { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -385,11 +387,11 @@ impl Visit for Const { } impl SuperVisit for Const { - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -399,24 +401,24 @@ impl SuperVisit for Const { if let Some(_) = bound_var.shifted_out_to(outer_binder) { visitor.visit_free_var(*bound_var, outer_binder) } else { - R::new() + ControlFlow::CONTINUE } } ConstValue::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder), ConstValue::Placeholder(universe) => { visitor.visit_free_placeholder(*universe, outer_binder) } - ConstValue::Concrete(_) => R::new(), + ConstValue::Concrete(_) => ControlFlow::CONTINUE, } } } impl Visit for Goal { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -425,11 +427,11 @@ impl Visit for Goal { } impl SuperVisit for Goal { - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -439,11 +441,11 @@ impl SuperVisit for Goal { } impl Visit for ProgramClause { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -452,11 +454,11 @@ impl Visit for ProgramClause { } impl Visit for WhereClause { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -465,11 +467,11 @@ impl Visit for WhereClause { } impl Visit for DomainGoal { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { diff --git a/chalk-ir/src/visit/binder_impls.rs b/chalk-ir/src/visit/binder_impls.rs index ab0bf559d72..9fc3b0f5f81 100644 --- a/chalk-ir/src/visit/binder_impls.rs +++ b/chalk-ir/src/visit/binder_impls.rs @@ -4,14 +4,14 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::interner::HasInterner; -use crate::{Binders, Canonical, DebruijnIndex, FnPointer, Interner, Visit, VisitResult, Visitor}; +use crate::{Binders, Canonical, ControlFlow, DebruijnIndex, FnPointer, Interner, Visit, Visitor}; impl Visit for FnPointer { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -26,11 +26,11 @@ impl Visit for Binders where T: HasInterner + Visit, { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -43,11 +43,11 @@ where I: Interner, T: HasInterner + Visit, { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { diff --git a/chalk-ir/src/visit/boring_impls.rs b/chalk-ir/src/visit/boring_impls.rs index a34e9696966..2cd6b8b38c7 100644 --- a/chalk-ir/src/visit/boring_impls.rs +++ b/chalk-ir/src/visit/boring_impls.rs @@ -5,41 +5,36 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::{ - AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId, - ForeignDefId, GeneratorId, GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, - PlaceholderIndex, ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, - Safety, Scalar, Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, - Visitor, + try_break, AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, ControlFlow, + DebruijnIndex, FloatTy, FnDefId, ForeignDefId, GeneratorId, GenericArg, Goals, ImplId, IntTy, + Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, ProgramClauses, + QuantifiedWhereClauses, QuantifierKind, Safety, Scalar, Substitution, SuperVisit, TraitId, + UintTy, UniverseIndex, Visit, Visitor, }; use std::{marker::PhantomData, sync::Arc}; /// Convenience function to visit all the items in the iterator it. -pub fn visit_iter<'i, T, I, R>( +pub fn visit_iter<'i, T, I>( it: impl Iterator, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, -) -> R +) -> ControlFlow<()> where T: Visit, I: 'i + Interner, - R: VisitResult, { - let mut result = R::new(); for e in it { - result = result.combine(e.visit_with(visitor, outer_binder)); - if result.return_early() { - return result; - } + try_break!(e.visit_with(visitor, outer_binder)); } - result + ControlFlow::CONTINUE } impl, I: Interner> Visit for &T { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -48,11 +43,11 @@ impl, I: Interner> Visit for &T { } impl, I: Interner> Visit for Vec { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -61,11 +56,11 @@ impl, I: Interner> Visit for Vec { } impl, I: Interner> Visit for &[T] { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -74,11 +69,11 @@ impl, I: Interner> Visit for &[T] { } impl, I: Interner> Visit for Box { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -87,11 +82,11 @@ impl, I: Interner> Visit for Box { } impl, I: Interner> Visit for Arc { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -102,16 +97,14 @@ impl, I: Interner> Visit for Arc { macro_rules! tuple_visit { ($($n:ident),*) => { impl<$($n: Visit,)* I: Interner> Visit for ($($n,)*) { - fn visit_with<'i, R: VisitResult>(&self, visitor: &mut dyn Visitor<'i, I, Result = R>, outer_binder: DebruijnIndex) -> R where I: 'i + fn visit_with<'i>(&self, visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex) -> ControlFlow<()> where I: 'i { #[allow(non_snake_case)] let &($(ref $n),*) = self; - let mut result = R::new(); $( - result = result.combine($n.visit_with(visitor, outer_binder)); - if result.return_early() { return result; } + try_break!($n.visit_with(visitor, outer_binder)); )* - result + ControlFlow::CONTINUE } } } @@ -123,27 +116,27 @@ tuple_visit!(A, B, C, D); tuple_visit!(A, B, C, D, E); impl, I: Interner> Visit for Option { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { match self { Some(e) => e.visit_with(visitor, outer_binder), - None => R::new(), + None => ControlFlow::CONTINUE, } } } impl Visit for GenericArg { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -153,11 +146,11 @@ impl Visit for GenericArg { } impl Visit for Substitution { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -167,11 +160,11 @@ impl Visit for Substitution { } impl Visit for Goals { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -185,15 +178,15 @@ impl Visit for Goals { macro_rules! const_visit { ($t:ty) => { impl $crate::visit::Visit for $t { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - _visitor: &mut dyn ($crate::visit::Visitor<'i, I, Result = R>), + _visitor: &mut dyn ($crate::visit::Visitor<'i, I>), _outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { - R::new() + ControlFlow::CONTINUE } } }; @@ -219,15 +212,15 @@ const_visit!(Safety); macro_rules! id_visit { ($t:ident) => { impl $crate::visit::Visit for $t { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - _visitor: &mut dyn ($crate::visit::Visitor<'i, I, Result = R>), + _visitor: &mut dyn ($crate::visit::Visitor<'i, I>), _outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { - R::new() + ControlFlow::CONTINUE } } }; @@ -244,11 +237,11 @@ id_visit!(GeneratorId); id_visit!(ForeignDefId); impl SuperVisit for ProgramClause { - fn super_visit_with<'i, R: VisitResult>( + fn super_visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -259,11 +252,11 @@ impl SuperVisit for ProgramClause { } impl Visit for ProgramClauses { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -274,11 +267,11 @@ impl Visit for ProgramClauses { } impl Visit for Constraints { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -289,11 +282,11 @@ impl Visit for Constraints { } impl Visit for QuantifiedWhereClauses { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn Visitor<'i, I, Result = R>, + visitor: &mut dyn Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { @@ -304,14 +297,14 @@ impl Visit for QuantifiedWhereClauses { } impl Visit for PhantomData { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - _visitor: &mut dyn Visitor<'i, I, Result = R>, + _visitor: &mut dyn Visitor<'i, I>, _outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { - R::new() + ControlFlow::CONTINUE } } diff --git a/chalk-ir/src/visit/visitors.rs b/chalk-ir/src/visit/visitors.rs index 892280eb1a9..32b68208832 100644 --- a/chalk-ir/src/visit/visitors.rs +++ b/chalk-ir/src/visit/visitors.rs @@ -1,6 +1,6 @@ //! Visitor helpers -use crate::{BoundVar, DebruijnIndex, Interner, Visit, VisitResult, Visitor}; +use crate::{BoundVar, ControlFlow, DebruijnIndex, Interner, Visit, Visitor}; /// Visitor extensions. pub trait VisitExt: Visit { @@ -10,52 +10,18 @@ pub trait VisitExt: Visit { &mut FindFreeVarsVisitor { interner }, DebruijnIndex::INNERMOST, ) - .to_bool() + .is_break() } } impl VisitExt for T where T: Visit {} -/// Helper visitor for finding a specific value. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[allow(missing_docs)] -pub struct FindAny { - pub found: bool, -} - -impl FindAny { - /// Visitor has found the value. - pub const FOUND: FindAny = FindAny { found: true }; - - /// Checks whether the value has been found. - pub fn to_bool(&self) -> bool { - self.found - } -} - -impl VisitResult for FindAny { - fn new() -> Self { - FindAny { found: false } - } - - fn return_early(&self) -> bool { - self.found - } - fn combine(self, other: Self) -> Self { - FindAny { - found: self.found || other.found, - } - } -} - struct FindFreeVarsVisitor<'i, I: Interner> { interner: &'i I, } impl<'i, I: Interner> Visitor<'i, I> for FindFreeVarsVisitor<'i, I> { - type Result = FindAny; - - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I> { self } @@ -67,7 +33,7 @@ impl<'i, I: Interner> Visitor<'i, I> for FindFreeVarsVisitor<'i, I> { &mut self, _bound_var: BoundVar, _outer_binder: DebruijnIndex, - ) -> Self::Result { - FindAny::FOUND + ) -> ControlFlow<()> { + ControlFlow::BREAK } } diff --git a/chalk-solve/src/clauses/builtin_traits/unsize.rs b/chalk-solve/src/clauses/builtin_traits/unsize.rs index 37b6c738f07..9962c343d4e 100644 --- a/chalk-solve/src/clauses/builtin_traits/unsize.rs +++ b/chalk-solve/src/clauses/builtin_traits/unsize.rs @@ -7,7 +7,7 @@ use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{ cast::Cast, interner::HasInterner, - visit::{visitors::FindAny, SuperVisit, Visit, VisitResult, Visitor}, + visit::{ControlFlow, SuperVisit, Visit, Visitor}, Binders, Const, ConstValue, DebruijnIndex, DomainGoal, DynTy, EqGoal, Goal, LifetimeOutlives, QuantifiedWhereClauses, Substitution, TraitId, Ty, TyKind, TypeOutlives, WhereClause, }; @@ -19,13 +19,11 @@ struct UnsizeParameterCollector<'a, I: Interner> { } impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> { - type Result = (); - - fn as_dyn(&mut self) -> &mut dyn Visitor<'a, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'a, I> { self } - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<()> { let interner = self.interner; match ty.kind(interner) { @@ -34,12 +32,13 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> { if bound_var.debruijn.shifted_in() == outer_binder { self.parameters.insert(bound_var.index); } + ControlFlow::CONTINUE } _ => ty.super_visit_with(self, outer_binder), } } - fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> ControlFlow<()> { let interner = self.interner; if let ConstValue::BoundVar(bound_var) = constant.data(interner).value { @@ -48,6 +47,7 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> { self.parameters.insert(bound_var.index); } } + ControlFlow::CONTINUE } fn interner(&self) -> &'a I { @@ -74,13 +74,11 @@ struct ParameterOccurenceCheck<'a, 'p, I: Interner> { } impl<'a, 'p, I: Interner> Visitor<'a, I> for ParameterOccurenceCheck<'a, 'p, I> { - type Result = FindAny; - - fn as_dyn(&mut self) -> &mut dyn Visitor<'a, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'a, I> { self } - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<()> { let interner = self.interner; match ty.kind(interner) { @@ -88,16 +86,16 @@ impl<'a, 'p, I: Interner> Visitor<'a, I> for ParameterOccurenceCheck<'a, 'p, I> if bound_var.debruijn.shifted_in() == outer_binder && self.parameters.contains(&bound_var.index) { - FindAny::FOUND + ControlFlow::BREAK } else { - FindAny::new() + ControlFlow::CONTINUE } } _ => ty.super_visit_with(self, outer_binder), } } - fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> Self::Result { + fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> ControlFlow<()> { let interner = self.interner; match constant.data(interner).value { @@ -105,12 +103,12 @@ impl<'a, 'p, I: Interner> Visitor<'a, I> for ParameterOccurenceCheck<'a, 'p, I> if bound_var.debruijn.shifted_in() == outer_binder && self.parameters.contains(&bound_var.index) { - FindAny::FOUND + ControlFlow::BREAK } else { - FindAny::new() + ControlFlow::CONTINUE } } - _ => FindAny::new(), + _ => ControlFlow::CONTINUE, } } @@ -128,7 +126,8 @@ fn uses_outer_binder_params( interner, parameters, }; - v.visit_with(&mut visitor, DebruijnIndex::INNERMOST) == FindAny::FOUND + v.visit_with(&mut visitor, DebruijnIndex::INNERMOST) + .is_break() } fn principal_id<'a, I: Interner>( diff --git a/chalk-solve/src/clauses/env_elaborator.rs b/chalk-solve/src/clauses/env_elaborator.rs index da7c9481e7e..c499c9dbc92 100644 --- a/chalk-solve/src/clauses/env_elaborator.rs +++ b/chalk-solve/src/clauses/env_elaborator.rs @@ -8,7 +8,7 @@ use crate::RustIrDatabase; use crate::Ty; use crate::{debug_span, TyKind}; use chalk_ir::interner::Interner; -use chalk_ir::visit::{Visit, Visitor}; +use chalk_ir::visit::{ControlFlow, Visit, Visitor}; use chalk_ir::{DebruijnIndex, Environment}; use rustc_hash::FxHashSet; use tracing::instrument; @@ -54,9 +54,7 @@ impl<'me, I: Interner> EnvElaborator<'me, I> { } impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { - type Result = (); - - fn as_dyn(&mut self) -> &mut dyn Visitor<'me, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'me, I> { self } @@ -64,7 +62,7 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { self.db.interner() } #[instrument(level = "debug", skip(self, _outer_binder))] - fn visit_ty(&mut self, ty: &Ty, _outer_binder: DebruijnIndex) { + fn visit_ty(&mut self, ty: &Ty, _outer_binder: DebruijnIndex) -> ControlFlow<()> { match ty.kind(self.interner()) { TyKind::Alias(alias_ty) => { match_alias_ty(&mut self.builder, self.environment, alias_ty) @@ -84,9 +82,14 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { .unwrap() } } + ControlFlow::CONTINUE } - fn visit_domain_goal(&mut self, domain_goal: &DomainGoal, outer_binder: DebruijnIndex) { + fn visit_domain_goal( + &mut self, + domain_goal: &DomainGoal, + outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { if let DomainGoal::FromEnv(from_env) = domain_goal { debug_span!("visit_domain_goal", ?from_env); match from_env { @@ -103,9 +106,12 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { .associated_ty_data(associated_ty_id) .to_program_clauses(&mut self.builder, self.environment); } + ControlFlow::CONTINUE } FromEnv::Ty(ty) => ty.visit_with(self, outer_binder), } + } else { + ControlFlow::CONTINUE } } } diff --git a/chalk-solve/src/infer/ucanonicalize.rs b/chalk-solve/src/infer/ucanonicalize.rs index dd06024eb77..67b0af3fd84 100644 --- a/chalk-solve/src/infer/ucanonicalize.rs +++ b/chalk-solve/src/infer/ucanonicalize.rs @@ -1,7 +1,7 @@ use crate::debug_span; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::{HasInterner, Interner}; -use chalk_ir::visit::{Visit, Visitor}; +use chalk_ir::visit::{ControlFlow, Visit, Visitor}; use chalk_ir::*; use super::InferenceTable; @@ -205,14 +205,17 @@ impl<'i, I: Interner> Visitor<'i, I> for UCollector<'_, 'i, I> where I: 'i, { - type Result = (); - - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = ()> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I> { self } - fn visit_free_placeholder(&mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex) { + fn visit_free_placeholder( + &mut self, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { self.universes.add(universe.ui); + ControlFlow::CONTINUE } fn forbid_inference_vars(&self) -> bool { diff --git a/chalk-solve/src/logging_db/id_collector.rs b/chalk-solve/src/logging_db/id_collector.rs index 050c40b57ac..664a357576b 100644 --- a/chalk-solve/src/logging_db/id_collector.rs +++ b/chalk-solve/src/logging_db/id_collector.rs @@ -2,7 +2,7 @@ use super::RecordedItemId; use crate::RustIrDatabase; use chalk_ir::{ interner::Interner, - visit::Visitor, + visit::{ControlFlow, Visitor}, visit::{SuperVisit, Visit}, AliasTy, DebruijnIndex, TyKind, WhereClause, }; @@ -63,7 +63,7 @@ pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase>( assoc_ty_datum .bounds_on_self(collector.db.interner()) .visit_with(&mut collector, DebruijnIndex::INNERMOST); - assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST) + assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); } } RecordedItemId::OpaqueTy(opaque_id) => { @@ -108,8 +108,7 @@ impl<'i, I: Interner, DB: RustIrDatabase> Visitor<'i, I> for IdCollector<'i, where I: 'i, { - type Result = (); - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I> { self } fn interner(&self) -> &'i I { @@ -120,7 +119,7 @@ where &mut self, ty: &chalk_ir::Ty, outer_binder: chalk_ir::DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { match ty.kind(self.db.interner()) { TyKind::Adt(adt, _) => self.record(*adt), TyKind::FnDef(fn_def, _) => self.record(*fn_def), @@ -148,7 +147,7 @@ where &mut self, where_clause: &WhereClause, outer_binder: DebruijnIndex, - ) -> Self::Result { + ) -> ControlFlow<()> { match where_clause { WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id), WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { diff --git a/chalk-solve/src/rust_ir.rs b/chalk-solve/src/rust_ir.rs index 95122eeb0d0..57d65a53422 100644 --- a/chalk-solve/src/rust_ir.rs +++ b/chalk-solve/src/rust_ir.rs @@ -7,7 +7,8 @@ use chalk_ir::cast::Cast; use chalk_ir::fold::shift::Shift; use chalk_ir::interner::Interner; use chalk_ir::{ - visit::{Visit, VisitResult}, + try_break, + visit::{ControlFlow, Visit}, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, Ty, TyKind, VariableKind, WhereClause, WithKind, @@ -141,19 +142,16 @@ pub struct FnDefDatum { /// Avoids visiting `I::FnAbi` impl Visit for FnDefDatum { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { - let result = R::new().combine(self.id.visit_with(visitor, outer_binder)); - if result.return_early() { - return result; - } - result.combine(self.binders.visit_with(visitor, outer_binder)) + try_break!(self.id.visit_with(visitor, outer_binder)); + self.binders.visit_with(visitor, outer_binder) } } @@ -491,23 +489,17 @@ pub struct AssociatedTyDatum { // Manual implementation to avoid I::Identifier type. impl Visit for AssociatedTyDatum { - fn visit_with<'i, R: VisitResult>( + fn visit_with<'i>( &self, - visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I>, outer_binder: DebruijnIndex, - ) -> R + ) -> ControlFlow<()> where I: 'i, { - let result = R::new().combine(self.trait_id.visit_with(visitor, outer_binder)); - if result.return_early() { - return result; - } - let result = result.combine(self.id.visit_with(visitor, outer_binder)); - if result.return_early() { - return result; - } - result.combine(self.binders.visit_with(visitor, outer_binder)) + try_break!(self.trait_id.visit_with(visitor, outer_binder)); + try_break!(self.id.visit_with(visitor, outer_binder)); + self.binders.visit_with(visitor, outer_binder) } } diff --git a/chalk-solve/src/solve/truncate.rs b/chalk-solve/src/solve/truncate.rs index 54a525b34ef..e73bb2ec97e 100644 --- a/chalk-solve/src/solve/truncate.rs +++ b/chalk-solve/src/solve/truncate.rs @@ -2,7 +2,7 @@ use crate::infer::InferenceTable; use chalk_ir::interner::Interner; -use chalk_ir::visit::{SuperVisit, Visit, Visitor}; +use chalk_ir::visit::{ControlFlow, SuperVisit, Visit, Visitor}; use chalk_ir::*; use std::cmp::max; @@ -39,16 +39,14 @@ impl<'infer, 'i, I: Interner> TySizeVisitor<'infer, 'i, I> { } impl<'infer, 'i, I: Interner> Visitor<'i, I> for TySizeVisitor<'infer, 'i, I> { - type Result = (); - - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I> { self } - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) { + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<()> { if let Some(normalized_ty) = self.infer.normalize_ty_shallow(self.interner, ty) { normalized_ty.visit_with(self, outer_binder); - return; + return ControlFlow::CONTINUE; } self.size += 1; @@ -63,6 +61,7 @@ impl<'infer, 'i, I: Interner> Visitor<'i, I> for TySizeVisitor<'infer, 'i, I> { if self.depth == 0 { self.size = 0; } + ControlFlow::CONTINUE } fn interner(&self) -> &'i I { diff --git a/chalk-solve/src/wf.rs b/chalk-solve/src/wf.rs index 57410e8ff7e..77b8d001b0c 100644 --- a/chalk-solve/src/wf.rs +++ b/chalk-solve/src/wf.rs @@ -7,7 +7,7 @@ use chalk_ir::{ cast::*, fold::shift::Shift, interner::Interner, - visit::{Visit, VisitResult, Visitor}, + visit::{ControlFlow, Visit, Visitor}, *, }; use tracing::debug; @@ -69,9 +69,7 @@ impl<'i, I: Interner> InputTypeCollector<'i, I> { } impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { - type Result = (); - - fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I> { self } @@ -79,22 +77,24 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { self.interner } - fn visit_where_clause(&mut self, where_clause: &WhereClause, outer_binder: DebruijnIndex) { + fn visit_where_clause( + &mut self, + where_clause: &WhereClause, + outer_binder: DebruijnIndex, + ) -> ControlFlow<()> { match where_clause { WhereClause::AliasEq(alias_eq) => alias_eq .alias .clone() .intern(self.interner) .visit_with(self, outer_binder), - WhereClause::Implemented(trait_ref) => { - trait_ref.visit_with(self, outer_binder); - } + WhereClause::Implemented(trait_ref) => trait_ref.visit_with(self, outer_binder), WhereClause::TypeOutlives(TypeOutlives { ty, .. }) => ty.visit_with(self, outer_binder), - WhereClause::LifetimeOutlives(..) => {} + WhereClause::LifetimeOutlives(..) => ControlFlow::CONTINUE, } } - fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) { + fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<()> { let interner = self.interner(); let mut push_ty = || { @@ -105,105 +105,110 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { TyKind::Adt(id, substitution) => { push_ty(); id.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::AssociatedType(assoc_ty, substitution) => { push_ty(); assoc_ty.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Scalar(scalar) => { push_ty(); - scalar.visit_with(self, outer_binder); + scalar.visit_with(self, outer_binder) } TyKind::Str => { push_ty(); + ControlFlow::CONTINUE } TyKind::Tuple(arity, substitution) => { push_ty(); arity.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::OpaqueType(opaque_ty, substitution) => { push_ty(); opaque_ty.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Slice(substitution) => { push_ty(); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::FnDef(fn_def, substitution) => { push_ty(); fn_def.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Ref(mutability, lifetime, ty) => { push_ty(); mutability.visit_with(self, outer_binder); lifetime.visit_with(self, outer_binder); - ty.visit_with(self, outer_binder); + ty.visit_with(self, outer_binder) } TyKind::Raw(mutability, substitution) => { push_ty(); mutability.visit_with(self, outer_binder); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Never => { push_ty(); + ControlFlow::CONTINUE } TyKind::Array(ty, const_) => { push_ty(); - ty.visit_with(self, outer_binder) - .combine(const_.visit_with(self, outer_binder)) + ty.visit_with(self, outer_binder); + const_.visit_with(self, outer_binder) } TyKind::Closure(_id, substitution) => { push_ty(); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Generator(_generator, substitution) => { push_ty(); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::GeneratorWitness(_witness, substitution) => { push_ty(); - substitution.visit_with(self, outer_binder); + substitution.visit_with(self, outer_binder) } TyKind::Foreign(_foreign_ty) => { push_ty(); + ControlFlow::CONTINUE } TyKind::Error => { push_ty(); + ControlFlow::CONTINUE } TyKind::Dyn(clauses) => { push_ty(); - clauses.visit_with(self, outer_binder); + clauses.visit_with(self, outer_binder) } TyKind::Alias(AliasTy::Projection(proj)) => { push_ty(); - proj.visit_with(self, outer_binder); + proj.visit_with(self, outer_binder) } TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { push_ty(); - opaque_ty.visit_with(self, outer_binder); + opaque_ty.visit_with(self, outer_binder) } TyKind::Placeholder(_) => { push_ty(); + ControlFlow::CONTINUE } // Type parameters do not carry any input types (so we can sort of assume they are // always WF). - TyKind::BoundVar(..) => (), + TyKind::BoundVar(..) => ControlFlow::CONTINUE, // Higher-kinded types such as `for<'a> fn(&'a u32)` introduce their own implied // bounds, and these bounds will be enforced upon calling such a function. In some // sense, well-formedness requirements for the input types of an HKT will be enforced // lazily, so no need to include them here. - TyKind::Function(..) => (), + TyKind::Function(..) => ControlFlow::CONTINUE, TyKind::InferenceVar(..) => { panic!("unexpected inference variable in wf rules: {:?}", ty) From c3d0a619a522f824b12e0ed62cf4e28726b1a2bb Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 31 Oct 2020 16:47:08 +0100 Subject: [PATCH 2/2] Add documentation for `ControlFlow` and `try_break!` --- chalk-ir/src/visit.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/chalk-ir/src/visit.rs b/chalk-ir/src/visit.rs index 6406695c981..9608c9296ef 100644 --- a/chalk-ir/src/visit.rs +++ b/chalk-ir/src/visit.rs @@ -14,21 +14,27 @@ pub use visitors::VisitExt; /// An copy of the unstable `std::ops::ControlFlow` for use in Chalk visitors. pub enum ControlFlow { + /// Continue in the loop, using the given value for the next iteration Continue(C), + /// Exit the loop, yielding the given value Break(B), } impl ControlFlow { + /// Returns `true` if this is a `Break` variant. #[inline] pub fn is_break(&self) -> bool { matches!(*self, ControlFlow::Break(_)) } + /// Returns `true` if this is a `Continue` variant. #[inline] pub fn is_continue(&self) -> bool { matches!(*self, ControlFlow::Continue(_)) } + /// Converts the `ControlFlow` into an `Option` which is `Some` + /// if the `ControlFlow` was `Break` and `None` otherwise. #[inline] pub fn break_value(self) -> Option { match self { @@ -39,13 +45,20 @@ impl ControlFlow { } impl ControlFlow { + /// It's frequently the case that there's no value needed with `Continue`, + /// so this provides a way to avoid typing `(())`, if you prefer it. pub const CONTINUE: Self = ControlFlow::Continue(()); } impl ControlFlow<(), C> { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. pub const BREAK: Self = ControlFlow::Break(()); } +/// Unwraps a `ControlFlow` or propagates its `Break` value. +/// This replaces the `Try` implementation that would be used +/// with `std::ops::ControlFlow`. #[macro_export] macro_rules! try_break { ($expr:expr) => {