diff --git a/chalk-derive/src/lib.rs b/chalk-derive/src/lib.rs index ecf01307033..00035aea7ae 100644 --- a/chalk-derive/src/lib.rs +++ b/chalk-derive/src/lib.rs @@ -3,17 +3,17 @@ extern crate proc_macro; use proc_macro2::{Span, TokenStream}; use quote::quote; use quote::ToTokens; -use syn::{parse_quote, DeriveInput, GenericParam, Ident, TypeParamBound}; +use syn::{parse_quote, DeriveInput, Ident, TypeParam, TypeParamBound}; use synstructure::decl_derive; /// Checks whether a generic parameter has a `: HasInterner` bound -fn has_interner(param: &GenericParam) -> Option<&Ident> { +fn has_interner(param: &TypeParam) -> Option<&Ident> { bounded_by_trait(param, "HasInterner") } /// Checks whether a generic parameter has a `: Interner` bound -fn is_interner(param: &GenericParam) -> Option<&Ident> { +fn is_interner(param: &TypeParam) -> Option<&Ident> { bounded_by_trait(param, "Interner") } @@ -28,48 +28,44 @@ fn has_interner_attr(input: &DeriveInput) -> Option { ) } -fn bounded_by_trait<'p>(param: &'p GenericParam, name: &str) -> Option<&'p Ident> { +fn bounded_by_trait<'p>(param: &'p TypeParam, name: &str) -> Option<&'p Ident> { let name = Some(String::from(name)); - match param { - GenericParam::Type(ref t) => t.bounds.iter().find_map(|b| { - if let TypeParamBound::Trait(trait_bound) = b { - if trait_bound - .path - .segments - .last() - .map(|s| s.ident.to_string()) - == name - { - return Some(&t.ident); - } + param.bounds.iter().find_map(|b| { + if let TypeParamBound::Trait(trait_bound) = b { + if trait_bound + .path + .segments + .last() + .map(|s| s.ident.to_string()) + == name + { + return Some(¶m.ident); } - None - }), - _ => None, - } + } + None + }) } -fn get_generic_param(input: &DeriveInput) -> &GenericParam { - match input.generics.params.len() { - 1 => {} +fn get_intern_param(input: &DeriveInput) -> Option<(DeriveKind, &Ident)> { + let mut params = input.generics.type_params().filter_map(|param| { + has_interner(param) + .map(|ident| (DeriveKind::FromHasInterner, ident)) + .or_else(|| is_interner(param).map(|ident| (DeriveKind::FromInterner, ident))) + }); - 0 => panic!( - "deriving this trait requires a single type parameter or a `#[has_interner]` attr" - ), + let param = params.next(); + assert!(params.next().is_none(), "deriving this trait only works with at most one type parameter that implements HasInterner or Interner"); - _ => panic!("deriving this trait only works with a single type parameter"), - }; - &input.generics.params[0] + param } -fn get_generic_param_name(input: &DeriveInput) -> Option<&Ident> { - match get_generic_param(input) { - GenericParam::Type(t) => Some(&t.ident), - _ => None, - } +fn get_intern_param_name(input: &DeriveInput) -> &Ident { + get_intern_param(input) + .expect("deriving this trait requires a parameter that implements HasInterner or Interner") + .1 } -fn find_interner(s: &mut synstructure::Structure) -> (TokenStream, DeriveKind) { +fn try_find_interner(s: &mut synstructure::Structure) -> Option<(TokenStream, DeriveKind)> { let input = s.ast(); if let Some(arg) = has_interner_attr(input) { @@ -79,35 +75,40 @@ fn find_interner(s: &mut synstructure::Structure) -> (TokenStream, DeriveKind) { // struct S { // // } - return (arg, DeriveKind::FromHasInternerAttr); + return Some((arg, DeriveKind::FromHasInternerAttr)); } - let generic_param0 = get_generic_param(input); - - if let Some(param) = has_interner(generic_param0) { - // HasInterner bound: - // - // Example: - // - // struct Binders { } - s.add_impl_generic(parse_quote! { _I }); - - s.add_where_predicate(parse_quote! { _I: ::chalk_ir::interner::Interner }); - s.add_where_predicate( - parse_quote! { #param: ::chalk_ir::interner::HasInterner }, - ); + get_intern_param(input).map(|generic_param0| match generic_param0 { + (DeriveKind::FromHasInterner, param) => { + // HasInterner bound: + // + // Example: + // + // struct Binders { } + s.add_impl_generic(parse_quote! { _I }); + + s.add_where_predicate(parse_quote! { _I: ::chalk_ir::interner::Interner }); + s.add_where_predicate( + parse_quote! { #param: ::chalk_ir::interner::HasInterner }, + ); + + (quote! { _I }, DeriveKind::FromHasInterner) + } + (DeriveKind::FromInterner, i) => { + // Interner bound: + // + // Example: + // + // struct Foo { } + (quote! { #i }, DeriveKind::FromInterner) + } + _ => unreachable!(), + }) +} - (quote! { _I }, DeriveKind::FromHasInterner) - } else if let Some(i) = is_interner(generic_param0) { - // Interner bound: - // - // Example: - // - // struct Foo { } - (quote! { #i }, DeriveKind::FromInterner) - } else { - panic!("deriving this trait requires a parameter that implements HasInterner or Interner",); - } +fn find_interner(s: &mut synstructure::Structure) -> (TokenStream, DeriveKind) { + try_find_interner(s) + .expect("deriving this trait requires a `#[has_interner]` attr or a parameter that implements HasInterner or Interner") } #[derive(Copy, Clone, PartialEq)] @@ -117,6 +118,7 @@ enum DeriveKind { FromInterner, } +decl_derive!([FallibleTypeFolder, attributes(has_interner)] => derive_fallible_type_folder); decl_derive!([HasInterner, attributes(has_interner)] => derive_has_interner); decl_derive!([TypeVisitable, attributes(has_interner)] => derive_type_visitable); decl_derive!([TypeSuperVisitable, attributes(has_interner)] => derive_type_super_visitable); @@ -173,7 +175,7 @@ fn derive_any_type_visitable( }); if kind == DeriveKind::FromHasInterner { - let param = get_generic_param_name(input).unwrap(); + let param = get_intern_param_name(input); s.add_where_predicate(parse_quote! { #param: ::chalk_ir::visit::TypeVisitable<#interner> }); } @@ -269,7 +271,7 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream { vi.construct(|_, index| { let bind = &bindings[index]; quote! { - ::chalk_ir::fold::TypeFoldable::fold_with(#bind, folder, outer_binder)? + ::chalk_ir::fold::TypeFoldable::try_fold_with(#bind, folder, outer_binder)? } }) }); @@ -277,7 +279,7 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream { let input = s.ast(); if kind == DeriveKind::FromHasInterner { - let param = get_generic_param_name(input).unwrap(); + let param = get_intern_param_name(input); s.add_where_predicate(parse_quote! { #param: ::chalk_ir::fold::TypeFoldable<#interner> }); }; @@ -285,9 +287,9 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream { s.bound_impl( quote!(::chalk_ir::fold::TypeFoldable<#interner>), quote! { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn ::chalk_ir::fold::TypeFolder < #interner, Error = E >, + folder: &mut dyn ::chalk_ir::fold::FallibleTypeFolder < #interner, Error = E >, outer_binder: ::chalk_ir::DebruijnIndex, ) -> ::std::result::Result { Ok(match self { #body }) @@ -295,3 +297,157 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream { }, ) } + +fn derive_fallible_type_folder(mut s: synstructure::Structure) -> TokenStream { + let interner = try_find_interner(&mut s).map_or_else( + || { + s.add_impl_generic(parse_quote! { _I }); + s.add_where_predicate(parse_quote! { _I: ::chalk_ir::interner::Interner }); + quote! { _I } + }, + |(interner, _)| interner, + ); + s.underscore_const(true); + s.unbound_impl( + quote!(::chalk_ir::fold::FallibleTypeFolder<#interner>), + quote! { + type Error = ::core::convert::Infallible; + + fn as_dyn(&mut self) -> &mut dyn ::chalk_ir::fold::FallibleTypeFolder { + self + } + + fn try_fold_ty( + &mut self, + ty: ::chalk_ir::Ty<#interner>, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Ty<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_ty(self, ty, outer_binder)) + } + + fn try_fold_lifetime( + &mut self, + lifetime: ::chalk_ir::Lifetime<#interner>, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Lifetime<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_lifetime(self, lifetime, outer_binder)) + } + + fn try_fold_const( + &mut self, + constant: ::chalk_ir::Const<#interner>, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Const<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_const(self, constant, outer_binder)) + } + + fn try_fold_program_clause( + &mut self, + clause: ::chalk_ir::ProgramClause<#interner>, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::ProgramClause<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_program_clause(self, clause, outer_binder)) + } + + fn try_fold_goal( + &mut self, + goal: ::chalk_ir::Goal<#interner>, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Goal<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_goal(self, goal, outer_binder)) + } + + fn forbid_free_vars(&self) -> bool { + ::chalk_ir::fold::TypeFolder::forbid_free_vars(self) + } + + fn try_fold_free_var_ty( + &mut self, + bound_var: ::chalk_ir::BoundVar, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Ty<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_var_ty(self, bound_var, outer_binder)) + } + + fn try_fold_free_var_lifetime( + &mut self, + bound_var: ::chalk_ir::BoundVar, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Lifetime<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_var_lifetime(self, bound_var, outer_binder)) + } + + fn try_fold_free_var_const( + &mut self, + ty: ::chalk_ir::Ty<#interner>, + bound_var: ::chalk_ir::BoundVar, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Const<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_var_const(self, ty, bound_var, outer_binder)) + } + + fn forbid_free_placeholders(&self) -> bool { + ::chalk_ir::fold::TypeFolder::forbid_free_placeholders(self) + } + + fn try_fold_free_placeholder_ty( + &mut self, + universe: ::chalk_ir::PlaceholderIndex, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Ty<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_placeholder_ty(self, universe, outer_binder)) + } + + fn try_fold_free_placeholder_lifetime( + &mut self, + universe: ::chalk_ir::PlaceholderIndex, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Lifetime<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_placeholder_lifetime(self, universe, outer_binder)) + } + + fn try_fold_free_placeholder_const( + &mut self, + ty: ::chalk_ir::Ty<#interner>, + universe: ::chalk_ir::PlaceholderIndex, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Const<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_free_placeholder_const(self, ty, universe, outer_binder)) + } + + fn forbid_inference_vars(&self) -> bool { + ::chalk_ir::fold::TypeFolder::forbid_inference_vars(self) + } + + fn try_fold_inference_ty( + &mut self, + var: ::chalk_ir::InferenceVar, + kind: ::chalk_ir::TyVariableKind, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Ty<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_inference_ty(self, var, kind, outer_binder)) + } + + fn try_fold_inference_lifetime( + &mut self, + var: ::chalk_ir::InferenceVar, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Lifetime<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_inference_lifetime(self, var, outer_binder)) + } + + fn try_fold_inference_const( + &mut self, + ty: ::chalk_ir::Ty<#interner>, + var: ::chalk_ir::InferenceVar, + outer_binder: ::chalk_ir::DebruijnIndex, + ) -> ::core::result::Result<::chalk_ir::Const<#interner>, Self::Error> { + ::core::result::Result::Ok(::chalk_ir::fold::TypeFolder::fold_inference_const(self, ty, var, outer_binder)) + } + + fn interner(&self) -> #interner { + ::chalk_ir::fold::TypeFolder::interner(self) + } + }, + ) +} diff --git a/chalk-engine/src/normalize_deep.rs b/chalk-engine/src/normalize_deep.rs index d7c45befe79..9f36f3ce526 100644 --- a/chalk-engine/src/normalize_deep.rs +++ b/chalk-engine/src/normalize_deep.rs @@ -1,9 +1,11 @@ +use chalk_derive::FallibleTypeFolder; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{TypeFoldable, TypeFolder}; use chalk_ir::interner::Interner; use chalk_ir::*; use chalk_solve::infer::InferenceTable; +#[derive(FallibleTypeFolder)] pub(crate) struct DeepNormalizer<'table, I: Interner> { table: &'table mut InferenceTable, interner: I, @@ -27,7 +29,7 @@ impl DeepNormalizer<'_, I> { value: T, ) -> T { value - .fold_with( + .try_fold_with( &mut DeepNormalizer { interner, table }, DebruijnIndex::INNERMOST, ) @@ -36,9 +38,7 @@ impl DeepNormalizer<'_, I> { } impl TypeFolder for DeepNormalizer<'_, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -47,18 +47,18 @@ impl TypeFolder for DeepNormalizer<'_, I> { var: InferenceVar, kind: TyVariableKind, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let interner = self.interner; match self.table.probe_var(var) { - Some(ty) => Ok(ty + Some(ty) => ty .assert_ty_ref(interner) .clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in(interner)), // FIXME shift + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in(interner), // FIXME shift None => { // Normalize all inference vars which have been unified into a // single variable. Ena calls this the "root" variable. - Ok(self.table.inference_var_root(var).to_ty(interner, kind)) + self.table.inference_var_root(var).to_ty(interner, kind) } } } @@ -67,15 +67,15 @@ impl TypeFolder for DeepNormalizer<'_, I> { &mut self, var: InferenceVar, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let interner = self.interner; match self.table.probe_var(var) { - Some(l) => Ok(l + Some(l) => l .assert_lifetime_ref(interner) .clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in(interner)), - None => Ok(var.to_lifetime(interner)), // FIXME shift + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in(interner), + None => var.to_lifetime(interner), // FIXME shift } } @@ -84,15 +84,15 @@ impl TypeFolder for DeepNormalizer<'_, I> { ty: Ty, var: InferenceVar, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { let interner = self.interner; match self.table.probe_var(var) { - Some(c) => Ok(c + Some(c) => c .assert_const_ref(interner) .clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in(interner)), - None => Ok(var.to_const(interner, ty)), // FIXME shift + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in(interner), + None => var.to_const(interner, ty), // FIXME shift } } diff --git a/chalk-engine/src/strand.rs b/chalk-engine/src/strand.rs index ccc392ee1e5..da25a778d87 100644 --- a/chalk-engine/src/strand.rs +++ b/chalk-engine/src/strand.rs @@ -3,7 +3,7 @@ use crate::{ExClause, TableIndex, TimeStamp}; use std::fmt::Debug; use chalk_derive::HasInterner; -use chalk_ir::fold::{TypeFoldable, TypeFolder}; +use chalk_ir::fold::{FallibleTypeFolder, TypeFoldable}; use chalk_ir::interner::Interner; use chalk_ir::{Canonical, DebruijnIndex, UniverseMap}; @@ -36,13 +36,13 @@ pub(crate) struct SelectedSubgoal { } impl TypeFoldable for Strand { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { Ok(Strand { - ex_clause: self.ex_clause.fold_with(folder, outer_binder)?, + ex_clause: self.ex_clause.try_fold_with(folder, outer_binder)?, last_pursued_time: self.last_pursued_time, selected_subgoal: self.selected_subgoal, }) diff --git a/chalk-ir/src/fold.rs b/chalk-ir/src/fold.rs index 390d8809bb4..fa8f0c06334 100644 --- a/chalk-ir/src/fold.rs +++ b/chalk-ir/src/fold.rs @@ -1,6 +1,7 @@ //! Traits for transforming bits of IR. use crate::*; +use std::convert::Infallible; use std::fmt::Debug; mod binder_impls; @@ -17,8 +18,13 @@ pub use self::subst::Subst; /// certain changes applied. The idea is that it contains methods that /// let you swap types/lifetimes for new types/lifetimes; meanwhile, /// each bit of IR implements the `TypeFoldable` trait which, given a -/// `TypeFolder`, will reconstruct itself, invoking the folder's methods -/// to transform each of the types/lifetimes embedded within. +/// `FallibleTypeFolder`, will reconstruct itself, invoking the folder's +/// methods to transform each of the types/lifetimes embedded within. +/// +/// As the name suggests, folds performed by `FallibleTypeFolder` can +/// fail (with type `Error`); if the folder cannot fail, consider +/// implementing `TypeFolder` instead (which is an infallible, but +/// otherwise equivalent, trait). /// /// # Usage patterns /// @@ -29,15 +35,15 @@ pub use self::subst::Subst; /// more often, just free existential variables) that appear within /// the term. /// -/// For this reason, the `TypeFolder` trait extends two other traits that -/// contain methods that are invoked when just those particular +/// For this reason, the `FallibleTypeFolder` trait extends two other +/// traits that contain methods that are invoked when just those particular /// /// In particular, folders can intercept references to free variables /// (either existentially or universally quantified) and replace them /// with other types/lifetimes as appropriate. /// -/// To create a folder `F`, one never implements `TypeFolder` directly, but instead -/// implements one of each of these three sub-traits: +/// To create a folder `F`, one never implements `FallibleTypeFolder` +/// directly, but instead implements one of each of these three sub-traits: /// /// - `FreeVarFolder` -- folds `BoundVar` instances that appear free /// in the term being folded (use `DefaultFreeVarFolder` to @@ -49,73 +55,78 @@ pub use self::subst::Subst; /// that appear in the term being folded (use /// `DefaultPlaceholderFolder` to ignore/forbid these altogether) /// -/// To **apply** a folder, use the `TypeFoldable::fold_with` method, like so +/// To **apply** a folder, use the `TypeFoldable::try_fold_with` method, +/// like so /// /// ```rust,ignore -/// let x = x.fold_with(&mut folder, 0); +/// let x = x.try_fold_with(&mut folder, 0); /// ``` -pub trait TypeFolder { +pub trait FallibleTypeFolder { /// The type this folder returns when folding fails. This is /// commonly [`NoSolution`]. type Error; /// Creates a `dyn` value from this folder. Unfortunately, this - /// must be added manually to each impl of TypeFolder; it permits the - /// default implements below to create a `&mut dyn TypeFolder` from - /// `Self` without knowing what `Self` is (by invoking this - /// method). Effectively, this limits impls of `TypeFolder` to types - /// for which we are able to create a dyn value (i.e., not `[T]` - /// types). - fn as_dyn(&mut self) -> &mut dyn TypeFolder; + /// must be added manually to each impl of FallibleTypeFolder; it + /// permits the default implements below to create a + /// `&mut dyn FallibleTypeFolder` from `Self` without knowing what + /// `Self` is (by invoking this method). Effectively, this limits + /// impls of `FallibleTypeFolder` to types for which we are able to + /// create a dyn value (i.e., not `[T]` types). + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder; /// Top-level callback: invoked for each `Ty` that is /// encountered when folding. By default, invokes - /// `super_fold_with`, which will in turn invoke the more - /// specialized folding methods below, like `fold_free_var_ty`. - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Result, Self::Error> { - ty.super_fold_with(self.as_dyn(), outer_binder) + /// `try_super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `try_fold_free_var_ty`. + fn try_fold_ty( + &mut self, + ty: Ty, + outer_binder: DebruijnIndex, + ) -> Result, Self::Error> { + ty.try_super_fold_with(self.as_dyn(), outer_binder) } /// Top-level callback: invoked for each `Lifetime` that is /// encountered when folding. By default, invokes - /// `super_fold_with`, which will in turn invoke the more - /// specialized folding methods below, like `fold_free_var_lifetime`. - fn fold_lifetime( + /// `try_super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `try_fold_free_var_lifetime`. + fn try_fold_lifetime( &mut self, lifetime: Lifetime, outer_binder: DebruijnIndex, ) -> Result, Self::Error> { - lifetime.super_fold_with(self.as_dyn(), outer_binder) + lifetime.try_super_fold_with(self.as_dyn(), outer_binder) } /// Top-level callback: invoked for each `Const` that is /// encountered when folding. By default, invokes - /// `super_fold_with`, which will in turn invoke the more - /// specialized folding methods below, like `fold_free_var_const`. - fn fold_const( + /// `try_super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `try_fold_free_var_const`. + fn try_fold_const( &mut self, constant: Const, outer_binder: DebruijnIndex, ) -> Result, Self::Error> { - constant.super_fold_with(self.as_dyn(), outer_binder) + constant.try_super_fold_with(self.as_dyn(), outer_binder) } /// Invoked for every program clause. By default, recursively folds the goals contents. - fn fold_program_clause( + fn try_fold_program_clause( &mut self, clause: ProgramClause, outer_binder: DebruijnIndex, ) -> Result, Self::Error> { - clause.super_fold_with(self.as_dyn(), outer_binder) + clause.try_super_fold_with(self.as_dyn(), outer_binder) } /// Invoked for every goal. By default, recursively folds the goals contents. - fn fold_goal( + fn try_fold_goal( &mut self, goal: Goal, outer_binder: DebruijnIndex, ) -> Result, Self::Error> { - goal.super_fold_with(self.as_dyn(), outer_binder) + goal.try_super_fold_with(self.as_dyn(), outer_binder) } /// If overridden to return true, then folding will panic if a @@ -134,7 +145,7 @@ pub trait TypeFolder { /// /// This should return a type suitable for a context with /// `binders` in scope. - fn fold_free_var_ty( + fn try_fold_free_var_ty( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, @@ -150,8 +161,8 @@ pub trait TypeFolder { } } - /// As `fold_free_var_ty`, but for lifetimes. - fn fold_free_var_lifetime( + /// As `try_fold_free_var_ty`, but for lifetimes. + fn try_fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, @@ -167,8 +178,8 @@ pub trait TypeFolder { } } - /// As `fold_free_var_ty`, but for constants. - fn fold_free_var_const( + /// As `try_fold_free_var_ty`, but for constants. + fn try_fold_free_var_const( &mut self, ty: Ty, bound_var: BoundVar, @@ -182,7 +193,7 @@ pub trait TypeFolder { } else { let bound_var = bound_var.shifted_in_from(outer_binder); Ok(ConstData { - ty: ty.fold_with(self.as_dyn(), outer_binder)?, + ty: ty.try_fold_with(self.as_dyn(), outer_binder)?, value: ConstValue::::BoundVar(bound_var), } .intern(self.interner())) @@ -203,7 +214,7 @@ pub trait TypeFolder { /// - `universe` is the universe of the `TypeName::ForAll` that was found /// - `binders` is the number of binders in scope #[allow(unused_variables)] - fn fold_free_placeholder_ty( + fn try_fold_free_placeholder_ty( &mut self, universe: PlaceholderIndex, outer_binder: DebruijnIndex, @@ -215,9 +226,9 @@ pub trait TypeFolder { } } - /// As with `fold_free_placeholder_ty`, but for lifetimes. + /// As with `try_fold_free_placeholder_ty`, but for lifetimes. #[allow(unused_variables)] - fn fold_free_placeholder_lifetime( + fn try_fold_free_placeholder_lifetime( &mut self, universe: PlaceholderIndex, outer_binder: DebruijnIndex, @@ -229,9 +240,9 @@ pub trait TypeFolder { } } - /// As with `fold_free_placeholder_ty`, but for constants. + /// As with `try_fold_free_placeholder_ty`, but for constants. #[allow(unused_variables)] - fn fold_free_placeholder_const( + fn try_fold_free_placeholder_const( &mut self, ty: Ty, universe: PlaceholderIndex, @@ -240,7 +251,10 @@ pub trait TypeFolder { if self.forbid_free_placeholders() { panic!("unexpected placeholder const `{:?}`", universe) } else { - Ok(universe.to_const(self.interner(), ty.fold_with(self.as_dyn(), outer_binder)?)) + Ok(universe.to_const( + self.interner(), + ty.try_fold_with(self.as_dyn(), outer_binder)?, + )) } } @@ -259,7 +273,7 @@ pub trait TypeFolder { /// - `universe` is the universe of the `TypeName::ForAll` that was found /// - `binders` is the number of binders in scope #[allow(unused_variables)] - fn fold_inference_ty( + fn try_fold_inference_ty( &mut self, var: InferenceVar, kind: TyVariableKind, @@ -272,9 +286,9 @@ pub trait TypeFolder { } } - /// As with `fold_inference_ty`, but for lifetimes. + /// As with `try_fold_inference_ty`, but for lifetimes. #[allow(unused_variables)] - fn fold_inference_lifetime( + fn try_fold_inference_lifetime( &mut self, var: InferenceVar, outer_binder: DebruijnIndex, @@ -286,9 +300,9 @@ pub trait TypeFolder { } } - /// As with `fold_inference_ty`, but for constants. + /// As with `try_fold_inference_ty`, but for constants. #[allow(unused_variables)] - fn fold_inference_const( + fn try_fold_inference_const( &mut self, ty: Ty, var: InferenceVar, @@ -297,7 +311,293 @@ pub trait TypeFolder { if self.forbid_inference_vars() { panic!("unexpected inference const `{:?}`", var) } else { - Ok(var.to_const(self.interner(), ty.fold_with(self.as_dyn(), outer_binder)?)) + Ok(var.to_const( + self.interner(), + ty.try_fold_with(self.as_dyn(), outer_binder)?, + )) + } + } + + /// Gets the interner that is being folded from. + fn interner(&self) -> I; +} + +/// A "folder" is a transformer that can be used to make a copy of +/// some term -- that is, some bit of IR, such as a `Goal` -- with +/// certain changes applied. The idea is that it contains methods that +/// let you swap types/lifetimes for new types/lifetimes; meanwhile, +/// each bit of IR implements the `TypeFoldable` trait which, given a +/// `TypeFolder`, will reconstruct itself, invoking the folder's methods +/// to transform each of the types/lifetimes embedded within. +/// +/// Folds performed by `TypeFolder` cannot fail. If folds might fail, +/// consider implementing `FallibleTypeFolder` instead (which is a +/// fallible, but otherwise equivalent, trait). +/// +/// # Usage patterns +/// +/// ## Substituting for free variables +/// +/// Most of the time, though, we are not interested in adjust +/// arbitrary types/lifetimes, but rather just free variables (even +/// more often, just free existential variables) that appear within +/// the term. +/// +/// For this reason, the `TypeFolder` trait extends two other traits that +/// contain methods that are invoked when just those particular +/// +/// In particular, folders can intercept references to free variables +/// (either existentially or universally quantified) and replace them +/// with other types/lifetimes as appropriate. +/// +/// To create a folder `F`, one never implements `TypeFolder` directly, but instead +/// implements one of each of these three sub-traits: +/// +/// - `FreeVarFolder` -- folds `BoundVar` instances that appear free +/// in the term being folded (use `DefaultFreeVarFolder` to +/// ignore/forbid these altogether) +/// - `InferenceFolder` -- folds existential `InferenceVar` instances +/// that appear in the term being folded (use +/// `DefaultInferenceFolder` to ignore/forbid these altogether) +/// - `PlaceholderFolder` -- folds universal `Placeholder` instances +/// that appear in the term being folded (use +/// `DefaultPlaceholderFolder` to ignore/forbid these altogether) +/// +/// To **apply** a folder, use the `TypeFoldable::fold_with` method, like so +/// +/// ```rust,ignore +/// let x = x.fold_with(&mut folder, 0); +/// ``` +pub trait TypeFolder: FallibleTypeFolder { + /// Creates a `dyn` value from this folder. Unfortunately, this + /// must be added manually to each impl of TypeFolder; it permits the + /// default implements below to create a `&mut dyn TypeFolder` from + /// `Self` without knowing what `Self` is (by invoking this + /// method). Effectively, this limits impls of `TypeFolder` to types + /// for which we are able to create a dyn value (i.e., not `[T]` + /// types). + fn as_dyn(&mut self) -> &mut dyn TypeFolder; + + /// Top-level callback: invoked for each `Ty` that is + /// encountered when folding. By default, invokes + /// `super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `fold_free_var_ty`. + fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty { + ty.super_fold_with(TypeFolder::as_dyn(self), outer_binder) + } + + /// Top-level callback: invoked for each `Lifetime` that is + /// encountered when folding. By default, invokes + /// `super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `fold_free_var_lifetime`. + fn fold_lifetime(&mut self, lifetime: Lifetime, outer_binder: DebruijnIndex) -> Lifetime { + lifetime.super_fold_with(TypeFolder::as_dyn(self), outer_binder) + } + + /// Top-level callback: invoked for each `Const` that is + /// encountered when folding. By default, invokes + /// `super_fold_with`, which will in turn invoke the more + /// specialized folding methods below, like `fold_free_var_const`. + fn fold_const(&mut self, constant: Const, outer_binder: DebruijnIndex) -> Const { + constant.super_fold_with(TypeFolder::as_dyn(self), outer_binder) + } + + /// Invoked for every program clause. By default, recursively folds the goals contents. + fn fold_program_clause( + &mut self, + clause: ProgramClause, + outer_binder: DebruijnIndex, + ) -> ProgramClause { + clause.super_fold_with(TypeFolder::as_dyn(self), outer_binder) + } + + /// Invoked for every goal. By default, recursively folds the goals contents. + fn fold_goal(&mut self, goal: Goal, outer_binder: DebruijnIndex) -> Goal { + goal.super_fold_with(TypeFolder::as_dyn(self), outer_binder) + } + + /// If overridden to return true, then folding will panic if a + /// free variable is encountered. This should be done if free + /// type/lifetime variables are not expected. + fn forbid_free_vars(&self) -> bool { + false + } + + /// Invoked for `TyKind::BoundVar` instances that are not bound + /// within the type being folded over: + /// + /// - `depth` is the depth of the `TyKind::BoundVar`; this has + /// been adjusted to account for binders in scope. + /// - `binders` is the number of binders in scope. + /// + /// This should return a type suitable for a context with + /// `binders` in scope. + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { + if TypeFolder::forbid_free_vars(self) { + panic!( + "unexpected free variable with depth `{:?}` with outer binder {:?}", + bound_var, outer_binder + ) + } else { + let bound_var = bound_var.shifted_in_from(outer_binder); + TyKind::::BoundVar(bound_var).intern(TypeFolder::interner(self)) + } + } + + /// As `fold_free_var_ty`, but for lifetimes. + fn fold_free_var_lifetime( + &mut self, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> Lifetime { + if TypeFolder::forbid_free_vars(self) { + panic!( + "unexpected free variable with depth `{:?}` with outer binder {:?}", + bound_var, outer_binder + ) + } else { + let bound_var = bound_var.shifted_in_from(outer_binder); + LifetimeData::::BoundVar(bound_var).intern(TypeFolder::interner(self)) + } + } + + /// As `fold_free_var_ty`, but for constants. + fn fold_free_var_const( + &mut self, + ty: Ty, + bound_var: BoundVar, + outer_binder: DebruijnIndex, + ) -> Const { + if TypeFolder::forbid_free_vars(self) { + panic!( + "unexpected free variable with depth `{:?}` with outer binder {:?}", + bound_var, outer_binder + ) + } else { + let bound_var = bound_var.shifted_in_from(outer_binder); + ConstData { + ty: ty.fold_with(TypeFolder::as_dyn(self), outer_binder), + value: ConstValue::::BoundVar(bound_var), + } + .intern(TypeFolder::interner(self)) + } + } + + /// If overridden to return true, we will panic when a free + /// placeholder type/lifetime/const is encountered. + fn forbid_free_placeholders(&self) -> bool { + false + } + + /// Invoked for each occurrence of a placeholder type; these are + /// used when we instantiate binders universally. Returns a type + /// to use instead, which should be suitably shifted to account + /// for `binders`. + /// + /// - `universe` is the universe of the `TypeName::ForAll` that was found + /// - `binders` is the number of binders in scope + #[allow(unused_variables)] + fn fold_free_placeholder_ty( + &mut self, + universe: PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> Ty { + if TypeFolder::forbid_free_placeholders(self) { + panic!("unexpected placeholder type `{:?}`", universe) + } else { + universe.to_ty::(TypeFolder::interner(self)) + } + } + + /// As with `fold_free_placeholder_ty`, but for lifetimes. + #[allow(unused_variables)] + fn fold_free_placeholder_lifetime( + &mut self, + universe: PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> Lifetime { + if TypeFolder::forbid_free_placeholders(self) { + panic!("unexpected placeholder lifetime `{:?}`", universe) + } else { + universe.to_lifetime(TypeFolder::interner(self)) + } + } + + /// As with `fold_free_placeholder_ty`, but for constants. + #[allow(unused_variables)] + fn fold_free_placeholder_const( + &mut self, + ty: Ty, + universe: PlaceholderIndex, + outer_binder: DebruijnIndex, + ) -> Const { + if TypeFolder::forbid_free_placeholders(self) { + panic!("unexpected placeholder const `{:?}`", universe) + } else { + universe.to_const( + TypeFolder::interner(self), + ty.fold_with(TypeFolder::as_dyn(self), outer_binder), + ) + } + } + + /// If overridden to return true, inference variables will trigger + /// panics when folded. Used when inference variables are + /// unexpected. + fn forbid_inference_vars(&self) -> bool { + false + } + + /// Invoked for each occurrence of a inference type; these are + /// used when we instantiate binders universally. Returns a type + /// to use instead, which should be suitably shifted to account + /// for `binders`. + /// + /// - `universe` is the universe of the `TypeName::ForAll` that was found + /// - `binders` is the number of binders in scope + #[allow(unused_variables)] + fn fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + outer_binder: DebruijnIndex, + ) -> Ty { + if TypeFolder::forbid_inference_vars(self) { + panic!("unexpected inference type `{:?}`", var) + } else { + var.to_ty(TypeFolder::interner(self), kind) + } + } + + /// As with `fold_inference_ty`, but for lifetimes. + #[allow(unused_variables)] + fn fold_inference_lifetime( + &mut self, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Lifetime { + if TypeFolder::forbid_inference_vars(self) { + panic!("unexpected inference lifetime `'{:?}`", var) + } else { + var.to_lifetime(TypeFolder::interner(self)) + } + } + + /// As with `fold_inference_ty`, but for constants. + #[allow(unused_variables)] + fn fold_inference_const( + &mut self, + ty: Ty, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Const { + if TypeFolder::forbid_inference_vars(self) { + panic!("unexpected inference const `{:?}`", var) + } else { + var.to_const( + TypeFolder::interner(self), + ty.fold_with(TypeFolder::as_dyn(self), outer_binder), + ) } } @@ -316,11 +616,19 @@ pub trait TypeFoldable: Debug + Sized { /// folder. Typically `binders` starts as 0, but is adjusted when /// we encounter `Binders` in the IR or other similar /// constructs. - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result; + + /// A convenient alternative to `try_fold_with` for use with infallible + /// folders. Do not override this method, to ensure coherence with + /// `try_fold_with`. + fn fold_with(self, folder: &mut dyn TypeFolder, outer_binder: DebruijnIndex) -> Self { + self.try_fold_with(FallibleTypeFolder::as_dyn(folder), outer_binder) + .unwrap() + } } /// For types where "fold" invokes a callback on the `TypeFolder`, the @@ -328,23 +636,31 @@ pub trait TypeFoldable: Debug + Sized { /// the contents of the type. pub trait TypeSuperFoldable: TypeFoldable { /// Recursively folds the value. - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result; + + /// A convenient alternative to `try_super_fold_with` for use with + /// infallible folders. Do not override this method, to ensure coherence + /// with `try_super_fold_with`. + fn super_fold_with(self, folder: &mut dyn TypeFolder, outer_binder: DebruijnIndex) -> Self { + self.try_super_fold_with(FallibleTypeFolder::as_dyn(folder), outer_binder) + .unwrap() + } } -/// "Folding" a type invokes the `fold_ty` method on the folder; this -/// usually (in turn) invokes `super_fold_ty` to fold the individual +/// "Folding" a type invokes the `try_fold_ty` method on the folder; this +/// usually (in turn) invokes `try_super_fold_ty` to fold the individual /// parts. impl TypeFoldable for Ty { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - folder.fold_ty(self, outer_binder) + folder.try_fold_ty(self, outer_binder) } } @@ -353,9 +669,9 @@ impl TypeSuperFoldable for Ty where I: Interner, { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result, E> { let interner = folder.interner(); @@ -366,7 +682,7 @@ where // that we have traversed during folding; // therefore, it is free. Let the folder have a // crack at it. - folder.fold_free_var_ty(bound_var1, outer_binder)? + folder.try_fold_free_var_ty(bound_var1, outer_binder)? } else { // This variable was bound within the binders that // we folded over, so just return a bound @@ -374,83 +690,86 @@ where self } } - TyKind::Dyn(clauses) => TyKind::Dyn(clauses.clone().fold_with(folder, outer_binder)?) - .intern(folder.interner()), + TyKind::Dyn(clauses) => { + TyKind::Dyn(clauses.clone().try_fold_with(folder, outer_binder)?) + .intern(folder.interner()) + } TyKind::InferenceVar(var, kind) => { - folder.fold_inference_ty(*var, *kind, outer_binder)? + folder.try_fold_inference_ty(*var, *kind, outer_binder)? } - TyKind::Placeholder(ui) => folder.fold_free_placeholder_ty(*ui, outer_binder)?, - TyKind::Alias(proj) => TyKind::Alias(proj.clone().fold_with(folder, outer_binder)?) - .intern(folder.interner()), - TyKind::Function(fun) => TyKind::Function(fun.clone().fold_with(folder, outer_binder)?) + TyKind::Placeholder(ui) => folder.try_fold_free_placeholder_ty(*ui, outer_binder)?, + TyKind::Alias(proj) => TyKind::Alias(proj.clone().try_fold_with(folder, outer_binder)?) .intern(folder.interner()), + TyKind::Function(fun) => { + TyKind::Function(fun.clone().try_fold_with(folder, outer_binder)?) + .intern(folder.interner()) + } TyKind::Adt(id, substitution) => TyKind::Adt( - id.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + id.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::AssociatedType(assoc_ty, substitution) => TyKind::AssociatedType( - assoc_ty.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + assoc_ty.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), - TyKind::Scalar(scalar) => { - TyKind::Scalar(scalar.fold_with(folder, outer_binder)?).intern(folder.interner()) - } + TyKind::Scalar(scalar) => TyKind::Scalar(scalar.try_fold_with(folder, outer_binder)?) + .intern(folder.interner()), TyKind::Str => TyKind::Str.intern(folder.interner()), TyKind::Tuple(arity, substitution) => TyKind::Tuple( *arity, - substitution.clone().fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::OpaqueType(opaque_ty, substitution) => TyKind::OpaqueType( - opaque_ty.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + opaque_ty.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Slice(substitution) => { - TyKind::Slice(substitution.clone().fold_with(folder, outer_binder)?) + TyKind::Slice(substitution.clone().try_fold_with(folder, outer_binder)?) .intern(folder.interner()) } TyKind::FnDef(fn_def, substitution) => TyKind::FnDef( - fn_def.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + fn_def.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Ref(mutability, lifetime, ty) => TyKind::Ref( - mutability.fold_with(folder, outer_binder)?, - lifetime.clone().fold_with(folder, outer_binder)?, - ty.clone().fold_with(folder, outer_binder)?, + mutability.try_fold_with(folder, outer_binder)?, + lifetime.clone().try_fold_with(folder, outer_binder)?, + ty.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Raw(mutability, ty) => TyKind::Raw( - mutability.fold_with(folder, outer_binder)?, - ty.clone().fold_with(folder, outer_binder)?, + mutability.try_fold_with(folder, outer_binder)?, + ty.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Never => TyKind::Never.intern(folder.interner()), TyKind::Array(ty, const_) => TyKind::Array( - ty.clone().fold_with(folder, outer_binder)?, - const_.clone().fold_with(folder, outer_binder)?, + ty.clone().try_fold_with(folder, outer_binder)?, + const_.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Closure(id, substitution) => TyKind::Closure( - id.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + id.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Generator(id, substitution) => TyKind::Generator( - id.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + id.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::GeneratorWitness(id, substitution) => TyKind::GeneratorWitness( - id.fold_with(folder, outer_binder)?, - substitution.clone().fold_with(folder, outer_binder)?, + id.try_fold_with(folder, outer_binder)?, + substitution.clone().try_fold_with(folder, outer_binder)?, ) .intern(folder.interner()), TyKind::Foreign(id) => { - TyKind::Foreign(id.fold_with(folder, outer_binder)?).intern(folder.interner()) + TyKind::Foreign(id.try_fold_with(folder, outer_binder)?).intern(folder.interner()) } TyKind::Error => TyKind::Error.intern(folder.interner()), }) @@ -461,12 +780,12 @@ where /// usually (in turn) invokes `super_fold_lifetime` to fold the individual /// parts. impl TypeFoldable for Lifetime { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - folder.fold_lifetime(self, outer_binder) + folder.try_fold_lifetime(self, outer_binder) } } @@ -474,9 +793,9 @@ impl TypeSuperFoldable for Lifetime where I: Interner, { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result, E> { let interner = folder.interner(); @@ -487,7 +806,7 @@ where // that we have traversed during folding; // therefore, it is free. Let the folder have a // crack at it. - folder.fold_free_var_lifetime(bound_var1, outer_binder) + folder.try_fold_free_var_lifetime(bound_var1, outer_binder) } else { // This variable was bound within the binders that // we folded over, so just return a bound @@ -495,9 +814,11 @@ where Ok(self) } } - LifetimeData::InferenceVar(var) => folder.fold_inference_lifetime(*var, outer_binder), + LifetimeData::InferenceVar(var) => { + folder.try_fold_inference_lifetime(*var, outer_binder) + } LifetimeData::Placeholder(universe) => { - folder.fold_free_placeholder_lifetime(*universe, outer_binder) + folder.try_fold_free_placeholder_lifetime(*universe, outer_binder) } LifetimeData::Static => Ok(LifetimeData::::Static.intern(folder.interner())), LifetimeData::Empty(ui) => Ok(LifetimeData::::Empty(*ui).intern(folder.interner())), @@ -511,12 +832,12 @@ where /// usually (in turn) invokes `super_fold_const` to fold the individual /// parts. impl TypeFoldable for Const { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - folder.fold_const(self, outer_binder) + folder.try_fold_const(self, outer_binder) } } @@ -524,27 +845,27 @@ impl TypeSuperFoldable for Const where I: Interner, { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result, E> { let interner = folder.interner(); let ConstData { ref ty, ref value } = self.data(interner); - let mut fold_ty = || ty.clone().fold_with(folder, outer_binder); + let mut fold_ty = || ty.clone().try_fold_with(folder, outer_binder); match value { ConstValue::BoundVar(bound_var) => { if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) { - folder.fold_free_var_const(ty.clone(), bound_var1, outer_binder) + folder.try_fold_free_var_const(ty.clone(), bound_var1, outer_binder) } else { Ok(self) } } ConstValue::InferenceVar(var) => { - folder.fold_inference_const(ty.clone(), *var, outer_binder) + folder.try_fold_inference_const(ty.clone(), *var, outer_binder) } ConstValue::Placeholder(universe) => { - folder.fold_free_placeholder_const(ty.clone(), *universe, outer_binder) + folder.try_fold_free_placeholder_const(ty.clone(), *universe, outer_binder) } ConstValue::Concrete(ev) => Ok(ConstData { ty: fold_ty()?, @@ -560,20 +881,20 @@ where /// Folding a goal invokes the `fold_goal` callback (which will, by /// default, invoke super-fold). impl TypeFoldable for Goal { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - folder.fold_goal(self, outer_binder) + folder.try_fold_goal(self, outer_binder) } } /// Superfold folds recursively. impl TypeSuperFoldable for Goal { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); @@ -581,7 +902,7 @@ impl TypeSuperFoldable for Goal { interner, self.data(interner) .clone() - .fold_with(folder, outer_binder)?, + .try_fold_with(folder, outer_binder)?, )) } } @@ -590,11 +911,11 @@ impl TypeSuperFoldable for Goal { /// callback on the folder (which will, by default, invoke the /// `super_fold_with` method on the program clause). impl TypeFoldable for ProgramClause { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - folder.fold_program_clause(self, outer_binder) + folder.try_fold_program_clause(self, outer_binder) } } diff --git a/chalk-ir/src/fold/binder_impls.rs b/chalk-ir/src/fold/binder_impls.rs index 8b35238c759..1f44c162962 100644 --- a/chalk-ir/src/fold/binder_impls.rs +++ b/chalk-ir/src/fold/binder_impls.rs @@ -6,9 +6,9 @@ use crate::*; impl TypeFoldable for FnPointer { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let FnPointer { @@ -18,7 +18,7 @@ impl TypeFoldable for FnPointer { } = self; Ok(FnPointer { num_binders, - substitution: substitution.fold_with(folder, outer_binder.shifted_in())?, + substitution: substitution.try_fold_with(folder, outer_binder.shifted_in())?, sig: FnSig { abi: sig.abi, safety: sig.safety, @@ -33,16 +33,16 @@ where T: HasInterner + TypeFoldable, I: Interner, { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let Binders { binders: self_binders, value: self_value, } = self; - let value = self_value.fold_with(folder, outer_binder.shifted_in())?; + let value = self_value.try_fold_with(folder, outer_binder.shifted_in())?; let binders = VariableKinds { interned: self_binders.interned().clone(), }; @@ -55,16 +55,16 @@ where I: Interner, T: HasInterner + TypeFoldable, { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let Canonical { binders: self_binders, value: self_value, } = self; - let value = self_value.fold_with(folder, outer_binder.shifted_in())?; + let value = self_value.try_fold_with(folder, outer_binder.shifted_in())?; let binders = CanonicalVarKinds { interned: self_binders.interned().clone(), }; diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs index 74fb43aeb43..fb4e3e30b9d 100644 --- a/chalk-ir/src/fold/boring_impls.rs +++ b/chalk-ir/src/fold/boring_impls.rs @@ -9,33 +9,33 @@ use crate::*; use std::marker::PhantomData; impl, I: Interner> TypeFoldable for Vec { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - in_place::fallible_map_vec(self, |e| e.fold_with(folder, outer_binder)) + in_place::fallible_map_vec(self, |e| e.try_fold_with(folder, outer_binder)) } } impl, I: Interner> TypeFoldable for Box { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { - in_place::fallible_map_box(self, |e| e.fold_with(folder, outer_binder)) + in_place::fallible_map_box(self, |e| e.try_fold_with(folder, outer_binder)) } } macro_rules! tuple_fold { ($($n:ident),*) => { impl<$($n: TypeFoldable,)* I: Interner> TypeFoldable for ($($n,)*) { - fn fold_with(self, folder: &mut dyn TypeFolder, outer_binder: DebruijnIndex) -> Result + fn try_fold_with(self, folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex) -> Result { #[allow(non_snake_case)] let ($($n),*) = self; - Ok(($($n.fold_with(folder, outer_binder)?,)*)) + Ok(($($n.try_fold_with(folder, outer_binder)?,)*)) } } } @@ -47,22 +47,22 @@ tuple_fold!(A, B, C, D); tuple_fold!(A, B, C, D, E); impl, I: Interner> TypeFoldable for Option { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { match self { None => Ok(None), - Some(e) => Ok(Some(e.fold_with(folder, outer_binder)?)), + Some(e) => Ok(Some(e.try_fold_with(folder, outer_binder)?)), } } } impl TypeFoldable for GenericArg { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); @@ -70,15 +70,15 @@ impl TypeFoldable for GenericArg { let data = self .data(interner) .clone() - .fold_with(folder, outer_binder)?; + .try_fold_with(folder, outer_binder)?; Ok(GenericArg::new(interner, data)) } } impl TypeFoldable for Substitution { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); @@ -86,67 +86,67 @@ impl TypeFoldable for Substitution { let folded = self .iter(interner) .cloned() - .map(|p| p.fold_with(folder, outer_binder)); + .map(|p| p.try_fold_with(folder, outer_binder)); Substitution::from_fallible(interner, folded) } } impl TypeFoldable for Goals { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); let folded = self .iter(interner) .cloned() - .map(|p| p.fold_with(folder, outer_binder)); + .map(|p| p.try_fold_with(folder, outer_binder)); Goals::from_fallible(interner, folded) } } impl TypeFoldable for ProgramClauses { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); let folded = self .iter(interner) .cloned() - .map(|p| p.fold_with(folder, outer_binder)); + .map(|p| p.try_fold_with(folder, outer_binder)); ProgramClauses::from_fallible(interner, folded) } } impl TypeFoldable for QuantifiedWhereClauses { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); let folded = self .iter(interner) .cloned() - .map(|p| p.fold_with(folder, outer_binder)); + .map(|p| p.try_fold_with(folder, outer_binder)); QuantifiedWhereClauses::from_fallible(interner, folded) } } impl TypeFoldable for Constraints { - fn fold_with( + fn try_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> Result { let interner = folder.interner(); let folded = self .iter(interner) .cloned() - .map(|p| p.fold_with(folder, outer_binder)); + .map(|p| p.try_fold_with(folder, outer_binder)); Constraints::from_fallible(interner, folded) } } @@ -156,9 +156,9 @@ impl TypeFoldable for Constraints { macro_rules! copy_fold { ($t:ty) => { impl $crate::fold::TypeFoldable for $t { - fn fold_with( + fn try_fold_with( self, - _folder: &mut dyn ($crate::fold::TypeFolder), + _folder: &mut dyn ($crate::fold::FallibleTypeFolder), _outer_binder: DebruijnIndex, ) -> ::std::result::Result { Ok(self) @@ -187,9 +187,9 @@ copy_fold!(Safety); macro_rules! id_fold { ($t:ident) => { impl $crate::fold::TypeFoldable for $t { - fn fold_with( + fn try_fold_with( self, - _folder: &mut dyn ($crate::fold::TypeFolder), + _folder: &mut dyn ($crate::fold::FallibleTypeFolder), _outer_binder: DebruijnIndex, ) -> ::std::result::Result { Ok(self) @@ -209,32 +209,34 @@ id_fold!(GeneratorId); id_fold!(ForeignDefId); impl TypeSuperFoldable for ProgramClauseData { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> ::std::result::Result { - Ok(ProgramClauseData(self.0.fold_with(folder, outer_binder)?)) + Ok(ProgramClauseData( + self.0.try_fold_with(folder, outer_binder)?, + )) } } impl TypeSuperFoldable for ProgramClause { - fn super_fold_with( + fn try_super_fold_with( self, - folder: &mut dyn TypeFolder, + folder: &mut dyn FallibleTypeFolder, outer_binder: DebruijnIndex, ) -> ::std::result::Result { let clause = self.data(folder.interner()).clone(); Ok(clause - .super_fold_with(folder, outer_binder)? + .try_super_fold_with(folder, outer_binder)? .intern(folder.interner())) } } impl TypeFoldable for PhantomData { - fn fold_with( + fn try_fold_with( self, - _folder: &mut dyn TypeFolder, + _folder: &mut dyn FallibleTypeFolder, _outer_binder: DebruijnIndex, ) -> ::std::result::Result { Ok(PhantomData) diff --git a/chalk-ir/src/fold/shift.rs b/chalk-ir/src/fold/shift.rs index cfbe6f114a0..f7e5e4a4abd 100644 --- a/chalk-ir/src/fold/shift.rs +++ b/chalk-ir/src/fold/shift.rs @@ -1,6 +1,5 @@ //! Shifting of debruijn indices -use super::TypeFoldable; use crate::*; /// Methods for converting debruijn indices to move values into or out @@ -29,7 +28,7 @@ impl, I: Interner> Shift for T { } fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> T { - self.fold_with( + self.try_fold_with( &mut Shifter { source_binder, interner, @@ -40,7 +39,7 @@ impl, I: Interner> Shift for T { } fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible { - self.fold_with( + self.try_fold_with( &mut DownShifter { target_binder, interner, @@ -55,12 +54,13 @@ impl, I: Interner> Shift for T { } /// A folder that adjusts debruijn indices by a certain amount. -struct Shifter { +#[derive(FallibleTypeFolder)] +struct Shifter { source_binder: DebruijnIndex, interner: I, } -impl Shifter { +impl Shifter { /// Given a free variable at `depth`, shifts that depth to `depth /// + self.adjustment`, and then wraps *that* within the internal /// set `binders`. @@ -72,29 +72,22 @@ impl Shifter { } impl TypeFolder for Shifter { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } - fn fold_free_var_ty( - &mut self, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible> { - Ok(TyKind::::BoundVar(self.adjust(bound_var, outer_binder)).intern(self.interner())) + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { + TyKind::::BoundVar(self.adjust(bound_var, outer_binder)) + .intern(TypeFolder::interner(self)) } fn fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { - Ok( - LifetimeData::::BoundVar(self.adjust(bound_var, outer_binder)) - .intern(self.interner()), - ) + ) -> Lifetime { + LifetimeData::::BoundVar(self.adjust(bound_var, outer_binder)) + .intern(TypeFolder::interner(self)) } fn fold_free_var_const( @@ -102,11 +95,10 @@ impl TypeFolder for Shifter { ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { // const types don't have free variables, so we can skip folding `ty` - Ok(self - .adjust(bound_var, outer_binder) - .to_const(self.interner(), ty)) + self.adjust(bound_var, outer_binder) + .to_const(TypeFolder::interner(self), ty) } fn interner(&self) -> I { @@ -141,14 +133,14 @@ impl DownShifter { } } -impl TypeFolder for DownShifter { +impl FallibleTypeFolder for DownShifter { type Error = NoSolution; - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { self } - fn fold_free_var_ty( + fn try_fold_free_var_ty( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, @@ -156,7 +148,7 @@ impl TypeFolder for DownShifter { Ok(TyKind::::BoundVar(self.adjust(bound_var, outer_binder)?).intern(self.interner())) } - fn fold_free_var_lifetime( + fn try_fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, @@ -167,7 +159,7 @@ impl TypeFolder for DownShifter { ) } - fn fold_free_var_const( + fn try_fold_free_var_const( &mut self, ty: Ty, bound_var: BoundVar, diff --git a/chalk-ir/src/fold/subst.rs b/chalk-ir/src/fold/subst.rs index 89ffe6e0fa2..7cff8d89c91 100644 --- a/chalk-ir/src/fold/subst.rs +++ b/chalk-ir/src/fold/subst.rs @@ -2,6 +2,7 @@ use super::*; use crate::fold::shift::Shift; /// Substitution used during folding +#[derive(FallibleTypeFolder)] pub struct Subst<'s, I: Interner> { /// Values to substitute. A reference to a free variable with /// index `i` will be mapped to `parameters[i]` -- if `i > @@ -14,7 +15,7 @@ impl Subst<'_, I> { /// Applies the substitution by folding pub fn apply>(interner: I, parameters: &[GenericArg], value: T) -> T { value - .fold_with( + .try_fold_with( &mut Subst { parameters, interner, @@ -26,9 +27,7 @@ impl Subst<'_, I> { } impl TypeFolder for Subst<'_, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -51,24 +50,20 @@ impl TypeFolder for Subst<'_, I> { /// for { [A, u32] } /// ^ represented as `^0.0` /// ``` - fn fold_free_var_ty( - &mut self, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible> { + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { if let Some(index) = bound_var.index_if_innermost() { - match self.parameters[index].data(self.interner()) { - GenericArgData::Ty(t) => { - Ok(t.clone().shifted_in_from(self.interner(), outer_binder)) - } + match self.parameters[index].data(TypeFolder::interner(self)) { + GenericArgData::Ty(t) => t + .clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder), _ => panic!("mismatched kinds in substitution"), } } else { - Ok(bound_var + bound_var .shifted_out() .expect("cannot fail because this is not the innermost") .shifted_in_from(outer_binder) - .to_ty(self.interner())) + .to_ty(TypeFolder::interner(self)) } } @@ -77,20 +72,20 @@ impl TypeFolder for Subst<'_, I> { &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { if let Some(index) = bound_var.index_if_innermost() { - match self.parameters[index].data(self.interner()) { - GenericArgData::Lifetime(l) => { - Ok(l.clone().shifted_in_from(self.interner(), outer_binder)) - } + match self.parameters[index].data(TypeFolder::interner(self)) { + GenericArgData::Lifetime(l) => l + .clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder), _ => panic!("mismatched kinds in substitution"), } } else { - Ok(bound_var + bound_var .shifted_out() .unwrap() .shifted_in_from(outer_binder) - .to_lifetime(self.interner())) + .to_lifetime(TypeFolder::interner(self)) } } @@ -100,20 +95,20 @@ impl TypeFolder for Subst<'_, I> { ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { if let Some(index) = bound_var.index_if_innermost() { - match self.parameters[index].data(self.interner()) { - GenericArgData::Const(c) => { - Ok(c.clone().shifted_in_from(self.interner(), outer_binder)) - } + match self.parameters[index].data(TypeFolder::interner(self)) { + GenericArgData::Const(c) => c + .clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder), _ => panic!("mismatched kinds in substitution"), } } else { - Ok(bound_var + bound_var .shifted_out() .unwrap() .shifted_in_from(outer_binder) - .to_const(self.interner(), ty)) + .to_const(TypeFolder::interner(self), ty) } } diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index ffc5cfcf285..b40ac3f5259 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -8,9 +8,11 @@ extern crate self as chalk_ir; use crate::cast::{Cast, CastTo, Caster}; use crate::fold::shift::Shift; -use crate::fold::{Subst, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use crate::fold::{FallibleTypeFolder, Subst, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor, VisitExt}; -use chalk_derive::{HasInterner, TypeFoldable, TypeSuperVisitable, TypeVisitable, Zip}; +use chalk_derive::{ + FallibleTypeFolder, HasInterner, TypeFoldable, TypeSuperVisitable, TypeVisitable, Zip, +}; use std::marker::PhantomData; use std::ops::ControlFlow; @@ -2725,6 +2727,7 @@ impl Substitution { } } +#[derive(FallibleTypeFolder)] struct SubstFolder<'i, I: Interner, A: AsParameters> { interner: I, subst: &'i A, @@ -2791,8 +2794,8 @@ impl> Substitute for A { T: TypeFoldable, { value - .fold_with( - &mut &SubstFolder { + .try_fold_with( + &mut SubstFolder { interner, subst: self, }, @@ -2825,33 +2828,29 @@ impl<'a, I: Interner> ToGenericArg for (usize, &'a VariableKind) { } } -impl<'i, I: Interner, A: AsParameters> TypeFolder for &SubstFolder<'i, I, A> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { +impl<'i, I: Interner, A: AsParameters> TypeFolder for SubstFolder<'i, I, A> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } - fn fold_free_var_ty( - &mut self, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible> { + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let ty = self.at(bound_var.index); - let ty = ty.assert_ty_ref(self.interner()); - Ok(ty.clone().shifted_in_from(self.interner(), outer_binder)) + let ty = ty.assert_ty_ref(TypeFolder::interner(self)); + ty.clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let l = self.at(bound_var.index); - let l = l.assert_lifetime_ref(self.interner()); - Ok(l.clone().shifted_in_from(self.interner(), outer_binder)) + let l = l.assert_lifetime_ref(TypeFolder::interner(self)); + l.clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn fold_free_var_const( @@ -2859,11 +2858,12 @@ impl<'i, I: Interner, A: AsParameters> TypeFolder for &SubstFolder<'i, I, _ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let c = self.at(bound_var.index); - let c = c.assert_const_ref(self.interner()); - Ok(c.clone().shifted_in_from(self.interner(), outer_binder)) + let c = c.assert_const_ref(TypeFolder::interner(self)); + c.clone() + .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn interner(&self) -> I { diff --git a/chalk-solve/src/clauses/generalize.rs b/chalk-solve/src/clauses/generalize.rs index 91f7e7b832f..bff05b36995 100644 --- a/chalk-solve/src/clauses/generalize.rs +++ b/chalk-solve/src/clauses/generalize.rs @@ -6,14 +6,16 @@ //! happen with `dyn Trait` currently; that's the only case where we use the //! types passed to `program_clauses` in the clauses we generate. +use chalk_derive::FallibleTypeFolder; use chalk_ir::{ fold::{TypeFoldable, TypeFolder}, interner::{HasInterner, Interner}, - Binders, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, Fallible, Lifetime, - LifetimeData, NoSolution, Ty, TyKind, TyVariableKind, VariableKind, VariableKinds, + Binders, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, Lifetime, LifetimeData, Ty, + TyKind, TyVariableKind, VariableKind, VariableKinds, }; use rustc_hash::FxHashMap; +#[derive(FallibleTypeFolder)] pub struct Generalize { binders: Vec>, mapping: FxHashMap, @@ -31,7 +33,7 @@ impl Generalize { interner, }; let value = value - .fold_with(&mut generalize, DebruijnIndex::INNERMOST) + .try_fold_with(&mut generalize, DebruijnIndex::INNERMOST) .unwrap(); Binders::new( VariableKinds::from_iter(interner, generalize.binders), @@ -41,17 +43,11 @@ impl Generalize { } impl TypeFolder for Generalize { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } - fn fold_free_var_ty( - &mut self, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Fallible> { + fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); @@ -59,7 +55,7 @@ impl TypeFolder for Generalize { i }); let new_var = BoundVar::new(outer_binder, *new_index); - Ok(TyKind::BoundVar(new_var).intern(self.interner())) + TyKind::BoundVar(new_var).intern(TypeFolder::interner(self)) } fn fold_free_var_const( @@ -67,7 +63,7 @@ impl TypeFolder for Generalize { ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); @@ -75,18 +71,18 @@ impl TypeFolder for Generalize { i }); let new_var = BoundVar::new(outer_binder, *new_index); - Ok(ConstData { + ConstData { ty, value: ConstValue::BoundVar(new_var), } - .intern(self.interner())) + .intern(TypeFolder::interner(self)) } fn fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); @@ -94,7 +90,7 @@ impl TypeFolder for Generalize { i }); let new_var = BoundVar::new(outer_binder, *new_index); - Ok(LifetimeData::BoundVar(new_var).intern(self.interner())) + LifetimeData::BoundVar(new_var).intern(TypeFolder::interner(self)) } fn interner(&self) -> I { diff --git a/chalk-solve/src/infer/canonicalize.rs b/chalk-solve/src/infer/canonicalize.rs index cd55056f264..56fe88a5630 100644 --- a/chalk-solve/src/infer/canonicalize.rs +++ b/chalk-solve/src/infer/canonicalize.rs @@ -1,4 +1,5 @@ use crate::debug_span; +use chalk_derive::FallibleTypeFolder; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use chalk_ir::interner::{HasInterner, Interner}; @@ -39,7 +40,9 @@ impl InferenceTable { max_universe: UniverseIndex::root(), interner, }; - let value = value.fold_with(&mut q, DebruijnIndex::INNERMOST).unwrap(); + let value = value + .try_fold_with(&mut q, DebruijnIndex::INNERMOST) + .unwrap(); let free_vars = q.free_vars.clone(); Canonicalized { @@ -61,6 +64,7 @@ pub struct Canonicalized { pub free_vars: Vec>, } +#[derive(FallibleTypeFolder)] struct Canonicalizer<'q, I: Interner> { table: &'q mut InferenceTable, free_vars: Vec>, @@ -102,9 +106,7 @@ impl<'q, I: Interner> Canonicalizer<'q, I> { } impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -112,20 +114,20 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let interner = self.interner; self.max_universe = max(self.max_universe, universe.ui); - Ok(universe.to_ty(interner)) + universe.to_ty(interner) } fn fold_free_placeholder_lifetime( &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let interner = self.interner; self.max_universe = max(self.max_universe, universe.ui); - Ok(universe.to_lifetime(interner)) + universe.to_lifetime(interner) } fn fold_free_placeholder_const( @@ -133,10 +135,10 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { ty: Ty, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { let interner = self.interner; self.max_universe = max(self.max_universe, universe.ui); - Ok(universe.to_const(interner, ty)) + universe.to_const(interner, ty) } fn forbid_free_vars(&self) -> bool { @@ -149,16 +151,15 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { var: InferenceVar, kind: TyVariableKind, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let interner = self.interner; match self.table.probe_var(var) { Some(ty) => { let ty = ty.assert_ty_ref(interner); debug!("bound to {:?}", ty); - Ok(ty - .clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in_from(interner, outer_binder)) + ty.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) } None => { // If this variable is not yet bound, find its @@ -170,7 +171,7 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); debug!(position=?bound_var, "not yet unified"); - Ok(TyKind::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner)) + TyKind::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner) } } } @@ -180,25 +181,22 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { &mut self, var: InferenceVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let interner = self.interner; match self.table.probe_var(var) { Some(l) => { let l = l.assert_lifetime_ref(interner); debug!("bound to {:?}", l); - Ok(l.clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in_from(interner, outer_binder)) + l.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) } None => { let free_var = ParameterEnaVariable::new(VariableKind::Lifetime, self.table.unify.find(var)); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); debug!(position=?bound_var, "not yet unified"); - Ok( - LifetimeData::BoundVar(bound_var.shifted_in_from(outer_binder)) - .intern(interner), - ) + LifetimeData::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner) } } } @@ -209,15 +207,15 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { ty: Ty, var: InferenceVar, outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { let interner = self.interner; match self.table.probe_var(var) { Some(c) => { let c = c.assert_const_ref(interner); debug!("bound to {:?}", c); - Ok(c.clone() - .fold_with(self, DebruijnIndex::INNERMOST)? - .shifted_in_from(interner, outer_binder)) + c.clone() + .fold_with(self, DebruijnIndex::INNERMOST) + .shifted_in_from(interner, outer_binder) } None => { let free_var = ParameterEnaVariable::new( @@ -226,18 +224,14 @@ impl<'i, I: Interner> TypeFolder for Canonicalizer<'i, I> { ); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); debug!(position = ?bound_var, "not yet unified"); - Ok(bound_var + bound_var .shifted_in_from(outer_binder) - .to_const(interner, ty)) + .to_const(interner, ty) } } } - fn fold_lifetime( - &mut self, - lifetime: Lifetime, - outer_binder: DebruijnIndex, - ) -> Fallible> { + fn fold_lifetime(&mut self, lifetime: Lifetime, outer_binder: DebruijnIndex) -> Lifetime { match *lifetime.data(self.interner) { LifetimeData::Empty(ui) if ui.counter != 0 => { // ReEmpty in non-root universes is only used by lexical region diff --git a/chalk-solve/src/infer/invert.rs b/chalk-solve/src/infer/invert.rs index 36e32ee428c..e5bc3590ced 100644 --- a/chalk-solve/src/infer/invert.rs +++ b/chalk-solve/src/infer/invert.rs @@ -1,3 +1,4 @@ +use chalk_derive::FallibleTypeFolder; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{TypeFoldable, TypeFolder}; use chalk_ir::interner::HasInterner; @@ -90,7 +91,7 @@ impl InferenceTable { assert!(quantified.binders.is_empty(interner)); let inverted = quantified .value - .fold_with(&mut Inverter::new(interner, self), DebruijnIndex::INNERMOST) + .try_fold_with(&mut Inverter::new(interner, self), DebruijnIndex::INNERMOST) .unwrap(); Some(inverted) } @@ -109,6 +110,7 @@ impl InferenceTable { } } +#[derive(FallibleTypeFolder)] struct Inverter<'q, I: Interner> { table: &'q mut InferenceTable, inverted_ty: FxHashMap>, @@ -128,9 +130,7 @@ impl<'q, I: Interner> Inverter<'q, I> { } impl<'i, I: Interner> TypeFolder for Inverter<'i, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -138,28 +138,26 @@ impl<'i, I: Interner> TypeFolder for Inverter<'i, I> { &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let table = &mut self.table; - Ok(self - .inverted_ty + self.inverted_ty .entry(universe) .or_insert_with(|| table.new_variable(universe.ui)) - .to_ty(self.interner()) - .shifted_in(self.interner())) + .to_ty(TypeFolder::interner(self)) + .shifted_in(TypeFolder::interner(self)) } fn fold_free_placeholder_lifetime( &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let table = &mut self.table; - Ok(self - .inverted_lifetime + self.inverted_lifetime .entry(universe) .or_insert_with(|| table.new_variable(universe.ui)) - .to_lifetime(self.interner()) - .shifted_in(self.interner())) + .to_lifetime(TypeFolder::interner(self)) + .shifted_in(TypeFolder::interner(self)) } fn forbid_free_vars(&self) -> bool { diff --git a/chalk-solve/src/infer/ucanonicalize.rs b/chalk-solve/src/infer/ucanonicalize.rs index 6f09a4490eb..b44880e3764 100644 --- a/chalk-solve/src/infer/ucanonicalize.rs +++ b/chalk-solve/src/infer/ucanonicalize.rs @@ -1,4 +1,5 @@ use crate::debug_span; +use chalk_derive::FallibleTypeFolder; use chalk_ir::fold::{TypeFoldable, TypeFolder}; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::visit::{TypeVisitable, TypeVisitor}; @@ -36,7 +37,7 @@ impl InferenceTable { let value1 = value0 .value .clone() - .fold_with( + .try_fold_with( &mut UMapToCanonical { universes: &universes, interner, @@ -169,7 +170,7 @@ impl UniverseMapExt for UniverseMap { let value = canonical_value .value .clone() - .fold_with( + .try_fold_with( &mut UMapFromCanonical { interner, universes: self, @@ -217,15 +218,14 @@ impl TypeVisitor for UCollector<'_, I> { } } -struct UMapToCanonical<'q, I> { +#[derive(FallibleTypeFolder)] +struct UMapToCanonical<'q, I: Interner> { interner: I, universes: &'q UniverseMap, } impl<'i, I: Interner> TypeFolder for UMapToCanonical<'i, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -237,33 +237,33 @@ impl<'i, I: Interner> TypeFolder for UMapToCanonical<'i, I> { &mut self, universe0: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let ui = self .universes .map_universe_to_canonical(universe0.ui) .expect("Expected UCollector to encounter this universe"); - Ok(PlaceholderIndex { + PlaceholderIndex { ui, idx: universe0.idx, } - .to_ty(self.interner())) + .to_ty(TypeFolder::interner(self)) } fn fold_free_placeholder_lifetime( &mut self, universe0: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let universe = self .universes .map_universe_to_canonical(universe0.ui) .expect("Expected UCollector to encounter this universe"); - Ok(PlaceholderIndex { + PlaceholderIndex { ui: universe, idx: universe0.idx, } - .to_lifetime(self.interner())) + .to_lifetime(TypeFolder::interner(self)) } fn fold_free_placeholder_const( @@ -271,17 +271,17 @@ impl<'i, I: Interner> TypeFolder for UMapToCanonical<'i, I> { ty: Ty, universe0: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Const { let universe = self .universes .map_universe_to_canonical(universe0.ui) .expect("Expected UCollector to encounter this universe"); - Ok(PlaceholderIndex { + PlaceholderIndex { ui: universe, idx: universe0.idx, } - .to_const(self.interner(), ty)) + .to_const(TypeFolder::interner(self), ty) } fn interner(&self) -> I { @@ -289,15 +289,14 @@ impl<'i, I: Interner> TypeFolder for UMapToCanonical<'i, I> { } } -struct UMapFromCanonical<'q, I> { +#[derive(FallibleTypeFolder)] +struct UMapFromCanonical<'q, I: Interner> { interner: I, universes: &'q UniverseMap, } impl<'i, I: Interner> TypeFolder for UMapFromCanonical<'i, I> { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -305,26 +304,26 @@ impl<'i, I: Interner> TypeFolder for UMapFromCanonical<'i, I> { &mut self, universe0: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Ty { let ui = self.universes.map_universe_from_canonical(universe0.ui); - Ok(PlaceholderIndex { + PlaceholderIndex { ui, idx: universe0.idx, } - .to_ty(self.interner())) + .to_ty(TypeFolder::interner(self)) } fn fold_free_placeholder_lifetime( &mut self, universe0: PlaceholderIndex, _outer_binder: DebruijnIndex, - ) -> Fallible> { + ) -> Lifetime { let universe = self.universes.map_universe_from_canonical(universe0.ui); - Ok(PlaceholderIndex { + PlaceholderIndex { ui: universe, idx: universe0.idx, } - .to_lifetime(self.interner())) + .to_lifetime(TypeFolder::interner(self)) } fn forbid_inference_vars(&self) -> bool { diff --git a/chalk-solve/src/infer/unify.rs b/chalk-solve/src/infer/unify.rs index 469fdd27f94..3c9d617537f 100644 --- a/chalk-solve/src/infer/unify.rs +++ b/chalk-solve/src/infer/unify.rs @@ -2,7 +2,7 @@ use super::var::*; use super::*; use crate::debug_span; use chalk_ir::cast::Cast; -use chalk_ir::fold::{TypeFoldable, TypeFolder}; +use chalk_ir::fold::{FallibleTypeFolder, TypeFoldable}; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::zip::{Zip, Zipper}; use chalk_ir::UnificationDatabase; @@ -876,7 +876,7 @@ impl<'t, I: Interner> Unifier<'t, I> { debug!("trying fold_with on {:?}", ty); let ty1 = ty .clone() - .fold_with( + .try_fold_with( &mut OccursCheck::new(self, var, universe_index), DebruijnIndex::INNERMOST, ) @@ -1133,7 +1133,7 @@ impl<'t, I: Interner> Unifier<'t, I> { // as the variable is unified. let universe_index = self.table.universe_of_unbound_var(var); - let c1 = c.clone().fold_with( + let c1 = c.clone().try_fold_with( &mut OccursCheck::new(self, var, universe_index), DebruijnIndex::INNERMOST, )?; @@ -1246,14 +1246,14 @@ impl<'u, 't, I: Interner> OccursCheck<'u, 't, I> { } } -impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { +impl<'i, I: Interner> FallibleTypeFolder for OccursCheck<'_, 'i, I> { type Error = NoSolution; - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { self } - fn fold_free_placeholder_ty( + fn try_fold_free_placeholder_ty( &mut self, universe: PlaceholderIndex, _outer_binder: DebruijnIndex, @@ -1270,7 +1270,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { } } - fn fold_free_placeholder_const( + fn try_fold_free_placeholder_const( &mut self, ty: Ty, universe: PlaceholderIndex, @@ -1285,7 +1285,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { } #[instrument(level = "debug", skip(self))] - fn fold_free_placeholder_lifetime( + fn try_fold_free_placeholder_lifetime( &mut self, ui: PlaceholderIndex, _outer_binder: DebruijnIndex, @@ -1319,7 +1319,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { } } - fn fold_inference_ty( + fn try_fold_inference_ty( &mut self, var: InferenceVar, kind: TyVariableKind, @@ -1333,7 +1333,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { let normalized_ty = normalized_ty.assert_ty_ref(interner); let normalized_ty = normalized_ty .clone() - .fold_with(self, DebruijnIndex::INNERMOST)?; + .try_fold_with(self, DebruijnIndex::INNERMOST)?; assert!(!normalized_ty.needs_shift(interner)); Ok(normalized_ty) } @@ -1369,7 +1369,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { } } - fn fold_inference_const( + fn try_fold_inference_const( &mut self, ty: Ty, var: InferenceVar, @@ -1383,7 +1383,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { let normalized_const = normalized_const.assert_const_ref(interner); let normalized_const = normalized_const .clone() - .fold_with(self, DebruijnIndex::INNERMOST)?; + .try_fold_with(self, DebruijnIndex::INNERMOST)?; assert!(!normalized_const.needs_shift(interner)); Ok(normalized_const) } @@ -1415,7 +1415,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { } } - fn fold_inference_lifetime( + fn try_fold_inference_lifetime( &mut self, var: InferenceVar, outer_binder: DebruijnIndex, @@ -1444,7 +1444,7 @@ impl<'i, I: Interner> TypeFolder for OccursCheck<'_, 'i, I> { InferenceValue::Bound(l) => { let l = l.assert_lifetime_ref(interner); - let l = l.clone().fold_with(self, outer_binder)?; + let l = l.clone().try_fold_with(self, outer_binder)?; assert!(!l.needs_shift(interner)); Ok(l) }