From 9bce5394b92d100657543d0a5cf4eb5b815c5f5b Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:46:41 -0400 Subject: [PATCH 01/11] Add `FnDef` and `FnDefId` to chalk-ir --- chalk-ir/src/cast.rs | 9 +++++++++ chalk-ir/src/debug.rs | 7 +++++++ chalk-ir/src/fold/boring_impls.rs | 1 + chalk-ir/src/interner.rs | 9 +++++++++ chalk-ir/src/lib.rs | 6 ++++++ chalk-ir/src/visit/boring_impls.rs | 5 +++-- 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/chalk-ir/src/cast.rs b/chalk-ir/src/cast.rs index 390b120aa58..cb2a614c8d0 100644 --- a/chalk-ir/src/cast.rs +++ b/chalk-ir/src/cast.rs @@ -303,6 +303,15 @@ where } } +impl CastTo> for FnDefId +where + I: Interner, +{ + fn cast_to(self, _interner: &I) -> TypeName { + TypeName::FnDef(self) + } +} + impl CastTo for &T where T: Clone + HasInterner, diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index a3f97a23f6c..73afd7ceafb 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -21,6 +21,12 @@ impl Debug for AssocTypeId { } } +impl Debug for FnDefId { + fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result { + I::debug_fn_def_id(*self, fmt).unwrap_or_else(|| write!(fmt, "FnDefId({:?})", self.0)) + } +} + impl Debug for Ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) @@ -146,6 +152,7 @@ impl Debug for TypeName { TypeName::Tuple(arity) => write!(fmt, "{:?}", arity), TypeName::OpaqueType(opaque_ty) => write!(fmt, "!{:?}", opaque_ty), TypeName::Slice => write!(fmt, "{{slice}}"), + TypeName::FnDef(fn_def) => write!(fmt, "{:?}", fn_def), TypeName::Raw(mutability) => write!(fmt, "{:?}", mutability), TypeName::Ref(mutability) => write!(fmt, "{:?}", mutability), TypeName::Error => write!(fmt, "{{error}}"), diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs index bc001ac1f9b..40778e755e5 100644 --- a/chalk-ir/src/fold/boring_impls.rs +++ b/chalk-ir/src/fold/boring_impls.rs @@ -281,6 +281,7 @@ id_fold!(AdtId, transfer_adt_id); id_fold!(TraitId); id_fold!(AssocTypeId); id_fold!(OpaqueTyId); +id_fold!(FnDefId); impl> SuperFold for ProgramClauseData { fn super_fold_with<'i>( diff --git a/chalk-ir/src/interner.rs b/chalk-ir/src/interner.rs index 8dfe3c049b7..de114a8aac6 100644 --- a/chalk-ir/src/interner.rs +++ b/chalk-ir/src/interner.rs @@ -4,6 +4,7 @@ use crate::ApplicationTy; use crate::AssocTypeId; use crate::CanonicalVarKind; use crate::CanonicalVarKinds; +use crate::FnDefId; use crate::GenericArg; use crate::GenericArgData; use crate::Goal; @@ -206,6 +207,14 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + #[allow(unused_variables)] + fn debug_fn_def_id( + fn_def_id: FnDefId, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Prints the debug representation of an alias. To get good /// results, this requires inspecting TLS, and is difficult to /// code without reference to a specific interner (and hence diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index ae51665bb99..3b805630d30 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -169,6 +169,9 @@ pub enum TypeName { /// a placeholder for opaque types like `impl Trait` OpaqueType(OpaqueTyId), + /// a function definition + FnDef(FnDefId), + /// the string primitive type Str, @@ -237,6 +240,9 @@ pub struct AssocTypeId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OpaqueTyId(pub I::DefId); +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct FnDefId(pub I::DefId); + impl_debugs!(ImplId, ClauseId); #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] diff --git a/chalk-ir/src/visit/boring_impls.rs b/chalk-ir/src/visit/boring_impls.rs index b5a6b12a428..6ede102f013 100644 --- a/chalk-ir/src/visit/boring_impls.rs +++ b/chalk-ir/src/visit/boring_impls.rs @@ -5,8 +5,8 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::{ - AdtId, AssocTypeId, ClausePriority, DebruijnIndex, FloatTy, GenericArg, Goals, ImplId, IntTy, - Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, ProgramClauseData, + AdtId, AssocTypeId, ClausePriority, DebruijnIndex, FloatTy, FnDefId, GenericArg, Goals, ImplId, + IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, ProgramClauseData, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Scalar, Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, }; @@ -236,6 +236,7 @@ id_visit!(AdtId); id_visit!(TraitId); id_visit!(OpaqueTyId); id_visit!(AssocTypeId); +id_visit!(FnDefId); impl SuperVisit for ProgramClause { fn super_visit_with<'i, R: VisitResult>( From 768e7a212acd135d35850eb54fe58e0b8827ba3f Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:53:54 -0400 Subject: [PATCH 02/11] Track `FnDef` information in databases --- chalk-integration/src/db.rs | 6 ++++++ chalk-integration/src/program.rs | 18 ++++++++++++++---- chalk-rust-ir/src/lib.rs | 23 ++++++++++++++++++++--- chalk-solve/src/lib.rs | 2 ++ 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/chalk-integration/src/db.rs b/chalk-integration/src/db.rs index a67a3d2e8a2..5d2d69110f0 100644 --- a/chalk-integration/src/db.rs +++ b/chalk-integration/src/db.rs @@ -10,6 +10,7 @@ use chalk_ir::AssocTypeId; use chalk_ir::Canonical; use chalk_ir::ConstrainedSubst; use chalk_ir::Environment; +use chalk_ir::FnDefId; use chalk_ir::GenericArg; use chalk_ir::Goal; use chalk_ir::ImplId; @@ -22,6 +23,7 @@ use chalk_rust_ir::AdtDatum; use chalk_rust_ir::AssociatedTyDatum; use chalk_rust_ir::AssociatedTyValue; use chalk_rust_ir::AssociatedTyValueId; +use chalk_rust_ir::FnDefDatum; use chalk_rust_ir::ImplDatum; use chalk_rust_ir::OpaqueTyDatum; use chalk_rust_ir::TraitDatum; @@ -114,6 +116,10 @@ impl RustIrDatabase for ChalkDatabase { self.program_ir().unwrap().adt_datum(id) } + fn fn_def_datum(&self, id: FnDefId) -> Arc> { + self.program_ir().unwrap().fn_def_datum(id) + } + fn impls_for_trait( &self, trait_id: TraitId, diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index 773d92de16d..f11b285312f 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -3,13 +3,13 @@ use crate::{tls, Identifier, TypeKind}; use chalk_ir::could_match::CouldMatch; use chalk_ir::debug::Angle; use chalk_ir::{ - debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, GenericArg, Goal, Goals, - ImplId, Lifetime, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication, + debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, FnDefId, GenericArg, + Goal, Goals, ImplId, Lifetime, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication, ProgramClauses, ProjectionTy, Substitution, TraitId, Ty, }; use chalk_rust_ir::{ - AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, ImplDatum, ImplType, - OpaqueTyDatum, TraitDatum, WellKnownTrait, + AdtDatum, AssociatedTyDatum, AssociatedTyValue, AssociatedTyValueId, FnDefDatum, ImplDatum, + ImplType, OpaqueTyDatum, TraitDatum, WellKnownTrait, }; use chalk_solve::split::Split; use chalk_solve::RustIrDatabase; @@ -25,6 +25,10 @@ pub struct Program { /// For each ADT: pub adt_kinds: BTreeMap, TypeKind>, + pub fn_def_ids: BTreeMap>, + + pub fn_def_kinds: BTreeMap, TypeKind>, + /// From trait name to item-id. Used during lowering only. pub trait_ids: BTreeMap>, @@ -34,6 +38,8 @@ pub struct Program { /// For each ADT: pub adt_data: BTreeMap, Arc>>, + pub fn_def_data: BTreeMap, Arc>>, + /// For each impl: pub impl_data: BTreeMap, Arc>>, @@ -334,6 +340,10 @@ impl RustIrDatabase for Program { self.adt_data[&id].clone() } + fn fn_def_datum(&self, id: FnDefId) -> Arc> { + self.fn_def_data[&id].clone() + } + fn impls_for_trait( &self, trait_id: TraitId, diff --git a/chalk-rust-ir/src/lib.rs b/chalk-rust-ir/src/lib.rs index 85b4b0ec5a0..656e6df549f 100644 --- a/chalk-rust-ir/src/lib.rs +++ b/chalk-rust-ir/src/lib.rs @@ -9,9 +9,9 @@ use chalk_ir::cast::Cast; use chalk_ir::fold::shift::Shift; use chalk_ir::interner::{Interner, TargetInterner}; use chalk_ir::{ - AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, GenericArg, ImplId, OpaqueTyId, - ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, Ty, TyData, - TypeName, VariableKind, WhereClause, WithKind, + AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, + OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, + Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, }; use std::iter; @@ -103,6 +103,23 @@ pub struct AdtFlags { pub fundamental: bool, } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FnDefDatum { + pub id: FnDefId, + pub binders: Binders>, + pub flags: FnDefFlags, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +pub struct FnDefDatumBound { + pub argument_types: Vec>, + pub return_type: Ty, + pub where_clauses: Vec>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FnDefFlags {} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate representation (rust_ir) of a Trait Definition. For /// example, given the following rust code: diff --git a/chalk-solve/src/lib.rs b/chalk-solve/src/lib.rs index 6be11c40e75..9747e6da4e8 100644 --- a/chalk-solve/src/lib.rs +++ b/chalk-solve/src/lib.rs @@ -38,6 +38,8 @@ pub trait RustIrDatabase: Debug { /// Returns the datum for the impl with the given id. fn adt_datum(&self, adt_id: AdtId) -> Arc>; + fn fn_def_datum(&self, fn_def_id: FnDefId) -> Arc>; + /// Returns the datum for the impl with the given id. fn impl_datum(&self, impl_id: ImplId) -> Arc>; From 4e0f1e2b2da1aea6a5e5f629a59706865177a392 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:55:05 -0400 Subject: [PATCH 03/11] Implement program clause generation for `FnDef` --- chalk-solve/src/clauses.rs | 4 ++ chalk-solve/src/clauses/program_clauses.rs | 57 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 921fdfbebf3..35f08613092 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -412,6 +412,10 @@ fn match_type_name( TypeName::Slice => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), TypeName::Raw(_) => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), TypeName::Ref(_) => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), + TypeName::FnDef(fn_def_id) => builder + .db + .fn_def_datum(fn_def_id) + .to_program_clauses(builder), } } diff --git a/chalk-solve/src/clauses/program_clauses.rs b/chalk-solve/src/clauses/program_clauses.rs index ffe5355c7e2..6bd3c8cd4c5 100644 --- a/chalk-solve/src/clauses/program_clauses.rs +++ b/chalk-solve/src/clauses/program_clauses.rs @@ -337,6 +337,63 @@ impl ToProgramClauses for AdtDatum { } } +impl ToProgramClauses for FnDefDatum { + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + debug_heading!("FnDatum::to_program_clauses(self={:?})", self); + + let interner = builder.interner(); + let binders = self.binders.map_ref(|b| &b.where_clauses); + builder.push_binders(&binders, |builder, where_clauses| { + let self_appl_ty = &ApplicationTy { + name: self.id.cast(interner), + substitution: builder.substitution_in_scope(), + }; + let self_ty = self_appl_ty.clone().intern(interner); + + // forall { + // WF(foo) :- WF(T: Eq). + // } + builder.push_clause( + WellFormed::Ty(self_ty.clone()), + where_clauses + .iter() + .cloned() + .map(|qwc| qwc.into_well_formed_goal(interner)), + ); + + // forall { + // IsFullyVisible(foo) :- IsFullyVisible(T). + // } + builder.push_clause( + DomainGoal::IsFullyVisible(self_ty.clone()), + self_appl_ty + .type_parameters(interner) + .map(|ty| DomainGoal::IsFullyVisible(ty).cast::>(interner)), + ); + + for qwc in where_clauses { + // Generate implied bounds rules. We have to push the binders from the where-clauses + // too -- e.g., if we had `fn foo Bar<&'a i32>>()`, we would + // create a reverse rule like: + // + // ```notrust + // forall { FromEnv(T: Bar<&'a i32>) :- FromEnv(foo) } + // ``` + // + // In other words, you can assume `T: Bar<&'a i32>` + // for any `'a` *if* you are assuming that `foo` is + // well formed. + builder.push_binders(&qwc, |builder, wc| { + builder.push_clause( + wc.into_from_env_goal(interner), + Some(self_ty.clone().from_env()), + ); + }); + } + }); + } +} + impl ToProgramClauses for TraitDatum { /// Given the following trait declaration: `trait Ord where Self: Eq { ... }`, generate: /// From cc4d2578beb63953d03903775dc0922f9678f01a Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:56:08 -0400 Subject: [PATCH 04/11] Basic parsing of `FnDef`s --- chalk-parse/src/ast.rs | 14 ++++++++++++++ chalk-parse/src/parser.lalrpop | 27 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index 310d40b299b..c22ddf3aee6 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -21,6 +21,7 @@ pub struct Program { #[derive(Clone, PartialEq, Eq, Debug)] pub enum Item { StructDefn(StructDefn), + FnDefn(FnDefn), TraitDefn(TraitDefn), OpaqueTyDefn(OpaqueTyDefn), Impl(Impl), @@ -42,6 +43,19 @@ pub struct StructFlags { pub fundamental: bool, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FnDefn { + pub name: Identifier, + pub variable_kinds: Vec, + pub where_clauses: Vec, + pub argument_types: Vec, + pub return_type: Ty, + pub flags: FnDefFlags, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FnDefFlags {} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct TraitDefn { pub name: Identifier, diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index edcea0d0315..73da1d9479a 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -14,6 +14,7 @@ Items: Vec = { Item: Option = { Comment => None, StructDefn => Some(Item::StructDefn(<>)), + FnDefn => Some(Item::FnDefn(<>)), TraitDefn => Some(Item::TraitDefn(<>)), OpaqueTyDefn => Some(Item::OpaqueTyDefn(<>)), Impl => Some(Item::Impl(<>)), @@ -67,6 +68,32 @@ StructDefn: StructDefn = { } }; +FnReturn: Ty = { + "->" => ty, +}; + +FnDefn: FnDefn = { + "fn" >"(" ")" + ";" => FnDefn + { + name: n, + variable_kinds: p, + where_clauses: w, + argument_types: args, + return_type: ret_ty.unwrap_or_else(|| Ty::Tuple { types: Vec::new() }), + flags: FnDefFlags { + }, + } +}; + +FnArg: Ty = { + Id ":" => arg_ty +}; + +FnArgs: Vec = { + > +}; + TraitDefn: TraitDefn = { "trait" > "{" "}" => TraitDefn From 19d4430586ee3b8d212214fca8bb18037c19121f Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:56:34 -0400 Subject: [PATCH 05/11] Implement lowering for `FnDef` --- chalk-integration/src/lib.rs | 1 + chalk-integration/src/lowering.rs | 143 ++++++++++++++++++++++++++++-- 2 files changed, 135 insertions(+), 9 deletions(-) diff --git a/chalk-integration/src/lib.rs b/chalk-integration/src/lib.rs index df6a48a576d..702eff51f2b 100644 --- a/chalk-integration/src/lib.rs +++ b/chalk-integration/src/lib.rs @@ -22,6 +22,7 @@ pub use interner::{Identifier, RawId}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TypeSort { Struct, + FnDef, Trait, Opaque, } diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index c8c4513a5b3..18c4fdbc1c5 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -2,7 +2,7 @@ use crate::interner::ChalkIr; use chalk_ir::cast::{Cast, Caster}; use chalk_ir::interner::HasInterner; use chalk_ir::{ - self, AdtId, AssocTypeId, BoundVar, ClausePriority, DebruijnIndex, ImplId, OpaqueTyId, + self, AdtId, AssocTypeId, BoundVar, ClausePriority, DebruijnIndex, FnDefId, ImplId, OpaqueTyId, QuantifiedWhereClauses, Substitution, ToGenericArg, TraitId, }; use chalk_parse::ast::*; @@ -19,9 +19,11 @@ use crate::program::Program as LoweredProgram; use crate::{Identifier as Ident, RawId, TypeKind, TypeSort}; type AdtIds = BTreeMap>; +type FnDefIds = BTreeMap>; type TraitIds = BTreeMap>; type OpaqueTyIds = BTreeMap>; type AdtKinds = BTreeMap, TypeKind>; +type FnDefKinds = BTreeMap, TypeKind>; type TraitKinds = BTreeMap, TypeKind>; type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId, Ident), AssociatedTyLookup>; type AssociatedTyValueIds = @@ -36,6 +38,8 @@ pub type LowerResult = Result; struct Env<'k> { adt_ids: &'k AdtIds, adt_kinds: &'k AdtKinds, + fn_def_ids: &'k FnDefIds, + fn_def_kinds: &'k FnDefKinds, trait_ids: &'k TraitIds, trait_kinds: &'k TraitKinds, opaque_ty_ids: &'k OpaqueTyIds, @@ -73,6 +77,7 @@ struct AssociatedTyLookup { enum TypeLookup { Adt(chalk_ir::AdtId), GenericArg(BoundVar), + FnDef(chalk_ir::FnDefId), Opaque(chalk_ir::OpaqueTyId), } @@ -96,6 +101,10 @@ impl<'k> Env<'k> { return Ok(TypeLookup::Adt(*id)); } + if let Some(id) = self.fn_def_ids.get(&name.str) { + return Ok(TypeLookup::FnDef(*id)); + } + if let Some(id) = self.opaque_ty_ids.get(&name.str) { return Ok(TypeLookup::Opaque(*id)); } @@ -140,6 +149,10 @@ impl<'k> Env<'k> { &self.adt_kinds[&id] } + fn fn_def_kind(&self, id: chalk_ir::FnDefId) -> &TypeKind { + &self.fn_def_kinds[&id] + } + fn trait_kind(&self, id: chalk_ir::TraitId) -> &TypeKind { &self.trait_kinds[&id] } @@ -240,9 +253,11 @@ impl LowerProgram for Program { } let mut adt_ids = BTreeMap::new(); + let mut fn_def_ids = BTreeMap::new(); let mut trait_ids = BTreeMap::new(); let mut opaque_ty_ids = BTreeMap::new(); let mut adt_kinds = BTreeMap::new(); + let mut fn_def_kinds = BTreeMap::new(); let mut trait_kinds = BTreeMap::new(); let mut opaque_ty_kinds = BTreeMap::new(); let mut object_safe_traits = HashSet::new(); @@ -254,6 +269,12 @@ impl LowerProgram for Program { adt_ids.insert(type_kind.name.clone(), id); adt_kinds.insert(id, type_kind); } + Item::FnDefn(defn) => { + let type_kind = defn.lower_type_kind()?; + let id = FnDefId(raw_id); + fn_def_ids.insert(type_kind.name.clone(), id); + fn_def_kinds.insert(id, type_kind); + } Item::TraitDefn(defn) => { let type_kind = defn.lower_type_kind()?; let id = TraitId(raw_id); @@ -276,6 +297,7 @@ impl LowerProgram for Program { } let mut adt_data = BTreeMap::new(); + let mut fn_def_data = BTreeMap::new(); let mut trait_data = BTreeMap::new(); let mut well_known_traits = BTreeMap::new(); let mut impl_data = BTreeMap::new(); @@ -287,6 +309,8 @@ impl LowerProgram for Program { let empty_env = Env { adt_ids: &adt_ids, adt_kinds: &adt_kinds, + fn_def_ids: &fn_def_ids, + fn_def_kinds: &fn_def_kinds, trait_ids: &trait_ids, trait_kinds: &trait_kinds, opaque_ty_ids: &opaque_ty_ids, @@ -299,6 +323,13 @@ impl LowerProgram for Program { let adt_id = AdtId(raw_id); adt_data.insert(adt_id, Arc::new(d.lower_adt(adt_id, &empty_env)?)); } + Item::FnDefn(ref defn) => { + let fn_def_id = FnDefId(raw_id); + fn_def_data.insert( + fn_def_id, + Arc::new(defn.lower_fn_def(fn_def_id, &empty_env)?), + ); + } Item::TraitDefn(ref trait_defn) => { let trait_id = TraitId(raw_id); let trait_datum = trait_defn.lower_trait(trait_id, &empty_env)?; @@ -454,10 +485,13 @@ impl LowerProgram for Program { let program = LoweredProgram { adt_ids, + fn_def_ids, trait_ids, adt_kinds, + fn_def_kinds, trait_kinds, adt_data, + fn_def_data, trait_data, well_known_traits, impl_data, @@ -538,6 +572,16 @@ impl LowerParameterMap for StructDefn { } } +impl LowerParameterMap for FnDefn { + fn synthetic_parameters(&self) -> Option { + None + } + + fn declared_parameters(&self) -> &[VariableKind] { + &self.variable_kinds + } +} + impl LowerParameterMap for Impl { fn synthetic_parameters(&self) -> Option { None @@ -631,6 +675,26 @@ impl LowerTypeKind for StructDefn { } } +impl LowerTypeKind for FnDefn { + fn lower_type_kind(&self) -> LowerResult { + let interner = &ChalkIr; + Ok(TypeKind { + sort: TypeSort::FnDef, + name: self.name.str.clone(), + binders: chalk_ir::Binders::new( + chalk_ir::VariableKinds::from(interner, self.all_parameters().anonymize()), + crate::Unit, + ), + }) + } +} + +impl LowerWhereClauses for FnDefn { + fn where_clauses(&self) -> &[QuantifiedWhereClause] { + &self.where_clauses + } +} + impl LowerWhereClauses for StructDefn { fn where_clauses(&self) -> &[QuantifiedWhereClause] { &self.where_clauses @@ -850,6 +914,42 @@ impl LowerAdtDefn for StructDefn { } } +trait LowerFnDefn { + fn lower_fn_def( + &self, + fn_def_id: chalk_ir::FnDefId, + env: &Env, + ) -> LowerResult>; +} + +impl LowerFnDefn for FnDefn { + fn lower_fn_def( + &self, + fn_def_id: chalk_ir::FnDefId, + env: &Env, + ) -> LowerResult> { + let binders = env.in_binders(self.all_parameters(), |env| { + let args: LowerResult<_> = self.argument_types.iter().map(|t| t.lower(env)).collect(); + let where_clauses = self.lower_where_clauses(env)?; + let return_type = self.return_type.lower(env)?; + + Ok(rust_ir::FnDefDatumBound { + argument_types: args?, + where_clauses, + return_type, + }) + })?; + + let flags = rust_ir::FnDefFlags {}; + + Ok(rust_ir::FnDefDatum { + id: fn_def_id, + binders, + flags, + }) + } +} + trait LowerTraitRef { fn lower(&self, env: &Env) -> LowerResult>; } @@ -1121,6 +1221,22 @@ impl LowerTy for Ty { } } TypeLookup::GenericArg(d) => Ok(chalk_ir::TyData::BoundVar(d).intern(interner)), + TypeLookup::FnDef(id) => { + let k = env.fn_def_kind(id); + if k.binders.len(interner) > 0 { + Err(RustIrError::IncorrectNumberOfTypeParameters { + identifier: name.clone(), + expected: k.binders.len(interner), + actual: 0, + }) + } else { + Ok(chalk_ir::TyData::Function(chalk_ir::Fn { + num_binders: k.binders.len(interner), + substitution: chalk_ir::Substitution::empty(interner), + }) + .intern(interner)) + } + } TypeLookup::Opaque(id) => Ok(chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque( chalk_ir::OpaqueTy { opaque_ty_id: id, @@ -1157,14 +1273,14 @@ impl LowerTy for Ty { .intern(interner)), Ty::Apply { name, ref args } => { - let id = match env.lookup_type(name)? { - TypeLookup::Adt(id) => id, + let (id, k) = match env.lookup_type(name)? { + TypeLookup::Adt(id) => (id.0, env.adt_kind(id)), TypeLookup::GenericArg(_) | TypeLookup::Opaque(_) => { Err(RustIrError::CannotApplyTypeParameter(name.clone()))? } + TypeLookup::FnDef(id) => (id.0, env.fn_def_kind(id)), }; - let k = env.adt_kind(id); if k.binders.len(interner) != args.len() { Err(RustIrError::IncorrectNumberOfTypeParameters { identifier: name.clone(), @@ -1188,11 +1304,18 @@ impl LowerTy for Ty { } } - Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { - name: chalk_ir::TypeName::Adt(id), - substitution, - }) - .intern(interner)) + match k.sort { + TypeSort::FnDef => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { + name: chalk_ir::TypeName::FnDef(FnDefId(id)), + substitution, + }) + .intern(interner)), + _ => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { + name: chalk_ir::TypeName::Adt(AdtId(id)), + substitution, + }) + .intern(interner)), + } } Ty::Projection { ref proj } => Ok(chalk_ir::TyData::Alias( @@ -1485,9 +1608,11 @@ impl LowerGoal for Goal { let env = Env { adt_ids: &program.adt_ids, + fn_def_ids: &program.fn_def_ids, trait_ids: &program.trait_ids, opaque_ty_ids: &program.opaque_ty_ids, adt_kinds: &program.adt_kinds, + fn_def_kinds: &program.fn_def_kinds, trait_kinds: &program.trait_kinds, associated_ty_lookups: &associated_ty_lookups, parameter_map: BTreeMap::new(), From 126bfb61b9f82c9040d1b0aa672cad77a3b78502 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 10 May 2020 16:57:12 -0400 Subject: [PATCH 06/11] Add basic lowering and WF tests for `FnDef`s --- tests/lowering/mod.rs | 25 +++++++++++++++++++++++++ tests/test/functions.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/tests/lowering/mod.rs b/tests/lowering/mod.rs index 040ab7c1ddc..60f370ee8ed 100644 --- a/tests/lowering/mod.rs +++ b/tests/lowering/mod.rs @@ -559,3 +559,28 @@ fn slices() { } } } + +#[test] +fn fn_defs() { + lowering_success! { + program { + trait Quux { } + + fn foo<'a, T>(bar: T, baz: &'a mut T) -> u32 + where T: Quux; + } + } + + lowering_error! { + program { + trait Quux { } + + fn foo(bar: TT) -> T + where T: Quux; + } + + error_msg { + "invalid type name `TT`" + } + } +} diff --git a/tests/test/functions.rs b/tests/test/functions.rs index d58428aa500..e0844eca1b6 100644 --- a/tests/test/functions.rs +++ b/tests/test/functions.rs @@ -23,3 +23,42 @@ fn functions_are_sized() { } } } + +#[test] +fn fn_defs() { + test! { + program { + trait Foo { } + + struct Bar { } + + struct Xyzzy { } + impl Foo for Xyzzy { } + + fn baz(quux: T) -> T + where T: Foo; + + fn garply(thud: i32) -> i32; + } + + goal { + WellFormed(baz) + } yields { + "No possible solution" + } + + goal { + WellFormed(baz) + } yields { + "Unique" + } + + goal { + WellFormed(garply) + } yields { + "Unique" + } + + + } +} From 1918c3bb05b9dc21b8366c0fd5c25da650239bce Mon Sep 17 00:00:00 2001 From: nathanwhit Date: Tue, 12 May 2020 11:30:59 -0400 Subject: [PATCH 07/11] Add test for `FnDef` implied bounds --- tests/test/functions.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test/functions.rs b/tests/test/functions.rs index e0844eca1b6..3a6d6a83c50 100644 --- a/tests/test/functions.rs +++ b/tests/test/functions.rs @@ -59,6 +59,26 @@ fn fn_defs() { "Unique" } + } +} + +#[test] +fn fn_def_implied_bounds_from_env() { + test! { + program { + trait Foo { } + struct Bar { } + impl Foo for Bar { } + + fn baz() where T: Foo; + } + goal { + if (FromEnv(baz)) { + Bar: Foo + } + } yields { + "Unique" + } } } From 7856f3fb74dcb6284ac329a508b47b47212a19d1 Mon Sep 17 00:00:00 2001 From: nathanwhit Date: Tue, 12 May 2020 12:48:33 -0400 Subject: [PATCH 08/11] Refactor/clean up program clause generation Simplifies creation of `FnDefDatum` and `StructDatum` program clauses --- chalk-solve/src/clauses/program_clauses.rs | 210 ++++++++++++--------- 1 file changed, 120 insertions(+), 90 deletions(-) diff --git a/chalk-solve/src/clauses/program_clauses.rs b/chalk-solve/src/clauses/program_clauses.rs index 6bd3c8cd4c5..8049d446ff2 100644 --- a/chalk-solve/src/clauses/program_clauses.rs +++ b/chalk-solve/src/clauses/program_clauses.rs @@ -1,6 +1,6 @@ use crate::clauses::builder::ClauseBuilder; use crate::split::Split; -use chalk_ir::cast::{Cast, Caster}; +use chalk_ir::cast::{Cast, CastTo, Caster}; use chalk_ir::interner::Interner; use chalk_ir::*; use chalk_rust_ir::*; @@ -180,6 +180,95 @@ impl ToProgramClauses for OpaqueTyDatum { } } +fn application_ty( + builder: &mut ClauseBuilder<'_, I>, + id: impl CastTo>, +) -> ApplicationTy { + let interner = builder.interner(); + ApplicationTy { + name: id.cast(interner), + substitution: builder.substitution_in_scope(), + } +} + +fn interned_application_ty(interner: &I, appl_ty: &ApplicationTy) -> Ty { + appl_ty.clone().intern(interner) +} + +fn well_formed_program_clauses<'a, I, Wc>( + builder: &'a mut ClauseBuilder<'_, I>, + id: impl CastTo>, + where_clauses: Wc, +) where + I: Interner, + Wc: Iterator>, +{ + // Given a type definition `struct Foo { }` generate the clause + // forall { + // WF(Foo) :- WF(T: Eq). + // } + let interner = builder.interner(); + let appl_ty = application_ty(builder, id); + let ty = appl_ty.clone().intern(interner); + builder.push_clause( + WellFormed::Ty(ty.clone()), + where_clauses + .cloned() + .map(|qwc| qwc.into_well_formed_goal(interner)), + ); +} + +fn fully_visible_program_clauses<'a, I>( + builder: &'a mut ClauseBuilder<'_, I>, + id: impl CastTo>, +) where + I: Interner, +{ + // Given a type definition `struct Foo { }` generate the clause + // forall { + // IsFullyVisible(Foo) :- IsFullyVisible(T). + // } + let interner = builder.interner(); + let appl_ty = application_ty(builder, id); + let ty = interned_application_ty(interner, &appl_ty); + builder.push_clause( + DomainGoal::IsFullyVisible(ty.clone()), + appl_ty + .type_parameters(interner) + .map(|typ| DomainGoal::IsFullyVisible(typ).cast::>(interner)), + ); +} + +fn implied_bounds_program_clauses<'a, I, Wc>( + builder: &'a mut ClauseBuilder<'_, I>, + id: impl CastTo>, + where_clauses: Wc, +) where + I: Interner, + Wc: Iterator>, +{ + let interner = builder.interner(); + let appl_ty = application_ty(builder, id); + let ty = interned_application_ty(interner, &appl_ty); + + for qwc in where_clauses { + // Generate implied bounds rules. We have to push the binders from the where-clauses + // too -- e.g., if we had `struct Foo Bar<&'a i32>>`, we would + // create a reverse rule like: + // + // ```notrust + // forall { FromEnv(T: Bar<&'a i32>) :- FromEnv(Foo) } + // ``` + // + // In other words, you can assume `T: Bar<&'a i32>` + // for any `'a` *if* you are assuming that `Foo` is + // well formed. + builder.push_binders(&qwc, |builder, wc| { + builder.push_clause(wc.into_from_env_goal(interner), Some(ty.clone().from_env())); + }); + } +} + impl ToProgramClauses for AdtDatum { /// Given the following type definition: `struct Foo { }`, generate: /// @@ -234,33 +323,17 @@ impl ToProgramClauses for AdtDatum { let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); + let id = self.id; + builder.push_binders(&binders, |builder, where_clauses| { - let self_appl_ty = &ApplicationTy { - name: self.id.cast(interner), - substitution: builder.substitution_in_scope(), - }; - let self_ty = self_appl_ty.clone().intern(interner); + well_formed_program_clauses(builder, id, where_clauses.iter()); - // forall { - // WF(Foo) :- WF(T: Eq). - // } - builder.push_clause( - WellFormed::Ty(self_ty.clone()), - where_clauses - .iter() - .cloned() - .map(|qwc| qwc.into_well_formed_goal(interner)), - ); + implied_bounds_program_clauses(builder, id, where_clauses.iter()); - // forall { - // IsFullyVisible(Foo) :- IsFullyVisible(T). - // } - builder.push_clause( - DomainGoal::IsFullyVisible(self_ty.clone()), - self_appl_ty - .type_parameters(interner) - .map(|ty| DomainGoal::IsFullyVisible(ty).cast::>(interner)), - ); + fully_visible_program_clauses(builder, id); + + let self_appl_ty = application_ty(builder, id); + let self_ty = interned_application_ty(interner, &self_appl_ty); // Fundamental types often have rules in the form of: // Goal(FundamentalType) :- Goal(T) @@ -313,83 +386,40 @@ impl ToProgramClauses for AdtDatum { if self.flags.fundamental { fundamental_rule!(DownstreamType); } - - for qwc in where_clauses { - // Generate implied bounds rules. We have to push the binders from the where-clauses - // too -- e.g., if we had `struct Foo Bar<&'a i32>>`, we would - // create a reverse rule like: - // - // ```notrust - // forall { FromEnv(T: Bar<&'a i32>) :- FromEnv(Foo) } - // ``` - // - // In other words, you can assume `T: Bar<&'a i32>` - // for any `'a` *if* you are assuming that `Foo` is - // well formed. - builder.push_binders(&qwc, |builder, wc| { - builder.push_clause( - wc.into_from_env_goal(interner), - Some(self_ty.clone().from_env()), - ); - }); - } }); } } impl ToProgramClauses for FnDefDatum { + /// Given the following function definition: `fn bar() where T: Eq`, generate: + /// + /// ```notrust + /// -- Rule WellFormed-Type + /// forall { + /// WF(bar) :- WF(T: Eq) + /// } + /// + /// -- Rule Implied-Bound-From-Type + /// forall { + /// FromEnv(T: Eq) :- FromEnv(bar). + /// } + /// + /// forall { + /// IsFullyVisible(bar) :- IsFullyVisible(T). + /// } + /// ``` fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { debug_heading!("FnDatum::to_program_clauses(self={:?})", self); - let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); - builder.push_binders(&binders, |builder, where_clauses| { - let self_appl_ty = &ApplicationTy { - name: self.id.cast(interner), - substitution: builder.substitution_in_scope(), - }; - let self_ty = self_appl_ty.clone().intern(interner); + let id = self.id; - // forall { - // WF(foo) :- WF(T: Eq). - // } - builder.push_clause( - WellFormed::Ty(self_ty.clone()), - where_clauses - .iter() - .cloned() - .map(|qwc| qwc.into_well_formed_goal(interner)), - ); + builder.push_binders(&binders, |builder, where_clauses| { + well_formed_program_clauses(builder, id, where_clauses.iter()); - // forall { - // IsFullyVisible(foo) :- IsFullyVisible(T). - // } - builder.push_clause( - DomainGoal::IsFullyVisible(self_ty.clone()), - self_appl_ty - .type_parameters(interner) - .map(|ty| DomainGoal::IsFullyVisible(ty).cast::>(interner)), - ); + implied_bounds_program_clauses(builder, id, where_clauses.iter()); - for qwc in where_clauses { - // Generate implied bounds rules. We have to push the binders from the where-clauses - // too -- e.g., if we had `fn foo Bar<&'a i32>>()`, we would - // create a reverse rule like: - // - // ```notrust - // forall { FromEnv(T: Bar<&'a i32>) :- FromEnv(foo) } - // ``` - // - // In other words, you can assume `T: Bar<&'a i32>` - // for any `'a` *if* you are assuming that `foo` is - // well formed. - builder.push_binders(&qwc, |builder, wc| { - builder.push_clause( - wc.into_from_env_goal(interner), - Some(self_ty.clone().from_env()), - ); - }); - } + fully_visible_program_clauses(builder, id); }); } } From d267a40ec2433ff9c7f396951d7ff186de67ca89 Mon Sep 17 00:00:00 2001 From: nathanwhit Date: Thu, 14 May 2020 12:59:16 -0400 Subject: [PATCH 09/11] Remove unused `FnDefFlag` structs --- chalk-integration/src/lowering.rs | 3 --- chalk-parse/src/ast.rs | 4 ---- chalk-parse/src/parser.lalrpop | 2 -- chalk-rust-ir/src/lib.rs | 4 ---- 4 files changed, 13 deletions(-) diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 18c4fdbc1c5..4b1bcc4932e 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -940,12 +940,9 @@ impl LowerFnDefn for FnDefn { }) })?; - let flags = rust_ir::FnDefFlags {}; - Ok(rust_ir::FnDefDatum { id: fn_def_id, binders, - flags, }) } } diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index c22ddf3aee6..c72c6cbfe1d 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -50,12 +50,8 @@ pub struct FnDefn { pub where_clauses: Vec, pub argument_types: Vec, pub return_type: Ty, - pub flags: FnDefFlags, } -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FnDefFlags {} - #[derive(Clone, PartialEq, Eq, Debug)] pub struct TraitDefn { pub name: Identifier, diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index 73da1d9479a..371450bdc11 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -81,8 +81,6 @@ FnDefn: FnDefn = { where_clauses: w, argument_types: args, return_type: ret_ty.unwrap_or_else(|| Ty::Tuple { types: Vec::new() }), - flags: FnDefFlags { - }, } }; diff --git a/chalk-rust-ir/src/lib.rs b/chalk-rust-ir/src/lib.rs index 656e6df549f..0e465165d51 100644 --- a/chalk-rust-ir/src/lib.rs +++ b/chalk-rust-ir/src/lib.rs @@ -107,7 +107,6 @@ pub struct AdtFlags { pub struct FnDefDatum { pub id: FnDefId, pub binders: Binders>, - pub flags: FnDefFlags, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] @@ -117,9 +116,6 @@ pub struct FnDefDatumBound { pub where_clauses: Vec>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct FnDefFlags {} - #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate representation (rust_ir) of a Trait Definition. For /// example, given the following rust code: From 89e5a9688b1fb614fc2b5133eb2a4deed10a2ab2 Mon Sep 17 00:00:00 2001 From: nathanwhit Date: Thu, 14 May 2020 13:00:33 -0400 Subject: [PATCH 10/11] Clean up and document program clause generation --- chalk-solve/src/clauses/program_clauses.rs | 102 ++++++++++++++------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/chalk-solve/src/clauses/program_clauses.rs b/chalk-solve/src/clauses/program_clauses.rs index 8049d446ff2..e7349654729 100644 --- a/chalk-solve/src/clauses/program_clauses.rs +++ b/chalk-solve/src/clauses/program_clauses.rs @@ -182,33 +182,44 @@ impl ToProgramClauses for OpaqueTyDatum { fn application_ty( builder: &mut ClauseBuilder<'_, I>, - id: impl CastTo>, + type_name: impl CastTo>, ) -> ApplicationTy { let interner = builder.interner(); ApplicationTy { - name: id.cast(interner), + name: type_name.cast(interner), substitution: builder.substitution_in_scope(), } } -fn interned_application_ty(interner: &I, appl_ty: &ApplicationTy) -> Ty { - appl_ty.clone().intern(interner) -} - +/// Generates the "well-formed" program clauses for an applicative type +/// with the name `type_name`. For example, given a struct definition: +/// +/// ```ignore +/// struct Foo { } +/// ``` +/// +/// we would generate the clause: +/// +/// ```notrust +/// forall { +/// WF(Foo) :- WF(T: Eq). +/// } +/// ``` +/// +/// # Parameters +/// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope +/// - type_name -- in our example above, the name `Foo` +/// - where_clauses -- the list of where clauses declared on the type (`T: Eq`, in our example) fn well_formed_program_clauses<'a, I, Wc>( builder: &'a mut ClauseBuilder<'_, I>, - id: impl CastTo>, + type_name: impl CastTo>, where_clauses: Wc, ) where I: Interner, Wc: Iterator>, { - // Given a type definition `struct Foo { }` generate the clause - // forall { - // WF(Foo) :- WF(T: Eq). - // } let interner = builder.interner(); - let appl_ty = application_ty(builder, id); + let appl_ty = application_ty(builder, type_name); let ty = appl_ty.clone().intern(interner); builder.push_clause( WellFormed::Ty(ty.clone()), @@ -218,19 +229,34 @@ fn well_formed_program_clauses<'a, I, Wc>( ); } +/// Generates the "fully visible" program clauses for an applicative type +/// with the name `type_name`. For example, given a struct definition: +/// +/// ```ignore +/// struct Foo { } +/// ``` +/// +/// we would generate the clause: +/// +/// ```notrust +/// forall { +/// IsFullyVisible(Foo) :- IsFullyVisible(T). +/// } +/// ``` +/// +/// # Parameters +/// +/// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope +/// - type_name -- in our example above, the name `Foo` fn fully_visible_program_clauses<'a, I>( builder: &'a mut ClauseBuilder<'_, I>, - id: impl CastTo>, + type_name: impl CastTo>, ) where I: Interner, { - // Given a type definition `struct Foo { }` generate the clause - // forall { - // IsFullyVisible(Foo) :- IsFullyVisible(T). - // } let interner = builder.interner(); - let appl_ty = application_ty(builder, id); - let ty = interned_application_ty(interner, &appl_ty); + let appl_ty = application_ty(builder, type_name); + let ty = appl_ty.clone().intern(interner); builder.push_clause( DomainGoal::IsFullyVisible(ty.clone()), appl_ty @@ -239,30 +265,38 @@ fn fully_visible_program_clauses<'a, I>( ); } +/// Generates the "implied bounds" clauses for an applicative +/// type with the name `type_name`. For example, if `type_name` +/// represents a struct `S` that is declared like: +/// +/// ```ignore +/// struct S where T: Eq { } +/// ``` +/// +/// then we would generate the rule: +/// +/// ```notrust +/// FromEnv(T: Eq) :- FromEnv(S) +/// ``` +/// +/// # Parameters +/// +/// - builder -- the clause builder. We assume all the generic types from `S` are in scope. +/// - type_name -- in our example above, the name `S` +/// - where_clauses -- the list of where clauses declared on the type (`T: Eq`, in our example). fn implied_bounds_program_clauses<'a, I, Wc>( builder: &'a mut ClauseBuilder<'_, I>, - id: impl CastTo>, + type_name: impl CastTo>, where_clauses: Wc, ) where I: Interner, Wc: Iterator>, { let interner = builder.interner(); - let appl_ty = application_ty(builder, id); - let ty = interned_application_ty(interner, &appl_ty); + let appl_ty = application_ty(builder, type_name); + let ty = appl_ty.clone().intern(interner); for qwc in where_clauses { - // Generate implied bounds rules. We have to push the binders from the where-clauses - // too -- e.g., if we had `struct Foo Bar<&'a i32>>`, we would - // create a reverse rule like: - // - // ```notrust - // forall { FromEnv(T: Bar<&'a i32>) :- FromEnv(Foo) } - // ``` - // - // In other words, you can assume `T: Bar<&'a i32>` - // for any `'a` *if* you are assuming that `Foo` is - // well formed. builder.push_binders(&qwc, |builder, wc| { builder.push_clause(wc.into_from_env_goal(interner), Some(ty.clone().from_env())); }); @@ -333,7 +367,7 @@ impl ToProgramClauses for AdtDatum { fully_visible_program_clauses(builder, id); let self_appl_ty = application_ty(builder, id); - let self_ty = interned_application_ty(interner, &self_appl_ty); + let self_ty = self_appl_ty.clone().intern(interner); // Fundamental types often have rules in the form of: // Goal(FundamentalType) :- Goal(T) From 4b23e07a1040ec50c62c54c493bb7003c67d05b4 Mon Sep 17 00:00:00 2001 From: nathanwhit Date: Thu, 14 May 2020 13:02:14 -0400 Subject: [PATCH 11/11] Document chalk-rust-ir representation of `FnDef` --- chalk-rust-ir/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/chalk-rust-ir/src/lib.rs b/chalk-rust-ir/src/lib.rs index 0e465165d51..1d3b9b47f1f 100644 --- a/chalk-rust-ir/src/lib.rs +++ b/chalk-rust-ir/src/lib.rs @@ -104,15 +104,45 @@ pub struct AdtFlags { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] +/// A rust intermediate represention (rust_ir) of a function definition/declaration. +/// For example, in the following rust code: +/// +/// ```ignore +/// fn foo() -> i32 where T: Eq; +/// ``` +/// +/// This would represent the declaration of `foo`. +/// +/// Note this is distinct from a function pointer, which points to +/// a function with a given type signature, whereas this represents +/// a specific function definition. pub struct FnDefDatum { pub id: FnDefId, pub binders: Binders>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +/// Represents the bounds on a `FnDefDatum`, including +/// the function definition's type signature and where clauses. pub struct FnDefDatumBound { + /// Types of the function's arguments + /// ```ignore + /// fn foo(bar: i32, baz: T); + /// ^^^ ^ + /// ``` + /// pub argument_types: Vec>, + /// Return type of the function + /// ```ignore + /// fn foo() -> i32; + /// ^^^ + /// ``` pub return_type: Ty, + /// Where clauses defined on the function + /// ```ignore + /// fn foo() where T: Eq; + /// ^^^^^^^^^^^ + /// ``` pub where_clauses: Vec>, }