diff --git a/chalk-engine/src/slg.rs b/chalk-engine/src/slg.rs index f3522e77765..25e1c8164f9 100644 --- a/chalk-engine/src/slg.rs +++ b/chalk-engine/src/slg.rs @@ -293,6 +293,8 @@ impl MayInvalidate { // Only variants left are placeholder = concrete, which always fails (ConstValue::Placeholder(_), _) | (ConstValue::Concrete(_), _) => true, + + _ => todo!(), } } diff --git a/chalk-engine/src/slg/aggregate.rs b/chalk-engine/src/slg/aggregate.rs index c53d39c52d0..8fcde693122 100644 --- a/chalk-engine/src/slg/aggregate.rs +++ b/chalk-engine/src/slg/aggregate.rs @@ -551,6 +551,8 @@ impl AntiUnifier<'_, I> { (ConstValue::Placeholder(_), _) | (_, ConstValue::Placeholder(_)) => { self.new_const_variable(ty) } + + _ => todo!(), } } diff --git a/chalk-engine/src/slg/resolvent.rs b/chalk-engine/src/slg/resolvent.rs index 5661497d344..147162da132 100644 --- a/chalk-engine/src/slg/resolvent.rs +++ b/chalk-engine/src/slg/resolvent.rs @@ -687,6 +687,15 @@ impl<'i, I: Interner> Zipper for AnswerSubstitutor<'i, I> { Ok(()) } + (ConstValue::Function(name1, args1), ConstValue::Function(name2, args2)) => { + assert!(name1 == name2); + Ok(()) + } + + (ConstValue::Function(..), ConstValue::Concrete(_)) | (ConstValue::Concrete(_), ConstValue::Function(..)) => { + Ok(()) + } + (ConstValue::InferenceVar(_), _) | (_, ConstValue::InferenceVar(_)) => panic!( "unexpected inference var in answer `{:?}` or pending goal `{:?}`", answer, pending, @@ -694,10 +703,12 @@ impl<'i, I: Interner> Zipper for AnswerSubstitutor<'i, I> { (ConstValue::BoundVar(_), _) | (ConstValue::Placeholder(_), _) + | (ConstValue::Function(..), _) | (ConstValue::Concrete(_), _) => panic!( "structural mismatch between answer `{:?}` and pending goal `{:?}`", answer, pending, ), + } } diff --git a/chalk-integration/src/db.rs b/chalk-integration/src/db.rs index 765baeffa80..413a559d0b6 100644 --- a/chalk-integration/src/db.rs +++ b/chalk-integration/src/db.rs @@ -1,6 +1,6 @@ use crate::{ error::ChalkError, - interner::ChalkIr, + interner::{ChalkIr, ConstEval}, lowering::lower_goal, program::Program, query::{Lowering, LoweringDatabase}, @@ -26,13 +26,15 @@ use std::sync::Arc; #[derive(Default)] pub struct ChalkDatabase { storage: salsa::Storage, + interner: ChalkIr, } impl Database for ChalkDatabase {} impl ChalkDatabase { - pub fn with(program_text: &str, solver_choice: SolverChoice) -> Self { + pub fn with(program_text: &str, const_eval: ConstEval, solver_choice: SolverChoice) -> Self { let mut db = ChalkDatabase::default(); + db.interner.const_eval_fn = const_eval; db.set_program_text(Arc::new(program_text.to_string())); db.set_solver_choice(solver_choice); db @@ -174,7 +176,7 @@ impl RustIrDatabase for ChalkDatabase { } fn interner(&self) -> ChalkIr { - ChalkIr + self.interner } fn is_object_safe(&self, trait_id: TraitId) -> bool { diff --git a/chalk-integration/src/interner.rs b/chalk-integration/src/interner.rs index e99999c5c56..90888f53e44 100644 --- a/chalk-integration/src/interner.rs +++ b/chalk-integration/src/interner.rs @@ -50,10 +50,22 @@ impl Debug for ChalkFnAbi { } } +pub type ConstEval = fn(String, Vec) -> u32; + /// The default "interner" and the only interner used by chalk /// itself. In this interner, no interning actually occurs. #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct ChalkIr; +pub struct ChalkIr { + pub const_eval_fn: ConstEval, +} + +impl Default for ChalkIr { + fn default() -> Self { + ChalkIr { + const_eval_fn: |_, _| panic!("const eval is not supported on this interner"), + } + } +} impl Interner for ChalkIr { type InternedType = Arc>; @@ -265,6 +277,10 @@ impl Interner for ChalkIr { c1 == c2 } + fn const_eval(&self, name: String, args: Vec) -> u32 { + (self.const_eval_fn)(name, args) + } + fn intern_generic_arg(self, generic_arg: GenericArgData) -> GenericArgData { generic_arg } diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 965f2e63e6e..c87be67c061 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -108,7 +108,7 @@ lower_param_map!( ); fn get_type_of_usize() -> chalk_ir::Ty { - chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(ChalkIr) + chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(ChalkIr::default()) } impl Lower for VariableKind { @@ -818,6 +818,14 @@ impl LowerWithEnv for Const { fn lower(&self, env: &Env) -> LowerResult { let interner = env.interner(); match self { + Const::Function(f) => Ok(chalk_ir::ConstData { + ty: get_type_of_usize(), + value: chalk_ir::ConstValue::Function( + f.name.to_string(), + f.args.iter().map(|x| x.lower(env)).collect::, _>>()?, + ), + } + .intern(interner)), Const::Id(name) => { let parameter = env.lookup_generic_arg(name)?; parameter @@ -1013,7 +1021,7 @@ impl LowerWithEnv for (&TraitDefn, chalk_ir::TraitId) { } pub fn lower_goal(goal: &Goal, program: &LoweredProgram) -> LowerResult> { - let interner = ChalkIr; + let interner = ChalkIr::default(); let associated_ty_lookups: BTreeMap<_, _> = program .associated_ty_data .iter() @@ -1054,6 +1062,7 @@ pub fn lower_goal(goal: &Goal, program: &LoweredProgram) -> LowerResult { impl Kinded for chalk_ir::GenericArg { fn kind(&self) -> Kind { - let interner = ChalkIr; + let interner = ChalkIr::default(); match self.data(interner) { chalk_ir::GenericArgData::Ty(_) => Kind::Ty, chalk_ir::GenericArgData::Lifetime(_) => Kind::Lifetime, diff --git a/chalk-integration/src/lowering/env.rs b/chalk-integration/src/lowering/env.rs index 092baf17a64..493756e6a3a 100644 --- a/chalk-integration/src/lowering/env.rs +++ b/chalk-integration/src/lowering/env.rs @@ -54,6 +54,7 @@ pub struct Env<'k> { /// GenericArg identifiers are used as keys, therefore /// all identifiers in an environment must be unique (no shadowing). pub parameter_map: ParameterMap, + pub interner: ChalkIr, } /// Information about an associated type **declaration** (i.e., an @@ -88,7 +89,7 @@ pub enum TypeLookup<'k> { impl Env<'_> { pub fn interner(&self) -> ChalkIr { - ChalkIr + self.interner } pub fn lookup_generic_arg( diff --git a/chalk-integration/src/lowering/program_lowerer.rs b/chalk-integration/src/lowering/program_lowerer.rs index b8c88cff140..ed3054aef17 100644 --- a/chalk-integration/src/lowering/program_lowerer.rs +++ b/chalk-integration/src/lowering/program_lowerer.rs @@ -22,7 +22,6 @@ use crate::{interner::ChalkIr, TypeKind, TypeSort}; #[derive(Default)] pub(super) struct ProgramLowerer { next_item_index: u32, - associated_ty_lookups: AssociatedTyLookups, associated_ty_value_ids: AssociatedTyValueIds, adt_ids: AdtIds, @@ -178,6 +177,7 @@ impl ProgramLowerer { parameter_map: BTreeMap::new(), auto_traits: &self.auto_traits, foreign_ty_ids: &self.foreign_ty_ids, + interner: ChalkIr::default(), }; match *item { @@ -248,11 +248,11 @@ impl ProgramLowerer { let upvar_tys: LowerResult>> = defn.upvars.iter().map(|ty| ty.lower(&env)).collect(); let substitution = chalk_ir::Substitution::from_iter( - ChalkIr, - upvar_tys?.into_iter().map(|ty| ty.cast(ChalkIr)), + ChalkIr::default(), + upvar_tys?.into_iter().map(|ty| ty.cast(ChalkIr::default())), ); Ok(chalk_ir::TyKind::Tuple(defn.upvars.len(), substitution) - .intern(ChalkIr)) + .intern(ChalkIr::default())) })?; closure_upvars.insert(closure_def_id, upvars); } @@ -501,6 +501,7 @@ impl ProgramLowerer { custom_clauses, object_safe_traits: self.object_safe_traits, foreign_ty_ids: self.foreign_ty_ids, + interner: ChalkIr::default(), }) } } @@ -517,7 +518,7 @@ macro_rules! lower_type_kind { sort: TypeSort::$sort, name: self.name.str.clone(), binders: chalk_ir::Binders::new( - VariableKinds::from_iter(ChalkIr, $params(self).anonymize()), + VariableKinds::from_iter(ChalkIr::default(), $params(self).anonymize()), crate::Unit, ), }) diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index cc9d9e293e5..9082fbf0f36 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -105,6 +105,9 @@ pub struct Program { /// For each foreign type `extern { type A; }` pub foreign_ty_ids: BTreeMap>, + + /// interner of this program + pub interner: ChalkIr, } impl Program { @@ -528,7 +531,7 @@ impl RustIrDatabase for Program { } fn interner(&self) -> ChalkIr { - ChalkIr + self.interner } fn is_object_safe(&self, trait_id: TraitId) -> bool { diff --git a/chalk-integration/src/test_macros.rs b/chalk-integration/src/test_macros.rs index 96bfeb0d61e..650c0b13c87 100644 --- a/chalk-integration/src/test_macros.rs +++ b/chalk-integration/src/test_macros.rs @@ -9,18 +9,18 @@ macro_rules! ty { }), chalk_ir::Substitution::from_iter( - chalk_integration::interner::ChalkIr, + chalk_integration::interner::ChalkIr::default(), vec![$(arg!($arg)),*] as Vec> ), ) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (function $n:tt $($arg:tt)*) => { chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders: $n, substitution: chalk_ir::FnSubst(chalk_ir::Substitution::from_iter( - chalk_integration::interner::ChalkIr, + chalk_integration::interner::ChalkIr::default(), vec![$(arg!($arg)),*] as Vec> )), sig: chalk_ir::FnSig { @@ -28,39 +28,39 @@ macro_rules! ty { abi: ::FnAbi::Rust, variadic: false, } - }).intern(chalk_integration::interner::ChalkIr) + }).intern(chalk_integration::interner::ChalkIr::default()) }; (placeholder $n:expr) => { chalk_ir::TyKind::Placeholder(PlaceholderIndex { ui: UniverseIndex { counter: $n }, idx: 0, - }).intern(chalk_integration::interner::ChalkIr) + }).intern(chalk_integration::interner::ChalkIr::default()) }; (projection (item $n:tt) $($arg:tt)*) => { chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id: AssocTypeId(chalk_integration::interner::RawId { index: $n }), substitution: chalk_ir::Substitution::from_iter( - chalk_integration::interner::ChalkIr, + chalk_integration::interner::ChalkIr::default(), vec![$(arg!($arg)),*] as Vec> ), - }).intern(chalk_integration::interner::ChalkIr) + }).intern(chalk_integration::interner::ChalkIr::default()) }; (infer $b:expr) => { chalk_ir::TyKind::InferenceVar(chalk_ir::InferenceVar::from($b), chalk_ir::TyVariableKind::General) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (bound $d:tt $b:tt) => { chalk_ir::TyKind::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (bound $b:expr) => { chalk_ir::TyKind::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (expr $b:expr) => { @@ -76,14 +76,14 @@ macro_rules! ty { macro_rules! arg { ((lifetime $b:tt)) => { chalk_ir::GenericArg::new( - chalk_integration::interner::ChalkIr, + chalk_integration::interner::ChalkIr::default(), chalk_ir::GenericArgData::Lifetime(lifetime!($b)), ) }; ($arg:tt) => { chalk_ir::GenericArg::new( - chalk_integration::interner::ChalkIr, + chalk_integration::interner::ChalkIr::default(), chalk_ir::GenericArgData::Ty(ty!($arg)), ) }; @@ -93,22 +93,22 @@ macro_rules! arg { macro_rules! lifetime { (infer $b:expr) => { chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from($b)) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (bound $d:tt $b:tt) => { chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (bound $b:expr) => { chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (placeholder $b:expr) => { chalk_ir::LifetimeData::Placeholder(PlaceholderIndex { ui: UniverseIndex { counter: $b }, idx: 0}) - .intern(chalk_integration::interner::ChalkIr) + .intern(chalk_integration::interner::ChalkIr::default()) }; (expr $b:expr) => { @@ -123,6 +123,6 @@ macro_rules! lifetime { #[macro_export] macro_rules! empty_substitution { () => { - chalk_ir::Substitution::empty(chalk_integration::interner::ChalkIr) + chalk_ir::Substitution::empty(chalk_integration::interner::ChalkIr::default()) }; } diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index e4c5ab56a51..eaf7fbc669a 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -359,6 +359,7 @@ impl Debug for ConstData { ConstValue::InferenceVar(var) => write!(fmt, "{:?}", var), ConstValue::Placeholder(index) => write!(fmt, "{:?}", index), ConstValue::Concrete(evaluated) => write!(fmt, "{:?}", evaluated), + ConstValue::Function(name, _) => write!(fmt, "#{}()", name), } } } diff --git a/chalk-ir/src/fold.rs b/chalk-ir/src/fold.rs index 9b1eea3e7d7..4ae0a77e886 100644 --- a/chalk-ir/src/fold.rs +++ b/chalk-ir/src/fold.rs @@ -566,6 +566,16 @@ where }), } .intern(folder.interner())), + ConstValue::Function(name, args) => Ok(ConstData { + ty: fold_ty()?, + value: ConstValue::Function( + name.clone(), + args.into_iter() + .map(|x| x.clone().super_fold_with(folder, outer_binder)) + .collect::, _>>()?, + ), + } + .intern(folder.interner())), } } } diff --git a/chalk-ir/src/interner.rs b/chalk-ir/src/interner.rs index 7c80faf8cf1..556a94f6a7f 100644 --- a/chalk-ir/src/interner.rs +++ b/chalk-ir/src/interner.rs @@ -501,6 +501,9 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash + Sized { c2: &Self::InternedConcreteConst, ) -> bool; + /// Evaluate a function if all of its parameters are concerete constants + fn const_eval(&self, name: String, args: Vec) -> Self::InternedConcreteConst; + /// Create an "interned" parameter from `data`. This is not /// normally invoked directly; instead, you invoke /// `GenericArgData::intern` (which will ultimately call this diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 2dd073ffc82..0f6713b0b92 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -681,6 +681,22 @@ where { } +impl ConstData { + fn compute_flags(&self, interner: I) -> TypeFlags { + self.ty.data(interner).flags | match self.value { + ConstValue::BoundVar(_) | ConstValue::Concrete(_) => TypeFlags::empty(), + ConstValue::InferenceVar(_) => { + TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE + } + ConstValue::Placeholder(_) => { + TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE + } + // FIXME: we should iterate over each parameter + ConstValue::Function(..) => TypeFlags::empty(), + } + } +} + impl TyKind { /// Casts the type data to a type. pub fn intern(self, interner: I) -> Ty { @@ -710,16 +726,7 @@ impl TyKind { let flags = ty.data(interner).flags; let const_data = const_ty.data(interner); flags - | const_data.ty.data(interner).flags - | match const_data.value { - ConstValue::BoundVar(_) | ConstValue::Concrete(_) => TypeFlags::empty(), - ConstValue::InferenceVar(_) => { - TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE - } - ConstValue::Placeholder(_) => { - TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE - } - } + | const_data.compute_flags(interner) } TyKind::Placeholder(_) => TypeFlags::HAS_TY_PLACEHOLDER, TyKind::Dyn(dyn_ty) => { @@ -1181,6 +1188,7 @@ impl Const { ConstValue::InferenceVar(_) => false, ConstValue::Placeholder(_) => false, ConstValue::Concrete(_) => false, + ConstValue::Function(..) => false, } } } @@ -1205,10 +1213,11 @@ pub enum ConstValue { Placeholder(PlaceholderIndex), /// Concrete constant value. Concrete(ConcreteConst), + /// A mapping from Some other constants. Used for storing abstract const expressions + /// like `N+1` in `impl Trait for Foo` + Function(String, Vec>), } -impl Copy for ConstValue where I::InternedConcreteConst: Copy {} - impl ConstData { /// Wraps the constant data in a `Const`. pub fn intern(self, interner: I) -> Const { @@ -1503,19 +1512,7 @@ impl GenericArg { GenericArgData::Lifetime(lifetime) => lifetime.compute_flags(interner), GenericArgData::Const(constant) => { let data = constant.data(interner); - let flags = data.ty.data(interner).flags; - match data.value { - ConstValue::BoundVar(_) => flags, - ConstValue::InferenceVar(_) => { - flags | TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE - } - ConstValue::Placeholder(_) => { - flags - | TypeFlags::HAS_CT_PLACEHOLDER - | TypeFlags::STILL_FURTHER_SPECIALIZABLE - } - ConstValue::Concrete(_) => flags, - } + data.compute_flags(interner) } } } diff --git a/chalk-ir/src/visit.rs b/chalk-ir/src/visit.rs index 3096ad5a5a9..c7b7cdc259d 100644 --- a/chalk-ir/src/visit.rs +++ b/chalk-ir/src/visit.rs @@ -368,6 +368,12 @@ impl SuperVisit for Const { visitor.visit_free_placeholder(*universe, outer_binder) } ConstValue::Concrete(_) => ControlFlow::Continue(()), + ConstValue::Function(_, args) => { + for arg in args { + arg.super_visit_with(visitor, outer_binder)? + } + ControlFlow::Continue(()) + }, } } } diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index 0f0e9c54663..b88282d9fe9 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -206,9 +206,16 @@ pub enum GenericArg { Const(Const), } +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Function { + pub name: Identifier, + pub args: Vec, +} + #[derive(Clone, PartialEq, Eq, Debug)] pub enum Const { Id(Identifier), + Function(Function), Value(u32), } diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index 8f20258560e..29ad2f7945d 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -493,8 +493,13 @@ Lifetime: Lifetime = { ConstWithoutId: Const = { ConstValue => Const::Value(<>), + Function => Const::Function(<>), }; +Function: Function = { + "#" "(" > ")" => Function { name, args }, +} + Const : Const = { Id => Const::Id(<>), ConstWithoutId, diff --git a/chalk-solve/src/display/ty.rs b/chalk-solve/src/display/ty.rs index 8135536d1e2..ebc9705881e 100644 --- a/chalk-solve/src/display/ty.rs +++ b/chalk-solve/src/display/ty.rs @@ -262,6 +262,7 @@ impl RenderAsRust for ConstValue { ConstValue::InferenceVar(_) => write!(f, "_"), ConstValue::Placeholder(_) => write!(f, ""), ConstValue::Concrete(value) => write!(f, "{:?}", value.interned), + ConstValue::Function(..) => write!(f, ""), } } } diff --git a/chalk-solve/src/infer.rs b/chalk-solve/src/infer.rs index ffe5e6ab445..ac969e04ec0 100644 --- a/chalk-solve/src/infer.rs +++ b/chalk-solve/src/infer.rs @@ -29,6 +29,10 @@ pub struct InferenceSnapshot { #[allow(type_alias_bounds)] pub type ParameterEnaVariable = WithKind>; +fn get_type_of_usize(interner: I) -> chalk_ir::Ty { + chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(interner) +} + impl InferenceTable { /// Create an empty inference table with no variables. pub fn new() -> Self { @@ -142,6 +146,26 @@ impl InferenceTable { } pub fn normalize_const_shallow(&mut self, interner: I, leaf: &Const) -> Option> { + if let ConstValue::Function(name, args) = &leaf.data(interner).value { + let r = args.iter().map(|x| { + if let ConstValue::Concrete(x) = &interner.const_data(dbg!(x).interned()).value { + Some(x.interned.clone()) + } else { + None + } + }).collect::>>().map(|args| { + chalk_ir::ConstData { + ty: get_type_of_usize(interner), + value: chalk_ir::ConstValue::Concrete(ConcreteConst { + interned: interner.const_eval(name.clone(), args), + }), + } + .intern(interner) + }); + if r.is_some() { + return r; + } + } self.probe_var(leaf.inference_var(interner)?) .map(|p| p.assert_const_ref(interner).clone()) } diff --git a/chalk-solve/src/infer/unify.rs b/chalk-solve/src/infer/unify.rs index 19b98621d46..bb54e2bc149 100644 --- a/chalk-solve/src/infer/unify.rs +++ b/chalk-solve/src/infer/unify.rs @@ -1098,13 +1098,15 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying an inference variables with a non-inference variable. (&ConstValue::InferenceVar(var), &ConstValue::Concrete(_)) - | (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) => { + | (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) + | (&ConstValue::InferenceVar(var), &ConstValue::Function(..)) => { debug!(?var, ty=?b, "unify_var_ty"); self.unify_var_const(var, b) } (&ConstValue::Concrete(_), &ConstValue::InferenceVar(var)) - | (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) => { + | (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) + | (&ConstValue::Function(..), &ConstValue::InferenceVar(var)) => { debug!(?var, ty=?a, "unify_var_ty"); self.unify_var_const(var, a) } @@ -1121,8 +1123,18 @@ impl<'t, I: Interner> Unifier<'t, I> { } } - (&ConstValue::Concrete(_), &ConstValue::Placeholder(_)) - | (&ConstValue::Placeholder(_), &ConstValue::Concrete(_)) => Err(NoSolution), + (ConstValue::Function(name1, args1), ConstValue::Function(name2, args2)) => { + if name1 == name2 && args1.len() == args2.len() { + todo!() + } else { + Err(NoSolution) + } + } + + (&ConstValue::Concrete(_), &ConstValue::Placeholder(_) | &ConstValue::Function(..)) + | (&ConstValue::Placeholder(_) | &ConstValue::Function(..), &ConstValue::Concrete(_)) + | (&ConstValue::Placeholder(_), &ConstValue::Function(..)) + | (&ConstValue::Function(..), &ConstValue::Placeholder(_)) => Err(NoSolution), (ConstValue::BoundVar(_), _) | (_, ConstValue::BoundVar(_)) => panic!( "unification encountered bound variable: a={:?} b={:?}", diff --git a/src/main.rs b/src/main.rs index c1e85b4ac18..68ddc2c955a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,7 @@ impl LoadedProgram { /// /// [`SolverChoice`]: struct.solve.SolverChoice.html fn new(text: String, solver_choice: SolverChoice) -> Result { - let db = ChalkDatabase::with(&text, solver_choice); + let db = ChalkDatabase::with(&text, |_, _| panic!("unknown const eval"), solver_choice); Ok(LoadedProgram { text, db }) } @@ -70,7 +70,8 @@ impl LoadedProgram { let peeled_goal = goal.into_peeled_goal(self.db.interner()); if multiple_answers { if self.db.solve_multiple(&peeled_goal, &mut |v, has_next| { - println!("{}\n", v.as_ref().map(|v| v.display(ChalkIr))); + let interner = ChalkIr::default(); + println!("{}\n", v.as_ref().map(|v| v.display(interner))); if has_next { if let Some(ref mut rl) = rl { loop { @@ -97,7 +98,7 @@ impl LoadedProgram { } } else { match self.db.solve(&peeled_goal) { - Some(v) => println!("{}\n", v.display(ChalkIr)), + Some(v) => println!("{}\n", v.display(ChalkIr::default())), None => println!("No possible solution.\n"), } } diff --git a/tests/display/unique_names.rs b/tests/display/unique_names.rs index eb0131fde36..fa589eec6f0 100644 --- a/tests/display/unique_names.rs +++ b/tests/display/unique_names.rs @@ -218,7 +218,7 @@ pub fn write_program_duplicated_names(db: &Program) -> String { /// Only checks that the resulting program parses, not that it matches any /// particular format. Use returned data to perform further checks. pub fn run_reparse_with_duplicate_names<'a>(program_text: &'a str) -> ReparseTestResult<'a> { - let original_db = chalk_integration::db::ChalkDatabase::with(program_text, <_>::default()); + let original_db = chalk_integration::db::ChalkDatabase::with(program_text, |_, _| panic!(), <_>::default()); let original_program = original_db.program_ir().unwrap_or_else(|e| { panic!( "unable to lower test program:\n{}\nSource:\n{}\n", @@ -228,7 +228,7 @@ pub fn run_reparse_with_duplicate_names<'a>(program_text: &'a str) -> ReparseTes let output_text = tls::set_current_program(&original_program, || { write_program_duplicated_names(&*original_program) }); - let output_db = chalk_integration::db::ChalkDatabase::with(&output_text, <_>::default()); + let output_db = chalk_integration::db::ChalkDatabase::with(&output_text, |_, _| panic!(), <_>::default()); let output_program = output_db.program_ir().unwrap_or_else(|e| { panic!( "error lowering writer output:\n{}\nNew source:\n{}\n", diff --git a/tests/display/util.rs b/tests/display/util.rs index 5180d1363db..bacff1577d0 100644 --- a/tests/display/util.rs +++ b/tests/display/util.rs @@ -187,14 +187,14 @@ pub fn reparse_into_different_test<'a>( program_text: &'a str, target_text: &'a str, ) -> ReparseTestResult<'a> { - let original_db = chalk_integration::db::ChalkDatabase::with(program_text, <_>::default()); + let original_db = chalk_integration::db::ChalkDatabase::with(program_text, |_, _| panic!(), <_>::default()); let original_program = original_db.program_ir().unwrap_or_else(|e| { panic!( "unable to lower test program:\n{}\nSource:\n{}\n", e, program_text ) }); - let target_db = chalk_integration::db::ChalkDatabase::with(target_text, <_>::default()); + let target_db = chalk_integration::db::ChalkDatabase::with(target_text, |_, _| panic!(), <_>::default()); let target_program = target_db.program_ir().unwrap_or_else(|e| { panic!( "unable to lower test program:\n{}\nSource:\n{}\n", @@ -203,7 +203,7 @@ pub fn reparse_into_different_test<'a>( }); let output_text = tls::set_current_program(&original_program, || write_program(&original_program)); - let output_db = chalk_integration::db::ChalkDatabase::with(&output_text, <_>::default()); + let output_db = chalk_integration::db::ChalkDatabase::with(&output_text, |_, _| panic!(), <_>::default()); let output_program = output_db.program_ir().unwrap_or_else(|e| { panic!( "error lowering writer output:\n{}\nNew source:\n{}\n", diff --git a/tests/integration/panic.rs b/tests/integration/panic.rs index caee4c0523d..4b6d70ae927 100644 --- a/tests/integration/panic.rs +++ b/tests/integration/panic.rs @@ -27,6 +27,7 @@ impl Default for PanickingMethod { #[derive(Debug, Default)] struct MockDatabase { panicking_method: PanickingMethod, + interner: ChalkIr, } impl UnificationDatabase for MockDatabase { @@ -68,7 +69,7 @@ impl RustIrDatabase for MockDatabase { Arc::new(TraitDatum { id, binders: Binders::new( - VariableKinds::empty(ChalkIr), + VariableKinds::empty(ChalkIr::default()), TraitDatumBound { where_clauses: vec![], }, @@ -95,16 +96,16 @@ impl RustIrDatabase for MockDatabase { assert_eq!(id.0.index, 1); let substitution = Ty::new( - ChalkIr, - TyKind::Adt(AdtId(RawId { index: 1 }), Substitution::empty(ChalkIr)), + ChalkIr::default(), + TyKind::Adt(AdtId(RawId { index: 1 }), Substitution::empty(ChalkIr::default())), ); let binders = Binders::new( - VariableKinds::empty(ChalkIr), + VariableKinds::empty(ChalkIr::default()), ImplDatumBound { trait_ref: TraitRef { trait_id: TraitId(RawId { index: 0 }), - substitution: Substitution::from1(ChalkIr, substitution), + substitution: Substitution::from1(ChalkIr::default(), substitution), }, where_clauses: vec![], }, @@ -137,7 +138,7 @@ impl RustIrDatabase for MockDatabase { // Only needed because we always access the adt datum for logging Arc::new(AdtDatum { binders: Binders::empty( - ChalkIr, + ChalkIr::default(), AdtDatumBound { variants: vec![], where_clauses: vec![], @@ -207,15 +208,14 @@ impl RustIrDatabase for MockDatabase { panic!("program_clauses_for_env panic") } - ProgramClauses::empty(ChalkIr) + ProgramClauses::empty(ChalkIr::default()) } fn interner(&self) -> ChalkIr { if let PanickingMethod::Interner = self.panicking_method { panic!("interner panic") } - - ChalkIr + self.interner } fn is_object_safe(&self, trait_id: TraitId) -> bool { @@ -272,23 +272,23 @@ fn prepare_goal() -> UCanonical>> { // Foo: Bar UCanonical { canonical: Canonical { - binders: CanonicalVarKinds::empty(ChalkIr), + binders: CanonicalVarKinds::empty(ChalkIr::default()), value: InEnvironment { - environment: Environment::new(ChalkIr), + environment: Environment::new(ChalkIr::default()), goal: GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(TraitRef { trait_id: TraitId(interner::RawId { index: 0 }), substitution: Substitution::from1( - ChalkIr, + ChalkIr::default(), Ty::new( - ChalkIr, + ChalkIr::default(), TyKind::Adt( AdtId(interner::RawId { index: 1 }), - Substitution::empty(ChalkIr), + Substitution::empty(ChalkIr::default()), ), ), ), }))) - .intern(ChalkIr), + .intern(ChalkIr::default()), }, }, universes: 1, @@ -305,6 +305,7 @@ fn custom_clauses_panics() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::CustomClauses, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); @@ -326,6 +327,7 @@ fn trait_datum_panics() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::TraitDatum, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); @@ -347,6 +349,7 @@ fn impl_datum_panics() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::ImplDatum, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); @@ -368,6 +371,7 @@ fn impls_for_trait() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::ImplsForTrait, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); @@ -389,6 +393,7 @@ fn program_clauses_for_env() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::ProgramClausesForEnv, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); @@ -410,6 +415,7 @@ fn interner() { // solve goal but this will panic let mut db = MockDatabase { panicking_method: PanickingMethod::Interner, + interner: ChalkIr::default(), }; let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { solver.solve(&db, &peeled_goal); diff --git a/tests/logging_db/util.rs b/tests/logging_db/util.rs index 758ecb7649c..621e79da911 100644 --- a/tests/logging_db/util.rs +++ b/tests/logging_db/util.rs @@ -34,6 +34,7 @@ pub fn logging_db_output_sufficient( let output_text = { let db = ChalkDatabase::with( &program_text[1..program_text.len() - 1], + |_, _| panic!(), SolverChoice::default(), ); @@ -72,7 +73,7 @@ pub fn logging_db_output_sufficient( println!("----------------------------------------------------------------------"); println!("logging db output program:\n{}\n", output_text); - let db = ChalkDatabase::with(&output_text, SolverChoice::default()); + let db = ChalkDatabase::with(&output_text, |_, _| panic!(), SolverChoice::default()); // Note: we are explicitly not calling `.checked_program()`, as our output // is not intended to be well formed. diff --git a/tests/lowering/mod.rs b/tests/lowering/mod.rs index 0a74b297132..d5f4deb3eef 100644 --- a/tests/lowering/mod.rs +++ b/tests/lowering/mod.rs @@ -151,7 +151,7 @@ fn assoc_tys() { #[test] fn goal_quantifiers() { - let db = ChalkDatabase::with("trait Foo { }", SolverChoice::default()); + let db = ChalkDatabase::with("trait Foo { }", |_, _| panic!(), SolverChoice::default()); let goal = db .parse_and_lower_goal("forall {exists {forall {Z: Foo}}}") .unwrap(); @@ -179,7 +179,8 @@ fn atc_accounting() { struct Iter<'a, T> { } ", - SolverChoice::default(), + |_, _| panic!(), + SolverChoice::default(), ); db.with_program(|program| { let atv_text = format!( diff --git a/tests/test/constants.rs b/tests/test/constants.rs index 550446aee27..7d846b26c60 100644 --- a/tests/test/constants.rs +++ b/tests/test/constants.rs @@ -105,6 +105,45 @@ fn generic_impl() { } } + +#[test] +fn const_expr() { + test! { + const_eval { + |name, args| { + match name.as_str() { + "le128" => (args[0] < 128) as u32, + _ => panic!("Unknown function"), + } + } + } + + program { + struct S {} + + trait Trait {} + + struct Assert {} + trait IsTrue {} + impl IsTrue for Assert<1> {} + + impl Trait for S where Assert<#le128(N)>: IsTrue {} + } + + goal { + S<3>: Trait + } yields { + "Unique; substitution[], lifetime constraints []" + } + + goal { + S<240>: Trait + } yields { + "No possible solution" + } + } +} + #[test] fn placeholders_eq() { test! { diff --git a/tests/test/mod.rs b/tests/test/mod.rs index d483eaf5ad5..9665f384e17 100644 --- a/tests/test/mod.rs +++ b/tests/test/mod.rs @@ -3,6 +3,7 @@ use crate::test_util::assert_same; use chalk_integration::db::ChalkDatabase; use chalk_integration::interner::ChalkIr; +use chalk_integration::interner::ConstEval; use chalk_integration::lowering::lower_goal; use chalk_integration::query::LoweringDatabase; use chalk_integration::SolverChoice; @@ -28,7 +29,7 @@ pub fn assert_result(mut result: Option>, expected: &str, inte _ => {} } let result = match result { - Some(v) => format!("{}", v.display(ChalkIr)), + Some(v) => format!("{}", v.display(ChalkIr::default())), None => format!("No possible solution"), }; @@ -49,11 +50,17 @@ pub enum TestGoal { macro_rules! test { (program $program:tt $($goals:tt)*) => {{ let (program, goals) = parse_test_data!(program $program $($goals)*); - solve_goal(program, goals, true) + solve_goal(program, goals, |_, _| panic!("const eval not provided"), true) }}; + + (const_eval $const_eval:tt program $program:tt $($goals:tt)*) => {{ + let (program, goals) = parse_test_data!(program $program $($goals)*); + solve_goal(program, goals, $const_eval, true) + }}; + (disable_coherence; program $program:tt $($goals:tt)*) => {{ let (program, goals) = parse_test_data!(program $program $($goals)*); - solve_goal(program, goals, false) + solve_goal(program, goals, |_, _| panic!("const eval not provided"), false) }}; } @@ -219,7 +226,12 @@ macro_rules! parse_test_data { }; } -fn solve_goal(program_text: &str, goals: Vec<(&str, SolverChoice, TestGoal)>, coherence: bool) { +fn solve_goal( + program_text: &str, + goals: Vec<(&str, SolverChoice, TestGoal)>, + const_eval: ConstEval, + coherence: bool, +) { with_tracing_logs(|| { println!("program {}", program_text); assert!(program_text.starts_with("{")); @@ -227,6 +239,7 @@ fn solve_goal(program_text: &str, goals: Vec<(&str, SolverChoice, TestGoal)>, co let mut db = ChalkDatabase::with( &program_text[1..program_text.len() - 1], + const_eval, SolverChoice::default(), ); @@ -273,10 +286,11 @@ fn solve_goal(program_text: &str, goals: Vec<(&str, SolverChoice, TestGoal)>, co db.solve_multiple(&peeled_goal, &mut |result, next_result| { match expected.next() { Some(expected) => { + let interner = ChalkIr::default(); assert_same( &format!( "{}", - result.as_ref().map(|v| v.display(ChalkIr)) + result.as_ref().map(|v| v.display(interner)) ), expected, ); @@ -299,8 +313,9 @@ fn solve_goal(program_text: &str, goals: Vec<(&str, SolverChoice, TestGoal)>, co .next() { Some(solution) => { + let interner = ChalkIr::default(); assert_same( - &format!("{}", result.as_ref().map(|v| v.display(ChalkIr))), + &format!("{}", result.as_ref().map(|v| v.display(interner))), solution, ); if !next_result { diff --git a/tests/test/type_flags.rs b/tests/test/type_flags.rs index bf39a9a8b03..0ddc531ed4b 100644 --- a/tests/test/type_flags.rs +++ b/tests/test/type_flags.rs @@ -7,7 +7,7 @@ use chalk_ir::{PlaceholderIndex, TyKind, TypeFlags, UniverseIndex}; fn placeholder_ty_flags_correct() { let placeholder_ty = ty!(placeholder 0); assert_eq!( - placeholder_ty.data(ChalkIr).flags, + placeholder_ty.data(ChalkIr::default()).flags, TypeFlags::HAS_TY_PLACEHOLDER ); } @@ -19,24 +19,24 @@ fn opaque_ty_flags_correct() { 0: chalk_integration::interner::RawId { index: 0 }, }, substitution: chalk_ir::Substitution::from_iter( - ChalkIr, + ChalkIr::default(), Some( chalk_ir::ConstData { ty: TyKind::Placeholder(PlaceholderIndex { ui: chalk_ir::UniverseIndex::ROOT, idx: 0, }) - .intern(ChalkIr), + .intern(ChalkIr::default()), value: chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(0)), } - .intern(ChalkIr) - .cast(ChalkIr), + .intern(ChalkIr::default()) + .cast(ChalkIr::default()), ), ), })) - .intern(ChalkIr); + .intern(ChalkIr::default()); assert_eq!( - opaque_ty.data(ChalkIr).flags, + opaque_ty.data(ChalkIr::default()).flags, TypeFlags::HAS_TY_OPAQUE | TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE @@ -46,7 +46,7 @@ fn opaque_ty_flags_correct() { #[test] fn dyn_ty_flags_correct() { - let internal_ty = TyKind::Scalar(chalk_ir::Scalar::Bool).intern(ChalkIr); + let internal_ty = TyKind::Scalar(chalk_ir::Scalar::Bool).intern(ChalkIr::default()); let projection_ty = chalk_ir::ProjectionTy { associated_ty_id: chalk_ir::AssocTypeId { 0: chalk_integration::interner::RawId { index: 0 }, @@ -54,11 +54,11 @@ fn dyn_ty_flags_correct() { substitution: empty_substitution!(), }; let bounds = chalk_ir::Binders::>::empty( - ChalkIr, + ChalkIr::default(), chalk_ir::QuantifiedWhereClauses::from_iter( - ChalkIr, + ChalkIr::default(), vec![chalk_ir::Binders::>::empty( - ChalkIr, + ChalkIr::default(), chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { ty: internal_ty, alias: chalk_ir::AliasTy::Projection(projection_ty), @@ -70,9 +70,9 @@ fn dyn_ty_flags_correct() { lifetime: lifetime!(placeholder 5), bounds, }; - let ty = TyKind::Dyn(dyn_ty).intern(ChalkIr); + let ty = TyKind::Dyn(dyn_ty).intern(ChalkIr::default()); assert_eq!( - ty.data(ChalkIr).flags, + ty.data(ChalkIr::default()).flags, TypeFlags::HAS_TY_PROJECTION | TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_FREE_LOCAL_REGIONS @@ -82,8 +82,8 @@ fn dyn_ty_flags_correct() { #[test] fn flagless_ty_has_no_flags() { - let ty = TyKind::Str.intern(ChalkIr); - assert_eq!(ty.data(ChalkIr).flags, TypeFlags::empty()); + let ty = TyKind::Str.intern(ChalkIr::default()); + assert_eq!(ty.data(ChalkIr::default()).flags, TypeFlags::empty()); let fn_ty = TyKind::Function(chalk_ir::FnPointer { num_binders: 0, @@ -94,18 +94,18 @@ fn flagless_ty_has_no_flags() { variadic: false, }, }) - .intern(ChalkIr); - assert_eq!(fn_ty.data(ChalkIr).flags, TypeFlags::empty()); + .intern(ChalkIr::default()); + assert_eq!(fn_ty.data(ChalkIr::default()).flags, TypeFlags::empty()); } #[test] fn static_and_bound_lifetimes() { let substitutions = chalk_ir::Substitution::from_iter( - ChalkIr, + ChalkIr::default(), vec![ - chalk_ir::GenericArgData::Lifetime(chalk_ir::LifetimeData::Static.intern(ChalkIr)) - .intern(ChalkIr), - chalk_ir::GenericArgData::Lifetime(lifetime!(bound 5)).intern(ChalkIr), + chalk_ir::GenericArgData::Lifetime(chalk_ir::LifetimeData::Static.intern(ChalkIr::default())) + .intern(ChalkIr::default()), + chalk_ir::GenericArgData::Lifetime(lifetime!(bound 5)).intern(ChalkIr::default()), ], ); @@ -115,10 +115,10 @@ fn static_and_bound_lifetimes() { }, substitutions, ) - .intern(ChalkIr); + .intern(ChalkIr::default()); assert_eq!( - ty.data(ChalkIr).flags, + ty.data(ChalkIr::default()).flags, TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_LATE_BOUND ); } diff --git a/tests/test_util.rs b/tests/test_util.rs index ac8e21ca7a7..8fb6e387423 100644 --- a/tests/test_util.rs +++ b/tests/test_util.rs @@ -8,6 +8,7 @@ macro_rules! lowering_success { let result = chalk_solve::logging::with_tracing_logs(|| { chalk_integration::db::ChalkDatabase::with( &program_text[1..program_text.len() - 1], + |_, _| panic!("no const eval available"), chalk_integration::SolverChoice::default(), ) .checked_program() @@ -27,6 +28,7 @@ macro_rules! lowering_error { let error = chalk_solve::logging::with_tracing_logs(|| { chalk_integration::db::ChalkDatabase::with( &program_text[1..program_text.len() - 1], + |_, _| panic!("no const eval available"), chalk_integration::SolverChoice::default(), ) .checked_program()