From 33823781bf79be2d4f22f46712031026335ea7ed Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 12 Oct 2023 16:07:07 -0700 Subject: [PATCH 01/44] next: resolve in elems: Set --- crates/flux-tests/tests/lib/rmapk.rs | 1 - crates/flux-tests/tests/todo/rset.rs | 55 +++++++++++++--------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/crates/flux-tests/tests/lib/rmapk.rs b/crates/flux-tests/tests/lib/rmapk.rs index c82b0a3036..8bfee12967 100644 --- a/crates/flux-tests/tests/lib/rmapk.rs +++ b/crates/flux-tests/tests/lib/rmapk.rs @@ -7,7 +7,6 @@ fn set_is_empty(s: Set) -> bool { s == set_empty(0) } fn set_emp() -> Set { set_empty(0) } }] - /// define a type indexed by a map #[flux::opaque] #[flux::refined_by(keys: Set, vals: Map)] diff --git a/crates/flux-tests/tests/todo/rset.rs b/crates/flux-tests/tests/todo/rset.rs index 347ce08900..bbae7c325b 100644 --- a/crates/flux-tests/tests/todo/rset.rs +++ b/crates/flux-tests/tests/todo/rset.rs @@ -1,41 +1,38 @@ -#![allow(dead_code)] -#![flux::defs { - fn set_add(x: int, s: Set) -> Set { set_union(set_singleton(x), s) } -}] - +use std::hash::Hash; #[flux::opaque] #[flux::refined_by(elems: Set)] pub struct RSet { inner: std::collections::HashSet, } -impl RSet { - #[flux::trusted] - #[flux::sig(fn() -> RSet[set_empty(0)])] - pub fn new() -> Self { - Self { inner: std::collections::HashSet::new() } - } +#[flux::sig(fn (bool[true]))] +fn assert(_b: bool) {} - #[flux::trusted] - #[flux::sig(fn(self: &strg RSet[@s], elem: T) - ensures self: RSet[set_add(k, s.elems)])] - pub fn insert(&mut self, elem: T) { - self.inner.insert(elem); - } +pub fn empty() -> RSet { + RSet { inner: std::collections::HashSet::new() } +} - #[flux::trusted] - #[flux::sig(fn(&Set[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] - pub fn contains(&self, elem: &T) -> bool { - self.inner.contains(elem) - } +#[flux::trusted] +#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[ set_union(set_singleton(x), s) ])] +pub fn insert(set: &mut RSet, elem: T) +where + T: Eq + Hash, +{ + set.inner.insert(elem); } -#[flux::sig(fn (bool[true]))] -fn assert(_b: bool) {} +#[flux::trusted] +#[flux::sig(fn(set: &Set[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] +pub fn contains(set: &RSet, elem: &T) -> bool +where + T: Eq + Hash, +{ + set.inner.contains(elem) +} -fn test() { - let mut s = RSet::new(); - s.insert(1); - assert(s.contains(1)); - assert(!s.contains(2)); +pub fn test() { + let mut s = empty(); + insert(&mut s, 1); + assert(contains(&s, &1)); + assert(!contains(&s, &2)); } From 79e6d8203ff7016268f24aaedbe9e489042e4a46 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 12 Oct 2023 16:20:17 -0700 Subject: [PATCH 02/44] next: resolve in elems: Set --- crates/flux-desugar/src/desugar.rs | 5 +++-- crates/flux-desugar/src/lib.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 36bd741ca5..78f9553b5f 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1372,7 +1372,7 @@ fn resolve_app_sort( } fn resolve_base_sort_ident( - sess: &FluxSession, + _sess: &FluxSession, sort_decls: &fhir::SortDecls, ident: &surface::Ident, ) -> Result { @@ -1386,7 +1386,8 @@ fn resolve_base_sort_ident( let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; Ok(fhir::Sort::App(ctor, List::empty())) } else { - Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) + panic!("ICE: unknown sort: {:?}", ident.name); + // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) } } diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 864abf1ac6..28dae20be4 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -1,6 +1,6 @@ //! Desugaring from types in [`flux_syntax::surface`] to types in [`flux_middle::fhir`] //! -//! # NOTE +//! # [NOTE:Generics-and-Desugaring] //! //! Desugaring requires knowing the sort of each type so we can correctly resolve binders declared with //! @ syntax or arg syntax. In particular, to know the sort of a type parameter we need to know its @@ -56,7 +56,7 @@ pub fn desugar_struct_def( let (generics, predicates) = cx.as_lift_cx().lift_generics_with_predicates()?; genv.map().insert_generics(def_id, generics); - // Desugar of struct_def needs to happen AFTER inserting generics. See crate level comment + // Desugar of struct_def needs to happen AFTER inserting generics. See [NOTE:Generics-and-Desugaring] let struct_def = cx.desugar_struct_def(struct_def, &mut Binders::new())?; if config::dump_fhir() { dbg::dump_item_info(genv.tcx, owner_id, "fhir", &struct_def).unwrap(); From d6f64af42b43f3205b47d14f4c73e807bb95d616 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 06:45:53 -0700 Subject: [PATCH 03/44] got &Generics into resolve_sort --- crates/flux-desugar/src/desugar.rs | 44 +++++++++++++++++++++-------- crates/flux-driver/src/callbacks.rs | 5 +++- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 78f9553b5f..ba63b62827 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -17,6 +17,7 @@ use rustc_errors::{ErrorGuaranteed, IntoDiagnostic}; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::OwnerId; +use rustc_middle::ty::Generics; use rustc_span::{ def_id::LocalDefId, sym::{self}, @@ -52,7 +53,7 @@ pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result = defn .args .iter() - .map(|arg| resolve_sort(sess, sort_decls, &arg.sort)) + .map(|arg| resolve_sort(sess, sort_decls, None, &arg.sort)) .try_collect_exhaust()?; - let output = resolve_sort(sess, sort_decls, &defn.output)?; + let output = resolve_sort(sess, sort_decls, None, &defn.output)?; let sort = fhir::PolyFuncSort::new(0, inputs, output); let kind = if defn.body.is_some() { fhir::FuncKind::Def } else { fhir::FuncKind::Uif }; Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) @@ -80,6 +81,7 @@ pub fn desugar_refined_by( sess: &FluxSession, sort_decls: &fhir::SortDecls, owner_id: OwnerId, + generics: &rustc_middle::ty::Generics, refined_by: &surface::RefinedBy, ) -> Result { let mut set = FxHashSet::default(); @@ -93,13 +95,15 @@ pub fn desugar_refined_by( let early_bound_params: Vec<_> = refined_by .early_bound_params .iter() - .map(|param| resolve_sort(sess, sort_decls, ¶m.sort)) + .map(|param| resolve_sort(sess, sort_decls, Some(generics), ¶m.sort)) .try_collect_exhaust()?; let index_params: Vec<_> = refined_by .index_params .iter() - .map(|param| Ok((param.name.name, resolve_sort(sess, sort_decls, ¶m.sort)?))) + .map(|param| { + Ok((param.name.name, resolve_sort(sess, sort_decls, Some(generics), ¶m.sort)?)) + }) .try_collect_exhaust()?; Ok(fhir::RefinedBy::new(owner_id.def_id, early_bound_params, index_params, refined_by.span)) @@ -272,6 +276,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.push_layer(); binders.insert_params( self.genv, + Some(self.owner), struct_def .refined_by .iter() @@ -334,6 +339,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.push_layer(); binders.insert_params( self.genv, + Some(self.owner), enum_def .refined_by .iter() @@ -394,7 +400,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params(self.genv, ty_alias.refined_by.all_params())?; + binders.insert_params(self.genv, Some(self.owner), ty_alias.refined_by.all_params())?; let ty = self.desugar_ty(None, &ty_alias.ty, binders)?; @@ -580,6 +586,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { let span = ty.span; + let generics = self.genv.tcx.generics_of(self.owner.def_id); let kind = match &ty.kind { surface::TyKind::Base(bty) => { // CODESYNC(type-holes, 3) @@ -628,8 +635,12 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.push_layer(); for param in params { let fresh = binders.fresh(); - let sort = - resolve_sort(self.sess(), self.genv.map().sort_decls(), ¶m.sort)?; + let sort = resolve_sort( + self.sess(), + self.genv.map().sort_decls(), + Some(generics), + ¶m.sort, + )?; let binder = Binder::Refined(fresh, sort.clone(), false); binders.insert_binder(self.sess(), param.name, binder)?; } @@ -746,7 +757,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { } surface::RefineArg::Abs(params, body, span) => { binders.push_layer(); - binders.insert_params(self.genv, params)?; + binders.insert_params(self.genv, Some(self.owner), params)?; let body = self.as_expr_ctxt().desugar_expr(binders, body)?; let params = binders.pop_layer().into_params(self); Ok(fhir::RefineArg::Abs(params, body, *span, self.next_fhir_id())) @@ -1086,6 +1097,7 @@ impl DesugarCtxt<'_, '_> { } fn gather_input_params_fn_sig(&self, fn_sig: &surface::FnSig, binders: &mut Binders) -> Result { + let generics = self.genv.tcx.generics_of(self.owner.def_id); for param in fn_sig.generics.iter().flat_map(|g| &g.params) { let surface::GenericParamKind::Refine { sort } = ¶m.kind else { continue }; binders.insert_binder( @@ -1093,7 +1105,12 @@ impl DesugarCtxt<'_, '_> { param.name, Binder::Refined( binders.fresh(), - resolve_sort(self.genv.sess, self.genv.map().sort_decls(), sort)?, + resolve_sort( + self.genv.sess, + self.genv.map().sort_decls(), + Some(generics), + sort, + )?, false, ), )?; @@ -1305,6 +1322,7 @@ impl DesugarCtxt<'_, '_> { fn resolve_sort( sess: &FluxSession, sort_decls: &fhir::SortDecls, + _generics: Option<&Generics>, sort: &surface::Sort, ) -> Result { match sort { @@ -1402,22 +1420,24 @@ impl Binders { ) -> Result { let mut binders = Self::new(); binders.push_layer(); - binders.insert_params(genv, params)?; + binders.insert_params(genv, None, params)?; Ok(binders) } fn insert_params<'a>( &mut self, genv: &GlobalEnv, + owner: Option, params: impl IntoIterator, ) -> Result { + let generics = owner.map(|id| genv.tcx.generics_of(id)); for param in params { self.insert_binder( genv.sess, param.name, Binder::Refined( self.fresh(), - resolve_sort(genv.sess, genv.map().sort_decls(), ¶m.sort)?, + resolve_sort(genv.sess, genv.map().sort_decls(), generics, ¶m.sort)?, false, ), )?; diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index 009cb01dd8..af1b94e9f7 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -158,7 +158,10 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran .refined_bys() .try_for_each_exhaust(|(owner_id, refined_by)| { let refined_by = if let Some(refined_by) = refined_by { - desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, refined_by)? + let def_id = owner_id.to_def_id(); + let generics = tcx.generics_of(def_id); + println!("TRACE: {def_id:?} has generics: {generics:?}"); + desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, generics, refined_by)? } else { lift::lift_refined_by(tcx, owner_id) }; From bbe683ec50616937489145e86419095abf1320e6 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 06:49:34 -0700 Subject: [PATCH 04/44] got &Generics into resolve_sort --- crates/flux-driver/src/callbacks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index af1b94e9f7..66155900a0 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -160,7 +160,7 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran let refined_by = if let Some(refined_by) = refined_by { let def_id = owner_id.to_def_id(); let generics = tcx.generics_of(def_id); - println!("TRACE: {def_id:?} has generics: {generics:?}"); + // println!("TRACE: {def_id:?} has generics: {generics:?}"); desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, generics, refined_by)? } else { lift::lift_refined_by(tcx, owner_id) From c668a5d75a5e11f9653514c405722c2c4e8a571b Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 07:08:35 -0700 Subject: [PATCH 05/44] move sort-resolve functions into SortResolver impl --- crates/flux-desugar/src/desugar.rs | 281 +++++++++++++++++++--------- crates/flux-driver/src/callbacks.rs | 2 +- 2 files changed, 197 insertions(+), 86 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index ba63b62827..771769f871 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -53,7 +53,7 @@ pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result = defn .args .iter() - .map(|arg| resolve_sort(sess, sort_decls, None, &arg.sort)) + .map(|arg| SortResolver::resolve(sess, sort_decls, None, &arg.sort)) .try_collect_exhaust()?; - let output = resolve_sort(sess, sort_decls, None, &defn.output)?; + let output = SortResolver::resolve(sess, sort_decls, None, &defn.output)?; let sort = fhir::PolyFuncSort::new(0, inputs, output); let kind = if defn.body.is_some() { fhir::FuncKind::Def } else { fhir::FuncKind::Uif }; Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) @@ -95,14 +95,17 @@ pub fn desugar_refined_by( let early_bound_params: Vec<_> = refined_by .early_bound_params .iter() - .map(|param| resolve_sort(sess, sort_decls, Some(generics), ¶m.sort)) + .map(|param| SortResolver::resolve(sess, sort_decls, Some(generics), ¶m.sort)) .try_collect_exhaust()?; let index_params: Vec<_> = refined_by .index_params .iter() .map(|param| { - Ok((param.name.name, resolve_sort(sess, sort_decls, Some(generics), ¶m.sort)?)) + Ok(( + param.name.name, + SortResolver::resolve(sess, sort_decls, Some(generics), ¶m.sort)?, + )) }) .try_collect_exhaust()?; @@ -635,7 +638,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.push_layer(); for param in params { let fresh = binders.fresh(); - let sort = resolve_sort( + let sort = SortResolver::resolve( self.sess(), self.genv.map().sort_decls(), Some(generics), @@ -1105,7 +1108,7 @@ impl DesugarCtxt<'_, '_> { param.name, Binder::Refined( binders.fresh(), - resolve_sort( + SortResolver::resolve( self.genv.sess, self.genv.map().sort_decls(), Some(generics), @@ -1319,96 +1322,199 @@ impl DesugarCtxt<'_, '_> { } } -fn resolve_sort( - sess: &FluxSession, - sort_decls: &fhir::SortDecls, - _generics: Option<&Generics>, - sort: &surface::Sort, -) -> Result { - match sort { - surface::Sort::Base(sort) => resolve_base_sort(sess, sort_decls, sort), - surface::Sort::Func { inputs, output } => { - Ok(resolve_func_sort(sess, sort_decls, inputs, output)?.into()) +struct SortResolver<'a> { + sess: &'a FluxSession, + sort_decls: &'a fhir::SortDecls, + generics: Option<&'a Generics>, +} + +impl<'a> SortResolver<'a> { + pub fn resolve( + sess: &'a FluxSession, + sort_decls: &'a fhir::SortDecls, + generics: Option<&'a Generics>, + sort: &surface::Sort, + ) -> Result { + let sr = Self { sess, sort_decls, generics }; + sr.resolve_sort(sort) + } + + fn resolve_sort(&self, sort: &surface::Sort) -> Result { + match sort { + surface::Sort::Base(sort) => self.resolve_base_sort(sort), + surface::Sort::Func { inputs, output } => { + Ok(self.resolve_func_sort(inputs, output)?.into()) + } + surface::Sort::Infer => Ok(fhir::Sort::Wildcard), } - surface::Sort::Infer => Ok(fhir::Sort::Wildcard), } -} -fn resolve_func_sort( - sess: &FluxSession, - sort_decls: &fhir::SortDecls, - inputs: &[surface::BaseSort], - output: &surface::BaseSort, -) -> Result { - let inputs: Vec = inputs - .iter() - .map(|sort| resolve_base_sort(sess, sort_decls, sort)) - .try_collect_exhaust()?; - let output = resolve_base_sort(sess, sort_decls, output)?; - Ok(fhir::PolyFuncSort::new(0, inputs, output)) -} + fn resolve_func_sort( + &self, + inputs: &[surface::BaseSort], + output: &surface::BaseSort, + ) -> Result { + let inputs: Vec = inputs + .iter() + .map(|sort| self.resolve_base_sort(sort)) + .try_collect_exhaust()?; + let output = self.resolve_base_sort(output)?; + Ok(fhir::PolyFuncSort::new(0, inputs, output)) + } -fn resolve_base_sort( - sess: &FluxSession, - sort_decls: &fhir::SortDecls, - base: &surface::BaseSort, -) -> Result { - match base { - surface::BaseSort::Ident(ident) => resolve_base_sort_ident(sess, sort_decls, ident), - surface::BaseSort::BitVec(w) => Ok(fhir::Sort::BitVec(*w)), - surface::BaseSort::App(ident, args) => resolve_app_sort(sess, sort_decls, *ident, args), + fn resolve_base_sort(&self, base: &surface::BaseSort) -> Result { + match base { + surface::BaseSort::Ident(ident) => self.resolve_base_sort_ident(ident), + surface::BaseSort::BitVec(w) => Ok(fhir::Sort::BitVec(*w)), + surface::BaseSort::App(ident, args) => self.resolve_app_sort(*ident, args), + } } -} -fn resolve_sort_ctor(sess: &FluxSession, ident: surface::Ident) -> Result { - if ident.name == SORTS.set { - Ok(fhir::SortCtor::Set) - } else if ident.name == SORTS.map { - Ok(fhir::SortCtor::Map) - } else { - Err(sess.emit_err(errors::UnresolvedSort::new(ident))) + fn resolve_sort_ctor(&self, ident: surface::Ident) -> Result { + if ident.name == SORTS.set { + Ok(fhir::SortCtor::Set) + } else if ident.name == SORTS.map { + Ok(fhir::SortCtor::Map) + } else { + Err(self.sess.emit_err(errors::UnresolvedSort::new(ident))) + } } -} -fn resolve_app_sort( - sess: &FluxSession, - sort_decls: &fhir::SortDecls, - ident: surface::Ident, - args: &Vec, -) -> Result { - let ctor = resolve_sort_ctor(sess, ident)?; - let arity = ctor.arity(); - if args.len() == arity { - let args = args - .iter() - .map(|arg| resolve_base_sort(sess, sort_decls, arg)) - .try_collect_exhaust()?; - Ok(fhir::Sort::App(ctor, args)) - } else { - Err(sess.emit_err(errors::SortArityMismatch::new(ident.span, arity, args.len()))) + fn resolve_app_sort( + &self, + ident: surface::Ident, + args: &Vec, + ) -> Result { + let ctor = self.resolve_sort_ctor(ident)?; + let arity = ctor.arity(); + if args.len() == arity { + let args = args + .iter() + .map(|arg| self.resolve_base_sort(arg)) + .try_collect_exhaust()?; + Ok(fhir::Sort::App(ctor, args)) + } else { + Err(self + .sess + .emit_err(errors::SortArityMismatch::new(ident.span, arity, args.len()))) + } } -} -fn resolve_base_sort_ident( - _sess: &FluxSession, - sort_decls: &fhir::SortDecls, - ident: &surface::Ident, -) -> Result { - if ident.name == SORTS.int { - Ok(fhir::Sort::Int) - } else if ident.name == sym::bool { - Ok(fhir::Sort::Bool) - } else if ident.name == SORTS.real { - Ok(fhir::Sort::Real) - } else if sort_decls.get(&ident.name).is_some() { - let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; - Ok(fhir::Sort::App(ctor, List::empty())) - } else { - panic!("ICE: unknown sort: {:?}", ident.name); - // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) + fn resolve_base_sort_ident(&self, ident: &surface::Ident) -> Result { + if ident.name == SORTS.int { + Ok(fhir::Sort::Int) + } else if ident.name == sym::bool { + Ok(fhir::Sort::Bool) + } else if ident.name == SORTS.real { + Ok(fhir::Sort::Real) + } else if self.sort_decls.get(&ident.name).is_some() { + let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; + Ok(fhir::Sort::App(ctor, List::empty())) + } else { + panic!("ICE: unknown sort: {:?} with {:?}", ident.name, self.generics); + // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) + } } } +// fn resolve_sort( +// sess: &FluxSession, +// sort_decls: &fhir::SortDecls, +// generics: Option<&Generics>, +// sort: &surface::Sort, +// ) -> Result { +// match sort { +// surface::Sort::Base(sort) => resolve_base_sort(sess, sort_decls, generics, sort), +// surface::Sort::Func { inputs, output } => { +// Ok(resolve_func_sort(sess, sort_decls, generics, inputs, output)?.into()) +// } +// surface::Sort::Infer => Ok(fhir::Sort::Wildcard), +// } +// } + +// fn resolve_func_sort( +// sess: &FluxSession, +// sort_decls: &fhir::SortDecls, +// generics: Option<&Generics>, +// inputs: &[surface::BaseSort], +// output: &surface::BaseSort, +// ) -> Result { +// let inputs: Vec = inputs +// .iter() +// .map(|sort| resolve_base_sort(sess, sort_decls, generics, sort)) +// .try_collect_exhaust()?; +// let output = resolve_base_sort(sess, sort_decls, generics, output)?; +// Ok(fhir::PolyFuncSort::new(0, inputs, output)) +// } + +// fn resolve_base_sort( +// sess: &FluxSession, +// sort_decls: &fhir::SortDecls, +// generics: Option<&Generics>, +// base: &surface::BaseSort, +// ) -> Result { +// match base { +// surface::BaseSort::Ident(ident) => { +// resolve_base_sort_ident(sess, sort_decls, generics, ident) +// } +// surface::BaseSort::BitVec(w) => Ok(fhir::Sort::BitVec(*w)), +// surface::BaseSort::App(ident, args) => { +// resolve_app_sort(sess, sort_decls, generics, *ident, args) +// } +// } +// } + +// fn resolve_sort_ctor(sess: &FluxSession, ident: surface::Ident) -> Result { +// if ident.name == SORTS.set { +// Ok(fhir::SortCtor::Set) +// } else if ident.name == SORTS.map { +// Ok(fhir::SortCtor::Map) +// } else { +// Err(sess.emit_err(errors::UnresolvedSort::new(ident))) +// } +// } + +// fn resolve_app_sort( +// sess: &FluxSession, +// sort_decls: &fhir::SortDecls, +// generics: Option<&Generics>, +// ident: surface::Ident, +// args: &Vec, +// ) -> Result { +// let ctor = resolve_sort_ctor(sess, ident)?; +// let arity = ctor.arity(); +// if args.len() == arity { +// let args = args +// .iter() +// .map(|arg| resolve_base_sort(sess, sort_decls, generics, arg)) +// .try_collect_exhaust()?; +// Ok(fhir::Sort::App(ctor, args)) +// } else { +// Err(sess.emit_err(errors::SortArityMismatch::new(ident.span, arity, args.len()))) +// } +// } + +// fn resolve_base_sort_ident( +// _sess: &FluxSession, +// sort_decls: &fhir::SortDecls, +// generics: Option<&Generics>, +// ident: &surface::Ident, +// ) -> Result { +// if ident.name == SORTS.int { +// Ok(fhir::Sort::Int) +// } else if ident.name == sym::bool { +// Ok(fhir::Sort::Bool) +// } else if ident.name == SORTS.real { +// Ok(fhir::Sort::Real) +// } else if sort_decls.get(&ident.name).is_some() { +// let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; +// Ok(fhir::Sort::App(ctor, List::empty())) +// } else { +// panic!("ICE: unknown sort: {:?} with {generics:?}", ident.name); +// // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) +// } +// } + impl Binders { pub(crate) fn new() -> Binders { Binders { name_gen: IndexGen::new(), layers: vec![] } @@ -1437,7 +1543,12 @@ impl Binders { param.name, Binder::Refined( self.fresh(), - resolve_sort(genv.sess, genv.map().sort_decls(), generics, ¶m.sort)?, + SortResolver::resolve( + genv.sess, + genv.map().sort_decls(), + generics, + ¶m.sort, + )?, false, ), )?; diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index 66155900a0..af1b94e9f7 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -160,7 +160,7 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran let refined_by = if let Some(refined_by) = refined_by { let def_id = owner_id.to_def_id(); let generics = tcx.generics_of(def_id); - // println!("TRACE: {def_id:?} has generics: {generics:?}"); + println!("TRACE: {def_id:?} has generics: {generics:?}"); desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, generics, refined_by)? } else { lift::lift_refined_by(tcx, owner_id) From a25da2700e8f00fca60f69cf7096a5d968f5996e Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 07:09:24 -0700 Subject: [PATCH 06/44] move sort-resolve functions into SortResolver impl --- crates/flux-driver/src/callbacks.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index af1b94e9f7..af9af15f9f 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -160,7 +160,6 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran let refined_by = if let Some(refined_by) = refined_by { let def_id = owner_id.to_def_id(); let generics = tcx.generics_of(def_id); - println!("TRACE: {def_id:?} has generics: {generics:?}"); desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, generics, refined_by)? } else { lift::lift_refined_by(tcx, owner_id) From c887fed794743e69a171b7a7b91125941c8c9ec5 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 07:20:45 -0700 Subject: [PATCH 07/44] next: sort out sort-errors --- crates/flux-desugar/src/desugar.rs | 111 +++------------------------ crates/flux-tests/tests/todo/rset.rs | 4 +- 2 files changed, 11 insertions(+), 104 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 771769f871..6805ae615c 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1325,7 +1325,7 @@ impl DesugarCtxt<'_, '_> { struct SortResolver<'a> { sess: &'a FluxSession, sort_decls: &'a fhir::SortDecls, - generics: Option<&'a Generics>, + generic_params: FxHashMap, } impl<'a> SortResolver<'a> { @@ -1335,7 +1335,10 @@ impl<'a> SortResolver<'a> { generics: Option<&'a Generics>, sort: &surface::Sort, ) -> Result { - let sr = Self { sess, sort_decls, generics }; + let generic_params = generics + .map(|g| g.params.iter().map(|p| (p.name, p.def_id)).collect()) + .unwrap_or_default(); + let sr = Self { sess, sort_decls, generic_params }; sr.resolve_sort(sort) } @@ -1410,111 +1413,15 @@ impl<'a> SortResolver<'a> { } else if self.sort_decls.get(&ident.name).is_some() { let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; Ok(fhir::Sort::App(ctor, List::empty())) + } else if let Some(def_id) = self.generic_params.get(&ident.name) { + Ok(fhir::Sort::Param(*def_id)) } else { - panic!("ICE: unknown sort: {:?} with {:?}", ident.name, self.generics); - // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) + // panic!("ICE: unknown sort: {:?} with {:?}", ident.name, self.generics); + Err(self.sess.emit_err(errors::UnresolvedSort::new(*ident))) } } } -// fn resolve_sort( -// sess: &FluxSession, -// sort_decls: &fhir::SortDecls, -// generics: Option<&Generics>, -// sort: &surface::Sort, -// ) -> Result { -// match sort { -// surface::Sort::Base(sort) => resolve_base_sort(sess, sort_decls, generics, sort), -// surface::Sort::Func { inputs, output } => { -// Ok(resolve_func_sort(sess, sort_decls, generics, inputs, output)?.into()) -// } -// surface::Sort::Infer => Ok(fhir::Sort::Wildcard), -// } -// } - -// fn resolve_func_sort( -// sess: &FluxSession, -// sort_decls: &fhir::SortDecls, -// generics: Option<&Generics>, -// inputs: &[surface::BaseSort], -// output: &surface::BaseSort, -// ) -> Result { -// let inputs: Vec = inputs -// .iter() -// .map(|sort| resolve_base_sort(sess, sort_decls, generics, sort)) -// .try_collect_exhaust()?; -// let output = resolve_base_sort(sess, sort_decls, generics, output)?; -// Ok(fhir::PolyFuncSort::new(0, inputs, output)) -// } - -// fn resolve_base_sort( -// sess: &FluxSession, -// sort_decls: &fhir::SortDecls, -// generics: Option<&Generics>, -// base: &surface::BaseSort, -// ) -> Result { -// match base { -// surface::BaseSort::Ident(ident) => { -// resolve_base_sort_ident(sess, sort_decls, generics, ident) -// } -// surface::BaseSort::BitVec(w) => Ok(fhir::Sort::BitVec(*w)), -// surface::BaseSort::App(ident, args) => { -// resolve_app_sort(sess, sort_decls, generics, *ident, args) -// } -// } -// } - -// fn resolve_sort_ctor(sess: &FluxSession, ident: surface::Ident) -> Result { -// if ident.name == SORTS.set { -// Ok(fhir::SortCtor::Set) -// } else if ident.name == SORTS.map { -// Ok(fhir::SortCtor::Map) -// } else { -// Err(sess.emit_err(errors::UnresolvedSort::new(ident))) -// } -// } - -// fn resolve_app_sort( -// sess: &FluxSession, -// sort_decls: &fhir::SortDecls, -// generics: Option<&Generics>, -// ident: surface::Ident, -// args: &Vec, -// ) -> Result { -// let ctor = resolve_sort_ctor(sess, ident)?; -// let arity = ctor.arity(); -// if args.len() == arity { -// let args = args -// .iter() -// .map(|arg| resolve_base_sort(sess, sort_decls, generics, arg)) -// .try_collect_exhaust()?; -// Ok(fhir::Sort::App(ctor, args)) -// } else { -// Err(sess.emit_err(errors::SortArityMismatch::new(ident.span, arity, args.len()))) -// } -// } - -// fn resolve_base_sort_ident( -// _sess: &FluxSession, -// sort_decls: &fhir::SortDecls, -// generics: Option<&Generics>, -// ident: &surface::Ident, -// ) -> Result { -// if ident.name == SORTS.int { -// Ok(fhir::Sort::Int) -// } else if ident.name == sym::bool { -// Ok(fhir::Sort::Bool) -// } else if ident.name == SORTS.real { -// Ok(fhir::Sort::Real) -// } else if sort_decls.get(&ident.name).is_some() { -// let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; -// Ok(fhir::Sort::App(ctor, List::empty())) -// } else { -// panic!("ICE: unknown sort: {:?} with {generics:?}", ident.name); -// // Err(sess.emit_err(errors::UnresolvedSort::new(*ident))) -// } -// } - impl Binders { pub(crate) fn new() -> Binders { Binders { name_gen: IndexGen::new(), layers: vec![] } diff --git a/crates/flux-tests/tests/todo/rset.rs b/crates/flux-tests/tests/todo/rset.rs index bbae7c325b..a2ff595235 100644 --- a/crates/flux-tests/tests/todo/rset.rs +++ b/crates/flux-tests/tests/todo/rset.rs @@ -13,7 +13,7 @@ pub fn empty() -> RSet { } #[flux::trusted] -#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[ set_union(set_singleton(x), s) ])] +#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[ set_union(set_singleton(elem), s) ])] pub fn insert(set: &mut RSet, elem: T) where T: Eq + Hash, @@ -22,7 +22,7 @@ where } #[flux::trusted] -#[flux::sig(fn(set: &Set[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] +#[flux::sig(fn(set: &RSet[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] pub fn contains(set: &RSet, elem: &T) -> bool where T: Eq + Hash, From 67bc5e5dbc1745689481063da419014ad1210186 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 15:25:07 -0700 Subject: [PATCH 08/44] see hackmd -- track SortGenerics with DefId, and List with Record --- crates/flux-fhir-analysis/src/wf/sortck.rs | 1 + crates/flux-middle/src/fhir.rs | 3 +- crates/flux-middle/src/global_env.rs | 9 +++--- crates/flux-tests/tests/todo/rset.rs | 37 ++++++++++++++-------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index a3a21f4dae..71abd5a741 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -209,6 +209,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let sort = self[var.name].clone(); match sort { fhir::Sort::Record(def_id) => { + println!("TRACE: synth_expr: var {var:?} => {sort:?} ({def_id:?})"); self.genv .field_sort(def_id, fld.name) .cloned() diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 402b264dbf..a9d9b2bf49 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -497,7 +497,8 @@ pub enum Sort { Var(usize), /// A record sort corresponds to the sort associated with a type alias or an adt (struct/enum). /// Values of a record sort can be projected using dot notation to extract their fields. - Record(DefId), + /// the List is for the type parameters of (generic) record sorts + Record(DefId, List), /// The sort associated to a type variable Param(DefId), /// A sort that needs to be inferred diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 8591b72045..55949e16d4 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -268,6 +268,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { | fhir::Sort::Real | fhir::Sort::Unit | fhir::Sort::BitVec(_) + | fhir::Sort::Param(_) | fhir::Sort::Var(_) => true, fhir::Sort::Record(def_id) => { self.index_sorts_of(*def_id) @@ -275,11 +276,9 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { .all(|sort| self.has_equality(sort)) } fhir::Sort::App(ctor, sorts) => self.ctor_has_equality(ctor, sorts), - fhir::Sort::Loc - | fhir::Sort::Func(_) - | fhir::Sort::Param(_) - | fhir::Sort::Wildcard - | fhir::Sort::Infer(_) => false, + fhir::Sort::Loc | fhir::Sort::Func(_) | fhir::Sort::Wildcard | fhir::Sort::Infer(_) => { + false + } } } diff --git a/crates/flux-tests/tests/todo/rset.rs b/crates/flux-tests/tests/todo/rset.rs index a2ff595235..72b661faab 100644 --- a/crates/flux-tests/tests/todo/rset.rs +++ b/crates/flux-tests/tests/todo/rset.rs @@ -1,19 +1,28 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set)] -pub struct RSet { - inner: std::collections::HashSet, +#[flux::refined_by(elems: Set)] +pub struct RSet { + pub inner: std::collections::HashSet, +} + +#[flux::trusted] +#[flux::sig(fn(s: RSet) -> RSet[s.elems])] +pub fn id(s: RSet) -> RSet { + s } #[flux::sig(fn (bool[true]))] fn assert(_b: bool) {} +#[flux::trusted] +#[flux::sig(fn() -> RSet[set_empty(0)])] pub fn empty() -> RSet { - RSet { inner: std::collections::HashSet::new() } + let inner = std::collections::HashSet::new(); + RSet { inner } } #[flux::trusted] -#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[ set_union(set_singleton(elem), s) ])] +#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[set_union(set_singleton(elem), s)])] pub fn insert(set: &mut RSet, elem: T) where T: Eq + Hash, @@ -22,17 +31,17 @@ where } #[flux::trusted] -#[flux::sig(fn(set: &RSet[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] -pub fn contains(set: &RSet, elem: &T) -> bool +#[flux::sig(fn(set: &RSet[@s], &A[@elem]) -> bool[set_is_in(elem, s.elems)])] +pub fn contains(set: &RSet, elem: &A) -> bool where - T: Eq + Hash, + A: Eq + Hash, { set.inner.contains(elem) } -pub fn test() { - let mut s = empty(); - insert(&mut s, 1); - assert(contains(&s, &1)); - assert(!contains(&s, &2)); -} +// pub fn test() { +// let mut s = empty(); +// insert(&mut s, 1); +// assert(contains(&s, &1)); +// assert(!contains(&s, &2)); +// } From 609cccd36f3f5167a983c87a4adf9afd571d1e96 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 14 Oct 2023 15:26:53 -0700 Subject: [PATCH 09/44] see hackmd -- track SortGenerics with DefId, and List with Record TODO:NEXT --- crates/flux-fhir-analysis/src/wf/sortck.rs | 2 +- crates/flux-middle/src/fhir.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index 71abd5a741..a55fcdea89 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let sort = self[var.name].clone(); match sort { fhir::Sort::Record(def_id) => { - println!("TRACE: synth_expr: var {var:?} => {sort:?} ({def_id:?})"); + // println!("TRACE: synth_expr: var {var:?} => {sort:?} ({def_id:?})"); self.genv .field_sort(def_id, fld.name) .cloned() diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index a9d9b2bf49..345ec7b52e 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -498,7 +498,7 @@ pub enum Sort { /// A record sort corresponds to the sort associated with a type alias or an adt (struct/enum). /// Values of a record sort can be projected using dot notation to extract their fields. /// the List is for the type parameters of (generic) record sorts - Record(DefId, List), + Record(DefId /* TODO:NEXT , List */), /// The sort associated to a type variable Param(DefId), /// A sort that needs to be inferred From 729eadef0955ee4e94f04ab80304e8cb3667fffd Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Mon, 16 Oct 2023 21:43:53 -0700 Subject: [PATCH 10/44] phew, get Record(DefId, List) to work on all tests --- crates/flux-desugar/src/desugar.rs | 97 ++++++++++---- crates/flux-desugar/src/lib.rs | 2 + crates/flux-fhir-analysis/src/conv.rs | 32 +++-- crates/flux-fhir-analysis/src/wf/mod.rs | 2 +- crates/flux-fhir-analysis/src/wf/sortck.rs | 19 +-- crates/flux-middle/src/fhir.rs | 31 +++-- crates/flux-middle/src/fhir/lift.rs | 3 +- crates/flux-middle/src/global_env.rs | 139 +++++++++++++++++---- crates/flux-middle/src/rty/mod.rs | 2 +- crates/flux-syntax/src/surface.rs | 14 +++ 10 files changed, 267 insertions(+), 74 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 6805ae615c..4aca883387 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -8,7 +8,7 @@ use flux_middle::{ intern::List, }; use flux_syntax::surface; -use hir::{def::DefKind, ItemKind}; +use hir::{def::DefKind, ItemKind, PrimTy}; use rustc_data_structures::{ fx::{FxIndexMap, IndexEntry}, unord::UnordMap, @@ -718,13 +718,15 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { idxs: &surface::Indices, binders: &mut Binders, ) -> Result { + // let sort = self.genv.sort_of_bty(bty); + // println!("TRACE: desugar_indices {bty:?}: sort = {sort:?}"); if let [surface::RefineArg::Bind(ident, ..)] = &idxs.indices[..] { self.ident_into_refine_arg(*ident, binders) .transpose() .unwrap() - } else if let Some(fhir::Sort::Record(def_id)) = self.genv.sort_of_bty(bty) { + } else if let Some(fhir::Sort::Record(def_id, sort_args)) = self.genv.sort_of_bty(bty) { let flds = self.desugar_refine_args(&idxs.indices, binders)?; - Ok(fhir::RefineArg::Record(def_id, flds, idxs.span)) + Ok(fhir::RefineArg::Record(def_id, sort_args, flds, idxs.span)) } else if let [arg] = &idxs.indices[..] { self.desugar_refine_arg(arg, binders) } else { @@ -1071,6 +1073,19 @@ impl DesugarCtxt<'_, '_> { } }) } + // ORIGINAL + // fn gather_params_variant_ret( + // &self, + // ret: &surface::VariantRet, + // binders: &mut Binders, + // ) -> Result { + // self.gather_params_path(&ret.path, TypePos::Other, binders)?; + // let res = self.resolver_output.path_res_map[&ret.path.node_id]; + // let Some(sort) = self.genv.sort_of_res(res) else { + // return Err(self.emit_err(errors::RefinedUnrefinableType::new(ret.path.span))); + // }; + // self.gather_params_indices(sort, &ret.indices, TypePos::Other, binders) + // } fn gather_params_variant_ret( &self, @@ -1078,8 +1093,8 @@ impl DesugarCtxt<'_, '_> { binders: &mut Binders, ) -> Result { self.gather_params_path(&ret.path, TypePos::Other, binders)?; - let res = self.resolver_output.path_res_map[&ret.path.node_id]; - let Some(sort) = self.genv.sort_of_res(res) else { + // let Some(sort) = self.resolver_output.sort_of_surface_path(&ret.path) else { + let Some(sort) = sort_of_surface_path(self.genv, self.resolver_output, &ret.path) else { return Err(self.emit_err(errors::RefinedUnrefinableType::new(ret.path.span))); }; self.gather_params_indices(sort, &ret.indices, TypePos::Other, binders) @@ -1144,12 +1159,10 @@ impl DesugarCtxt<'_, '_> { fn gather_params_fun_arg(&self, arg: &surface::Arg, binders: &mut Binders) -> Result { match arg { surface::Arg::Constr(bind, path, _) => { - let res = self.resolver_output.path_res_map[&path.node_id]; - binders.insert_binder( - self.genv.sess, - *bind, - binders.binder_from_res(self.genv, res), - )?; + let Some(sort) = sort_of_surface_path(self.genv, self.resolver_output, path) else { + return Err(self.emit_err(errors::RefinedUnrefinableType::new(path.span))); + }; + binders.insert_binder(self.genv.sess, *bind, binders.binder_from_sort(sort))?; } surface::Arg::StrgRef(loc, ty) => { binders.insert_binder( @@ -1504,13 +1517,13 @@ impl Binders { Binder::Refined(self.fresh(), sort, true) } - fn binder_from_res(&self, genv: &GlobalEnv, res: fhir::Res) -> Binder { - if let Some(sort) = genv.sort_of_res(res) { - self.binder_from_sort(sort) - } else { - Binder::Unrefined - } - } + // fn binder_from_res(&self, genv: &GlobalEnv, res: fhir::Res) -> Binder { + // if let Some(sort) = genv.sort_of_res(res) { + // self.binder_from_sort(sort) + // } else { + // Binder::Unrefined + // } + // } fn binder_from_bty( &self, @@ -1623,16 +1636,56 @@ fn index_sort( // CODESYNC(sort-of, 4) sorts should be given consistently match &bty.kind { surface::BaseTyKind::Path(path) => { - let res = resolver_output.path_res_map[&path.node_id]; - genv.sort_of_res(res) + sort_of_surface_path(genv, resolver_output, path) + // let res = resolver_output.path_res_map[&path.node_id]; + // genv.sort_of_res(res) } surface::BaseTyKind::Slice(_) => Some(fhir::Sort::Int), } } +fn sort_of_surface_path( + genv: &GlobalEnv, + resolver_output: &ResolverOutput, + path: &surface::Path, +) -> Option { + let res = resolver_output.path_res_map[&path.node_id]; + + match res { + fhir::Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) => Some(fhir::Sort::Int), + fhir::Res::PrimTy(PrimTy::Bool) => Some(fhir::Sort::Bool), + fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => Some(fhir::Sort::Unit), + fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { + // TODO: duplication with sort_of_path + let mut sort_args = vec![]; + for arg in path.generics.iter() { + if let surface::GenericArg::Type(ty) = arg && + let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind && + let Some(sort) = sort_of_surface_path(genv, resolver_output, path) + { + sort_args.push(sort); + } + } + Some(fhir::Sort::Record(def_id, List::from_vec(sort_args))) + } + fhir::Res::Def(DefKind::TyParam, def_id) => { + let param = genv.get_generic_param(def_id.expect_local()); + match ¶m.kind { + fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, + } + } + + fhir::Res::Def(DefKind::AssocTy | DefKind::OpaqueTy, _) | fhir::Res::SelfTyParam { .. } => { + None + } + fhir::Res::SelfTyAlias { alias_to, .. } => genv.sort_of_self_ty_alias(alias_to), + fhir::Res::Def(..) => bug!("unexpected res {res:?}"), + } +} fn as_tuple<'a>(genv: &'a GlobalEnv, sort: &'a fhir::Sort) -> &'a [fhir::Sort] { - if let fhir::Sort::Record(def_id) = sort { - genv.index_sorts_of(*def_id) + if let fhir::Sort::Record(def_id, sort_args) = sort { + genv.index_sorts_of(*def_id, sort_args.clone()) } else { slice::from_ref(sort) } diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 28dae20be4..518916325f 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -150,6 +150,8 @@ pub fn desugar_fn_sig( // Desugar of fn_sig needs to happen AFTER inserting generics. See crate level comment let (generic_preds, fn_sig) = cx.desugar_fn_sig(fn_sig, &mut Binders::new())?; + // println!("TRACE: desugar_fn_sig {owner_id:?} => {fn_sig:?}"); + if config::dump_fhir() { dbg::dump_item_info(genv.tcx, def_id, "fhir", &fn_sig).unwrap(); } diff --git a/crates/flux-fhir-analysis/src/conv.rs b/crates/flux-fhir-analysis/src/conv.rs index f63b7ebe1a..33e08c9adb 100644 --- a/crates/flux-fhir-analysis/src/conv.rs +++ b/crates/flux-fhir-analysis/src/conv.rs @@ -193,12 +193,24 @@ pub(crate) fn conv_generics( }) } +fn sort_args_for_adt(genv: &GlobalEnv, def_id: impl Into) -> List { + let mut sort_args = vec![]; + for param in &genv.tcx.generics_of(def_id.into()).params { + if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind { + sort_args.push(fhir::Sort::Param(param.def_id)) + } + } + List::from_vec(sort_args) +} + pub(crate) fn adt_def_for_struct( genv: &GlobalEnv, invariants: Vec, struct_def: &fhir::StructDef, ) -> rty::AdtDef { - let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(struct_def.owner_id))); + let def_id = struct_def.owner_id; + let sort_args = sort_args_for_adt(genv, def_id); + let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(def_id, sort_args))); let adt_def = lowering::lower_adt_def(&genv.tcx.adt_def(struct_def.owner_id)); rty::AdtDef::new(adt_def, sort, invariants, struct_def.is_opaque()) } @@ -208,7 +220,9 @@ pub(crate) fn adt_def_for_enum( invariants: Vec, enum_def: &fhir::EnumDef, ) -> rty::AdtDef { - let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(enum_def.owner_id))); + let def_id = enum_def.owner_id; + let sort_args = sort_args_for_adt(genv, def_id); + let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(def_id, sort_args))); let adt_def = lowering::lower_adt_def(&genv.tcx.adt_def(enum_def.owner_id)); rty::AdtDef::new(adt_def, sort, invariants, false) } @@ -640,7 +654,7 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { return Ok(rty::Ty::param(param_ty)); } } - + // println!("TRACE: conv_base_ty {bty:?} {sort:?}"); let sort = conv_sort(self.genv, &sort.unwrap()); if sort.is_unit() { let idx = rty::Index::from(rty::Expr::unit()); @@ -710,7 +724,7 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { let expr = self.add_coercions(rty::Expr::abs(body), *fhir_id); (expr, rty::TupleTree::Leaf(false)) } - fhir::RefineArg::Record(_, flds, ..) => { + fhir::RefineArg::Record(_, _, flds, ..) => { let mut exprs = vec![]; let mut is_binder = vec![]; for arg in flds { @@ -1087,10 +1101,12 @@ impl LookupResult<'_> { fn is_record(&self) -> Option { match &self.kind { LookupResultKind::LateBoundList { - entry: Entry::Sort { sort: fhir::Sort::Record(def_id), .. }, + entry: Entry::Sort { sort: fhir::Sort::Record(def_id, _), .. }, .. } => Some(*def_id), - LookupResultKind::EarlyBound { sort: fhir::Sort::Record(def_id), .. } => Some(*def_id), + LookupResultKind::EarlyBound { sort: fhir::Sort::Record(def_id, _), .. } => { + Some(*def_id) + } _ => None, } } @@ -1142,8 +1158,8 @@ pub fn conv_sort(genv: &GlobalEnv, sort: &fhir::Sort) -> rty::Sort { fhir::Sort::Loc => rty::Sort::Loc, fhir::Sort::Unit => rty::Sort::unit(), fhir::Sort::Func(fsort) => rty::Sort::Func(conv_func_sort(genv, fsort)), - fhir::Sort::Record(def_id) => { - rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(*def_id))) + fhir::Sort::Record(def_id, args) => { + rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(*def_id, args.clone()))) } fhir::Sort::App(ctor, args) => { let ctor = conv_sort_ctor(ctor); diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index 2c654d8998..35fdb2e50a 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { Ok(()) } fhir::RefineArg::Abs(_, body, ..) => self.check_param_uses_expr(infcx, body, true), - fhir::RefineArg::Record(_, flds, ..) => { + fhir::RefineArg::Record(_, _, flds, ..) => { flds.iter() .try_for_each_exhaust(|arg| self.check_param_uses_refine_arg(infcx, arg)) } diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index a55fcdea89..493f8ee3dd 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -6,6 +6,7 @@ use flux_errors::ErrorGuaranteed; use flux_middle::{ fhir::{self, FhirId, FluxOwnerId, WfckResults}, global_env::GlobalEnv, + intern::List, }; use itertools::izip; use rustc_data_structures::unord::UnordMap; @@ -45,9 +46,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fhir::RefineArg::Abs(params, body, span, fhir_id) => { self.check_abs(params, body, span, fhir_id, expected) } - fhir::RefineArg::Record(def_id, flds, span) => { - self.check_record(*def_id, flds, *span)?; - let found = fhir::Sort::Record(*def_id); + fhir::RefineArg::Record(def_id, sort_args, flds, span) => { + self.check_record(*def_id, sort_args.clone(), flds, *span)?; + let found = fhir::Sort::Record(*def_id, sort_args.clone()); if &found != expected { return Err(self.emit_sort_mismatch(*span, expected, &found)); } @@ -92,10 +93,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn check_record( &mut self, def_id: DefId, + sort_args: List, args: &[fhir::RefineArg], span: Span, ) -> Result<(), ErrorGuaranteed> { - let sorts = self.genv.index_sorts_of(def_id); + let sorts = self.genv.index_sorts_of(def_id, sort_args); if args.len() != sorts.len() { return Err(self.emit_err(errors::ArgCountMismatch::new( Some(span), @@ -207,11 +209,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fhir::ExprKind::Dot(var, fld) => { let sort = self[var.name].clone(); - match sort { - fhir::Sort::Record(def_id) => { + match &sort { + fhir::Sort::Record(def_id, sort_args) => { // println!("TRACE: synth_expr: var {var:?} => {sort:?} ({def_id:?})"); + // let sort_args = sort_args.clone(); self.genv - .field_sort(def_id, fld.name) + .field_sort(*def_id, sort_args.clone(), fld.name) .cloned() .ok_or_else(|| self.emit_field_not_found(&sort, *fld)) } @@ -522,7 +525,7 @@ impl<'a> InferCtxt<'a, '_> { fn is_single_field_record(&mut self, sort: &fhir::Sort) -> Option<&'a fhir::Sort> { self.resolve_sort(sort).and_then(|s| { - if let fhir::Sort::Record(def_id) = s && let [sort] = self.genv.index_sorts_of(def_id) { + if let fhir::Sort::Record(def_id, sort_args) = s && let [sort] = self.genv.index_sorts_of(def_id, sort_args) { Some(sort) } else { None diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 345ec7b52e..24b304b826 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -392,7 +392,7 @@ pub enum RefineArg { is_binder: bool, }, Abs(Vec, Expr, Span, FhirId), - Record(DefId, Vec, Span), + Record(DefId, List, Vec, Span), } /// These are types of things that may be refined with indices or existentials @@ -432,7 +432,6 @@ pub struct TypeBinding { pub enum GenericArg { Lifetime(Lifetime), Type(Ty), - // Constraint(SurfaceIdent, Ty), } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -498,7 +497,7 @@ pub enum Sort { /// A record sort corresponds to the sort associated with a type alias or an adt (struct/enum). /// Values of a record sort can be projected using dot notation to extract their fields. /// the List is for the type parameters of (generic) record sorts - Record(DefId /* TODO:NEXT , List */), + Record(DefId, List), /// The sort associated to a type variable Param(DefId), /// A sort that needs to be inferred @@ -632,9 +631,8 @@ impl SortCtor { impl Ty { pub fn as_path(&self) -> Option<&Path> { match &self.kind { - TyKind::BaseTy(BaseTy { - kind: BaseTyKind::Path(QPath::Resolved(None, path)), .. - }) => Some(path), + TyKind::BaseTy(bty) | TyKind::Indexed(bty, _) => bty.as_path(), + TyKind::Constr(_, ty) | TyKind::Exists(_, ty) => ty.as_path(), _ => None, } } @@ -647,6 +645,12 @@ impl BaseTy { BaseTyKind::Path(QPath::Resolved(_, Path { res: Res::PrimTy(PrimTy::Bool), .. })) ) } + pub fn as_path(&self) -> Option<&Path> { + match &self.kind { + BaseTyKind::Path(QPath::Resolved(None, path)) => Some(path), + _ => None, + } + } } impl Res { @@ -847,7 +851,7 @@ impl Sort { | Sort::BitVec(_) | Sort::Param(_) | Sort::Wildcard - | Sort::Record(_) + | Sort::Record(_, _) | Sort::Infer(_) => self.clone(), Sort::Var(i) => subst[*i].clone(), Sort::App(c, args) => { @@ -1623,7 +1627,18 @@ impl fmt::Debug for Sort { Sort::Loc => write!(f, "loc"), Sort::Func(sort) => write!(f, "{sort}"), Sort::Unit => write!(f, "()"), - Sort::Record(def_id) => write!(f, "{}", pretty::def_id_to_string(*def_id)), + Sort::Record(def_id, sort_args) => { + if sort_args.is_empty() { + write!(f, "{}", pretty::def_id_to_string(*def_id)) + } else { + write!( + f, + "{}<{}>", + pretty::def_id_to_string(*def_id), + sort_args.iter().join(", ") + ) + } + } Sort::Param(def_id) => write!(f, "sortof({})", pretty::def_id_to_string(*def_id)), Sort::Wildcard => write!(f, "_"), Sort::Infer(vid) => write!(f, "{vid:?}"), diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index 3acca38b54..0fb70246b4 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -11,7 +11,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_middle::{middle::resolve_bound_vars::ResolvedArg, ty::TyCtxt}; -use crate::fhir; +use crate::{fhir, intern::List}; pub struct LiftCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -375,6 +375,7 @@ impl<'a, 'tcx> LiftCtxt<'a, 'tcx> { bty, idx: fhir::RefineArg::Record( self.owner.to_def_id(), + List::empty(), // TODO:RJ: or should we use the generics and just make it T1,...Tn? vec![], generics.span.shrink_to_hi(), ), diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 55949e16d4..46b5bed966 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -180,14 +180,16 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn sort_of_bty(&self, bty: &fhir::BaseTy) -> Option { match &bty.kind { - fhir::BaseTyKind::Path(fhir::QPath::Resolved(_, fhir::Path { res, .. })) => { - self.sort_of_res(*res) - } + fhir::BaseTyKind::Path(fhir::QPath::Resolved(_, path)) => self.sort_of_path(path), fhir::BaseTyKind::Slice(_) => Some(fhir::Sort::Int), } } - pub fn index_sorts_of(&self, def_id: impl Into) -> &[fhir::Sort] { + pub fn index_sorts_of( + &self, + def_id: impl Into, + sort_args: List, + ) -> &[fhir::Sort] { let def_id = def_id.into(); if let Some(local_id) = def_id.as_local().or_else(|| self.map().get_extern(def_id)) { self.map().refined_by(local_id).index_sorts() @@ -199,35 +201,99 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } } - pub fn sort_of_res(&self, res: fhir::Res) -> Option { - // CODESYNC(sort-of, 4) sorts should be given consistently - match res { + pub fn sort_of_path(&self, path: &fhir::Path) -> Option { + match path.res { fhir::Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) => Some(fhir::Sort::Int), fhir::Res::PrimTy(PrimTy::Bool) => Some(fhir::Sort::Bool), fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => { Some(fhir::Sort::Unit) } fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { - Some(fhir::Sort::Record(def_id)) - } - fhir::Res::SelfTyAlias { alias_to, .. } => { - let self_ty = self.tcx.type_of(alias_to).skip_binder(); - self.sort_of_self_ty(self_ty) - } - fhir::Res::Def(DefKind::TyParam, def_id) => { - let param = self.get_generic_param(def_id.expect_local()); - match ¶m.kind { - fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), - fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, + // println!("TRACE: sort_of_path (1) {def_id:?} with args = {:?}", path.args); + let mut sort_args = vec![]; + for arg in path.args.iter() { + if let fhir::GenericArg::Type(ty) = arg && + let Some(sort) = self.sort_of_ty(ty) + { + // let path = ty.as_path()?; + // sort_args.push(self.sort_of_path(path)?); + // let sort = self.sort_of_ty(ty); + // println!("TRACE: sort_of_path (2) {ty:?} => {sort:?}"); + sort_args.push(sort); + } } + Some(fhir::Sort::Record(def_id, List::from_vec(sort_args))) } + fhir::Res::SelfTyAlias { alias_to, .. } => self.sort_of_self_ty_alias(alias_to), + fhir::Res::Def(DefKind::TyParam, def_id) => self.sort_of_generic_param(def_id), fhir::Res::Def(DefKind::AssocTy | DefKind::OpaqueTy, _) | fhir::Res::SelfTyParam { .. } => None, - fhir::Res::Def(..) => bug!("unexpected res {res:?}"), + fhir::Res::Def(..) => bug!("unexpected res {:?}", path.res), + } + } + + pub fn sort_of_self_ty_alias(&self, alias_to: DefId) -> Option { + // let self_ty = self.tcx.type_of(alias_to).skip_binder(); + let self_ty = self.tcx.type_of(alias_to).instantiate_identity(); + // println!("TRACE: sort_of_path (3) {alias_to:?} is {self_ty:?}"); + let res = self.sort_of_self_ty(alias_to, self_ty); + // println!("TRACE: sort_of_path (4) {self_ty:?} ==> {res:?}"); + res + } + + fn sort_of_generic_param(&self, def_id: DefId) -> Option { + let param = self.get_generic_param(def_id.expect_local()); + match ¶m.kind { + fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, + } + } + + // pub fn sort_of_res(&self, res: fhir::Res) -> Option { + // // CODESYNC(sort-of, 4) sorts should be given consistently + // match res { + // fhir::Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) => Some(fhir::Sort::Int), + // fhir::Res::PrimTy(PrimTy::Bool) => Some(fhir::Sort::Bool), + // fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => { + // Some(fhir::Sort::Unit) + // } + // fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { + // Some(fhir::Sort::Record(def_id)) + // } + // fhir::Res::SelfTyAlias { alias_to, .. } => { + // let self_ty = self.tcx.type_of(alias_to).skip_binder(); + // self.sort_of_self_ty(self_ty) + // } + // fhir::Res::Def(DefKind::TyParam, def_id) => { + // let param = self.get_generic_param(def_id.expect_local()); + // match ¶m.kind { + // fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + // fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, + // } + // } + // fhir::Res::Def(DefKind::AssocTy | DefKind::OpaqueTy, _) + // | fhir::Res::SelfTyParam { .. } => None, + // fhir::Res::Def(..) => bug!("unexpected res {res:?}"), + // } + // } + + fn sort_of_ty(&self, ty: &fhir::Ty) -> Option { + match &ty.kind { + fhir::TyKind::BaseTy(bty) | fhir::TyKind::Indexed(bty, _) => { + self.sort_of_path(bty.as_path()?) + } + fhir::TyKind::Exists(_, ty) | fhir::TyKind::Constr(_, ty) => self.sort_of_ty(ty), + fhir::TyKind::RawPtr(_, _) + | fhir::TyKind::Ref(_, _) + | fhir::TyKind::Tuple(_) + | fhir::TyKind::Array(_, _) + | fhir::TyKind::Never => Some(fhir::Sort::Unit), + fhir::TyKind::Hole(_) => Some(fhir::Sort::Wildcard), + _ => bug!("unexpected ty {ty:?}"), } } - fn sort_of_self_ty(&self, ty: rustc_middle::ty::Ty) -> Option { + fn sort_of_self_ty(&self, def_id: DefId, ty: rustc_middle::ty::Ty) -> Option { use rustc_middle::ty; // CODESYNC(sort-of, 4) sorts should be given consistently match ty.kind() { @@ -235,8 +301,24 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { ty::TyKind::Slice(_) | ty::TyKind::Int(_) | ty::TyKind::Uint(_) => { Some(fhir::Sort::Int) } - ty::TyKind::Adt(adt_def, _) => Some(fhir::Sort::Record(adt_def.did())), - ty::TyKind::Param(_) => todo!(), + ty::TyKind::Adt(adt_def, args) => { + let mut sort_args = vec![]; + for arg in args.iter() { + if let Some(ty) = arg.as_type() && + let Some(sort) = self.sort_of_self_ty(def_id, ty) + { + sort_args.push(sort) + } + } + Some(fhir::Sort::Record(adt_def.did(), List::from_vec(sort_args))) + } + ty::TyKind::Param(p) => { + let generic_param_def = self + .tcx + .generics_of(def_id) + .param_at(p.index as usize, self.tcx); + self.sort_of_generic_param(generic_param_def.def_id) + } ty::TyKind::Float(_) | ty::TyKind::Str | ty::TyKind::Char @@ -270,8 +352,8 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { | fhir::Sort::BitVec(_) | fhir::Sort::Param(_) | fhir::Sort::Var(_) => true, - fhir::Sort::Record(def_id) => { - self.index_sorts_of(*def_id) + fhir::Sort::Record(def_id, sort_args) => { + self.index_sorts_of(*def_id, sort_args.clone()) .iter() .all(|sort| self.has_equality(sort)) } @@ -288,7 +370,14 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { args.iter().all(|sort| self.has_equality(sort)) } - pub fn field_sort(&self, def_id: DefId, fld: Symbol) -> Option<&fhir::Sort> { + pub fn field_sort( + &self, + def_id: DefId, + sort_args: List, + fld: Symbol, + ) -> Option<&fhir::Sort> { + let generics = self.generics_of(def_id); + // println!("TRACE: field_sort of {def_id:?} with {generics:?}"); if let Some(local_id) = def_id.as_local() { self.map().refined_by(local_id).field_sort(fld) } else { diff --git a/crates/flux-middle/src/rty/mod.rs b/crates/flux-middle/src/rty/mod.rs index 7c8144ebb2..dd96f7853d 100644 --- a/crates/flux-middle/src/rty/mod.rs +++ b/crates/flux-middle/src/rty/mod.rs @@ -205,7 +205,7 @@ pub struct AdtDef(Interned); #[derive(Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] pub struct AdtDefData { invariants: Vec, - sort: Sort, + sort: Sort, // TODO: Binder opaque: bool, rustc: rustc::ty::AdtDef, } diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index d66196af49..fa5e621da0 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -247,6 +247,20 @@ pub enum TyKind { ImplTrait(NodeId, GenericBounds), } +impl Ty { + pub fn as_bty(&self) -> Option<&BaseTy> { + match &self.kind { + TyKind::Base(bty) | TyKind::Indexed { bty, .. } | TyKind::Exists { bty, .. } => { + Some(bty) + } + TyKind::GeneralExists { ty, .. } | TyKind::Constr(_, ty) => ty.as_bty(), + TyKind::Ref(_, _) + | TyKind::Tuple(_) + | TyKind::Array(_, _) + | TyKind::ImplTrait(_, _) => None, + } + } +} #[derive(Debug)] pub struct BaseTy { pub kind: BaseTyKind, From 789d061c33e4098782680628d71bb58a4ef4d1a3 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Mon, 16 Oct 2023 21:53:44 -0700 Subject: [PATCH 11/44] clippy ok --- crates/flux-desugar/src/desugar.rs | 3 ++- crates/flux-fhir-analysis/src/conv.rs | 2 +- crates/flux-middle/src/global_env.rs | 18 +++++++----------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 4aca883387..2192d12250 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1658,7 +1658,7 @@ fn sort_of_surface_path( fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { // TODO: duplication with sort_of_path let mut sort_args = vec![]; - for arg in path.generics.iter() { + for arg in &path.generics { if let surface::GenericArg::Type(ty) = arg && let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind && let Some(sort) = sort_of_surface_path(genv, resolver_output, path) @@ -1680,6 +1680,7 @@ fn sort_of_surface_path( None } fhir::Res::SelfTyAlias { alias_to, .. } => genv.sort_of_self_ty_alias(alias_to), + fhir::Res::Def(..) => bug!("unexpected res {res:?}"), } } diff --git a/crates/flux-fhir-analysis/src/conv.rs b/crates/flux-fhir-analysis/src/conv.rs index 33e08c9adb..a4f4f90dc1 100644 --- a/crates/flux-fhir-analysis/src/conv.rs +++ b/crates/flux-fhir-analysis/src/conv.rs @@ -197,7 +197,7 @@ fn sort_args_for_adt(genv: &GlobalEnv, def_id: impl Into) -> List GlobalEnv<'sess, 'tcx> { pub fn index_sorts_of( &self, def_id: impl Into, - sort_args: List, + _sort_args: List, ) -> &[fhir::Sort] { let def_id = def_id.into(); if let Some(local_id) = def_id.as_local().or_else(|| self.map().get_extern(def_id)) { @@ -211,7 +211,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { // println!("TRACE: sort_of_path (1) {def_id:?} with args = {:?}", path.args); let mut sort_args = vec![]; - for arg in path.args.iter() { + for arg in &path.args { if let fhir::GenericArg::Type(ty) = arg && let Some(sort) = self.sort_of_ty(ty) { @@ -233,12 +233,8 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } pub fn sort_of_self_ty_alias(&self, alias_to: DefId) -> Option { - // let self_ty = self.tcx.type_of(alias_to).skip_binder(); let self_ty = self.tcx.type_of(alias_to).instantiate_identity(); - // println!("TRACE: sort_of_path (3) {alias_to:?} is {self_ty:?}"); - let res = self.sort_of_self_ty(alias_to, self_ty); - // println!("TRACE: sort_of_path (4) {self_ty:?} ==> {res:?}"); - res + self.sort_of_self_ty(alias_to, self_ty) } fn sort_of_generic_param(&self, def_id: DefId) -> Option { @@ -303,11 +299,11 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } ty::TyKind::Adt(adt_def, args) => { let mut sort_args = vec![]; - for arg in args.iter() { + for arg in *args { if let Some(ty) = arg.as_type() && let Some(sort) = self.sort_of_self_ty(def_id, ty) { - sort_args.push(sort) + sort_args.push(sort); } } Some(fhir::Sort::Record(adt_def.did(), List::from_vec(sort_args))) @@ -373,10 +369,10 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn field_sort( &self, def_id: DefId, - sort_args: List, + _sort_args: List, fld: Symbol, ) -> Option<&fhir::Sort> { - let generics = self.generics_of(def_id); + let _generics = self.generics_of(def_id); // println!("TRACE: field_sort of {def_id:?} with {generics:?}"); if let Some(local_id) = def_id.as_local() { self.map().refined_by(local_id).field_sort(fld) From 08ef2991ba97f86d5c08309491eddd412949ead2 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Mon, 16 Oct 2023 21:54:40 -0700 Subject: [PATCH 12/44] mark the places to proceed next --- crates/flux-middle/src/global_env.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 108da668fe..b5562b1102 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -188,7 +188,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn index_sorts_of( &self, def_id: impl Into, - _sort_args: List, + sort_args: List, ) -> &[fhir::Sort] { let def_id = def_id.into(); if let Some(local_id) = def_id.as_local().or_else(|| self.map().get_extern(def_id)) { @@ -209,16 +209,11 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { Some(fhir::Sort::Unit) } fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { - // println!("TRACE: sort_of_path (1) {def_id:?} with args = {:?}", path.args); let mut sort_args = vec![]; for arg in &path.args { if let fhir::GenericArg::Type(ty) = arg && let Some(sort) = self.sort_of_ty(ty) { - // let path = ty.as_path()?; - // sort_args.push(self.sort_of_path(path)?); - // let sort = self.sort_of_ty(ty); - // println!("TRACE: sort_of_path (2) {ty:?} => {sort:?}"); sort_args.push(sort); } } @@ -369,10 +364,10 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn field_sort( &self, def_id: DefId, - _sort_args: List, + sort_args: List, fld: Symbol, ) -> Option<&fhir::Sort> { - let _generics = self.generics_of(def_id); + let generics = self.generics_of(def_id); // println!("TRACE: field_sort of {def_id:?} with {generics:?}"); if let Some(local_id) = def_id.as_local() { self.map().refined_by(local_id).field_sort(fld) From 5c3ba9ccfd669cc981ba8bc26bbdd8e3f5cd274c Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 18 Oct 2023 20:23:29 -0700 Subject: [PATCH 13/44] add rset00 test --- crates/flux-desugar/src/desugar.rs | 42 ++++++++--- crates/flux-desugar/src/lib.rs | 2 - crates/flux-fhir-analysis/src/conv.rs | 9 +-- crates/flux-fhir-analysis/src/wf/mod.rs | 4 +- crates/flux-fhir-analysis/src/wf/sortck.rs | 18 ++--- crates/flux-middle/src/fhir.rs | 75 +++++++++++++++++-- crates/flux-middle/src/fhir/lift.rs | 2 +- crates/flux-middle/src/global_env.rs | 29 ++++--- crates/flux-syntax/src/grammar.lalrpop | 12 +++ crates/flux-syntax/src/surface.rs | 1 + .../{todo/rset.rs => pos/surface/rset00.rs} | 25 +++++-- 11 files changed, 160 insertions(+), 59 deletions(-) rename crates/flux-tests/tests/{todo/rset.rs => pos/surface/rset00.rs} (74%) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 2192d12250..ec899f621d 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1,4 +1,4 @@ -use std::{borrow::Borrow, iter, slice}; +use std::{borrow::Borrow, iter}; use flux_common::{bug, index::IndexGen, iter::IterExt, span_bug}; use flux_errors::FluxSession; @@ -19,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::OwnerId; use rustc_middle::ty::Generics; use rustc_span::{ - def_id::LocalDefId, + def_id::{DefId, LocalDefId}, sym::{self}, symbol::kw, Span, Symbol, @@ -77,6 +77,26 @@ pub fn func_def_to_func_decl( Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) } +fn sort_params( + generics: &rustc_middle::ty::Generics, + refined_by: &surface::RefinedBy, +) -> Vec { + let sort_params: FxHashSet<_> = refined_by + .sort_params + .iter() + .map(|ident| ident.name) + .collect(); + let mut params = vec![]; + for param in &generics.params { + if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && + sort_params.contains(¶m.name) + { + params.push(param.def_id); + } + } + params +} + pub fn desugar_refined_by( sess: &FluxSession, sort_decls: &fhir::SortDecls, @@ -108,8 +128,14 @@ pub fn desugar_refined_by( )) }) .try_collect_exhaust()?; - - Ok(fhir::RefinedBy::new(owner_id.def_id, early_bound_params, index_params, refined_by.span)) + let sort_params: Vec<_> = sort_params(generics, refined_by); + Ok(fhir::RefinedBy::new( + owner_id.def_id, + sort_params, + early_bound_params, + index_params, + refined_by.span, + )) } pub(crate) struct DesugarCtxt<'a, 'tcx> { @@ -718,8 +744,6 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { idxs: &surface::Indices, binders: &mut Binders, ) -> Result { - // let sort = self.genv.sort_of_bty(bty); - // println!("TRACE: desugar_indices {bty:?}: sort = {sort:?}"); if let [surface::RefineArg::Bind(ident, ..)] = &idxs.indices[..] { self.ident_into_refine_arg(*ident, binders) .transpose() @@ -1684,11 +1708,11 @@ fn sort_of_surface_path( fhir::Res::Def(..) => bug!("unexpected res {res:?}"), } } -fn as_tuple<'a>(genv: &'a GlobalEnv, sort: &'a fhir::Sort) -> &'a [fhir::Sort] { +fn as_tuple<'a>(genv: &'a GlobalEnv, sort: &'a fhir::Sort) -> Vec { if let fhir::Sort::Record(def_id, sort_args) = sort { - genv.index_sorts_of(*def_id, sort_args.clone()) + genv.index_sorts_of(*def_id, sort_args) } else { - slice::from_ref(sort) + vec![sort.clone()] } } diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 518916325f..28dae20be4 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -150,8 +150,6 @@ pub fn desugar_fn_sig( // Desugar of fn_sig needs to happen AFTER inserting generics. See crate level comment let (generic_preds, fn_sig) = cx.desugar_fn_sig(fn_sig, &mut Binders::new())?; - // println!("TRACE: desugar_fn_sig {owner_id:?} => {fn_sig:?}"); - if config::dump_fhir() { dbg::dump_item_info(genv.tcx, def_id, "fhir", &fn_sig).unwrap(); } diff --git a/crates/flux-fhir-analysis/src/conv.rs b/crates/flux-fhir-analysis/src/conv.rs index a4f4f90dc1..ed9a289294 100644 --- a/crates/flux-fhir-analysis/src/conv.rs +++ b/crates/flux-fhir-analysis/src/conv.rs @@ -210,7 +210,7 @@ pub(crate) fn adt_def_for_struct( ) -> rty::AdtDef { let def_id = struct_def.owner_id; let sort_args = sort_args_for_adt(genv, def_id); - let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(def_id, sort_args))); + let sort = rty::Sort::tuple(conv_sorts(genv, &genv.index_sorts_of(def_id, &sort_args))); let adt_def = lowering::lower_adt_def(&genv.tcx.adt_def(struct_def.owner_id)); rty::AdtDef::new(adt_def, sort, invariants, struct_def.is_opaque()) } @@ -222,7 +222,7 @@ pub(crate) fn adt_def_for_enum( ) -> rty::AdtDef { let def_id = enum_def.owner_id; let sort_args = sort_args_for_adt(genv, def_id); - let sort = rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(def_id, sort_args))); + let sort = rty::Sort::tuple(conv_sorts(genv, &genv.index_sorts_of(def_id, &sort_args))); let adt_def = lowering::lower_adt_def(&genv.tcx.adt_def(enum_def.owner_id)); rty::AdtDef::new(adt_def, sort, invariants, false) } @@ -654,7 +654,6 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { return Ok(rty::Ty::param(param_ty)); } } - // println!("TRACE: conv_base_ty {bty:?} {sort:?}"); let sort = conv_sort(self.genv, &sort.unwrap()); if sort.is_unit() { let idx = rty::Index::from(rty::Expr::unit()); @@ -1158,8 +1157,8 @@ pub fn conv_sort(genv: &GlobalEnv, sort: &fhir::Sort) -> rty::Sort { fhir::Sort::Loc => rty::Sort::Loc, fhir::Sort::Unit => rty::Sort::unit(), fhir::Sort::Func(fsort) => rty::Sort::Func(conv_func_sort(genv, fsort)), - fhir::Sort::Record(def_id, args) => { - rty::Sort::tuple(conv_sorts(genv, genv.index_sorts_of(*def_id, args.clone()))) + fhir::Sort::Record(def_id, sort_args) => { + rty::Sort::tuple(conv_sorts(genv, &genv.index_sorts_of(*def_id, sort_args))) } fhir::Sort::App(ctor, args) => { let ctor = conv_sort_ctor(ctor); diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index 35fdb2e50a..4d7fefae79 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -436,7 +436,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { ) -> Result<(), ErrorGuaranteed> { match &path.res { fhir::Res::Def(DefKind::TyAlias { .. }, def_id) => { - let sorts = self.genv.early_bound_sorts_of(*def_id); + let sorts = self.genv.early_bound_sorts_of(*def_id, &[]); if path.refine.len() != sorts.len() { return self.emit_err(errors::EarlyBoundArgCountMismatch::new( path.span, @@ -445,7 +445,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { )); } iter::zip(&path.refine, sorts) - .try_for_each_exhaust(|(arg, sort)| self.check_refine_arg(infcx, arg, sort))?; + .try_for_each_exhaust(|(arg, sort)| self.check_refine_arg(infcx, arg, &sort))?; } fhir::Res::SelfTyParam { .. } | fhir::Res::SelfTyAlias { .. } diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index 493f8ee3dd..7d15d8775e 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -6,7 +6,6 @@ use flux_errors::ErrorGuaranteed; use flux_middle::{ fhir::{self, FhirId, FluxOwnerId, WfckResults}, global_env::GlobalEnv, - intern::List, }; use itertools::izip; use rustc_data_structures::unord::UnordMap; @@ -47,7 +46,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.check_abs(params, body, span, fhir_id, expected) } fhir::RefineArg::Record(def_id, sort_args, flds, span) => { - self.check_record(*def_id, sort_args.clone(), flds, *span)?; + self.check_record(*def_id, sort_args, flds, *span)?; let found = fhir::Sort::Record(*def_id, sort_args.clone()); if &found != expected { return Err(self.emit_sort_mismatch(*span, expected, &found)); @@ -93,7 +92,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn check_record( &mut self, def_id: DefId, - sort_args: List, + sort_args: &[fhir::Sort], args: &[fhir::RefineArg], span: Span, ) -> Result<(), ErrorGuaranteed> { @@ -107,7 +106,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ))); } izip!(args, sorts) - .map(|(arg, expected)| self.check_refine_arg(arg, expected)) + .map(|(arg, expected)| self.check_refine_arg(arg, &expected)) .try_collect_exhaust() } @@ -211,11 +210,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let sort = self[var.name].clone(); match &sort { fhir::Sort::Record(def_id, sort_args) => { - // println!("TRACE: synth_expr: var {var:?} => {sort:?} ({def_id:?})"); - // let sort_args = sort_args.clone(); self.genv .field_sort(*def_id, sort_args.clone(), fld.name) - .cloned() .ok_or_else(|| self.emit_field_not_found(&sort, *fld)) } fhir::Sort::Bool | fhir::Sort::Int | fhir::Sort::Real => { @@ -523,10 +519,12 @@ impl<'a> InferCtxt<'a, '_> { }) } - fn is_single_field_record(&mut self, sort: &fhir::Sort) -> Option<&'a fhir::Sort> { + fn is_single_field_record(&mut self, sort: &fhir::Sort) -> Option { self.resolve_sort(sort).and_then(|s| { - if let fhir::Sort::Record(def_id, sort_args) = s && let [sort] = self.genv.index_sorts_of(def_id, sort_args) { - Some(sort) + if let fhir::Sort::Record(def_id, sort_args) = s && + let [sort] = &self.genv.index_sorts_of(def_id, &sort_args)[..] + { + Some(sort.clone()) } else { None } diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 24b304b826..194f9a5887 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -537,6 +537,17 @@ impl PolyFuncSort { .collect(); FuncSort { inputs_and_output } } + + pub fn param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { + let params = self.params; + let args = self + .fsort + .inputs_and_output + .iter() + .map(|arg| arg.param_subst(subst)) + .collect(); + PolyFuncSort { params, fsort: FuncSort { inputs_and_output: args } } + } } #[derive(Clone)] @@ -734,6 +745,8 @@ impl Ident { pub struct RefinedBy { pub def_id: DefId, pub span: Span, + /// Sort parameters e.g. #[flux::refined_by( { elems: Set } )] + sort_params: Vec, /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, /// The number of early bound parameters @@ -776,6 +789,7 @@ impl Generics { impl RefinedBy { pub fn new( def_id: impl Into, + sort_params: impl IntoIterator, early_bound_params: impl IntoIterator, index_params: impl IntoIterator, span: Span, @@ -786,26 +800,49 @@ impl RefinedBy { .into_iter() .inspect(|(_, sort)| sorts.push(sort.clone())) .collect(); - RefinedBy { def_id: def_id.into(), span, index_params, early_bound, sorts } + let sort_params = sort_params.into_iter().collect(); + RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } pub fn field_index(&self, fld: Symbol) -> Option { self.index_params.get_index_of(&fld) } - pub fn field_sort(&self, fld: Symbol) -> Option<&Sort> { - self.index_params.get(&fld) + fn param_subst(&self, sort_args: &[Sort]) -> SortParamSubst { + // TODO: check arities? + self.sort_params + .iter() + .zip(sort_args) + .map(|(def_id, sort)| (*def_id, sort.clone())) + .collect() + } + + pub fn field_sort(&self, fld: Symbol, sort_args: &[Sort]) -> Option { + let subst = self.param_subst(sort_args); + self.index_params + .get(&fld) + .map(|sort| sort.param_subst(&subst)) } - pub fn early_bound_sorts(&self) -> &[Sort] { - &self.sorts[..self.early_bound] + pub fn early_bound_sorts(&self, sort_args: &[Sort]) -> Vec { + let subst = &self.param_subst(sort_args); + self.sorts[..self.early_bound] + .iter() + .map(|sort| sort.param_subst(subst)) + .collect() } - pub fn index_sorts(&self) -> &[Sort] { - &self.sorts[self.early_bound..] + pub fn index_sorts(&self, sort_args: &[Sort]) -> Vec { + let subst = &self.param_subst(sort_args); + self.sorts[self.early_bound..] + .iter() + .map(|sort| sort.param_subst(subst)) + .collect() } } +type SortParamSubst = FxHashMap; + impl Sort { /// Returns `true` if the sort is [`Bool`]. /// @@ -840,7 +877,7 @@ impl Sort { Self::App(SortCtor::Map, List::from_vec(vec![k, v])) } - /// replace all "sort-parameters" (indexed 0...n-1) with the corresponding sort in `subst` + /// replace all "sort-vars" (indexed 0...n-1) with the corresponding sort in `subst` fn subst(&self, subst: &[Sort]) -> Sort { match self { Sort::Int @@ -861,6 +898,28 @@ impl Sort { Sort::Func(_) => bug!("unexpected subst in (nested) func-sort"), } } + + /// replace all `Param(def_id)` with their respective sort in `subst` + fn param_subst(&self, subst: &SortParamSubst) -> Sort { + match self { + Sort::Int + | Sort::Bool + | Sort::Real + | Sort::Loc + | Sort::Unit + | Sort::BitVec(_) + | Sort::Wildcard + | Sort::Record(_, _) + | Sort::Var(_) + | Sort::Infer(_) => self.clone(), + Sort::Param(def_id) => subst.get(def_id).unwrap_or(self).clone(), + Sort::App(c, args) => { + let args = args.iter().map(|arg| arg.param_subst(subst)).collect(); + Sort::App(c.clone(), args) + } + Sort::Func(fsort) => Sort::Func(fsort.param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), + } + } } impl ena::unify::UnifyKey for SortVid { diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index 0fb70246b4..ada680177a 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -25,7 +25,7 @@ pub fn lift_refined_by(tcx: TyCtxt, owner_id: OwnerId) -> fhir::RefinedBy { let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::TyAlias(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => { - fhir::RefinedBy::new(def_id, [], [], item.ident.span) + fhir::RefinedBy::new(def_id, [], [], [], item.ident.span) } _ => { bug!("expected struct, enum or type alias"); diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index b5562b1102..9ffbf75219 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -188,15 +188,15 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn index_sorts_of( &self, def_id: impl Into, - sort_args: List, - ) -> &[fhir::Sort] { + sort_args: &[fhir::Sort], + ) -> Vec { let def_id = def_id.into(); if let Some(local_id) = def_id.as_local().or_else(|| self.map().get_extern(def_id)) { - self.map().refined_by(local_id).index_sorts() + self.map().refined_by(local_id).index_sorts(sort_args) } else { self.cstore() .refined_by(def_id) - .map(fhir::RefinedBy::index_sorts) + .map(|rby| rby.index_sorts(sort_args)) .unwrap_or_default() } } @@ -322,13 +322,13 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } } - pub fn early_bound_sorts_of(&self, def_id: DefId) -> &[fhir::Sort] { + pub fn early_bound_sorts_of(&self, def_id: DefId, sort_args: &[fhir::Sort]) -> Vec { if let Some(local_id) = def_id.as_local() { - self.map().refined_by(local_id).early_bound_sorts() + self.map().refined_by(local_id).early_bound_sorts(sort_args) } else { self.cstore() .refined_by(def_id) - .map(fhir::RefinedBy::early_bound_sorts) + .map(|refined_by| refined_by.early_bound_sorts(sort_args)) .unwrap_or_default() } } @@ -344,7 +344,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { | fhir::Sort::Param(_) | fhir::Sort::Var(_) => true, fhir::Sort::Record(def_id, sort_args) => { - self.index_sorts_of(*def_id, sort_args.clone()) + self.index_sorts_of(*def_id, sort_args) .iter() .all(|sort| self.has_equality(sort)) } @@ -366,16 +366,15 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { def_id: DefId, sort_args: List, fld: Symbol, - ) -> Option<&fhir::Sort> { - let generics = self.generics_of(def_id); - // println!("TRACE: field_sort of {def_id:?} with {generics:?}"); - if let Some(local_id) = def_id.as_local() { - self.map().refined_by(local_id).field_sort(fld) + ) -> Option { + let poly_sort = if let Some(local_id) = def_id.as_local() { + self.map().refined_by(local_id).field_sort(fld, &sort_args) } else { self.cstore() .refined_by(def_id) - .and_then(|refined_by| refined_by.field_sort(fld)) - } + .and_then(|refined_by| refined_by.field_sort(fld, &sort_args)) + }; + poly_sort } pub fn field_index(&self, def_id: DefId, fld: Symbol) -> Option { diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 3a825585e2..411b2bf6db 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -47,6 +47,7 @@ pub TyAlias: surface::TyAlias = { => { let refined_by = surface::RefinedBy { + sort_params: vec![], early_bound_params: early_bound_params.unwrap_or_default(), index_params: index_params.unwrap_or_default(), span: cx.map_span(refined_by_lo, refined_by_hi) @@ -61,8 +62,19 @@ pub TyAlias: surface::TyAlias = { } } +SortParams: Vec = { + "<" > ">" => params, +} + pub RefinedBy: surface::RefinedBy = { + "<" > ">" "{" > "}" => surface::RefinedBy { + sort_params, + index_params, + early_bound_params: vec![], + span: cx.map_span(lo, hi) + }, > => surface::RefinedBy { + sort_params: vec![], index_params, early_bound_params: vec![], span: cx.map_span(lo, hi) diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index fa5e621da0..6f36c5b0b9 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -104,6 +104,7 @@ pub struct VariantRet { #[derive(Debug, Default)] pub struct RefinedBy { + pub sort_params: Vec, pub early_bound_params: Vec, pub index_params: Vec, pub span: Span, diff --git a/crates/flux-tests/tests/todo/rset.rs b/crates/flux-tests/tests/pos/surface/rset00.rs similarity index 74% rename from crates/flux-tests/tests/todo/rset.rs rename to crates/flux-tests/tests/pos/surface/rset00.rs index 72b661faab..416657f682 100644 --- a/crates/flux-tests/tests/todo/rset.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set)] +#[flux::refined_by( { elems: Set })] pub struct RSet { pub inner: std::collections::HashSet, } @@ -39,9 +39,20 @@ where set.inner.contains(elem) } -// pub fn test() { -// let mut s = empty(); -// insert(&mut s, 1); -// assert(contains(&s, &1)); -// assert(!contains(&s, &2)); -// } +pub fn test() { + let mut s = empty(); + let v0 = 666; + let v1 = 667; + insert(&mut s, v0); + assert(contains(&s, &v0)); + assert(!contains(&s, &v1)); +} + +#[flux::sig(fn(&i32[5]))] +fn foo(z: &i32) {} + +fn bar() { + let x = 5; + foo(&x); + foo(&5); +} From ac3bf090e0099671097e7b1b6f28c2b5197027f4 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 18 Oct 2023 20:24:58 -0700 Subject: [PATCH 14/44] add rset00 test --- crates/flux-tests/tests/neg/surface/rset00.rs | 49 +++++++++++++++++++ crates/flux-tests/tests/pos/surface/rset00.rs | 9 ---- 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 crates/flux-tests/tests/neg/surface/rset00.rs diff --git a/crates/flux-tests/tests/neg/surface/rset00.rs b/crates/flux-tests/tests/neg/surface/rset00.rs new file mode 100644 index 0000000000..7c761f8db1 --- /dev/null +++ b/crates/flux-tests/tests/neg/surface/rset00.rs @@ -0,0 +1,49 @@ +use std::hash::Hash; +#[flux::opaque] +#[flux::refined_by( { elems: Set })] +pub struct RSet { + pub inner: std::collections::HashSet, +} + +#[flux::trusted] +#[flux::sig(fn(s: RSet) -> RSet[s.elems])] +pub fn id(s: RSet) -> RSet { + s +} + +#[flux::sig(fn (bool[true]))] +fn assert(_b: bool) {} + +#[flux::trusted] +#[flux::sig(fn() -> RSet[set_empty(0)])] +pub fn empty() -> RSet { + let inner = std::collections::HashSet::new(); + RSet { inner } +} + +#[flux::trusted] +#[flux::sig(fn(set: &strg RSet[@s], elem: T) ensures set: RSet[set_union(set_singleton(elem), s)])] +pub fn insert(set: &mut RSet, elem: T) +where + T: Eq + Hash, +{ + set.inner.insert(elem); +} + +#[flux::trusted] +#[flux::sig(fn(set: &RSet[@s], &A[@elem]) -> bool[set_is_in(elem, s.elems)])] +pub fn contains(set: &RSet, elem: &A) -> bool +where + A: Eq + Hash, +{ + set.inner.contains(elem) +} + +pub fn test() { + let mut s = empty(); + let v0 = 666; + let v1 = 667; + insert(&mut s, v0); + assert(contains(&s, &v0)); + assert(contains(&s, &v1)); //~ ERROR refinement type +} diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index 416657f682..e3058470e9 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -47,12 +47,3 @@ pub fn test() { assert(contains(&s, &v0)); assert(!contains(&s, &v1)); } - -#[flux::sig(fn(&i32[5]))] -fn foo(z: &i32) {} - -fn bar() { - let x = 5; - foo(&x); - foo(&5); -} From c1e2c8978e504baa366f068e66a8468b39fcd552 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 19 Oct 2023 07:01:47 -0700 Subject: [PATCH 15/44] next: implement TODO_walk_over_sorts --- crates/flux-desugar/src/desugar.rs | 20 ---------- crates/flux-middle/src/fhir.rs | 40 +++++++++++++++++-- crates/flux-middle/src/fhir/lift.rs | 4 +- .../tests/neg/error_messages/wf/poly_sort.rs | 7 ++++ 4 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index ec899f621d..c0a2c5920c 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -77,26 +77,6 @@ pub fn func_def_to_func_decl( Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) } -fn sort_params( - generics: &rustc_middle::ty::Generics, - refined_by: &surface::RefinedBy, -) -> Vec { - let sort_params: FxHashSet<_> = refined_by - .sort_params - .iter() - .map(|ident| ident.name) - .collect(); - let mut params = vec![]; - for param in &generics.params { - if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && - sort_params.contains(¶m.name) - { - params.push(param.def_id); - } - } - params -} - pub fn desugar_refined_by( sess: &FluxSession, sort_decls: &fhir::SortDecls, diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 194f9a5887..68d5a6e04e 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -30,7 +30,7 @@ use rustc_data_structures::{ fx::FxIndexMap, unord::{ExtendUnord, UnordMap, UnordSet}, }; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; pub use rustc_hir::PrimTy; use rustc_hir::{ def::DefKind, @@ -789,7 +789,7 @@ impl Generics { impl RefinedBy { pub fn new( def_id: impl Into, - sort_params: impl IntoIterator, + generics: &Generics, early_bound_params: impl IntoIterator, index_params: impl IntoIterator, span: Span, @@ -800,10 +800,44 @@ impl RefinedBy { .into_iter() .inspect(|(_, sort)| sorts.push(sort.clone())) .collect(); - let sort_params = sort_params.into_iter().collect(); + // let sort_params = sort_params.into_iter().collect(); + let sort_params = Self::sort_params(generics, &sorts); RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } + fn sort_params(generics: &Generics, sorts: &Vec) -> Vec { + // let sort_params: FxHashSet<_> = refined_by + // .sort_params + // .iter() + // .map(|ident| ident.name) + // .collect(); + let mut sort_params: FxHashSet = Default::default(); + + TODO_walk_over_sorts_to_gather_all_Param_defids(); + + let mut params = vec![]; + for param in &generics.params { + let def_id = param.def_id.to_def_id(); + if let GenericParamKind::Type { .. } = param.kind && + sort_params.contains(&def_id) + { + params.push(def_id); + } + } + params + } + + pub fn trivial(def_id: impl Into, span: Span) -> Self { + RefinedBy { + def_id: def_id.into(), + sort_params: vec![], + span, + index_params: Default::default(), + early_bound: 0, + sorts: vec![], + } + } + pub fn field_index(&self, fld: Symbol) -> Option { self.index_params.get_index_of(&fld) } diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index ada680177a..ee4d98fa22 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -20,12 +20,12 @@ pub struct LiftCtxt<'a, 'tcx> { owner: OwnerId, } -pub fn lift_refined_by(tcx: TyCtxt, owner_id: OwnerId) -> fhir::RefinedBy { +pub fn lift_refined_by(tcx: TyCtxt, sess: &FluxSession, owner_id: OwnerId) -> fhir::RefinedBy { let def_id = owner_id.def_id; let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::TyAlias(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => { - fhir::RefinedBy::new(def_id, [], [], [], item.ident.span) + fhir::RefinedBy::trivial(def_id, item.ident.span) } _ => { bug!("expected struct, enum or type alias"); diff --git a/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs b/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs new file mode 100644 index 0000000000..860193eb30 --- /dev/null +++ b/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs @@ -0,0 +1,7 @@ +use std::hash::Hash; +#[flux::opaque] +// #[flux::refined_by( { elems: Set })] +#[flux::refined_by( elems: Set )] //~ ERROR unbound generic `Tiger` +pub struct RSet { + pub inner: std::collections::HashSet, +} From 90aec9fbd976ac5c35868529f9e98e8478ff18f3 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 09:59:17 -0700 Subject: [PATCH 16/44] remove sort_params from RefinedBy; find it from Sorts --- README.md | 21 +++++++++ crates/flux-desugar/src/desugar.rs | 5 +- crates/flux-middle/src/fhir.rs | 46 ++++++++++++++----- crates/flux-middle/src/fhir/lift.rs | 2 +- crates/flux-syntax/src/grammar.lalrpop | 8 ---- crates/flux-syntax/src/surface.rs | 1 - .../tests/neg/error_messages/wf/poly_sort.rs | 13 ++++-- crates/flux-tests/tests/neg/surface/rset00.rs | 2 +- crates/flux-tests/tests/pos/surface/rset00.rs | 2 +- 9 files changed, 70 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 63073569ab..81ad189c5b 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,24 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). Documentation, including installation and usage guides can be found on the [website](https://flux-rs.github.io/flux). + +----- +fn sort_params( + generics: &rustc_middle::ty::Generics, + refined_by: &surface::RefinedBy, +) -> Vec { + let sort_params: FxHashSet<_> = refined_by + .sort_params + .iter() + .map(|ident| ident.name) + .collect(); + let mut params = vec![]; + for param in &generics.params { + if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && + sort_params.contains(¶m.name) + { + params.push(param.def_id); + } + } + params +} \ No newline at end of file diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index c0a2c5920c..39a7f7c618 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -19,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::OwnerId; use rustc_middle::ty::Generics; use rustc_span::{ - def_id::{DefId, LocalDefId}, + def_id::LocalDefId, sym::{self}, symbol::kw, Span, Symbol, @@ -108,10 +108,9 @@ pub fn desugar_refined_by( )) }) .try_collect_exhaust()?; - let sort_params: Vec<_> = sort_params(generics, refined_by); Ok(fhir::RefinedBy::new( owner_id.def_id, - sort_params, + &generics, early_bound_params, index_params, refined_by.span, diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 68d5a6e04e..2c1a7ce0b9 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -789,7 +789,7 @@ impl Generics { impl RefinedBy { pub fn new( def_id: impl Into, - generics: &Generics, + generics: &rustc_middle::ty::Generics, early_bound_params: impl IntoIterator, index_params: impl IntoIterator, span: Span, @@ -800,25 +800,21 @@ impl RefinedBy { .into_iter() .inspect(|(_, sort)| sorts.push(sort.clone())) .collect(); - // let sort_params = sort_params.into_iter().collect(); let sort_params = Self::sort_params(generics, &sorts); RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - fn sort_params(generics: &Generics, sorts: &Vec) -> Vec { - // let sort_params: FxHashSet<_> = refined_by - // .sort_params - // .iter() - // .map(|ident| ident.name) - // .collect(); + fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { let mut sort_params: FxHashSet = Default::default(); - TODO_walk_over_sorts_to_gather_all_Param_defids(); + for sort in sorts { + sort.gather_sort_params(&mut sort_params); + } let mut params = vec![]; for param in &generics.params { - let def_id = param.def_id.to_def_id(); - if let GenericParamKind::Type { .. } = param.kind && + let def_id = param.def_id; + if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && sort_params.contains(&def_id) { params.push(def_id); @@ -954,6 +950,34 @@ impl Sort { Sort::Func(fsort) => Sort::Func(fsort.param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), } } + + pub fn gather_sort_params(&self, params: &mut FxHashSet) { + match self { + Sort::Int + | Sort::Bool + | Sort::Real + | Sort::Loc + | Sort::Unit + | Sort::BitVec(_) + | Sort::Var(_) + | Sort::Infer(_) + | Sort::Wildcard => {} + Sort::Param(def_id) => { + params.insert(*def_id); + } + Sort::App(_, args) => { + for arg in args { + arg.gather_sort_params(params); + } + } + Sort::Func(fsort) => { + for arg in &fsort.fsort.inputs_and_output { + arg.gather_sort_params(params); + } + } + Sort::Record(_, _) => bug!("unexpected record sort"), + } + } } impl ena::unify::UnifyKey for SortVid { diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index ee4d98fa22..9d08d37e0f 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -20,7 +20,7 @@ pub struct LiftCtxt<'a, 'tcx> { owner: OwnerId, } -pub fn lift_refined_by(tcx: TyCtxt, sess: &FluxSession, owner_id: OwnerId) -> fhir::RefinedBy { +pub fn lift_refined_by(tcx: TyCtxt, owner_id: OwnerId) -> fhir::RefinedBy { let def_id = owner_id.def_id; let item = tcx.hir().expect_item(def_id); match item.kind { diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 411b2bf6db..6ab9bcf802 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -47,7 +47,6 @@ pub TyAlias: surface::TyAlias = { => { let refined_by = surface::RefinedBy { - sort_params: vec![], early_bound_params: early_bound_params.unwrap_or_default(), index_params: index_params.unwrap_or_default(), span: cx.map_span(refined_by_lo, refined_by_hi) @@ -67,14 +66,7 @@ SortParams: Vec = { } pub RefinedBy: surface::RefinedBy = { - "<" > ">" "{" > "}" => surface::RefinedBy { - sort_params, - index_params, - early_bound_params: vec![], - span: cx.map_span(lo, hi) - }, > => surface::RefinedBy { - sort_params: vec![], index_params, early_bound_params: vec![], span: cx.map_span(lo, hi) diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index 6f36c5b0b9..fa5e621da0 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -104,7 +104,6 @@ pub struct VariantRet { #[derive(Debug, Default)] pub struct RefinedBy { - pub sort_params: Vec, pub early_bound_params: Vec, pub index_params: Vec, pub span: Span, diff --git a/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs b/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs index 860193eb30..d9705df59c 100644 --- a/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs +++ b/crates/flux-tests/tests/neg/error_messages/wf/poly_sort.rs @@ -1,7 +1,12 @@ use std::hash::Hash; #[flux::opaque] -// #[flux::refined_by( { elems: Set })] -#[flux::refined_by( elems: Set )] //~ ERROR unbound generic `Tiger` -pub struct RSet { - pub inner: std::collections::HashSet, +#[flux::refined_by(elems: Set)] //~ ERROR cannot find sort `Tiger` +pub struct Foo { + pub inner: std::collections::HashSet, +} + +#[flux::opaque] +#[flux::refined_by(elems: Set)] //~ ERROR cannot find sort `Set` +pub struct Bar { + pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/neg/surface/rset00.rs b/crates/flux-tests/tests/neg/surface/rset00.rs index 7c761f8db1..1bcfa6afdd 100644 --- a/crates/flux-tests/tests/neg/surface/rset00.rs +++ b/crates/flux-tests/tests/neg/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by( { elems: Set })] +#[flux::refined_by(elems: Set)] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index e3058470e9..438b43c542 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by( { elems: Set })] +#[flux::refined_by(elems: Set )] pub struct RSet { pub inner: std::collections::HashSet, } From 01d021d0061878116f5910f529a981f8976b09dc Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 18:32:55 -0700 Subject: [PATCH 17/44] support impl blocks --- README.md | 23 +-------- crates/flux-desugar/src/desugar.rs | 50 +++++++++---------- crates/flux-desugar/src/lib.rs | 13 ++++- crates/flux-driver/src/callbacks.rs | 17 ++++--- crates/flux-driver/src/collector.rs | 27 ++++++++++ crates/flux-syntax/src/grammar.lalrpop | 2 +- crates/flux-syntax/src/lib.rs | 8 +++ crates/flux-tests/tests/neg/surface/rset01.rs | 15 ++++++ crates/flux-tests/tests/pos/surface/rset01.rs | 15 ++++++ 9 files changed, 112 insertions(+), 58 deletions(-) create mode 100644 crates/flux-tests/tests/neg/surface/rset01.rs create mode 100644 crates/flux-tests/tests/pos/surface/rset01.rs diff --git a/README.md b/README.md index 81ad189c5b..0d3ddccd53 100644 --- a/README.md +++ b/README.md @@ -15,25 +15,4 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). # Docs Documentation, including installation and usage guides can be found on the -[website](https://flux-rs.github.io/flux). - ------ -fn sort_params( - generics: &rustc_middle::ty::Generics, - refined_by: &surface::RefinedBy, -) -> Vec { - let sort_params: FxHashSet<_> = refined_by - .sort_params - .iter() - .map(|ident| ident.name) - .collect(); - let mut params = vec![]; - for param in &generics.params { - if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && - sort_params.contains(¶m.name) - { - params.push(param.def_id); - } - } - params -} \ No newline at end of file +[website](https://flux-rs.github.io/flux). \ No newline at end of file diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 39a7f7c618..c2eb31e46d 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -196,9 +196,25 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { pub(crate) fn desugar_generics(&self, generics: &surface::Generics) -> Result { let hir_generics = self.genv.hir().get_generics(self.owner.def_id).unwrap(); - let generics_map: FxHashMap<_, _> = hir_generics - .params - .iter() + + let hir_generic_params = hir_generics.params.iter(); + // let parent_generic_params = self + // .genv + // .tcx + // .opt_local_parent(self.owner.def_id) + // .map(|parent_def_id| { + // self.genv + // .hir() + // .get_generics(parent_def_id) + // .unwrap() + // .params + // .iter() + // }) + // .into_iter() + // .flatten(); + + let generics_map: FxHashMap<_, _> = hir_generic_params + // .chain(parent_generic_params) .flat_map(|param| { if let hir::ParamName::Plain(name) = param.name { Some((name, param.def_id)) @@ -1076,19 +1092,6 @@ impl DesugarCtxt<'_, '_> { } }) } - // ORIGINAL - // fn gather_params_variant_ret( - // &self, - // ret: &surface::VariantRet, - // binders: &mut Binders, - // ) -> Result { - // self.gather_params_path(&ret.path, TypePos::Other, binders)?; - // let res = self.resolver_output.path_res_map[&ret.path.node_id]; - // let Some(sort) = self.genv.sort_of_res(res) else { - // return Err(self.emit_err(errors::RefinedUnrefinableType::new(ret.path.span))); - // }; - // self.gather_params_indices(sort, &ret.indices, TypePos::Other, binders) - // } fn gather_params_variant_ret( &self, @@ -1096,7 +1099,6 @@ impl DesugarCtxt<'_, '_> { binders: &mut Binders, ) -> Result { self.gather_params_path(&ret.path, TypePos::Other, binders)?; - // let Some(sort) = self.resolver_output.sort_of_surface_path(&ret.path) else { let Some(sort) = sort_of_surface_path(self.genv, self.resolver_output, &ret.path) else { return Err(self.emit_err(errors::RefinedUnrefinableType::new(ret.path.span))); }; @@ -1520,14 +1522,6 @@ impl Binders { Binder::Refined(self.fresh(), sort, true) } - // fn binder_from_res(&self, genv: &GlobalEnv, res: fhir::Res) -> Binder { - // if let Some(sort) = genv.sort_of_res(res) { - // self.binder_from_sort(sort) - // } else { - // Binder::Unrefined - // } - // } - fn binder_from_bty( &self, genv: &GlobalEnv, @@ -1637,14 +1631,15 @@ fn index_sort( bty: &surface::BaseTy, ) -> Option { // CODESYNC(sort-of, 4) sorts should be given consistently - match &bty.kind { + let res = match &bty.kind { surface::BaseTyKind::Path(path) => { sort_of_surface_path(genv, resolver_output, path) // let res = resolver_output.path_res_map[&path.node_id]; // genv.sort_of_res(res) } surface::BaseTyKind::Slice(_) => Some(fhir::Sort::Int), - } + }; + res } fn sort_of_surface_path( @@ -1673,6 +1668,7 @@ fn sort_of_surface_path( } fhir::Res::Def(DefKind::TyParam, def_id) => { let param = genv.get_generic_param(def_id.expect_local()); + match ¶m.kind { fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 28dae20be4..f701dcde19 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -178,10 +178,19 @@ pub fn desugar_fn_sig( pub fn desugar_generics_and_predicates( genv: &mut GlobalEnv, owner_id: OwnerId, + resolver_output: &ResolverOutput, + generics: Option<&surface::Generics>, ) -> Result<(), ErrorGuaranteed> { - let def_id = owner_id.def_id; - let (generics, predicates) = + let (lifted_generics, predicates) = LiftCtxt::new(genv.tcx, genv.sess, owner_id, None).lift_generics_with_predicates()?; + + let generics = if let Some(generics) = generics { + let cx = DesugarCtxt::new(genv, owner_id, resolver_output, None); + cx.desugar_generics(generics)? + } else { + lifted_generics + }; + let def_id = owner_id.def_id; genv.map().insert_generics(def_id, generics); genv.map_mut().insert_generic_predicates(def_id, predicates); Ok(()) diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index af9af15f9f..77830e8655 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -275,7 +275,9 @@ fn desugar_item( let ty_alias = specs.ty_aliases[&owner_id].as_ref(); desugar::desugar_type_alias(genv, owner_id, ty_alias, resolver_output)?; } - hir::ItemKind::OpaqueTy(_) => desugar::desugar_generics_and_predicates(genv, owner_id)?, + hir::ItemKind::OpaqueTy(_) => { + desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, None)? + } hir::ItemKind::Enum(..) => { let enum_def = &specs.enums[&owner_id]; desugar::desugar_enum_def(genv, owner_id, enum_def, resolver_output)?; @@ -285,7 +287,7 @@ fn desugar_item( desugar::desugar_struct_def(genv, owner_id, struct_def, resolver_output)?; } hir::ItemKind::Trait(.., items) => { - desugar::desugar_generics_and_predicates(genv, owner_id)?; + desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, None)?; items.iter().try_for_each_exhaust(|trait_item| { desugar_assoc_item( genv, @@ -297,7 +299,8 @@ fn desugar_item( })?; } hir::ItemKind::Impl(impl_) => { - desugar::desugar_generics_and_predicates(genv, owner_id)?; + let generics = specs.impls.get(&owner_id); + desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, generics)?; impl_.items.iter().try_for_each_exhaust(|impl_item| { desugar_assoc_item( genv, @@ -318,11 +321,13 @@ fn desugar_assoc_item( specs: &mut Specs, owner_id: OwnerId, kind: hir::AssocItemKind, - resolver_outpt: &ResolverOutput, + resolver_output: &ResolverOutput, ) -> Result<(), ErrorGuaranteed> { match kind { - hir::AssocItemKind::Fn { .. } => desugar_fn_sig(genv, specs, owner_id, resolver_outpt), - hir::AssocItemKind::Type => desugar::desugar_generics_and_predicates(genv, owner_id), + hir::AssocItemKind::Fn { .. } => desugar_fn_sig(genv, specs, owner_id, resolver_output), + hir::AssocItemKind::Type => { + desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, None) + } hir::AssocItemKind::Const => Ok(()), } } diff --git a/crates/flux-driver/src/collector.rs b/crates/flux-driver/src/collector.rs index 29768cd629..66e82d44fc 100644 --- a/crates/flux-driver/src/collector.rs +++ b/crates/flux-driver/src/collector.rs @@ -41,6 +41,7 @@ pub type Ignores = UnordSet; pub(crate) struct Specs { pub fn_sigs: UnordMap, pub structs: FxHashMap, + pub impls: FxHashMap, pub enums: FxHashMap, pub qualifs: Vec, pub func_defs: Vec, @@ -101,6 +102,7 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { ItemKind::Mod(..) => collector.parse_mod_spec(owner_id.def_id, attrs), ItemKind::TyAlias(..) => collector.parse_tyalias_spec(owner_id, attrs), ItemKind::Const(..) => collector.parse_const_spec(item, attrs), + ItemKind::Impl(_) => collector.parse_impl_spec(owner_id, attrs), _ => Ok(()), }; } @@ -185,6 +187,21 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { } } + fn parse_impl_spec( + &mut self, + owner_id: OwnerId, + attrs: &[Attribute], + ) -> Result<(), ErrorGuaranteed> { + let mut attrs = self.parse_flux_attrs(attrs)?; + self.report_dups(&attrs)?; + + if let Some(generics) = attrs.generics() { + self.specs.impls.insert(owner_id, generics); + } + + Ok(()) + } + fn parse_tyalias_spec( &mut self, owner_id: OwnerId, @@ -361,6 +378,9 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { ("refined_by", AttrArgs::Delimited(dargs)) => { self.parse(dargs, ParseSess::parse_refined_by, FluxAttrKind::RefinedBy)? } + ("generics", AttrArgs::Delimited(dargs)) => { + self.parse(dargs, ParseSess::parse_generics, FluxAttrKind::Generics)? + } ("field", AttrArgs::Delimited(dargs)) => { self.parse(dargs, ParseSess::parse_type, FluxAttrKind::Field)? } @@ -489,6 +509,7 @@ impl Specs { fn new() -> Specs { Specs { fn_sigs: Default::default(), + impls: Default::default(), structs: Default::default(), enums: Default::default(), qualifs: Vec::default(), @@ -546,6 +567,7 @@ enum FluxAttrKind { Opaque, FnSig(surface::FnSig), RefinedBy(surface::RefinedBy), + Generics(surface::Generics), QualNames(surface::QualNames), Items(Vec), TypeAlias(surface::TyAlias), @@ -636,6 +658,10 @@ impl FluxAttrs { read_attr!(self, RefinedBy) } + fn generics(&mut self) -> Option { + read_attr!(self, Generics) + } + fn field(&mut self) -> Option { read_attr!(self, Field) } @@ -674,6 +700,7 @@ impl FluxAttrKind { FluxAttrKind::FnSig(_) => attr_name!(FnSig), FluxAttrKind::ConstSig(_) => attr_name!(ConstSig), FluxAttrKind::RefinedBy(_) => attr_name!(RefinedBy), + FluxAttrKind::Generics(_) => attr_name!(Generics), FluxAttrKind::Items(_) => attr_name!(Items), FluxAttrKind::QualNames(_) => attr_name!(QualNames), FluxAttrKind::Field(_) => attr_name!(Field), diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 6ab9bcf802..1c9c8176a2 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -10,7 +10,7 @@ use lalrpop_util::ParseError; grammar(cx: &mut ParseCtxt<'_>); -Generics: surface::Generics = { +pub Generics: surface::Generics = { "<" > ">" => { surface::Generics { params, diff --git a/crates/flux-syntax/src/lib.rs b/crates/flux-syntax/src/lib.rs index 13640fee8c..98805e3f1b 100644 --- a/crates/flux-syntax/src/lib.rs +++ b/crates/flux-syntax/src/lib.rs @@ -41,6 +41,14 @@ impl ParseSess { parse!(self, grammar::RefinedByParser, tokens, span) } + pub fn parse_generics( + &mut self, + tokens: &TokenStream, + span: Span, + ) -> ParseResult { + parse!(self, grammar::GenericsParser, tokens, span) + } + pub fn parse_type_alias( &mut self, tokens: &TokenStream, diff --git a/crates/flux-tests/tests/neg/surface/rset01.rs b/crates/flux-tests/tests/neg/surface/rset01.rs new file mode 100644 index 0000000000..95d0c17450 --- /dev/null +++ b/crates/flux-tests/tests/neg/surface/rset01.rs @@ -0,0 +1,15 @@ +#[path = "../../lib/rset.rs"] +mod rset; +use rset::RSet; + +#[flux::sig(fn (bool[true]))] +fn assert(_b: bool) {} + +pub fn test() { + let mut s = RSet::new(); + let v0 = 666; + let v1 = 667; + s.insert(v0); + assert(s.contains(&v0)); + assert(s.contains(&v1)); //~ ERROR refinement type +} diff --git a/crates/flux-tests/tests/pos/surface/rset01.rs b/crates/flux-tests/tests/pos/surface/rset01.rs new file mode 100644 index 0000000000..068d3bf67a --- /dev/null +++ b/crates/flux-tests/tests/pos/surface/rset01.rs @@ -0,0 +1,15 @@ +#[path = "../../lib/rset.rs"] +mod rset; +use rset::RSet; + +#[flux::sig(fn (bool[true]))] +fn assert(_b: bool) {} + +pub fn test() { + let mut s = RSet::new(); + let v0 = 666; + let v1 = 667; + s.insert(v0); + assert(s.contains(&v0)); + assert(!s.contains(&v1)); +} From 93f15b28f1ffc4af91be00175b50ef6e9cabfa1c Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 18:52:05 -0700 Subject: [PATCH 18/44] ok. --- crates/flux-tests/tests/neg/surface/rset01.rs | 10 ++++++++++ crates/flux-tests/tests/pos/surface/rset01.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/crates/flux-tests/tests/neg/surface/rset01.rs b/crates/flux-tests/tests/neg/surface/rset01.rs index 95d0c17450..f0e219751f 100644 --- a/crates/flux-tests/tests/neg/surface/rset01.rs +++ b/crates/flux-tests/tests/neg/surface/rset01.rs @@ -13,3 +13,13 @@ pub fn test() { assert(s.contains(&v0)); assert(s.contains(&v1)); //~ ERROR refinement type } + +#[flux::sig(fn () -> RSet)] +pub fn test1() -> RSet { + let mut s = RSet::new(); + let v0 = 666; + let v1 = 667; + s.insert(v0); + s.insert(v1); + s //~ ERROR refinement type +} diff --git a/crates/flux-tests/tests/pos/surface/rset01.rs b/crates/flux-tests/tests/pos/surface/rset01.rs index 068d3bf67a..983f835fd8 100644 --- a/crates/flux-tests/tests/pos/surface/rset01.rs +++ b/crates/flux-tests/tests/pos/surface/rset01.rs @@ -13,3 +13,13 @@ pub fn test() { assert(s.contains(&v0)); assert(!s.contains(&v1)); } + +#[flux::sig(fn () -> RSet)] +pub fn test1() -> RSet { + let mut s = RSet::new(); + let v0 = 666; + let v1 = 667; + s.insert(v0); + s.insert(v1); + s +} From 14085775fbf2e8889cabbb1b37f3864a223d4510 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 19:14:03 -0700 Subject: [PATCH 19/44] next: tweak func-def parser --- crates/flux-tests/tests/lib/rmap.rs | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index a8c429f586..cf4c078b20 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -1,32 +1,41 @@ #![allow(dead_code)] #![flux::defs { - fn map_set(m:Map, k: int, v: int) -> Map { map_store(m, k, v) } - fn map_get(m: Map, k:int) -> int { map_select(m, k) } - fn map_def(v:int) -> Map { map_default(v) } + fn map_set(m:Map, k: K, v: V) -> Map { map_store(m, k, v) } + fn map_get(m: Map, k:K) -> V { map_select(m, k) } + fn map_def(v:V) -> Map { map_default(v) } }] +use std::hash::Hash; + /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by(map: Map)] -pub struct RMap { - inner: std::collections::HashMap, +#[flux::refined_by(map: Map)] +pub struct RMap { + inner: std::collections::HashMap, } -impl RMap { +#[flux::generics()] +impl RMap { #[flux::trusted] pub fn new() -> Self { Self { inner: std::collections::HashMap::new() } } #[flux::trusted] - #[flux::sig(fn(self: &strg RMap[@m], k: i32, v: i32) ensures self: RMap[map_set(m, k, v)])] - pub fn set(&mut self, k: i32, v: i32) { + #[flux::sig(fn(self: &strg RMap[@m], k: K, v: V) ensures self: RMap[map_set(m, k, v)])] + pub fn set(&mut self, k: K, v: V) + where + K: Eq + Hash, + { self.inner.insert(k, v); } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], k: i32) -> Option)] - pub fn get(&self, k: i32) -> Option { - self.inner.get(&k).copied() + #[flux::sig(fn(&RMap[@m], k: K) -> Option<&V[map_get(m, k)]>)] + pub fn get(&self, k: K) -> Option<&V> + where + K: Eq + Hash, + { + self.inner.get(&k) } } From 15865d67cc94f236fe632180887a99b0f0fe2470 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 22:55:47 -0700 Subject: [PATCH 20/44] done. --- crates/flux-desugar/src/desugar.rs | 69 ++++++++++++------- crates/flux-driver/src/callbacks.rs | 2 +- crates/flux-middle/src/fhir.rs | 1 + crates/flux-syntax/src/grammar.lalrpop | 13 ++-- crates/flux-syntax/src/surface.rs | 1 + crates/flux-tests/tests/lib/rmap.rs | 4 +- crates/flux-tests/tests/lib/rmapk.rs | 62 ++++++++++------- crates/flux-tests/tests/neg/surface/maps00.rs | 15 ++-- crates/flux-tests/tests/neg/surface/maps01.rs | 19 ++--- 9 files changed, 119 insertions(+), 67 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index c2eb31e46d..51eceb6ad9 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -33,7 +33,7 @@ pub fn desugar_qualifier( genv: &GlobalEnv, qualifier: &surface::Qualifier, ) -> Result { - let mut binders = Binders::from_params(genv, &qualifier.args)?; + let mut binders = Binders::from_params(genv, None, &qualifier.args)?; let index_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(qualifier.name.name), &index_gen); let expr = cx.desugar_expr(&binders, &qualifier.expr); @@ -48,14 +48,22 @@ pub fn desugar_qualifier( pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result> { if let Some(body) = defn.body { - let mut binders = Binders::from_params(genv, &defn.args)?; + let sort_vars = Some(&defn.sort_vars[..]); + let mut binders = Binders::from_params(genv, sort_vars, &defn.args)?; let local_id_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(defn.name.name), &local_id_gen); let expr = cx.desugar_expr(&binders, &body)?; let name = defn.name.name; - let sort = SortResolver::resolve(genv.sess, genv.map().sort_decls(), None, &defn.output)?; + let params = defn.sort_vars.len(); + let sort = SortResolver::resolve( + genv.sess, + genv.map().sort_decls(), + sort_vars, + None, + &defn.output, + )?; let args = binders.pop_layer().into_params(&cx); - Ok(Some(fhir::Defn { name, args, sort, expr })) + Ok(Some(fhir::Defn { name, params, args, sort, expr })) } else { Ok(None) } @@ -66,13 +74,15 @@ pub fn func_def_to_func_decl( sort_decls: &fhir::SortDecls, defn: &surface::FuncDef, ) -> Result { + let params = defn.sort_vars.len(); + let sort_vars = Some(&defn.sort_vars[..]); let inputs: Vec = defn .args .iter() - .map(|arg| SortResolver::resolve(sess, sort_decls, None, &arg.sort)) + .map(|arg| SortResolver::resolve(sess, sort_decls, sort_vars, None, &arg.sort)) .try_collect_exhaust()?; - let output = SortResolver::resolve(sess, sort_decls, None, &defn.output)?; - let sort = fhir::PolyFuncSort::new(0, inputs, output); + let output = SortResolver::resolve(sess, sort_decls, sort_vars, None, &defn.output)?; + let sort = fhir::PolyFuncSort::new(params, inputs, output); let kind = if defn.body.is_some() { fhir::FuncKind::Def } else { fhir::FuncKind::Uif }; Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) } @@ -95,7 +105,7 @@ pub fn desugar_refined_by( let early_bound_params: Vec<_> = refined_by .early_bound_params .iter() - .map(|param| SortResolver::resolve(sess, sort_decls, Some(generics), ¶m.sort)) + .map(|param| SortResolver::resolve(sess, sort_decls, None, Some(generics), ¶m.sort)) .try_collect_exhaust()?; let index_params: Vec<_> = refined_by @@ -104,13 +114,13 @@ pub fn desugar_refined_by( .map(|param| { Ok(( param.name.name, - SortResolver::resolve(sess, sort_decls, Some(generics), ¶m.sort)?, + SortResolver::resolve(sess, sort_decls, None, Some(generics), ¶m.sort)?, )) }) .try_collect_exhaust()?; Ok(fhir::RefinedBy::new( owner_id.def_id, - &generics, + generics, early_bound_params, index_params, refined_by.span, @@ -301,6 +311,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.insert_params( self.genv, Some(self.owner), + None, struct_def .refined_by .iter() @@ -364,6 +375,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders.insert_params( self.genv, Some(self.owner), + None, enum_def .refined_by .iter() @@ -424,7 +436,12 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params(self.genv, Some(self.owner), ty_alias.refined_by.all_params())?; + binders.insert_params( + self.genv, + Some(self.owner), + None, + ty_alias.refined_by.all_params(), + )?; let ty = self.desugar_ty(None, &ty_alias.ty, binders)?; @@ -662,6 +679,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { let sort = SortResolver::resolve( self.sess(), self.genv.map().sort_decls(), + None, Some(generics), ¶m.sort, )?; @@ -781,7 +799,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { } surface::RefineArg::Abs(params, body, span) => { binders.push_layer(); - binders.insert_params(self.genv, Some(self.owner), params)?; + binders.insert_params(self.genv, Some(self.owner), None, params)?; let body = self.as_expr_ctxt().desugar_expr(binders, body)?; let params = binders.pop_layer().into_params(self); Ok(fhir::RefineArg::Abs(params, body, *span, self.next_fhir_id())) @@ -1131,6 +1149,7 @@ impl DesugarCtxt<'_, '_> { SortResolver::resolve( self.genv.sess, self.genv.map().sort_decls(), + None, Some(generics), sort, )?, @@ -1344,19 +1363,24 @@ struct SortResolver<'a> { sess: &'a FluxSession, sort_decls: &'a fhir::SortDecls, generic_params: FxHashMap, + sort_params: FxHashMap, } impl<'a> SortResolver<'a> { pub fn resolve( sess: &'a FluxSession, sort_decls: &'a fhir::SortDecls, + sort_vars: Option<&[surface::Ident]>, generics: Option<&'a Generics>, sort: &surface::Sort, ) -> Result { let generic_params = generics .map(|g| g.params.iter().map(|p| (p.name, p.def_id)).collect()) .unwrap_or_default(); - let sr = Self { sess, sort_decls, generic_params }; + let sort_params = sort_vars + .map(|vars| vars.iter().enumerate().map(|(i, v)| (v.name, i)).collect()) + .unwrap_or_default(); + let sr = Self { sess, sort_decls, generic_params, sort_params }; sr.resolve_sort(sort) } @@ -1433,8 +1457,9 @@ impl<'a> SortResolver<'a> { Ok(fhir::Sort::App(ctor, List::empty())) } else if let Some(def_id) = self.generic_params.get(&ident.name) { Ok(fhir::Sort::Param(*def_id)) + } else if let Some(idx) = self.sort_params.get(&ident.name) { + Ok(fhir::Sort::Var(*idx)) } else { - // panic!("ICE: unknown sort: {:?} with {:?}", ident.name, self.generics); Err(self.sess.emit_err(errors::UnresolvedSort::new(*ident))) } } @@ -1447,11 +1472,12 @@ impl Binders { fn from_params<'a>( genv: &GlobalEnv, + sort_vars: Option<&[surface::Ident]>, params: impl IntoIterator, ) -> Result { let mut binders = Self::new(); binders.push_layer(); - binders.insert_params(genv, None, params)?; + binders.insert_params(genv, None, sort_vars, params)?; Ok(binders) } @@ -1459,6 +1485,7 @@ impl Binders { &mut self, genv: &GlobalEnv, owner: Option, + sort_vars: Option<&[surface::Ident]>, params: impl IntoIterator, ) -> Result { let generics = owner.map(|id| genv.tcx.generics_of(id)); @@ -1471,6 +1498,7 @@ impl Binders { SortResolver::resolve( genv.sess, genv.map().sort_decls(), + sort_vars, generics, ¶m.sort, )?, @@ -1631,15 +1659,10 @@ fn index_sort( bty: &surface::BaseTy, ) -> Option { // CODESYNC(sort-of, 4) sorts should be given consistently - let res = match &bty.kind { - surface::BaseTyKind::Path(path) => { - sort_of_surface_path(genv, resolver_output, path) - // let res = resolver_output.path_res_map[&path.node_id]; - // genv.sort_of_res(res) - } + match &bty.kind { + surface::BaseTyKind::Path(path) => sort_of_surface_path(genv, resolver_output, path), surface::BaseTyKind::Slice(_) => Some(fhir::Sort::Int), - }; - res + } } fn sort_of_surface_path( diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index 77830e8655..3f7c3ed5dc 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -276,7 +276,7 @@ fn desugar_item( desugar::desugar_type_alias(genv, owner_id, ty_alias, resolver_output)?; } hir::ItemKind::OpaqueTy(_) => { - desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, None)? + desugar::desugar_generics_and_predicates(genv, owner_id, resolver_output, None)?; } hir::ItemKind::Enum(..) => { let enum_def = &specs.enums[&owner_id]; diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 2c1a7ce0b9..e5222497ce 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -775,6 +775,7 @@ pub enum FuncKind { #[derive(Debug)] pub struct Defn { pub name: Symbol, + pub params: usize, pub args: Vec, pub sort: Sort, pub expr: Expr, diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 1c9c8176a2..0a7dab0000 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -96,14 +96,19 @@ Qualifier: surface::Qualifier = { } FuncDef: surface::FuncDef = { - "fn" "(" > ")" "->" "{" "}" => { - surface::FuncDef { name, args, output, body: Some(body) } + "fn" "(" > ")" "->" "{" "}" => { + surface::FuncDef { name, sort_vars: vars.unwrap_or_default(), args, output, body: Some(body) } }, - "fn" "(" > ")" "->" ";" => { - surface::FuncDef { name, args, output, body: None } + "fn" "(" > ")" "->" ";" => { + surface::FuncDef { name, sort_vars: vars.unwrap_or_default(), args, output, body: None } } } +SortVars: Vec = { + "<" > ">" => vars, +} + + SortDecl: surface::SortDecl = { "opaque" "sort" ";" => { surface::SortDecl { name } diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index fa5e621da0..13472139b4 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -38,6 +38,7 @@ pub struct Qualifier { #[derive(Debug)] pub struct FuncDef { pub name: Ident, + pub sort_vars: Vec, pub args: Vec, pub output: Sort, /// Body of the function. If not present this definition corresponds to an uninterpreted function. diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index cf4c078b20..c5979998c1 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -31,8 +31,8 @@ impl RMap { } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], k: K) -> Option<&V[map_get(m, k)]>)] - pub fn get(&self, k: K) -> Option<&V> + #[flux::sig(fn(&RMap[@m], &K[@k]) -> Option<&V[map_get(m, k)]>)] + pub fn get(&self, k: &K) -> Option<&V> where K: Eq + Hash, { diff --git a/crates/flux-tests/tests/lib/rmapk.rs b/crates/flux-tests/tests/lib/rmapk.rs index 8bfee12967..2cd9c0e72a 100644 --- a/crates/flux-tests/tests/lib/rmapk.rs +++ b/crates/flux-tests/tests/lib/rmapk.rs @@ -1,48 +1,64 @@ #![allow(dead_code)] #![flux::defs { - fn map_set(m:Map, k: int, v: int) -> Map { map_store(m, k, v) } - fn map_get(m: Map, k:int) -> int { map_select(m, k) } - fn map_def(v:int) -> Map { map_default(v) } - fn set_add(x: int, s: Set) -> Set { set_union(set_singleton(x), s) } - fn set_is_empty(s: Set) -> bool { s == set_empty(0) } - fn set_emp() -> Set { set_empty(0) } + fn map_set(m:Map, k: K, v: V) -> Map { map_store(m, k, v) } + fn map_get(m: Map, k:K) -> V { map_select(m, k) } + fn map_def(v:V) -> Map { map_default(v) } + fn set_add(x: T, s: Set) -> Set { set_union(set_singleton(x), s) } + fn set_is_empty(s: Set) -> bool { s == set_empty(0) } + fn set_emp() -> Set { set_empty(0) } }] + +use std::hash::Hash; + /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by(keys: Set, vals: Map)] -pub struct RMap { - inner: std::collections::HashMap, +#[flux::refined_by(keys: Set, vals: Map)] +pub struct RMap { + inner: std::collections::HashMap, } -impl RMap { +#[flux::generics()] +impl RMap { #[flux::trusted] - #[flux::sig(fn() -> RMap[set_empty(0), map_def(0)])] + #[flux::sig(fn() -> RMap{m: m.keys == set_empty(0)})] pub fn new() -> Self { Self { inner: std::collections::HashMap::new() } } #[flux::trusted] - #[flux::sig(fn(self: &strg RMap[@m], k: i32, v: i32) - ensures self: RMap[set_add(k, m.keys), map_set(m.vals, k, v)])] - pub fn set(&mut self, k: i32, v: i32) { + #[flux::sig(fn(self: &strg RMap[@m], k: K, v: V) + ensures self: RMap[set_add(k, m.keys), map_set(m.vals, k, v)])] + pub fn set(&mut self, k: K, v: V) + where + K: Eq + Hash, + { self.inner.insert(k, v); } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], k: i32) -> Option)] - pub fn get(&self, k: i32) -> Option { - self.inner.get(&k).copied() + #[flux::sig(fn(&RMap[@m], &K[@k]) -> Option<&V[map_get(m.vals, k)]>)] + pub fn get(&self, k: &K) -> Option<&V> + where + K: Eq + Hash, + { + self.inner.get(k) } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], k: i32) -> i32[map_get(m.vals, k)] requires set_is_in(k, m.keys))] - pub fn lookup(&self, k: i32) -> i32 { - *self.inner.get(&k).unwrap() + #[flux::sig(fn(&RMap[@m], &K[@k]) -> &V[map_get(m.vals, k)] requires set_is_in(k, m.keys))] + pub fn lookup(&self, k: &K) -> &V + where + K: Eq + Hash, + { + self.inner.get(k).unwrap() } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], k: i32) -> bool[set_is_in(k, m.keys)])] - pub fn contains(&self, k: i32) -> bool { - self.inner.contains_key(&k) + #[flux::sig(fn(&RMap[@m], &K[@k]) -> bool[set_is_in(k, m.keys)])] + pub fn contains(&self, k: &K) -> bool + where + K: Eq + Hash, + { + self.inner.contains_key(k) } } diff --git a/crates/flux-tests/tests/neg/surface/maps00.rs b/crates/flux-tests/tests/neg/surface/maps00.rs index c705466366..d91e84dc83 100644 --- a/crates/flux-tests/tests/neg/surface/maps00.rs +++ b/crates/flux-tests/tests/neg/surface/maps00.rs @@ -7,11 +7,14 @@ fn assert(_b: bool) {} pub fn test() { let mut m = RMap::new(); - m.set(10, 1); - m.set(20, 2); + let k0 = 10; + let k1 = 20; + let k2 = 30; - assert(1 + 1 == 2); - assert(m.get(10).unwrap() == 1); - assert(m.get(20).unwrap() == 2); - assert(m.get(30).unwrap() == 3); //~ ERROR refinement type + m.set(k0, 1); + m.set(k1, 2); + + assert(*m.get(&k0).unwrap() == 1); + assert(*m.get(&k1).unwrap() == 2); + assert(*m.get(&k2).unwrap() == 3); //~ ERROR refinement type } diff --git a/crates/flux-tests/tests/neg/surface/maps01.rs b/crates/flux-tests/tests/neg/surface/maps01.rs index 2f73ef9944..b5cd006f45 100644 --- a/crates/flux-tests/tests/neg/surface/maps01.rs +++ b/crates/flux-tests/tests/neg/surface/maps01.rs @@ -7,13 +7,16 @@ fn assert(_b: bool) {} pub fn test() { let mut m = RMap::new(); - m.set(10, 1); - m.set(20, 2); + let k0 = 10; + let k1 = 20; + let k2 = 30; - assert(1 + 1 == 2); - assert(m.get(20).unwrap() == 2); - assert(m.lookup(10) == 1); - assert(m.lookup(20) == 2); - assert(m.contains(10)); - assert(m.contains(30)); //~ ERROR refinement type + m.set(k0, 1); + m.set(k1, 2); + + assert(*m.get(&k1).unwrap() == 2); + assert(*m.lookup(&k0) == 1); + assert(*m.lookup(&k1) == 2); + assert(m.contains(&k0)); + assert(m.contains(&k2)); //~ ERROR refinement type } From da1814426de4c0cb44f72fa581c317e3c2eb112f Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 20 Oct 2023 23:05:19 -0700 Subject: [PATCH 21/44] oops, add files --- crates/flux-tests/tests/lib/rset.rs | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 crates/flux-tests/tests/lib/rset.rs diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs new file mode 100644 index 0000000000..3aa8eeed5f --- /dev/null +++ b/crates/flux-tests/tests/lib/rset.rs @@ -0,0 +1,37 @@ +#![allow(dead_code)] + +use std::hash::Hash; + +#[flux::opaque] +#[flux::refined_by(elems: Set )] +pub struct RSet { + pub inner: std::collections::HashSet, +} + +#[flux::generics()] +impl RSet { + #[flux::trusted] + #[flux::sig(fn() -> RSet[set_empty(0)])] + pub fn new() -> RSet { + let inner = std::collections::HashSet::new(); + RSet { inner } + } + + #[flux::trusted] + #[flux::sig(fn (set: &strg RSet[@s], elem: T) ensures set: RSet[set_union(set_singleton(elem), s)])] + pub fn insert(self: &mut Self, elem: T) + where + T: Eq + Hash, + { + self.inner.insert(elem); + } + + #[flux::trusted] + #[flux::sig(fn(set: &RSet[@s], &T[@elem]) -> bool[set_is_in(elem, s.elems)])] + pub fn contains(self: &Self, elem: &T) -> bool + where + T: Eq + Hash, + { + self.inner.contains(elem) + } +} From 07b2e954e02ede148044d1564d1140ce0066a563 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Mon, 23 Oct 2023 18:01:14 -0700 Subject: [PATCH 22/44] split SortResolver::resolve into with_x and resolve_sort --- crates/flux-desugar/src/desugar.rs | 166 +++++++++++++++-------------- 1 file changed, 88 insertions(+), 78 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 51eceb6ad9..01d80a53f7 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -33,7 +33,7 @@ pub fn desugar_qualifier( genv: &GlobalEnv, qualifier: &surface::Qualifier, ) -> Result { - let mut binders = Binders::from_params(genv, None, &qualifier.args)?; + let mut binders = Binders::from_params(genv, &[], &qualifier.args)?; let index_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(qualifier.name.name), &index_gen); let expr = cx.desugar_expr(&binders, &qualifier.expr); @@ -48,20 +48,15 @@ pub fn desugar_qualifier( pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result> { if let Some(body) = defn.body { - let sort_vars = Some(&defn.sort_vars[..]); - let mut binders = Binders::from_params(genv, sort_vars, &defn.args)?; + let sort_params = &defn.sort_vars[..]; + let mut binders = Binders::from_params(genv, sort_params, &defn.args)?; let local_id_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(defn.name.name), &local_id_gen); let expr = cx.desugar_expr(&binders, &body)?; let name = defn.name.name; let params = defn.sort_vars.len(); - let sort = SortResolver::resolve( - genv.sess, - genv.map().sort_decls(), - sort_vars, - None, - &defn.output, - )?; + let sort = SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params) + .resolve_sort(&defn.output)?; let args = binders.pop_layer().into_params(&cx); Ok(Some(fhir::Defn { name, params, args, sort, expr })) } else { @@ -75,13 +70,14 @@ pub fn func_def_to_func_decl( defn: &surface::FuncDef, ) -> Result { let params = defn.sort_vars.len(); - let sort_vars = Some(&defn.sort_vars[..]); + let sort_vars = &defn.sort_vars[..]; + let sr = SortResolver::with_sort_params(sess, sort_decls, sort_vars); let inputs: Vec = defn .args .iter() - .map(|arg| SortResolver::resolve(sess, sort_decls, sort_vars, None, &arg.sort)) + .map(|arg| sr.resolve_sort(&arg.sort)) .try_collect_exhaust()?; - let output = SortResolver::resolve(sess, sort_decls, sort_vars, None, &defn.output)?; + let output = sr.resolve_sort(&defn.output)?; let sort = fhir::PolyFuncSort::new(params, inputs, output); let kind = if defn.body.is_some() { fhir::FuncKind::Def } else { fhir::FuncKind::Uif }; Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) @@ -102,21 +98,18 @@ pub fn desugar_refined_by( Ok(()) } })?; + let sr = SortResolver::with_generics(sess, sort_decls, generics); + let early_bound_params: Vec<_> = refined_by .early_bound_params .iter() - .map(|param| SortResolver::resolve(sess, sort_decls, None, Some(generics), ¶m.sort)) + .map(|param| sr.resolve_sort(¶m.sort)) .try_collect_exhaust()?; let index_params: Vec<_> = refined_by .index_params .iter() - .map(|param| { - Ok(( - param.name.name, - SortResolver::resolve(sess, sort_decls, None, Some(generics), ¶m.sort)?, - )) - }) + .map(|param| Ok((param.name.name, sr.resolve_sort(¶m.sort)?))) .try_collect_exhaust()?; Ok(fhir::RefinedBy::new( owner_id.def_id, @@ -308,10 +301,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params( + binders.insert_params_with_owner( self.genv, - Some(self.owner), - None, + self.owner, struct_def .refined_by .iter() @@ -372,10 +364,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { .try_collect_exhaust()?; binders.push_layer(); - binders.insert_params( + binders.insert_params_with_owner( self.genv, - Some(self.owner), - None, + self.owner, enum_def .refined_by .iter() @@ -436,10 +427,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params( + binders.insert_params_with_owner( self.genv, - Some(self.owner), - None, + self.owner, ty_alias.refined_by.all_params(), )?; @@ -674,15 +664,14 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { } surface::TyKind::GeneralExists { params, ty, pred } => { binders.push_layer(); + let sr = SortResolver::with_generics( + self.sess(), + self.genv.map().sort_decls(), + generics, + ); for param in params { let fresh = binders.fresh(); - let sort = SortResolver::resolve( - self.sess(), - self.genv.map().sort_decls(), - None, - Some(generics), - ¶m.sort, - )?; + let sort = sr.resolve_sort(¶m.sort)?; let binder = Binder::Refined(fresh, sort.clone(), false); binders.insert_binder(self.sess(), param.name, binder)?; } @@ -799,7 +788,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { } surface::RefineArg::Abs(params, body, span) => { binders.push_layer(); - binders.insert_params(self.genv, Some(self.owner), None, params)?; + binders.insert_params_with_owner(self.genv, self.owner, params)?; let body = self.as_expr_ctxt().desugar_expr(binders, body)?; let params = binders.pop_layer().into_params(self); Ok(fhir::RefineArg::Abs(params, body, *span, self.next_fhir_id())) @@ -1139,22 +1128,14 @@ impl DesugarCtxt<'_, '_> { fn gather_input_params_fn_sig(&self, fn_sig: &surface::FnSig, binders: &mut Binders) -> Result { let generics = self.genv.tcx.generics_of(self.owner.def_id); + let sr = + SortResolver::with_generics(self.genv.sess, self.genv.map().sort_decls(), generics); for param in fn_sig.generics.iter().flat_map(|g| &g.params) { let surface::GenericParamKind::Refine { sort } = ¶m.kind else { continue }; binders.insert_binder( self.genv.sess, param.name, - Binder::Refined( - binders.fresh(), - SortResolver::resolve( - self.genv.sess, - self.genv.map().sort_decls(), - None, - Some(generics), - sort, - )?, - false, - ), + Binder::Refined(binders.fresh(), sr.resolve_sort(sort)?, false), )?; } for arg in &fn_sig.args { @@ -1367,23 +1348,45 @@ struct SortResolver<'a> { } impl<'a> SortResolver<'a> { - pub fn resolve( + pub fn with_sort_params( sess: &'a FluxSession, sort_decls: &'a fhir::SortDecls, - sort_vars: Option<&[surface::Ident]>, - generics: Option<&'a Generics>, - sort: &surface::Sort, - ) -> Result { - let generic_params = generics - .map(|g| g.params.iter().map(|p| (p.name, p.def_id)).collect()) - .unwrap_or_default(); - let sort_params = sort_vars - .map(|vars| vars.iter().enumerate().map(|(i, v)| (v.name, i)).collect()) - .unwrap_or_default(); - let sr = Self { sess, sort_decls, generic_params, sort_params }; - sr.resolve_sort(sort) + sort_params: &[surface::Ident], + ) -> Self { + let sort_params = sort_params + .iter() + .enumerate() + .map(|(i, v)| (v.name, i)) + .collect(); + Self { sess, sort_decls, generic_params: Default::default(), sort_params } } + pub fn with_generics( + sess: &'a FluxSession, + sort_decls: &'a fhir::SortDecls, + generics: &'a Generics, + ) -> Self { + let generic_params = generics.params.iter().map(|p| (p.name, p.def_id)).collect(); + Self { sess, sort_decls, sort_params: Default::default(), generic_params } + } + + // pub fn resolve( + // sess: &'a FluxSession, + // sort_decls: &'a fhir::SortDecls, + // sort_vars: Option<&[surface::Ident]>, + // generics: Option<&'a Generics>, + // sort: &surface::Sort, + // ) -> Result { + // let generic_params = generics + // .map(|g| g.params.iter().map(|p| (p.name, p.def_id)).collect()) + // .unwrap_or_default(); + // let sort_params = sort_vars + // .map(|vars| vars.iter().enumerate().map(|(i, v)| (v.name, i)).collect()) + // .unwrap_or_default(); + // let sr = Self { sess, sort_decls, generic_params, sort_params }; + // sr.resolve_sort(sort) + // } + fn resolve_sort(&self, sort: &surface::Sort) -> Result { match sort { surface::Sort::Base(sort) => self.resolve_base_sort(sort), @@ -1472,38 +1475,45 @@ impl Binders { fn from_params<'a>( genv: &GlobalEnv, - sort_vars: Option<&[surface::Ident]>, + sort_params: &[surface::Ident], params: impl IntoIterator, ) -> Result { let mut binders = Self::new(); binders.push_layer(); - binders.insert_params(genv, None, sort_vars, params)?; + binders.insert_params_with_sort_params(genv, sort_params, params)?; Ok(binders) } - fn insert_params<'a>( + fn insert_params_with_owner<'a>( + &mut self, + genv: &GlobalEnv, + owner: OwnerId, + params: impl IntoIterator, + ) -> Result { + let generics = genv.tcx.generics_of(owner); + let sr = SortResolver::with_generics(genv.sess, genv.map().sort_decls(), generics); + for param in params { + self.insert_binder( + genv.sess, + param.name, + Binder::Refined(self.fresh(), sr.resolve_sort(¶m.sort)?, false), + )?; + } + Ok(()) + } + + fn insert_params_with_sort_params<'a>( &mut self, genv: &GlobalEnv, - owner: Option, - sort_vars: Option<&[surface::Ident]>, + sort_params: &[surface::Ident], params: impl IntoIterator, ) -> Result { - let generics = owner.map(|id| genv.tcx.generics_of(id)); + let sr = SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); for param in params { self.insert_binder( genv.sess, param.name, - Binder::Refined( - self.fresh(), - SortResolver::resolve( - genv.sess, - genv.map().sort_decls(), - sort_vars, - generics, - ¶m.sort, - )?, - false, - ), + Binder::Refined(self.fresh(), sr.resolve_sort(¶m.sort)?, false), )?; } Ok(()) From 672d1bbdd46559ded389d3d1c161a0d333148119 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Tue, 24 Oct 2023 06:01:19 -0700 Subject: [PATCH 23/44] simplify binders.insert_params --- crates/flux-desugar/src/desugar.rs | 46 ++++++++++---------------- crates/flux-desugar/src/lib.rs | 9 ++--- crates/flux-middle/src/global_env.rs | 28 ---------------- crates/flux-syntax/src/grammar.lalrpop | 9 ++--- crates/flux-tests/tests/lib/rmap.rs | 2 +- crates/flux-tests/tests/lib/rmapk.rs | 2 +- crates/flux-tests/tests/lib/rset.rs | 2 +- 7 files changed, 29 insertions(+), 69 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 01d80a53f7..783668b5da 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -33,7 +33,11 @@ pub fn desugar_qualifier( genv: &GlobalEnv, qualifier: &surface::Qualifier, ) -> Result { - let mut binders = Binders::from_params(genv, &[], &qualifier.args)?; + let sort_params = &[]; + let sort_resolver = + SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); + + let mut binders = Binders::from_params(genv, &sort_resolver, &qualifier.args)?; let index_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(qualifier.name.name), &index_gen); let expr = cx.desugar_expr(&binders, &qualifier.expr); @@ -49,14 +53,15 @@ pub fn desugar_qualifier( pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result> { if let Some(body) = defn.body { let sort_params = &defn.sort_vars[..]; - let mut binders = Binders::from_params(genv, sort_params, &defn.args)?; + let sort_resolver = + SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); + let mut binders = Binders::from_params(genv, &sort_resolver, &defn.args)?; let local_id_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(defn.name.name), &local_id_gen); let expr = cx.desugar_expr(&binders, &body)?; let name = defn.name.name; let params = defn.sort_vars.len(); - let sort = SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params) - .resolve_sort(&defn.output)?; + let sort = sort_resolver.resolve_sort(&defn.output)?; let args = binders.pop_layer().into_params(&cx); Ok(Some(fhir::Defn { name, params, args, sort, expr })) } else { @@ -200,24 +205,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { pub(crate) fn desugar_generics(&self, generics: &surface::Generics) -> Result { let hir_generics = self.genv.hir().get_generics(self.owner.def_id).unwrap(); - let hir_generic_params = hir_generics.params.iter(); - // let parent_generic_params = self - // .genv - // .tcx - // .opt_local_parent(self.owner.def_id) - // .map(|parent_def_id| { - // self.genv - // .hir() - // .get_generics(parent_def_id) - // .unwrap() - // .params - // .iter() - // }) - // .into_iter() - // .flatten(); - - let generics_map: FxHashMap<_, _> = hir_generic_params - // .chain(parent_generic_params) + let generics_map: FxHashMap<_, _> = hir_generics + .params + .iter() .flat_map(|param| { if let hir::ParamName::Plain(name) = param.name { Some((name, param.def_id)) @@ -1475,12 +1465,12 @@ impl Binders { fn from_params<'a>( genv: &GlobalEnv, - sort_params: &[surface::Ident], + sort_resolver: &SortResolver, params: impl IntoIterator, ) -> Result { let mut binders = Self::new(); binders.push_layer(); - binders.insert_params_with_sort_params(genv, sort_params, params)?; + binders.insert_params(genv, sort_resolver, params)?; Ok(binders) } @@ -1502,18 +1492,18 @@ impl Binders { Ok(()) } - fn insert_params_with_sort_params<'a>( + fn insert_params<'a>( &mut self, genv: &GlobalEnv, - sort_params: &[surface::Ident], + sort_resolver: &SortResolver, params: impl IntoIterator, ) -> Result { - let sr = SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); + // let sr = SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); for param in params { self.insert_binder( genv.sess, param.name, - Binder::Refined(self.fresh(), sr.resolve_sort(¶m.sort)?, false), + Binder::Refined(self.fresh(), sort_resolver.resolve_sort(¶m.sort)?, false), )?; } Ok(()) diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index f701dcde19..97c77b8a66 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -1,6 +1,6 @@ //! Desugaring from types in [`flux_syntax::surface`] to types in [`flux_middle::fhir`] //! -//! # [NOTE:Generics-and-Desugaring] +//! # Generics-and-Desugaring //! //! Desugaring requires knowing the sort of each type so we can correctly resolve binders declared with //! @ syntax or arg syntax. In particular, to know the sort of a type parameter we need to know its @@ -56,7 +56,7 @@ pub fn desugar_struct_def( let (generics, predicates) = cx.as_lift_cx().lift_generics_with_predicates()?; genv.map().insert_generics(def_id, generics); - // Desugar of struct_def needs to happen AFTER inserting generics. See [NOTE:Generics-and-Desugaring] + // Desugar of struct_def needs to happen AFTER inserting generics. See #generics-and-desugaring let struct_def = cx.desugar_struct_def(struct_def, &mut Binders::new())?; if config::dump_fhir() { dbg::dump_item_info(genv.tcx, owner_id, "fhir", &struct_def).unwrap(); @@ -173,8 +173,9 @@ pub fn desugar_fn_sig( } /// HACK(nilehmann) this is a bit of a hack. We use it to properly register generics and predicates -/// for items that don't have surface syntax (impl blocks, traits, ...). In this cases we just [lift] -/// them from hir. +/// for items that don't have surface syntax (impl blocks, traits, ...), or for `impl` blocks with +/// explicit `generics` annotations. In the former case, we use `desugar`; in the latter cases we +/// just [lift] them from hir. pub fn desugar_generics_and_predicates( genv: &mut GlobalEnv, owner_id: OwnerId, diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 9ffbf75219..f44c431f27 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -240,34 +240,6 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } } - // pub fn sort_of_res(&self, res: fhir::Res) -> Option { - // // CODESYNC(sort-of, 4) sorts should be given consistently - // match res { - // fhir::Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) => Some(fhir::Sort::Int), - // fhir::Res::PrimTy(PrimTy::Bool) => Some(fhir::Sort::Bool), - // fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => { - // Some(fhir::Sort::Unit) - // } - // fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { - // Some(fhir::Sort::Record(def_id)) - // } - // fhir::Res::SelfTyAlias { alias_to, .. } => { - // let self_ty = self.tcx.type_of(alias_to).skip_binder(); - // self.sort_of_self_ty(self_ty) - // } - // fhir::Res::Def(DefKind::TyParam, def_id) => { - // let param = self.get_generic_param(def_id.expect_local()); - // match ¶m.kind { - // fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), - // fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, - // } - // } - // fhir::Res::Def(DefKind::AssocTy | DefKind::OpaqueTy, _) - // | fhir::Res::SelfTyParam { .. } => None, - // fhir::Res::Def(..) => bug!("unexpected res {res:?}"), - // } - // } - fn sort_of_ty(&self, ty: &fhir::Ty) -> Option { match &ty.kind { fhir::TyKind::BaseTy(bty) | fhir::TyKind::Indexed(bty, _) => { diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 0a7dab0000..939afe9b36 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -11,7 +11,7 @@ use lalrpop_util::ParseError; grammar(cx: &mut ParseCtxt<'_>); pub Generics: surface::Generics = { - "<" > ">" => { + > => { surface::Generics { params, span: cx.map_span(lo, hi), @@ -61,10 +61,6 @@ pub TyAlias: surface::TyAlias = { } } -SortParams: Vec = { - "<" > ">" => params, -} - pub RefinedBy: surface::RefinedBy = { > => surface::RefinedBy { index_params, @@ -150,7 +146,7 @@ pub FnSig: surface::FnSig = { "fn" - + ")?> "(" ")" " )?> @@ -166,6 +162,7 @@ pub FnSig: surface::FnSig = { } else { surface::FnRetTy::Default(cx.map_span(ret_lo, ret_hi)) }; + let generics = generics.map(|z| z.1); surface::FnSig { asyncness, generics, diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index c5979998c1..7dc175b203 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -14,7 +14,7 @@ pub struct RMap { inner: std::collections::HashMap, } -#[flux::generics()] +#[flux::generics(K as base, V as base)] impl RMap { #[flux::trusted] pub fn new() -> Self { diff --git a/crates/flux-tests/tests/lib/rmapk.rs b/crates/flux-tests/tests/lib/rmapk.rs index 2cd9c0e72a..0e142fa457 100644 --- a/crates/flux-tests/tests/lib/rmapk.rs +++ b/crates/flux-tests/tests/lib/rmapk.rs @@ -17,7 +17,7 @@ pub struct RMap { inner: std::collections::HashMap, } -#[flux::generics()] +#[flux::generics(K as base, V as base)] impl RMap { #[flux::trusted] #[flux::sig(fn() -> RMap{m: m.keys == set_empty(0)})] diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 3aa8eeed5f..70a244e03d 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -8,7 +8,7 @@ pub struct RSet { pub inner: std::collections::HashSet, } -#[flux::generics()] +#[flux::generics(T as base)] impl RSet { #[flux::trusted] #[flux::sig(fn() -> RSet[set_empty(0)])] From 82b86780d9a5988e334ff4255be49f07d66419d2 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 25 Oct 2023 10:44:40 -0700 Subject: [PATCH 24/44] apply nico's suggestions --- crates/flux-desugar/src/desugar.rs | 53 ++++++++++++------------------ 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 783668b5da..ef97cd84de 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -131,6 +131,7 @@ pub(crate) struct DesugarCtxt<'a, 'tcx> { owner: OwnerId, resolver_output: &'a ResolverOutput, opaque_tys: Option<&'a mut UnordMap>, + sort_resolver: SortResolver<'a>, } /// Keeps track of the surface level identifiers in scope and a mapping between them and a @@ -187,7 +188,17 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { resolver_output: &'a ResolverOutput, opaque_tys: Option<&'a mut UnordMap>, ) -> DesugarCtxt<'a, 'tcx> { - DesugarCtxt { genv, owner, local_id_gen: IndexGen::new(), resolver_output, opaque_tys } + let generics = genv.tcx.generics_of(owner); + let sort_resolver = + SortResolver::with_generics(genv.sess, genv.map().sort_decls(), generics); + DesugarCtxt { + genv, + owner, + local_id_gen: IndexGen::new(), + sort_resolver, + resolver_output, + opaque_tys, + } } fn with_new_owner<'b>(&'b mut self, owner: OwnerId) -> DesugarCtxt<'b, 'tcx> { @@ -291,9 +302,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params_with_owner( + binders.insert_params( self.genv, - self.owner, + &self.sort_resolver, struct_def .refined_by .iter() @@ -354,9 +365,9 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { .try_collect_exhaust()?; binders.push_layer(); - binders.insert_params_with_owner( + binders.insert_params( self.genv, - self.owner, + &self.sort_resolver, enum_def .refined_by .iter() @@ -417,11 +428,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { binders: &mut Binders, ) -> Result { binders.push_layer(); - binders.insert_params_with_owner( - self.genv, - self.owner, - ty_alias.refined_by.all_params(), - )?; + binders.insert_params(self.genv, &self.sort_resolver, ty_alias.refined_by.all_params())?; let ty = self.desugar_ty(None, &ty_alias.ty, binders)?; @@ -778,7 +785,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { } surface::RefineArg::Abs(params, body, span) => { binders.push_layer(); - binders.insert_params_with_owner(self.genv, self.owner, params)?; + binders.insert_params(self.genv, &self.sort_resolver, params)?; let body = self.as_expr_ctxt().desugar_expr(binders, body)?; let params = binders.pop_layer().into_params(self); Ok(fhir::RefineArg::Abs(params, body, *span, self.next_fhir_id())) @@ -1445,13 +1452,13 @@ impl<'a> SortResolver<'a> { Ok(fhir::Sort::Bool) } else if ident.name == SORTS.real { Ok(fhir::Sort::Real) - } else if self.sort_decls.get(&ident.name).is_some() { - let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; - Ok(fhir::Sort::App(ctor, List::empty())) } else if let Some(def_id) = self.generic_params.get(&ident.name) { Ok(fhir::Sort::Param(*def_id)) } else if let Some(idx) = self.sort_params.get(&ident.name) { Ok(fhir::Sort::Var(*idx)) + } else if self.sort_decls.get(&ident.name).is_some() { + let ctor = fhir::SortCtor::User { name: ident.name, arity: 0 }; + Ok(fhir::Sort::App(ctor, List::empty())) } else { Err(self.sess.emit_err(errors::UnresolvedSort::new(*ident))) } @@ -1474,24 +1481,6 @@ impl Binders { Ok(binders) } - fn insert_params_with_owner<'a>( - &mut self, - genv: &GlobalEnv, - owner: OwnerId, - params: impl IntoIterator, - ) -> Result { - let generics = genv.tcx.generics_of(owner); - let sr = SortResolver::with_generics(genv.sess, genv.map().sort_decls(), generics); - for param in params { - self.insert_binder( - genv.sess, - param.name, - Binder::Refined(self.fresh(), sr.resolve_sort(¶m.sort)?, false), - )?; - } - Ok(()) - } - fn insert_params<'a>( &mut self, genv: &GlobalEnv, From 1a390a96ef7cc85917f2a03e930d50e8fe4c4e16 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 25 Oct 2023 12:11:50 -0700 Subject: [PATCH 25/44] appease codesync --- crates/flux-desugar/src/desugar.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index ef97cd84de..710b65d175 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1659,6 +1659,7 @@ fn sort_of_surface_path( resolver_output: &ResolverOutput, path: &surface::Path, ) -> Option { + // CODESYNC(sort-of, 4) sorts should be given consistently let res = resolver_output.path_res_map[&path.node_id]; match res { From 3c5acdb5ab54bb7a3853d5612f8562d1c1d28895 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Fri, 27 Oct 2023 17:07:25 -0700 Subject: [PATCH 26/44] upto upto test00_bad --- crates/flux-desugar/src/desugar.rs | 17 ----- crates/flux-desugar/src/lib.rs | 8 ++- crates/flux-driver/src/collector.rs | 7 +- crates/flux-fhir-analysis/locales/en-US.ftl | 4 +- crates/flux-fhir-analysis/src/lib.rs | 1 - crates/flux-fhir-analysis/src/wf/errors.rs | 14 ++++ crates/flux-fhir-analysis/src/wf/mod.rs | 57 +++++++++++++-- crates/flux-fhir-analysis/src/wf/sortck.rs | 72 ++++++++++++++++++- crates/flux-middle/src/fhir.rs | 21 +++--- crates/flux-middle/src/fhir/lift.rs | 5 ++ crates/flux-middle/src/global_env.rs | 3 +- crates/flux-middle/src/rustc/ty.rs | 3 +- crates/flux-syntax/src/surface.rs | 1 + crates/flux-tests/tests/lib/rset.rs | 2 +- .../tests/neg/error_messages/wf/rset_base.rs | 67 +++++++++++++++++ crates/flux-tests/tests/pos/surface/rset00.rs | 20 ++++++ 16 files changed, 262 insertions(+), 40 deletions(-) create mode 100644 crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 710b65d175..09a8aa57a9 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -1367,23 +1367,6 @@ impl<'a> SortResolver<'a> { Self { sess, sort_decls, sort_params: Default::default(), generic_params } } - // pub fn resolve( - // sess: &'a FluxSession, - // sort_decls: &'a fhir::SortDecls, - // sort_vars: Option<&[surface::Ident]>, - // generics: Option<&'a Generics>, - // sort: &surface::Sort, - // ) -> Result { - // let generic_params = generics - // .map(|g| g.params.iter().map(|p| (p.name, p.def_id)).collect()) - // .unwrap_or_default(); - // let sort_params = sort_vars - // .map(|vars| vars.iter().enumerate().map(|(i, v)| (v.name, i)).collect()) - // .unwrap_or_default(); - // let sr = Self { sess, sort_decls, generic_params, sort_params }; - // sr.resolve_sort(sort) - // } - fn resolve_sort(&self, sort: &surface::Sort) -> Result { match sort { surface::Sort::Base(sort) => self.resolve_base_sort(sort), diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 97c77b8a66..65d02d9cad 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -1,6 +1,6 @@ //! Desugaring from types in [`flux_syntax::surface`] to types in [`flux_middle::fhir`] //! -//! # Generics-and-Desugaring +//! # Generics and Desugaring //! //! Desugaring requires knowing the sort of each type so we can correctly resolve binders declared with //! @ syntax or arg syntax. In particular, to know the sort of a type parameter we need to know its @@ -53,7 +53,11 @@ pub fn desugar_struct_def( let mut cx = DesugarCtxt::new(genv, owner_id, resolver_output, None); // Desugar and insert generics - let (generics, predicates) = cx.as_lift_cx().lift_generics_with_predicates()?; + let (generics, predicates) = if let Some(generics) = &struct_def.generics { + (cx.desugar_generics(generics)?, cx.as_lift_cx().lift_predicates()?) + } else { + cx.as_lift_cx().lift_generics_with_predicates()? + }; genv.map().insert_generics(def_id, generics); // Desugar of struct_def needs to happen AFTER inserting generics. See #generics-and-desugaring diff --git a/crates/flux-driver/src/collector.rs b/crates/flux-driver/src/collector.rs index 66e82d44fc..0bf8e0df40 100644 --- a/crates/flux-driver/src/collector.rs +++ b/crates/flux-driver/src/collector.rs @@ -245,9 +245,10 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { .insert(extern_def_id, owner_id.def_id); } - self.specs - .structs - .insert(owner_id, surface::StructDef { refined_by, fields, opaque, invariants }); + self.specs.structs.insert( + owner_id, + surface::StructDef { refined_by, generics: None, fields, opaque, invariants }, + ); Ok(()) } diff --git a/crates/flux-fhir-analysis/locales/en-US.ftl b/crates/flux-fhir-analysis/locales/en-US.ftl index b475be788a..4ca0962e42 100644 --- a/crates/flux-fhir-analysis/locales/en-US.ftl +++ b/crates/flux-fhir-analysis/locales/en-US.ftl @@ -80,6 +80,9 @@ fhir_analysis_expected_numeric = fhir_analysis_no_equality = values of sort `{$sort}` cannot be compared for equality +fhir_analysis_invalid_base_instance = + values of this type cannot be used as base sorted instances + fhir_analysis_param_not_determined = parameter `{$sym}` cannot be determined .label = undetermined parameter @@ -153,4 +156,3 @@ fhir_analysis_assoc_type_not_found = associated type not found .label = cannot resolve this associated type .note = flux cannot resolved associated types if they are defined in a super trait - diff --git a/crates/flux-fhir-analysis/src/lib.rs b/crates/flux-fhir-analysis/src/lib.rs index e808d6e6af..95814ecf14 100644 --- a/crates/flux-fhir-analysis/src/lib.rs +++ b/crates/flux-fhir-analysis/src/lib.rs @@ -294,7 +294,6 @@ fn check_wf_rust_item(genv: &GlobalEnv, def_id: LocalDefId) -> QueryResult { let owner_id = OwnerId { def_id }; - let fn_sig = genv.map().get_fn_sig(def_id); let mut wfckresults = wf::check_fn_sig(genv, fn_sig, owner_id)?; annot_check::check_fn_sig(genv.tcx, genv.sess, &mut wfckresults, owner_id, fn_sig)?; diff --git a/crates/flux-fhir-analysis/src/wf/errors.rs b/crates/flux-fhir-analysis/src/wf/errors.rs index 1ee9abac52..49c551eae9 100644 --- a/crates/flux-fhir-analysis/src/wf/errors.rs +++ b/crates/flux-fhir-analysis/src/wf/errors.rs @@ -196,6 +196,20 @@ impl<'a> InvalidPrimitiveDotAccess<'a> { } } +#[derive(Diagnostic)] +#[diag(fhir_analysis_invalid_base_instance, code = "FLUX")] +pub(super) struct InvalidBaseInstance<'a> { + #[primary_span] + span: Span, + ty: &'a fhir::Ty, +} + +impl<'a> InvalidBaseInstance<'a> { + pub(super) fn new(ty: &'a fhir::Ty) -> Self { + Self { ty, span: ty.span } + } +} + #[derive(Diagnostic)] #[diag(fhir_analysis_no_equality, code = "FLUX")] pub(super) struct NoEquality<'a> { diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index 4d7fefae79..a2bd29251b 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -19,7 +19,7 @@ use rustc_data_structures::{ }; use rustc_errors::{ErrorGuaranteed, IntoDiagnostic}; use rustc_hash::FxHashSet; -use rustc_hir::{def::DefKind, OwnerId}; +use rustc_hir::{def::DefKind, def_id::DefId, OwnerId}; use rustc_span::Symbol; use self::sortck::InferCtxt; @@ -234,7 +234,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { match bound { fhir::GenericBound::Trait(trait_ref, _) => self.check_path(infcx, &trait_ref.trait_ref), fhir::GenericBound::LangItemTrait(_, args, bindings) => { - self.check_generic_args(infcx, args)?; + self.check_generic_args(infcx, None, args)?; self.check_type_bindings(infcx, bindings)?; Ok(()) } @@ -362,7 +362,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { } fhir::TyKind::OpaqueDef(_, args, _refine_args, _) => { // TODO sanity check the _refine_args (though they should never fail!) but we'd need their expected sorts - self.check_generic_args(infcx, args) + self.check_generic_args(infcx, None, args) } fhir::TyKind::RawPtr(ty, _) => self.check_type(infcx, ty), fhir::TyKind::Hole(_) | fhir::TyKind::Never => Ok(()), @@ -382,11 +382,55 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { .try_collect_exhaust() } + fn check_ty_is_base(&self, ty: &fhir::Ty) -> Result<(), ErrorGuaranteed> { + match &ty.kind { + fhir::TyKind::BaseTy(_) | fhir::TyKind::Indexed(_, _) => Ok(()), + fhir::TyKind::Tuple(tys) => { + for ty in tys { + self.check_ty_is_base(&ty)? + } + Ok(()) + } + fhir::TyKind::Constr(_, ty) | fhir::TyKind::Exists(_, ty) => self.check_ty_is_base(&ty), + + fhir::TyKind::Ptr(_, _) + | fhir::TyKind::Ref(_, _) + | fhir::TyKind::Array(_, _) + | fhir::TyKind::RawPtr(_, _) + | fhir::TyKind::OpaqueDef(_, _, _, _) + | fhir::TyKind::Never + | fhir::TyKind::Hole(_) => self.emit_err(errors::InvalidBaseInstance::new(ty)), + } + } + + fn check_generic_args_kinds( + &self, + adt_id: Option, + args: &[fhir::GenericArg], + ) -> Result<(), ErrorGuaranteed> { + if let Some(def_id) = adt_id && + let Ok(generics) = self.genv.generics_of(def_id) && + let Some(local_def_id) = def_id.as_local() + { + let refined_by = self.genv.map().refined_by(local_def_id); + for (arg, param) in args.iter().zip(generics.params.iter()) { + if refined_by.is_base_generic(param.def_id) { + if let fhir::GenericArg::Type(ty) = arg { + self.check_ty_is_base(ty)? + } + } + } + } + Ok(()) + } + fn check_generic_args( &mut self, infcx: &mut InferCtxt, + adt_id: Option, args: &[fhir::GenericArg], ) -> Result<(), ErrorGuaranteed> { + self.check_generic_args_kinds(adt_id, args)?; args.iter() .try_for_each_exhaust(|arg| self.check_generic_arg(infcx, arg)) } @@ -453,7 +497,12 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { | fhir::Res::PrimTy(..) => {} } let snapshot = self.xi.snapshot(); - let args = self.check_generic_args(infcx, &path.args); + let adt_id = match &path.res { + // TODO:Enums + fhir::Res::Def(DefKind::Struct, did) => Some(*did), + _ => None, + }; + let args = self.check_generic_args(infcx, adt_id, &path.args); let bindings = self.check_type_bindings(infcx, &path.bindings); if !self.genv.is_box(path.res) { self.xi.rollback_to(snapshot); diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index 7d15d8775e..209eb2845c 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use super::errors; pub(super) struct InferCtxt<'a, 'tcx> { - genv: &'a GlobalEnv<'a, 'tcx>, + pub genv: &'a GlobalEnv<'a, 'tcx>, sorts: UnordMap, unification_table: InPlaceUnificationTable, wfckresults: fhir::WfckResults, @@ -35,6 +35,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + // CUT + // pub(super) fn check_refine_params( + // &mut self, + // owner_id: OwnerId, + // refine_params: &[fhir::RefineParam], + // ) -> Result<(), ErrorGuaranteed> { + // let allowed_generics: HashSet = self + // .genv + // .generics_of(owner_id) + // .emit(self.genv.sess)? + // .params + // .iter() + // .filter_map(|param| { + // if let GenericParamDefKind::BaseTy = param.kind { + // Some(param.def_id) + // } else { + // None + // } + // }) + // .collect(); + // println!("TRACE: check_refine_params {owner_id:?} {allowed_generics:?} {refine_params:?}"); + // for refine_param in refine_params { + // self.check_sort(&allowed_generics, &refine_param.sort)? + // } + // Ok(()) + // } + + // CUT + // fn check_sort( + // &self, + // allowed_generics: &HashSet, + // sort: &fhir::Sort, + // ) -> Result<(), ErrorGuaranteed> { + // match sort { + // fhir::Sort::Int + // | fhir::Sort::Bool + // | fhir::Sort::Real + // | fhir::Sort::Loc + // | fhir::Sort::Unit + // | fhir::Sort::BitVec(_) + // | fhir::Sort::Var(_) + // | fhir::Sort::Infer(_) + // | fhir::Sort::Wildcard => Ok(()), + // fhir::Sort::App(_, sorts) => { + // for sort in sorts { + // self.check_sort(allowed_generics, sort)?; + // } + // Ok(()) + // } + // fhir::Sort::Func(poly_func_sort) => { + // for sort in &poly_func_sort.skip_binders().inputs_and_output { + // self.check_sort(allowed_generics, sort)?; + // } + // Ok(()) + // } + // fhir::Sort::Record(_, sorts) => { + // for sort in sorts { + // self.check_sort(allowed_generics, sort)?; + // } + // Ok(()) + // } + // fhir::Sort::Param(def_id) => { + // if allowed_generics.contains(def_id) { + // Ok(()) + // } else { + // Err(self.emit_err(errors::InvalidGenericSort::new(span, sort))) + // } + // } + // } + // } pub(super) fn check_refine_arg( &mut self, arg: &fhir::RefineArg, diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index e5222497ce..e07403e27d 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -20,6 +20,7 @@ pub mod lift; use std::{ borrow::{Borrow, Cow}, + collections::HashSet, fmt, }; @@ -30,7 +31,7 @@ use rustc_data_structures::{ fx::FxIndexMap, unord::{ExtendUnord, UnordMap, UnordSet}, }; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; pub use rustc_hir::PrimTy; use rustc_hir::{ def::DefKind, @@ -746,7 +747,7 @@ pub struct RefinedBy { pub def_id: DefId, pub span: Span, /// Sort parameters e.g. #[flux::refined_by( { elems: Set } )] - sort_params: Vec, + sort_params: HashSet, /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, /// The number of early bound parameters @@ -805,20 +806,20 @@ impl RefinedBy { RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { - let mut sort_params: FxHashSet = Default::default(); + fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> HashSet { + let mut sort_params: HashSet = Default::default(); for sort in sorts { sort.gather_sort_params(&mut sort_params); } - let mut params = vec![]; + let mut params: HashSet = Default::default(); for param in &generics.params { let def_id = param.def_id; if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && sort_params.contains(&def_id) { - params.push(def_id); + params.insert(def_id); } } params @@ -827,7 +828,7 @@ impl RefinedBy { pub fn trivial(def_id: impl Into, span: Span) -> Self { RefinedBy { def_id: def_id.into(), - sort_params: vec![], + sort_params: Default::default(), span, index_params: Default::default(), early_bound: 0, @@ -870,6 +871,10 @@ impl RefinedBy { .map(|sort| sort.param_subst(subst)) .collect() } + + pub fn is_base_generic(&self, def_id: DefId) -> bool { + self.sort_params.contains(&def_id) + } } type SortParamSubst = FxHashMap; @@ -952,7 +957,7 @@ impl Sort { } } - pub fn gather_sort_params(&self, params: &mut FxHashSet) { + pub fn gather_sort_params(&self, params: &mut HashSet) { match self { Sort::Int | Sort::Bool diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index 9d08d37e0f..51986dc62b 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -151,6 +151,11 @@ impl<'a, 'tcx> LiftCtxt<'a, 'tcx> { self.lift_generics_inner(generics) } + pub fn lift_predicates(&mut self) -> Result { + let generics = self.tcx.hir().get_generics(self.owner.def_id).unwrap(); + self.lift_generic_predicates(generics) + } + fn lift_generic_param( &mut self, param: &hir::GenericParam, diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index f44c431f27..8d4304b963 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -252,7 +252,8 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { | fhir::TyKind::Array(_, _) | fhir::TyKind::Never => Some(fhir::Sort::Unit), fhir::TyKind::Hole(_) => Some(fhir::Sort::Wildcard), - _ => bug!("unexpected ty {ty:?}"), + fhir::TyKind::Ptr(_, _) => None, + fhir::TyKind::OpaqueDef(_, _, _, _) => None, } } diff --git a/crates/flux-middle/src/rustc/ty.rs b/crates/flux-middle/src/rustc/ty.rs index 9d04e36e9f..f47139e96d 100644 --- a/crates/flux-middle/src/rustc/ty.rs +++ b/crates/flux-middle/src/rustc/ty.rs @@ -473,7 +473,8 @@ impl TyKind { impl Ty { pub fn mk_adt(adt_def: AdtDef, args: impl Into) -> Ty { - TyKind::Adt(adt_def, args.into()).intern() + let args = args.into(); + TyKind::Adt(adt_def, args).intern() } pub fn mk_closure(def_id: DefId, args: impl Into) -> Ty { diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index 13472139b4..4d8775ac48 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -75,6 +75,7 @@ pub struct TyAlias { #[derive(Debug)] pub struct StructDef { + pub generics: Option, pub refined_by: Option, pub fields: Vec>, pub opaque: bool, diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 70a244e03d..109122fd7e 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -3,7 +3,7 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set )] +#[flux::refined_by(elems: Set)] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs b/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs new file mode 100644 index 0000000000..670be272b6 --- /dev/null +++ b/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs @@ -0,0 +1,67 @@ +#[path = "../../../lib/rset.rs"] +pub mod rset; + +use std::hash::Hash; + +use rset::RSet; + +/// TODO: Crashes, but should ACCEPT; passes in `main` but BREAKS in `rset` branch; +/// so should allow it in `rset` +pub fn test00_ok() -> Option { + Some(1) +} + +pub fn test00_bad() -> RSet { + //~^ ERROR values of this type cannot be used as base sorted instances + RSet::::new() +} + +fn mk_eq_hash() -> impl Eq + Hash { + 0 +} + +/* +#[flux::sig(fn(x:T) -> T[x])] +fn id(x: T) -> T { + x +} + +pub fn test_base() { + let z = mk_eq_hash(); + id(z); +} +/// TODO: This currently crashes. We should gracefully reject it. +/// x: impl Eq + Hash +/// This will try to create an `RSet` which can't be put into RSet +fn test02() { + let x = mk_eq_hash(); + let mut s = RSet::new(); + s.insert(x); +} + +/// TODO: currently accept but should REJECT gracefully as `RSet` is +/// not well-formed if `T` is of kind type (i.e. not marked `base`). +#[flux::sig(fn(RSet[@s]))] +fn test04(set: RSet) {} + +/// TODO: variant of `test04` above should be rejected, as `RSet[@s]` is +/// not well-formed unless `T` is marked as 'special'. +#[flux::sig(fn(RSet[@s]))] +pub fn test05(s: RSet) +where + T: Eq + Hash, +{ +} + +#[flux::sig(fn(x: T))] +fn foo(x: T) {} + +/// TODO: Fails with parameter inference call but should fail with kind error. +fn test06() { + let x = mk_eq_hash(); + foo(x); +} + + + +*/ diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index 438b43c542..bb9c1abd76 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -47,3 +47,23 @@ pub fn test() { assert(contains(&s, &v0)); assert(!contains(&s, &v1)); } + +// i32[10] + +#[flux::sig(fn(RSet 0}>[@s], y:i32{set_is_in(y, s.elems)}) )] +pub fn test2(s: RSet, y: i32) { + assert(contains(&s, &y)); +} + +#[flux::sig(fn(RSet[@s], y:T{set_is_in(y, s.elems)}))] +pub fn test3(s: RSet, y: T) +where + T: Eq + Hash, +{ + assert(contains(&s, &y)); +} + +#[flux::sig(fn(RSet[@s], y:i32{0 <= y && set_is_in(y, s.elems)}) )] +pub fn test4(s: RSet, y: i32) { + test3(s, y) +} From 96a010e98ea508f1b35ddb1d194a2c4e30bd345c Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 28 Oct 2023 06:54:15 -0700 Subject: [PATCH 27/44] ugh, temp checkin --- crates/flux-desugar/src/desugar.rs | 23 ++++--- crates/flux-desugar/src/lib.rs | 2 + crates/flux-driver/src/collector.rs | 4 +- crates/flux-fhir-analysis/src/wf/mod.rs | 11 +-- crates/flux-middle/src/fhir.rs | 21 ++++-- .../tests/neg/error_messages/wf/rset_base.rs | 67 ------------------- 6 files changed, 44 insertions(+), 84 deletions(-) delete mode 100644 crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 09a8aa57a9..3ab1132f4d 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -6,6 +6,7 @@ use flux_middle::{ fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, Res}, global_env::GlobalEnv, intern::List, + rty::GenericParamDefKind, }; use flux_syntax::surface; use hir::{def::DefKind, ItemKind, PrimTy}; @@ -1161,9 +1162,11 @@ impl DesugarCtxt<'_, '_> { fn gather_params_fun_arg(&self, arg: &surface::Arg, binders: &mut Binders) -> Result { match arg { surface::Arg::Constr(bind, path, _) => { - let Some(sort) = sort_of_surface_path(self.genv, self.resolver_output, path) else { + let zz = sort_of_surface_path(self.genv, self.resolver_output, path); + let Some(sort) = zz else { return Err(self.emit_err(errors::RefinedUnrefinableType::new(path.span))); }; + binders.insert_binder(self.genv.sess, *bind, binders.binder_from_sort(sort))?; } surface::Arg::StrgRef(loc, ty) => { @@ -1643,6 +1646,7 @@ fn sort_of_surface_path( path: &surface::Path, ) -> Option { // CODESYNC(sort-of, 4) sorts should be given consistently + let res = resolver_output.path_res_map[&path.node_id]; match res { @@ -1651,20 +1655,23 @@ fn sort_of_surface_path( fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => Some(fhir::Sort::Unit), fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { // TODO: duplication with sort_of_path + let Ok(generics) = genv.generics_of(def_id) else { return None }; let mut sort_args = vec![]; - for arg in &path.generics { - if let surface::GenericArg::Type(ty) = arg && - let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind && - let Some(sort) = sort_of_surface_path(genv, resolver_output, path) - { - sort_args.push(sort); + for (param, arg) in generics.params.iter().zip(&path.generics) { + if param.kind == GenericParamDefKind::BaseTy { + let surface::GenericArg::Type(ty) = arg else { return None }; + let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind else { + return None; + }; + let sort = sort_of_surface_path(genv, resolver_output, path)?; + sort_args.push(sort); } } + println!("TRACE: sort_of_surface_path: {def_id:?} {sort_args:?}"); Some(fhir::Sort::Record(def_id, List::from_vec(sort_args))) } fhir::Res::Def(DefKind::TyParam, def_id) => { let param = genv.get_generic_param(def_id.expect_local()); - match ¶m.kind { fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index 65d02d9cad..fce9fedbb6 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -58,6 +58,8 @@ pub fn desugar_struct_def( } else { cx.as_lift_cx().lift_generics_with_predicates()? }; + let refined_by = genv.map().refined_by(owner_id.def_id); + let generics = generics.with_refined_by(refined_by); genv.map().insert_generics(def_id, generics); // Desugar of struct_def needs to happen AFTER inserting generics. See #generics-and-desugaring diff --git a/crates/flux-driver/src/collector.rs b/crates/flux-driver/src/collector.rs index 0bf8e0df40..fa81064adb 100644 --- a/crates/flux-driver/src/collector.rs +++ b/crates/flux-driver/src/collector.rs @@ -226,6 +226,8 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { let refined_by = attrs.refined_by(); + let generics = attrs.generics(); + let fields = data .fields() .iter() @@ -247,7 +249,7 @@ impl<'tcx, 'a> SpecCollector<'tcx, 'a> { self.specs.structs.insert( owner_id, - surface::StructDef { refined_by, generics: None, fields, opaque, invariants }, + surface::StructDef { refined_by, generics, fields, opaque, invariants }, ); Ok(()) diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index a2bd29251b..8aa20054f1 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -12,6 +12,7 @@ use flux_errors::FluxSession; use flux_middle::{ fhir::{self, FluxOwnerId, SurfaceIdent, WfckResults}, global_env::GlobalEnv, + rty::GenericParamDefKind, }; use rustc_data_structures::{ snapshot_map::{self, SnapshotMap}, @@ -409,12 +410,14 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { args: &[fhir::GenericArg], ) -> Result<(), ErrorGuaranteed> { if let Some(def_id) = adt_id && - let Ok(generics) = self.genv.generics_of(def_id) && - let Some(local_def_id) = def_id.as_local() + let Ok(generics) = self.genv.generics_of(def_id) + //&& + // let Some(local_def_id) = def_id.as_local() { - let refined_by = self.genv.map().refined_by(local_def_id); + // let refined_by = self.genv.map().refined_by(local_def_id); for (arg, param) in args.iter().zip(generics.params.iter()) { - if refined_by.is_base_generic(param.def_id) { + // if refined_by.is_base_generic(param.def_id) { + if param.kind == GenericParamDefKind::BaseTy { if let fhir::GenericArg::Type(ty) = arg { self.check_ty_is_base(ty)? } diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index e07403e27d..9344bbf05d 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -747,7 +747,7 @@ pub struct RefinedBy { pub def_id: DefId, pub span: Span, /// Sort parameters e.g. #[flux::refined_by( { elems: Set } )] - sort_params: HashSet, + sort_params: Vec, // TODO: Why do we need order (why do tests break with HashSet?) /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, /// The number of early bound parameters @@ -786,6 +786,19 @@ impl Generics { pub(crate) fn get_param(&self, def_id: LocalDefId) -> &GenericParam { self.params.iter().find(|p| p.def_id == def_id).unwrap() } + + pub fn with_refined_by(self, refined_by: &RefinedBy) -> Self { + let mut params = vec![]; + for param in self.params { + let kind = if refined_by.is_base_generic(param.def_id.to_def_id()) { + GenericParamKind::BaseTy + } else { + param.kind + }; + params.push(GenericParam { def_id: param.def_id, kind }) + } + Generics { params } + } } impl RefinedBy { @@ -806,20 +819,20 @@ impl RefinedBy { RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> HashSet { + fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { let mut sort_params: HashSet = Default::default(); for sort in sorts { sort.gather_sort_params(&mut sort_params); } - let mut params: HashSet = Default::default(); + let mut params = vec![]; for param in &generics.params { let def_id = param.def_id; if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && sort_params.contains(&def_id) { - params.insert(def_id); + params.push(def_id); } } params diff --git a/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs b/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs deleted file mode 100644 index 670be272b6..0000000000 --- a/crates/flux-tests/tests/neg/error_messages/wf/rset_base.rs +++ /dev/null @@ -1,67 +0,0 @@ -#[path = "../../../lib/rset.rs"] -pub mod rset; - -use std::hash::Hash; - -use rset::RSet; - -/// TODO: Crashes, but should ACCEPT; passes in `main` but BREAKS in `rset` branch; -/// so should allow it in `rset` -pub fn test00_ok() -> Option { - Some(1) -} - -pub fn test00_bad() -> RSet { - //~^ ERROR values of this type cannot be used as base sorted instances - RSet::::new() -} - -fn mk_eq_hash() -> impl Eq + Hash { - 0 -} - -/* -#[flux::sig(fn(x:T) -> T[x])] -fn id(x: T) -> T { - x -} - -pub fn test_base() { - let z = mk_eq_hash(); - id(z); -} -/// TODO: This currently crashes. We should gracefully reject it. -/// x: impl Eq + Hash -/// This will try to create an `RSet` which can't be put into RSet -fn test02() { - let x = mk_eq_hash(); - let mut s = RSet::new(); - s.insert(x); -} - -/// TODO: currently accept but should REJECT gracefully as `RSet` is -/// not well-formed if `T` is of kind type (i.e. not marked `base`). -#[flux::sig(fn(RSet[@s]))] -fn test04(set: RSet) {} - -/// TODO: variant of `test04` above should be rejected, as `RSet[@s]` is -/// not well-formed unless `T` is marked as 'special'. -#[flux::sig(fn(RSet[@s]))] -pub fn test05(s: RSet) -where - T: Eq + Hash, -{ -} - -#[flux::sig(fn(x: T))] -fn foo(x: T) {} - -/// TODO: Fails with parameter inference call but should fail with kind error. -fn test06() { - let x = mk_eq_hash(); - foo(x); -} - - - -*/ From 4c718c6faf00d1befdff169758e7bf536b6a9dae Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 28 Oct 2023 06:54:32 -0700 Subject: [PATCH 28/44] ugh, temp checkin --- .../tests/neg/error_messages/wf/kinds00.rs | 26 ++++++++++++++ .../tests/neg/error_messages/wf/kinds01.rs | 36 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs create mode 100644 crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs diff --git a/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs b/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs new file mode 100644 index 0000000000..652651c1b2 --- /dev/null +++ b/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs @@ -0,0 +1,26 @@ +#[path = "../../../lib/rset.rs"] +pub mod rset; + +use std::hash::Hash; + +use rset::RSet; + +pub fn test00_ok() -> Option { + Some(1) +} + +pub fn test00_bad() -> RSet { + //~^ ERROR values of this type cannot be used as base sorted instances + RSet::::new() +} + +// // this is OK because we just dont generate an index for `soup` +// #[flux::sig(fn(soup:RSet))] +// pub fn test04(_s: RSet) {} + +#[flux::sig(fn(RSet[@salt]))] //~ ERROR type cannot be refined +pub fn test05(s: RSet) +where + T: Eq + Hash, +{ +} diff --git a/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs b/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs new file mode 100644 index 0000000000..851acccdae --- /dev/null +++ b/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs @@ -0,0 +1,36 @@ +#[path = "../../../lib/rset.rs"] +pub mod rset; + +use std::hash::Hash; + +use rset::RSet; + +fn mk_eq_hash() -> impl Eq + Hash { + 0 +} + +#[flux::sig(fn(x:T) -> T[x])] +fn id(x: T) {} + +pub fn test_base() { + let z = mk_eq_hash(); // TODO: REJECT + id(z); +} + +fn bob(x: T) { + id(x) // TODO: REJECT-but-actually-ok +} + +fn test_bob(x: T) { + let z = mk_eq_hash(); + bob(z) // TODO: REJECT-but-actually-ok +} + +/// TODO: This currently crashes. We should gracefully reject it. +/// x: impl Eq + Hash +/// This will try to create an `RSet` which can't be put into RSet +fn test02() { + let x = mk_eq_hash(); + let mut s = RSet::new(); + s.insert(x); +} From 0b537d0c15906a7883d6ed0be8d5ff711d5e1ff4 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 28 Oct 2023 21:13:31 -0700 Subject: [PATCH 29/44] phew, tests pass --- README.md | 5 +- crates/flux-desugar/src/desugar.rs | 35 ++++----- crates/flux-desugar/src/lib.rs | 9 +-- crates/flux-driver/src/callbacks.rs | 4 +- crates/flux-fhir-analysis/src/conv.rs | 9 ++- crates/flux-fhir-analysis/src/lib.rs | 2 +- crates/flux-fhir-analysis/src/wf/mod.rs | 6 +- crates/flux-fhir-analysis/src/wf/sortck.rs | 71 +------------------ crates/flux-middle/src/fhir.rs | 9 +-- crates/flux-middle/src/fhir/lift.rs | 8 +++ crates/flux-middle/src/global_env.rs | 28 +++++--- crates/flux-middle/src/rty/mod.rs | 31 +++++++- crates/flux-middle/src/rty/refining.rs | 5 +- crates/flux-refineck/locales/en-US.ftl | 3 + crates/flux-refineck/src/checker.rs | 7 ++ crates/flux-refineck/src/constraint_gen.rs | 31 +++++++- crates/flux-syntax/src/grammar.lalrpop | 1 + crates/flux-syntax/src/surface.rs | 1 + crates/flux-tests/tests/lib/rmap.rs | 11 +-- crates/flux-tests/tests/lib/rset.rs | 1 + .../tests/neg/error_messages/wf/kinds00.rs | 11 --- .../tests/neg/error_messages/wf/kinds01.rs | 37 +++------- .../tests/neg/error_messages/wf/kinds02.rs | 38 ++++++++++ crates/flux-tests/tests/neg/surface/maps00.rs | 1 - crates/flux-tests/tests/neg/surface/rset00.rs | 2 +- crates/flux-tests/tests/pos/surface/rset00.rs | 4 +- 26 files changed, 198 insertions(+), 172 deletions(-) create mode 100644 crates/flux-tests/tests/neg/error_messages/wf/kinds02.rs diff --git a/README.md b/README.md index 0d3ddccd53..b666890ef6 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,7 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). # Docs Documentation, including installation and usage guides can be found on the -[website](https://flux-rs.github.io/flux). \ No newline at end of file +[website](https://flux-rs.github.io/flux). + + +TRACE: insert_fn_sig DefId(0:14 ~ maps00[5caf]::rmap::{impl#0}::new) fn() -> {a0:RMap. RMap[K, V][a0] | true} \ No newline at end of file diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 3ab1132f4d..a8f2a5c537 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -3,10 +3,9 @@ use std::{borrow::Borrow, iter}; use flux_common::{bug, index::IndexGen, iter::IterExt, span_bug}; use flux_errors::FluxSession; use flux_middle::{ - fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, Res}, + fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, GenericParamKind, Res}, global_env::GlobalEnv, intern::List, - rty::GenericParamDefKind, }; use flux_syntax::surface; use hir::{def::DefKind, ItemKind, PrimTy}; @@ -234,6 +233,7 @@ impl<'a, 'tcx> DesugarCtxt<'a, 'tcx> { let kind = match ¶m.kind { surface::GenericParamKind::Type => fhir::GenericParamKind::Type { default: None }, surface::GenericParamKind::Base => fhir::GenericParamKind::BaseTy, + surface::GenericParamKind::Spl => fhir::GenericParamKind::SplTy, surface::GenericParamKind::Refine { .. } => { continue; } @@ -1633,7 +1633,7 @@ fn index_sort( resolver_output: &ResolverOutput, bty: &surface::BaseTy, ) -> Option { - // CODESYNC(sort-of, 4) sorts should be given consistently + // CODESYNC(sort-of, 3) sorts should be given consistently match &bty.kind { surface::BaseTyKind::Path(path) => sort_of_surface_path(genv, resolver_output, path), surface::BaseTyKind::Slice(_) => Some(fhir::Sort::Int), @@ -1645,8 +1645,7 @@ fn sort_of_surface_path( resolver_output: &ResolverOutput, path: &surface::Path, ) -> Option { - // CODESYNC(sort-of, 4) sorts should be given consistently - + // CODESYNC(sort-of-path, 2) sorts should be given consistently let res = resolver_output.path_res_map[&path.node_id]; match res { @@ -1655,25 +1654,27 @@ fn sort_of_surface_path( fhir::Res::PrimTy(PrimTy::Float(..) | PrimTy::Str | PrimTy::Char) => Some(fhir::Sort::Unit), fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { // TODO: duplication with sort_of_path - let Ok(generics) = genv.generics_of(def_id) else { return None }; let mut sort_args = vec![]; - for (param, arg) in generics.params.iter().zip(&path.generics) { - if param.kind == GenericParamDefKind::BaseTy { - let surface::GenericArg::Type(ty) = arg else { return None }; - let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind else { - return None; - }; - let sort = sort_of_surface_path(genv, resolver_output, path)?; - sort_args.push(sort); + if let Some(generics) = genv.map().get_generics(def_id) { + for (param, arg) in generics.params.iter().zip(&path.generics) { + if let GenericParamKind::SplTy = param.kind { + let surface::GenericArg::Type(ty) = arg else { return None }; + let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind else { + return None; + }; + let sort = sort_of_surface_path(genv, resolver_output, path)?; + sort_args.push(sort); + } } - } - println!("TRACE: sort_of_surface_path: {def_id:?} {sort_args:?}"); + }; Some(fhir::Sort::Record(def_id, List::from_vec(sort_args))) } fhir::Res::Def(DefKind::TyParam, def_id) => { let param = genv.get_generic_param(def_id.expect_local()); match ¶m.kind { - fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + fhir::GenericParamKind::BaseTy | fhir::GenericParamKind::SplTy => { + Some(fhir::Sort::Param(def_id)) + } fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, } } diff --git a/crates/flux-desugar/src/lib.rs b/crates/flux-desugar/src/lib.rs index fce9fedbb6..8ea41caa70 100644 --- a/crates/flux-desugar/src/lib.rs +++ b/crates/flux-desugar/src/lib.rs @@ -53,14 +53,7 @@ pub fn desugar_struct_def( let mut cx = DesugarCtxt::new(genv, owner_id, resolver_output, None); // Desugar and insert generics - let (generics, predicates) = if let Some(generics) = &struct_def.generics { - (cx.desugar_generics(generics)?, cx.as_lift_cx().lift_predicates()?) - } else { - cx.as_lift_cx().lift_generics_with_predicates()? - }; - let refined_by = genv.map().refined_by(owner_id.def_id); - let generics = generics.with_refined_by(refined_by); - genv.map().insert_generics(def_id, generics); + let predicates = cx.as_lift_cx().lift_predicates()?; // Desugar of struct_def needs to happen AFTER inserting generics. See #generics-and-desugaring let struct_def = cx.desugar_struct_def(struct_def, &mut Binders::new())?; diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index 3f7c3ed5dc..fa237c2f67 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -153,10 +153,11 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran .err() .or(err); - // Register RefinedBys + // Register RefinedBys (for structs and enums, which also registers their Generics) err = specs .refined_bys() .try_for_each_exhaust(|(owner_id, refined_by)| { + let generics = lift::lift_generics(tcx, sess, owner_id)?; let refined_by = if let Some(refined_by) = refined_by { let def_id = owner_id.to_def_id(); let generics = tcx.generics_of(def_id); @@ -164,6 +165,7 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran } else { lift::lift_refined_by(tcx, owner_id) }; + map.insert_generics(owner_id.def_id, generics.with_refined_by(&refined_by)); map.insert_refined_by(owner_id.def_id, refined_by); Ok(()) }) diff --git a/crates/flux-fhir-analysis/src/conv.rs b/crates/flux-fhir-analysis/src/conv.rs index ed9a289294..1bc3ef38a8 100644 --- a/crates/flux-fhir-analysis/src/conv.rs +++ b/crates/flux-fhir-analysis/src/conv.rs @@ -162,6 +162,7 @@ pub(crate) fn conv_generics( fhir::GenericParamKind::Type { default } => { rty::GenericParamDefKind::Type { has_default: default.is_some() } } + fhir::GenericParamKind::SplTy => rty::GenericParamDefKind::SplTy, fhir::GenericParamKind::BaseTy => rty::GenericParamDefKind::BaseTy, fhir::GenericParamKind::Lifetime => rty::GenericParamDefKind::Lifetime, }; @@ -395,8 +396,9 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { let kind = rty::BoundRegionKind::BrNamed(def_id.to_def_id(), name); Ok(rty::BoundVariableKind::Region(kind)) } - fhir::GenericParamKind::Type { default: _ } => bug!("unexpected!"), - fhir::GenericParamKind::BaseTy => bug!("unexpected!"), + fhir::GenericParamKind::Type { default: _ } + | fhir::GenericParamKind::BaseTy + | fhir::GenericParamKind::SplTy => bug!("unexpected!"), } } @@ -635,6 +637,9 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { fn conv_base_ty(&self, env: &mut Env, bty: &fhir::BaseTy) -> QueryResult { let sort = self.genv.sort_of_bty(bty); + // if sort.is_none() { + // println!("TRACE: conv_base_ty {bty:?} ==> None"); + // } if let fhir::BaseTyKind::Path(fhir::QPath::Resolved(self_ty, path)) = &bty.kind { if let fhir::Res::Def(DefKind::AssocTy, def_id) = path.res { diff --git a/crates/flux-fhir-analysis/src/lib.rs b/crates/flux-fhir-analysis/src/lib.rs index 95814ecf14..93046bbc0f 100644 --- a/crates/flux-fhir-analysis/src/lib.rs +++ b/crates/flux-fhir-analysis/src/lib.rs @@ -160,7 +160,7 @@ fn generics_of(genv: &GlobalEnv, local_id: LocalDefId) -> QueryResult Wf<'a, 'tcx> { ) -> Result<(), ErrorGuaranteed> { if let Some(def_id) = adt_id && let Ok(generics) = self.genv.generics_of(def_id) - //&& - // let Some(local_def_id) = def_id.as_local() { - // let refined_by = self.genv.map().refined_by(local_def_id); for (arg, param) in args.iter().zip(generics.params.iter()) { - // if refined_by.is_base_generic(param.def_id) { - if param.kind == GenericParamDefKind::BaseTy { + if param.kind == GenericParamDefKind::SplTy { if let fhir::GenericArg::Type(ty) = arg { self.check_ty_is_base(ty)? } diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index 209eb2845c..ccc0dd95d3 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -35,76 +35,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - // CUT - // pub(super) fn check_refine_params( - // &mut self, - // owner_id: OwnerId, - // refine_params: &[fhir::RefineParam], - // ) -> Result<(), ErrorGuaranteed> { - // let allowed_generics: HashSet = self - // .genv - // .generics_of(owner_id) - // .emit(self.genv.sess)? - // .params - // .iter() - // .filter_map(|param| { - // if let GenericParamDefKind::BaseTy = param.kind { - // Some(param.def_id) - // } else { - // None - // } - // }) - // .collect(); - // println!("TRACE: check_refine_params {owner_id:?} {allowed_generics:?} {refine_params:?}"); - // for refine_param in refine_params { - // self.check_sort(&allowed_generics, &refine_param.sort)? - // } - // Ok(()) - // } - - // CUT - // fn check_sort( - // &self, - // allowed_generics: &HashSet, - // sort: &fhir::Sort, - // ) -> Result<(), ErrorGuaranteed> { - // match sort { - // fhir::Sort::Int - // | fhir::Sort::Bool - // | fhir::Sort::Real - // | fhir::Sort::Loc - // | fhir::Sort::Unit - // | fhir::Sort::BitVec(_) - // | fhir::Sort::Var(_) - // | fhir::Sort::Infer(_) - // | fhir::Sort::Wildcard => Ok(()), - // fhir::Sort::App(_, sorts) => { - // for sort in sorts { - // self.check_sort(allowed_generics, sort)?; - // } - // Ok(()) - // } - // fhir::Sort::Func(poly_func_sort) => { - // for sort in &poly_func_sort.skip_binders().inputs_and_output { - // self.check_sort(allowed_generics, sort)?; - // } - // Ok(()) - // } - // fhir::Sort::Record(_, sorts) => { - // for sort in sorts { - // self.check_sort(allowed_generics, sort)?; - // } - // Ok(()) - // } - // fhir::Sort::Param(def_id) => { - // if allowed_generics.contains(def_id) { - // Ok(()) - // } else { - // Err(self.emit_err(errors::InvalidGenericSort::new(span, sort))) - // } - // } - // } - // } pub(super) fn check_refine_arg( &mut self, arg: &fhir::RefineArg, @@ -278,6 +208,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fhir::ExprKind::Dot(var, fld) => { let sort = self[var.name].clone(); + // println!("TRACE: synth_expr {:?} ==> {sort:?}", var.source_info.name); match &sort { fhir::Sort::Record(def_id, sort_args) => { self.genv diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 9344bbf05d..0b19d70298 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -65,6 +65,7 @@ pub struct GenericParam { #[derive(Debug)] pub enum GenericParamKind { Type { default: Option }, + SplTy, BaseTy, Lifetime, } @@ -144,7 +145,7 @@ type Cache = elsa::FrozenMap>, + generics: Cache>, predicates: ItemPredicates, opaque_tys: UnordMap, func_decls: FxHashMap, @@ -791,7 +792,7 @@ impl Generics { let mut params = vec![]; for param in self.params { let kind = if refined_by.is_base_generic(param.def_id.to_def_id()) { - GenericParamKind::BaseTy + GenericParamKind::SplTy } else { param.kind }; @@ -1090,7 +1091,7 @@ impl Map { } pub fn insert_generics(&self, def_id: LocalDefId, generics: Generics) { - self.generics.insert(def_id, Box::new(generics)); + self.generics.insert(def_id.to_def_id(), Box::new(generics)); } pub fn insert_generic_predicates(&mut self, def_id: LocalDefId, predicates: GenericPredicates) { @@ -1101,7 +1102,7 @@ impl Map { self.opaque_tys.extend_unord(opaque_tys.into_items()); } - pub fn get_generics(&self, def_id: LocalDefId) -> Option<&Generics> { + pub fn get_generics(&self, def_id: DefId) -> Option<&Generics> { self.generics.get(&def_id) } diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index 51986dc62b..4ab6f11c18 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -33,6 +33,14 @@ pub fn lift_refined_by(tcx: TyCtxt, owner_id: OwnerId) -> fhir::RefinedBy { } } +pub fn lift_generics<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + sess: &'a FluxSession, + owner_id: OwnerId, +) -> Result { + LiftCtxt::new(tcx, sess, owner_id, None).lift_generics() +} + pub fn lift_type_alias( tcx: TyCtxt, sess: &FluxSession, diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 8d4304b963..c16306995e 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -13,7 +13,7 @@ pub use rustc_span::{symbol::Ident, Symbol}; use crate::{ cstore::CrateStoreDyn, - fhir::{self, FluxLocalDefId, VariantIdx}, + fhir::{self, FluxLocalDefId, GenericParamKind, VariantIdx}, intern::List, queries::{Providers, Queries, QueryResult}, rty::{self, fold::TypeFoldable, normalize::Defns, refining::Refiner}, @@ -159,7 +159,10 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn get_generic_param(&self, def_id: LocalDefId) -> &fhir::GenericParam { let owner = self.hir().ty_param_owner(def_id); - self.map().get_generics(owner).unwrap().get_param(def_id) + self.map() + .get_generics(owner.to_def_id()) + .unwrap() + .get_param(def_id) } pub fn is_box(&self, res: fhir::Res) -> bool { @@ -202,6 +205,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } pub fn sort_of_path(&self, path: &fhir::Path) -> Option { + // CODESYNC(sort-of-path, 2) sorts should be given consistently match path.res { fhir::Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) => Some(fhir::Sort::Int), fhir::Res::PrimTy(PrimTy::Bool) => Some(fhir::Sort::Bool), @@ -210,13 +214,15 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { let mut sort_args = vec![]; - for arg in &path.args { - if let fhir::GenericArg::Type(ty) = arg && - let Some(sort) = self.sort_of_ty(ty) - { - sort_args.push(sort); + if let Some(generics) = self.map().get_generics(def_id) { + for (param, arg) in generics.params.iter().zip(&path.args) { + if let GenericParamKind::SplTy = param.kind { + let fhir::GenericArg::Type(ty) = arg else { return None }; + let sort = self.sort_of_ty(ty)?; + sort_args.push(sort); + } } - } + }; Some(fhir::Sort::Record(def_id, List::from_vec(sort_args))) } fhir::Res::SelfTyAlias { alias_to, .. } => self.sort_of_self_ty_alias(alias_to), @@ -235,7 +241,9 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { fn sort_of_generic_param(&self, def_id: DefId) -> Option { let param = self.get_generic_param(def_id.expect_local()); match ¶m.kind { - fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + fhir::GenericParamKind::BaseTy | fhir::GenericParamKind::SplTy => { + Some(fhir::Sort::Param(def_id)) + } fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, } } @@ -259,7 +267,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { fn sort_of_self_ty(&self, def_id: DefId, ty: rustc_middle::ty::Ty) -> Option { use rustc_middle::ty; - // CODESYNC(sort-of, 4) sorts should be given consistently + // CODESYNC(sort-of, 3) sorts should be given consistently match ty.kind() { ty::TyKind::Bool => Some(fhir::Sort::Bool), ty::TyKind::Slice(_) | ty::TyKind::Int(_) | ty::TyKind::Uint(_) => { diff --git a/crates/flux-middle/src/rty/mod.rs b/crates/flux-middle/src/rty/mod.rs index dd96f7853d..bddeba6b33 100644 --- a/crates/flux-middle/src/rty/mod.rs +++ b/crates/flux-middle/src/rty/mod.rs @@ -83,6 +83,7 @@ pub struct GenericParamDef { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum GenericParamDefKind { Type { has_default: bool }, + SplTy, BaseTy, Lifetime, Const { has_default: bool }, @@ -438,10 +439,19 @@ impl GenericArg { bug!("expected `rty::GenericArg::Ty`, found {:?}", self) } } + pub fn is_valid_base_arg(&self) -> bool { + let res = match self { + GenericArg::Ty(ty) => ty.kind().is_valid_base_ty(), + GenericArg::BaseTy(bty) => bty.skip_binder_as_ref().kind().is_valid_base_ty(), + _ => false, + }; + // println!("TRACE: is_valid_base arg: {:?} => {res:?}", self); + res + } fn from_param_def(param: &GenericParamDef) -> Self { match param.kind { - GenericParamDefKind::Type { .. } => { + GenericParamDefKind::Type { .. } | GenericParamDefKind::SplTy => { let param_ty = ParamTy { index: param.index, name: param.name }; GenericArg::Ty(Ty::param(param_ty)) } @@ -771,6 +781,10 @@ impl Binder { self.value } + pub fn skip_binder_as_ref(&self) -> &T { + &self.value + } + pub fn rebind(self, value: U) -> Binder { Binder { vars: self.vars, value } } @@ -1296,6 +1310,19 @@ impl TyKind { fn intern(self) -> Ty { Interned::new(TyS { kind: self }) } + + fn is_valid_base_ty(&self) -> bool { + match self { + TyKind::Param(_) | TyKind::Indexed(_, _) | TyKind::Exists(_) => true, + TyKind::Constr(_, ty) => ty.kind().is_valid_base_ty(), + TyKind::Uninit + | TyKind::Ptr(_, _) + | TyKind::Discr(_, _) + | TyKind::Downcast(_, _, _, _, _) + | TyKind::Blocked(_) + | TyKind::Alias(_, _) => false, + } + } } impl TyS { @@ -1468,7 +1495,7 @@ impl BaseTy { } pub fn sort(&self) -> Sort { - // CODESYNC(sort-of, 4) sorts should be given consistently + // CODESYNC(sort-of, 3) sorts should be given consistently match self { BaseTy::Int(_) | BaseTy::Uint(_) | BaseTy::Slice(_) => Sort::Int, BaseTy::Bool => Sort::Bool, diff --git a/crates/flux-middle/src/rty/refining.rs b/crates/flux-middle/src/rty/refining.rs index 5e00f3fba6..4853de11e8 100644 --- a/crates/flux-middle/src/rty/refining.rs +++ b/crates/flux-middle/src/rty/refining.rs @@ -231,6 +231,9 @@ impl<'a, 'tcx> Refiner<'a, 'tcx> { (rty::GenericParamDefKind::Type { .. }, rustc::ty::GenericArg::Ty(ty)) => { Ok(rty::GenericArg::Ty(self.refine_ty(ty)?)) } + (rty::GenericParamDefKind::SplTy, rustc::ty::GenericArg::Ty(ty)) => { + Ok(rty::GenericArg::Ty(self.refine_ty(ty)?)) + } (rty::GenericParamDefKind::BaseTy, rustc::ty::GenericArg::Ty(ty)) => { Ok(rty::GenericArg::BaseTy(self.refine_poly_ty(ty)?)) } @@ -320,7 +323,7 @@ impl<'a, 'tcx> Refiner<'a, 'tcx> { } rustc::ty::TyKind::Param(param_ty) => { match self.param(*param_ty)?.kind { - rty::GenericParamDefKind::Type { .. } => { + rty::GenericParamDefKind::Type { .. } | rty::GenericParamDefKind::SplTy => { return Ok(rty::Binder::new(rty::Ty::param(*param_ty), List::empty())); } rty::GenericParamDefKind::BaseTy => rty::BaseTy::Param(*param_ty), diff --git a/crates/flux-refineck/locales/en-US.ftl b/crates/flux-refineck/locales/en-US.ftl index 35f93c1cc1..4909a54da7 100644 --- a/crates/flux-refineck/locales/en-US.ftl +++ b/crates/flux-refineck/locales/en-US.ftl @@ -28,6 +28,9 @@ refineck_assert_error = refineck_param_inference_error = parameter inference error at function call +refineck_invalid_generic_arg = + cannot instantiate base or spl generic with opaque type + refineck_fold_error = type invariant may not hold (when place is folded) diff --git a/crates/flux-refineck/src/checker.rs b/crates/flux-refineck/src/checker.rs index 098385fe6b..865e95ae49 100644 --- a/crates/flux-refineck/src/checker.rs +++ b/crates/flux-refineck/src/checker.rs @@ -1342,6 +1342,7 @@ pub(crate) mod errors { Inference, OpaqueStruct(DefId), Query(QueryErr), + InvalidGenericArg, } impl CheckerError { @@ -1363,6 +1364,12 @@ pub(crate) mod errors { flux_errors::diagnostic_id(), ) } + CheckerErrKind::InvalidGenericArg => { + handler.struct_err_with_code( + fluent::refineck_invalid_generic_arg, + flux_errors::diagnostic_id(), + ) + } CheckerErrKind::OpaqueStruct(def_id) => { let mut builder = handler.struct_err_with_code( fluent::refineck_opaque_struct_error, diff --git a/crates/flux-refineck/src/constraint_gen.rs b/crates/flux-refineck/src/constraint_gen.rs index d603be8333..874974ca89 100644 --- a/crates/flux-refineck/src/constraint_gen.rs +++ b/crates/flux-refineck/src/constraint_gen.rs @@ -9,8 +9,9 @@ use flux_middle::{ evars::{EVarCxId, EVarSol, UnsolvedEvar}, fold::TypeFoldable, AliasTy, BaseTy, BinOp, Binder, Const, Constraint, ESpan, EVarGen, EarlyBinder, Expr, - ExprKind, FnOutput, GeneratorObligPredicate, GenericArg, GenericArgs, HoleKind, InferMode, - Mutability, Path, PolyFnSig, PolyVariant, PtrKind, Ref, Sort, TupleTree, Ty, TyKind, Var, + ExprKind, FnOutput, GeneratorObligPredicate, GenericArg, GenericArgs, GenericParamDefKind, + HoleKind, InferMode, Mutability, Path, PolyFnSig, PolyVariant, PtrKind, Ref, Sort, + TupleTree, Ty, TyKind, Var, }, rustc::mir::{BasicBlock, Place}, }; @@ -146,6 +147,26 @@ impl<'a, 'tcx> ConstrGen<'a, 'tcx> { Ok(res) } + fn check_generic_args( + &self, + did: DefId, + generic_args: &[GenericArg], + ) -> Result<(), CheckerErrKind> { + let generics = self.genv.generics_of(did)?; + for (idx, arg) in generic_args.iter().enumerate() { + let param = generics.param_at(idx, self.genv)?; + match param.kind { + GenericParamDefKind::SplTy | GenericParamDefKind::BaseTy => { + if !arg.is_valid_base_arg() { + return Err(CheckerErrKind::InvalidGenericArg); + } + } + _ => continue, + } + } + Ok(()) + } + #[allow(clippy::too_many_arguments)] pub(crate) fn check_fn_call( &mut self, @@ -184,6 +205,10 @@ impl<'a, 'tcx> ConstrGen<'a, 'tcx> { let callsite_def_id = self.def_id; let span = self.span; + if let Some(did) = callee_def_id { + self.check_generic_args(did, generic_args)?; + } + let mut infcx = self.infcx(rcx, ConstrReason::Call); let snapshot = rcx.snapshot(); @@ -698,7 +723,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } (GenericArg::BaseTy(_), GenericArg::BaseTy(_)) => { - tracked_span_bug!("sgeneric argument subtyping for base types is not implemented"); + tracked_span_bug!("generic argument subtyping for base types is not implemented"); } (GenericArg::Lifetime(_), GenericArg::Lifetime(_)) => Ok(()), _ => tracked_span_bug!("incompatible generic args: `{arg1:?}` `{arg2:?}"), diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 939afe9b36..944355db0e 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -25,6 +25,7 @@ GenericParam: surface::GenericParam = { let kind = match kind.as_str() { "type" => surface::GenericParamKind::Type, "base" => surface::GenericParamKind::Base, + "spl" => surface::GenericParamKind::Spl, _ => return Err(ParseError::User { error: UserParseError::UnexpectedToken(lo, hi) }) }; Ok(surface::GenericParam { name, kind }) diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index 4d8775ac48..9b1c440a80 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -60,6 +60,7 @@ pub struct GenericParam { #[derive(Debug)] pub enum GenericParamKind { Type, + Spl, Base, Refine { sort: Sort }, } diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index 7dc175b203..8f74fbc6ef 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -9,7 +9,7 @@ use std::hash::Hash; /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by(map: Map)] +#[flux::refined_by(vals: Map)] pub struct RMap { inner: std::collections::HashMap, } @@ -17,12 +17,15 @@ pub struct RMap { #[flux::generics(K as base, V as base)] impl RMap { #[flux::trusted] + + /// #[flux::sig(fn() -> RMap{m: true})] "OK" i.e. wraps K, V in existential + /// #[flux::sig(fn() -> RMap{m: true})] "CRASH" i.e. wraps K, V in LAMBDA pub fn new() -> Self { Self { inner: std::collections::HashMap::new() } } #[flux::trusted] - #[flux::sig(fn(self: &strg RMap[@m], k: K, v: V) ensures self: RMap[map_set(m, k, v)])] + #[flux::sig(fn(self: &strg RMap[@m], k: K, v: V) ensures self: RMap[map_set(m.vals, k, v)])] pub fn set(&mut self, k: K, v: V) where K: Eq + Hash, @@ -31,11 +34,11 @@ impl RMap { } #[flux::trusted] - #[flux::sig(fn(&RMap[@m], &K[@k]) -> Option<&V[map_get(m, k)]>)] + #[flux::sig(fn(&RMap[@m], &K[@k]) -> Option<&V[map_get(m.vals, k)]>)] pub fn get(&self, k: &K) -> Option<&V> where K: Eq + Hash, { - self.inner.get(&k) + self.inner.get(k) } } diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 109122fd7e..5a57195125 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -8,6 +8,7 @@ pub struct RSet { pub inner: std::collections::HashSet, } +// TODO: (RJ) I get some odd error with `T as spl` ...? #[flux::generics(T as base)] impl RSet { #[flux::trusted] diff --git a/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs b/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs index 652651c1b2..012a6e4b69 100644 --- a/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs +++ b/crates/flux-tests/tests/neg/error_messages/wf/kinds00.rs @@ -13,14 +13,3 @@ pub fn test00_bad() -> RSet { //~^ ERROR values of this type cannot be used as base sorted instances RSet::::new() } - -// // this is OK because we just dont generate an index for `soup` -// #[flux::sig(fn(soup:RSet))] -// pub fn test04(_s: RSet) {} - -#[flux::sig(fn(RSet[@salt]))] //~ ERROR type cannot be refined -pub fn test05(s: RSet) -where - T: Eq + Hash, -{ -} diff --git a/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs b/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs index 851acccdae..a4cb743b1c 100644 --- a/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs +++ b/crates/flux-tests/tests/neg/error_messages/wf/kinds01.rs @@ -5,32 +5,13 @@ use std::hash::Hash; use rset::RSet; -fn mk_eq_hash() -> impl Eq + Hash { - 0 -} - -#[flux::sig(fn(x:T) -> T[x])] -fn id(x: T) {} - -pub fn test_base() { - let z = mk_eq_hash(); // TODO: REJECT - id(z); -} - -fn bob(x: T) { - id(x) // TODO: REJECT-but-actually-ok -} - -fn test_bob(x: T) { - let z = mk_eq_hash(); - bob(z) // TODO: REJECT-but-actually-ok -} - -/// TODO: This currently crashes. We should gracefully reject it. -/// x: impl Eq + Hash -/// This will try to create an `RSet` which can't be put into RSet -fn test02() { - let x = mk_eq_hash(); - let mut s = RSet::new(); - s.insert(x); +// this is OK because we just dont generate an index for `soup` +#[flux::sig(fn(soup:RSet))] +pub fn test04(_s: RSet) {} + +#[flux::sig(fn(RSet[@salt]))] //~ ERROR type cannot be refined +pub fn test05(_s: RSet) +where + T: Eq + Hash, +{ } diff --git a/crates/flux-tests/tests/neg/error_messages/wf/kinds02.rs b/crates/flux-tests/tests/neg/error_messages/wf/kinds02.rs new file mode 100644 index 0000000000..3ecc680ff6 --- /dev/null +++ b/crates/flux-tests/tests/neg/error_messages/wf/kinds02.rs @@ -0,0 +1,38 @@ +#[path = "../../../lib/rset.rs"] +pub mod rset; + +use std::hash::Hash; + +use rset::RSet; + +fn mk_eq_hash() -> impl Eq + Hash { + 0 +} + +#[flux::sig(fn(x:T) -> T[x])] +fn id(x: T) -> T { + x +} + +// This will try to call id with an `RSet` which can't be a "base" +pub fn test00() { + let z = mk_eq_hash(); + id(z); //~ ERROR cannot instantiate +} + +// This will try to create an `RSet` which can't be put into RSet +pub fn test01() { + let x = mk_eq_hash(); + let mut s = RSet::new(); //~ ERROR cannot instantiate + s.insert(x); +} + +// #[flux::sig(fn(x:T))] +// pub fn test01(x: T) { +// id(x); // TODO: REJECT-but-actually-ok +// } + +// fn test_bob(x: T) { +// let z = mk_eq_hash(); +// bob(z); // TODO: REJECT-but-actually-ok +// } diff --git a/crates/flux-tests/tests/neg/surface/maps00.rs b/crates/flux-tests/tests/neg/surface/maps00.rs index d91e84dc83..b104432fc7 100644 --- a/crates/flux-tests/tests/neg/surface/maps00.rs +++ b/crates/flux-tests/tests/neg/surface/maps00.rs @@ -13,7 +13,6 @@ pub fn test() { m.set(k0, 1); m.set(k1, 2); - assert(*m.get(&k0).unwrap() == 1); assert(*m.get(&k1).unwrap() == 2); assert(*m.get(&k2).unwrap() == 3); //~ ERROR refinement type diff --git a/crates/flux-tests/tests/neg/surface/rset00.rs b/crates/flux-tests/tests/neg/surface/rset00.rs index 1bcfa6afdd..669cbee38a 100644 --- a/crates/flux-tests/tests/neg/surface/rset00.rs +++ b/crates/flux-tests/tests/neg/surface/rset00.rs @@ -15,7 +15,7 @@ pub fn id(s: RSet) -> RSet { fn assert(_b: bool) {} #[flux::trusted] -#[flux::sig(fn() -> RSet[set_empty(0)])] +#[flux::sig(fn() -> RSet[set_empty(0)])] pub fn empty() -> RSet { let inner = std::collections::HashSet::new(); RSet { inner } diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index bb9c1abd76..d85211c8a3 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -15,7 +15,7 @@ pub fn id(s: RSet) -> RSet { fn assert(_b: bool) {} #[flux::trusted] -#[flux::sig(fn() -> RSet[set_empty(0)])] +#[flux::sig(fn() -> RSet[set_empty(0)])] pub fn empty() -> RSet { let inner = std::collections::HashSet::new(); RSet { inner } @@ -31,7 +31,7 @@ where } #[flux::trusted] -#[flux::sig(fn(set: &RSet[@s], &A[@elem]) -> bool[set_is_in(elem, s.elems)])] +#[flux::sig(fn(set: &RSet[@soup], &A[@elem]) -> bool[set_is_in(elem, soup.elems)])] pub fn contains(set: &RSet, elem: &A) -> bool where A: Eq + Hash, From 6be28d7acaa4975647657ad3072b05c3c5a79821 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 28 Oct 2023 21:15:40 -0700 Subject: [PATCH 30/44] phew, tests pass --- crates/flux-fhir-analysis/src/wf/mod.rs | 6 +++--- crates/flux-middle/src/fhir.rs | 2 +- crates/flux-middle/src/fhir/lift.rs | 6 +++--- crates/flux-middle/src/rty/mod.rs | 6 ++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index ca0c48bfda..3597cd7d75 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -388,11 +388,11 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { fhir::TyKind::BaseTy(_) | fhir::TyKind::Indexed(_, _) => Ok(()), fhir::TyKind::Tuple(tys) => { for ty in tys { - self.check_ty_is_base(&ty)? + self.check_ty_is_base(ty)?; } Ok(()) } - fhir::TyKind::Constr(_, ty) | fhir::TyKind::Exists(_, ty) => self.check_ty_is_base(&ty), + fhir::TyKind::Constr(_, ty) | fhir::TyKind::Exists(_, ty) => self.check_ty_is_base(ty), fhir::TyKind::Ptr(_, _) | fhir::TyKind::Ref(_, _) @@ -415,7 +415,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { for (arg, param) in args.iter().zip(generics.params.iter()) { if param.kind == GenericParamDefKind::SplTy { if let fhir::GenericArg::Type(ty) = arg { - self.check_ty_is_base(ty)? + self.check_ty_is_base(ty)?; } } } diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 0b19d70298..ef89612e9b 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -796,7 +796,7 @@ impl Generics { } else { param.kind }; - params.push(GenericParam { def_id: param.def_id, kind }) + params.push(GenericParam { def_id: param.def_id, kind }); } Generics { params } } diff --git a/crates/flux-middle/src/fhir/lift.rs b/crates/flux-middle/src/fhir/lift.rs index 4ab6f11c18..adc4c690d4 100644 --- a/crates/flux-middle/src/fhir/lift.rs +++ b/crates/flux-middle/src/fhir/lift.rs @@ -33,9 +33,9 @@ pub fn lift_refined_by(tcx: TyCtxt, owner_id: OwnerId) -> fhir::RefinedBy { } } -pub fn lift_generics<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - sess: &'a FluxSession, +pub fn lift_generics( + tcx: TyCtxt, + sess: &FluxSession, owner_id: OwnerId, ) -> Result { LiftCtxt::new(tcx, sess, owner_id, None).lift_generics() diff --git a/crates/flux-middle/src/rty/mod.rs b/crates/flux-middle/src/rty/mod.rs index bddeba6b33..6fdd869423 100644 --- a/crates/flux-middle/src/rty/mod.rs +++ b/crates/flux-middle/src/rty/mod.rs @@ -440,13 +440,11 @@ impl GenericArg { } } pub fn is_valid_base_arg(&self) -> bool { - let res = match self { + match self { GenericArg::Ty(ty) => ty.kind().is_valid_base_ty(), GenericArg::BaseTy(bty) => bty.skip_binder_as_ref().kind().is_valid_base_ty(), _ => false, - }; - // println!("TRACE: is_valid_base arg: {:?} => {res:?}", self); - res + } } fn from_param_def(param: &GenericParamDef) -> Self { From 5b982cac99447fbf191b594315e3d3d70beee13b Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Sat, 28 Oct 2023 21:21:26 -0700 Subject: [PATCH 31/44] phew, tests pass --- crates/flux-tests/tests/lib/rset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 5a57195125..6895738128 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -8,7 +8,8 @@ pub struct RSet { pub inner: std::collections::HashSet, } -// TODO: (RJ) I get some odd error with `T as spl` ...? +// TODO: (RJ) I get some odd error with `T as spl` / cannot refine if I just remove this annotation! +// error: internal compiler error: crates/flux-middle/src/rty/subst.rs:353:30: expected base type for generic parameter, found `∃int. { i32[^0#0] | * }` #[flux::generics(T as base)] impl RSet { #[flux::trusted] From 432bbe44ad82e0757c8112f252776bc93660f501 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 14:03:14 -0700 Subject: [PATCH 32/44] Update README.md Co-authored-by: Nico Lehmann --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index b666890ef6..63073569ab 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,3 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). Documentation, including installation and usage guides can be found on the [website](https://flux-rs.github.io/flux). - - -TRACE: insert_fn_sig DefId(0:14 ~ maps00[5caf]::rmap::{impl#0}::new) fn() -> {a0:RMap. RMap[K, V][a0] | true} \ No newline at end of file From f53ba6f4f1ece5423bea2c52900af06cbd27f31a Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 14:14:07 -0700 Subject: [PATCH 33/44] Update crates/flux-middle/src/fhir.rs Co-authored-by: Nico Lehmann --- crates/flux-middle/src/fhir.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index ef89612e9b..3e37534121 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -658,6 +658,7 @@ impl BaseTy { BaseTyKind::Path(QPath::Resolved(_, Path { res: Res::PrimTy(PrimTy::Bool), .. })) ) } + pub fn as_path(&self) -> Option<&Path> { match &self.kind { BaseTyKind::Path(QPath::Resolved(None, path)) => Some(path), From 104fd50bcbab30d1a52fb3454b7a617cb391b9e4 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 16:10:41 -0700 Subject: [PATCH 34/44] Update crates/flux-fhir-analysis/src/wf/sortck.rs Co-authored-by: Nico Lehmann --- crates/flux-fhir-analysis/src/wf/sortck.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/flux-fhir-analysis/src/wf/sortck.rs b/crates/flux-fhir-analysis/src/wf/sortck.rs index ccc0dd95d3..a776abcb7a 100644 --- a/crates/flux-fhir-analysis/src/wf/sortck.rs +++ b/crates/flux-fhir-analysis/src/wf/sortck.rs @@ -208,7 +208,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fhir::ExprKind::Dot(var, fld) => { let sort = self[var.name].clone(); - // println!("TRACE: synth_expr {:?} ==> {sort:?}", var.source_info.name); match &sort { fhir::Sort::Record(def_id, sort_args) => { self.genv From bd5de6c1c86854a76c9228efffd5166404070469 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 16:31:11 -0700 Subject: [PATCH 35/44] address comments --- crates/flux-desugar/src/desugar.rs | 15 +++++++------- crates/flux-driver/src/callbacks.rs | 3 +-- crates/flux-fhir-analysis/src/lib.rs | 2 +- crates/flux-middle/src/fhir.rs | 30 ++++++++++++++++------------ crates/flux-middle/src/global_env.rs | 13 +++++------- crates/flux-middle/src/rty/mod.rs | 8 ++------ 6 files changed, 34 insertions(+), 37 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index a8f2a5c537..499a774fc3 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -3,9 +3,10 @@ use std::{borrow::Borrow, iter}; use flux_common::{bug, index::IndexGen, iter::IterExt, span_bug}; use flux_errors::FluxSession; use flux_middle::{ - fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, GenericParamKind, Res}, + fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, Res}, global_env::GlobalEnv, intern::List, + rty::GenericParamDefKind, }; use flux_syntax::surface; use hir::{def::DefKind, ItemKind, PrimTy}; @@ -1655,9 +1656,9 @@ fn sort_of_surface_path( fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { // TODO: duplication with sort_of_path let mut sort_args = vec![]; - if let Some(generics) = genv.map().get_generics(def_id) { + if let Ok(generics) = genv.generics_of(def_id) { for (param, arg) in generics.params.iter().zip(&path.generics) { - if let GenericParamKind::SplTy = param.kind { + if let GenericParamDefKind::SplTy = param.kind { let surface::GenericArg::Type(ty) = arg else { return None }; let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind else { return None; @@ -1672,10 +1673,10 @@ fn sort_of_surface_path( fhir::Res::Def(DefKind::TyParam, def_id) => { let param = genv.get_generic_param(def_id.expect_local()); match ¶m.kind { - fhir::GenericParamKind::BaseTy | fhir::GenericParamKind::SplTy => { - Some(fhir::Sort::Param(def_id)) - } - fhir::GenericParamKind::Type { .. } | fhir::GenericParamKind::Lifetime => None, + fhir::GenericParamKind::BaseTy => Some(fhir::Sort::Param(def_id)), + fhir::GenericParamKind::Type { .. } + | fhir::GenericParamKind::Lifetime + | fhir::GenericParamKind::SplTy => None, } } diff --git a/crates/flux-driver/src/callbacks.rs b/crates/flux-driver/src/callbacks.rs index fa237c2f67..c90405f6bb 100644 --- a/crates/flux-driver/src/callbacks.rs +++ b/crates/flux-driver/src/callbacks.rs @@ -159,8 +159,7 @@ fn stage1_desugar(genv: &mut GlobalEnv, specs: &Specs) -> Result<(), ErrorGuaran .try_for_each_exhaust(|(owner_id, refined_by)| { let generics = lift::lift_generics(tcx, sess, owner_id)?; let refined_by = if let Some(refined_by) = refined_by { - let def_id = owner_id.to_def_id(); - let generics = tcx.generics_of(def_id); + let generics = tcx.generics_of(owner_id); desugar::desugar_refined_by(sess, map.sort_decls(), owner_id, generics, refined_by)? } else { lift::lift_refined_by(tcx, owner_id) diff --git a/crates/flux-fhir-analysis/src/lib.rs b/crates/flux-fhir-analysis/src/lib.rs index 93046bbc0f..95814ecf14 100644 --- a/crates/flux-fhir-analysis/src/lib.rs +++ b/crates/flux-fhir-analysis/src/lib.rs @@ -160,7 +160,7 @@ fn generics_of(genv: &GlobalEnv, local_id: LocalDefId) -> QueryResult = elsa::FrozenMap>, + generics: Cache>, predicates: ItemPredicates, opaque_tys: UnordMap, func_decls: FxHashMap, @@ -540,7 +540,7 @@ impl PolyFuncSort { FuncSort { inputs_and_output } } - pub fn param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { + fn mk_param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { let params = self.params; let args = self .fsort @@ -644,8 +644,7 @@ impl SortCtor { impl Ty { pub fn as_path(&self) -> Option<&Path> { match &self.kind { - TyKind::BaseTy(bty) | TyKind::Indexed(bty, _) => bty.as_path(), - TyKind::Constr(_, ty) | TyKind::Exists(_, ty) => ty.as_path(), + TyKind::BaseTy(bty) => bty.as_path(), _ => None, } } @@ -816,11 +815,11 @@ impl RefinedBy { .into_iter() .inspect(|(_, sort)| sorts.push(sort.clone())) .collect(); - let sort_params = Self::sort_params(generics, &sorts); + let sort_params = Self::gather_sort_params(generics, &sorts); RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - fn sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { + fn gather_sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { let mut sort_params: HashSet = Default::default(); for sort in sorts { @@ -886,12 +885,12 @@ impl RefinedBy { .collect() } - pub fn is_base_generic(&self, def_id: DefId) -> bool { + fn is_base_generic(&self, def_id: DefId) -> bool { self.sort_params.contains(&def_id) } } -type SortParamSubst = FxHashMap; +type SortParamSubst = UnordMap; impl Sort { /// Returns `true` if the sort is [`Bool`]. @@ -962,16 +961,21 @@ impl Sort { | Sort::Record(_, _) | Sort::Var(_) | Sort::Infer(_) => self.clone(), - Sort::Param(def_id) => subst.get(def_id).unwrap_or(self).clone(), + Sort::Param(def_id) => { + subst + .get(def_id) + .unwrap_or_else(|| bug!("expected sort for param `{def_id:?}`")) + .clone() + } Sort::App(c, args) => { let args = args.iter().map(|arg| arg.param_subst(subst)).collect(); Sort::App(c.clone(), args) } - Sort::Func(fsort) => Sort::Func(fsort.param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), + Sort::Func(fsort) => Sort::Func(fsort.mk_param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), } } - pub fn gather_sort_params(&self, params: &mut HashSet) { + fn gather_sort_params(&self, params: &mut HashSet) { match self { Sort::Int | Sort::Bool @@ -1091,7 +1095,7 @@ impl Map { } pub fn insert_generics(&self, def_id: LocalDefId, generics: Generics) { - self.generics.insert(def_id.to_def_id(), Box::new(generics)); + self.generics.insert(def_id, Box::new(generics)); } pub fn insert_generic_predicates(&mut self, def_id: LocalDefId, predicates: GenericPredicates) { @@ -1102,7 +1106,7 @@ impl Map { self.opaque_tys.extend_unord(opaque_tys.into_items()); } - pub fn get_generics(&self, def_id: DefId) -> Option<&Generics> { + pub fn get_generics(&self, def_id: LocalDefId) -> Option<&Generics> { self.generics.get(&def_id) } diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index c16306995e..cd39b0038d 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -13,10 +13,10 @@ pub use rustc_span::{symbol::Ident, Symbol}; use crate::{ cstore::CrateStoreDyn, - fhir::{self, FluxLocalDefId, GenericParamKind, VariantIdx}, + fhir::{self, FluxLocalDefId, VariantIdx}, intern::List, queries::{Providers, Queries, QueryResult}, - rty::{self, fold::TypeFoldable, normalize::Defns, refining::Refiner}, + rty::{self, fold::TypeFoldable, normalize::Defns, refining::Refiner, GenericParamDefKind}, rustc::{self, ty}, }; @@ -159,10 +159,7 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { pub fn get_generic_param(&self, def_id: LocalDefId) -> &fhir::GenericParam { let owner = self.hir().ty_param_owner(def_id); - self.map() - .get_generics(owner.to_def_id()) - .unwrap() - .get_param(def_id) + self.map().get_generics(owner).unwrap().get_param(def_id) } pub fn is_box(&self, res: fhir::Res) -> bool { @@ -214,9 +211,9 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { } fhir::Res::Def(DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct, def_id) => { let mut sort_args = vec![]; - if let Some(generics) = self.map().get_generics(def_id) { + if let Ok(generics) = self.generics_of(def_id) { for (param, arg) in generics.params.iter().zip(&path.args) { - if let GenericParamKind::SplTy = param.kind { + if let GenericParamDefKind::SplTy = param.kind { let fhir::GenericArg::Type(ty) = arg else { return None }; let sort = self.sort_of_ty(ty)?; sort_args.push(sort); diff --git a/crates/flux-middle/src/rty/mod.rs b/crates/flux-middle/src/rty/mod.rs index 6fdd869423..7f752fa380 100644 --- a/crates/flux-middle/src/rty/mod.rs +++ b/crates/flux-middle/src/rty/mod.rs @@ -206,7 +206,7 @@ pub struct AdtDef(Interned); #[derive(Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] pub struct AdtDefData { invariants: Vec, - sort: Sort, // TODO: Binder + sort: Sort, // TODO: Binder as there may be Var in `Sort` opaque: bool, rustc: rustc::ty::AdtDef, } @@ -442,7 +442,7 @@ impl GenericArg { pub fn is_valid_base_arg(&self) -> bool { match self { GenericArg::Ty(ty) => ty.kind().is_valid_base_ty(), - GenericArg::BaseTy(bty) => bty.skip_binder_as_ref().kind().is_valid_base_ty(), + GenericArg::BaseTy(bty) => bty.as_ref().skip_binder().kind().is_valid_base_ty(), _ => false, } } @@ -779,10 +779,6 @@ impl Binder { self.value } - pub fn skip_binder_as_ref(&self) -> &T { - &self.value - } - pub fn rebind(self, value: U) -> Binder { Binder { vars: self.vars, value } } From 509ef55e3c1da261aac994218426443e3b0a51e8 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 17:25:22 -0700 Subject: [PATCH 36/44] Update crates/flux-fhir-analysis/src/conv.rs Co-authored-by: Nico Lehmann --- crates/flux-fhir-analysis/src/conv.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/flux-fhir-analysis/src/conv.rs b/crates/flux-fhir-analysis/src/conv.rs index 1bc3ef38a8..bdab838aec 100644 --- a/crates/flux-fhir-analysis/src/conv.rs +++ b/crates/flux-fhir-analysis/src/conv.rs @@ -637,9 +637,6 @@ impl<'a, 'tcx> ConvCtxt<'a, 'tcx> { fn conv_base_ty(&self, env: &mut Env, bty: &fhir::BaseTy) -> QueryResult { let sort = self.genv.sort_of_bty(bty); - // if sort.is_none() { - // println!("TRACE: conv_base_ty {bty:?} ==> None"); - // } if let fhir::BaseTyKind::Path(fhir::QPath::Resolved(self_ty, path)) = &bty.kind { if let fhir::Res::Def(DefKind::AssocTy, def_id) = path.res { From 8670ef1bb0958b3c47080ab5cb2ced4839690f0a Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Wed, 1 Nov 2023 17:31:32 -0700 Subject: [PATCH 37/44] next: convert Param to Var --- crates/flux-desugar/src/desugar.rs | 4 +- crates/flux-fhir-analysis/src/wf/mod.rs | 46 +++++++++++----------- crates/flux-refineck/src/constraint_gen.rs | 2 +- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 499a774fc3..b65536b258 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -6,7 +6,7 @@ use flux_middle::{ fhir::{self, lift::LiftCtxt, ExprKind, FhirId, FluxOwnerId, Res}, global_env::GlobalEnv, intern::List, - rty::GenericParamDefKind, + rty::{self}, }; use flux_syntax::surface; use hir::{def::DefKind, ItemKind, PrimTy}; @@ -1658,7 +1658,7 @@ fn sort_of_surface_path( let mut sort_args = vec![]; if let Ok(generics) = genv.generics_of(def_id) { for (param, arg) in generics.params.iter().zip(&path.generics) { - if let GenericParamDefKind::SplTy = param.kind { + if let rty::GenericParamDefKind::SplTy = param.kind { let surface::GenericArg::Type(ty) = arg else { return None }; let surface::BaseTyKind::Path(path) = &ty.as_bty()?.kind else { return None; diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index 3597cd7d75..c40ae4ad30 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -7,8 +7,8 @@ mod sortck; use std::iter; -use flux_common::{iter::IterExt, span_bug}; -use flux_errors::FluxSession; +use flux_common::{bug, iter::IterExt, span_bug}; +use flux_errors::{FluxSession, ResultExt}; use flux_middle::{ fhir::{self, FluxOwnerId, SurfaceIdent, WfckResults}, global_env::GlobalEnv, @@ -234,8 +234,9 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { ) -> Result<(), ErrorGuaranteed> { match bound { fhir::GenericBound::Trait(trait_ref, _) => self.check_path(infcx, &trait_ref.trait_ref), - fhir::GenericBound::LangItemTrait(_, args, bindings) => { - self.check_generic_args(infcx, None, args)?; + fhir::GenericBound::LangItemTrait(lang_item, args, bindings) => { + let def_id = self.genv.tcx.require_lang_item(*lang_item, None); + self.check_generic_args(infcx, def_id, args)?; self.check_type_bindings(infcx, bindings)?; Ok(()) } @@ -361,9 +362,10 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { self.check_type(infcx, ty)?; self.check_pred(infcx, pred) } - fhir::TyKind::OpaqueDef(_, args, _refine_args, _) => { + fhir::TyKind::OpaqueDef(item_id, args, _refine_args, _) => { // TODO sanity check the _refine_args (though they should never fail!) but we'd need their expected sorts - self.check_generic_args(infcx, None, args) + let def_id = item_id.owner_id.to_def_id(); + self.check_generic_args(infcx, def_id, args) } fhir::TyKind::RawPtr(ty, _) => self.check_type(infcx, ty), fhir::TyKind::Hole(_) | fhir::TyKind::Never => Ok(()), @@ -406,19 +408,18 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { fn check_generic_args_kinds( &self, - adt_id: Option, + def_id: DefId, args: &[fhir::GenericArg], ) -> Result<(), ErrorGuaranteed> { - if let Some(def_id) = adt_id && - let Ok(generics) = self.genv.generics_of(def_id) - { - for (arg, param) in args.iter().zip(generics.params.iter()) { - if param.kind == GenericParamDefKind::SplTy { + let generics = self.genv.generics_of(def_id).emit(self.genv.sess)?; + for (arg, param) in iter::zip(args, &generics.params) { + if param.kind == GenericParamDefKind::SplTy { if let fhir::GenericArg::Type(ty) = arg { - self.check_ty_is_base(ty)?; + self.check_ty_is_base(ty)?; + } else { + bug!("expected type argument got `{arg:?}`") } - } - } + } } Ok(()) } @@ -426,10 +427,10 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { fn check_generic_args( &mut self, infcx: &mut InferCtxt, - adt_id: Option, + def_id: DefId, args: &[fhir::GenericArg], ) -> Result<(), ErrorGuaranteed> { - self.check_generic_args_kinds(adt_id, args)?; + self.check_generic_args_kinds(def_id, args)?; args.iter() .try_for_each_exhaust(|arg| self.check_generic_arg(infcx, arg)) } @@ -496,17 +497,14 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { | fhir::Res::PrimTy(..) => {} } let snapshot = self.xi.snapshot(); - let adt_id = match &path.res { - // TODO:Enums - fhir::Res::Def(DefKind::Struct, did) => Some(*did), - _ => None, - }; - let args = self.check_generic_args(infcx, adt_id, &path.args); + + if let fhir::Res::Def(_kind, did) = &path.res /*&& !matches!(_kind, DefKind::TyParam) */ && path.args.len() > 0 { + self.check_generic_args(infcx, *did, &path.args)?; + } let bindings = self.check_type_bindings(infcx, &path.bindings); if !self.genv.is_box(path.res) { self.xi.rollback_to(snapshot); } - args?; bindings?; Ok(()) } diff --git a/crates/flux-refineck/src/constraint_gen.rs b/crates/flux-refineck/src/constraint_gen.rs index 874974ca89..df1e4b6738 100644 --- a/crates/flux-refineck/src/constraint_gen.rs +++ b/crates/flux-refineck/src/constraint_gen.rs @@ -156,7 +156,7 @@ impl<'a, 'tcx> ConstrGen<'a, 'tcx> { for (idx, arg) in generic_args.iter().enumerate() { let param = generics.param_at(idx, self.genv)?; match param.kind { - GenericParamDefKind::SplTy | GenericParamDefKind::BaseTy => { + GenericParamDefKind::BaseTy => { if !arg.is_valid_base_arg() { return Err(CheckerErrKind::InvalidGenericArg); } From 11a11e42c8f31835b689f92826bcdc34fdb2d8ec Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 09:03:35 -0700 Subject: [PATCH 38/44] Var thing works? --- README.md | 6 +- crates/flux-desugar/src/desugar.rs | 19 +- crates/flux-middle/src/fhir.rs | 219 +++++++++--------- crates/flux-syntax/src/grammar.lalrpop | 10 +- crates/flux-syntax/src/surface.rs | 1 + crates/flux-tests/tests/lib/rmap.rs | 2 +- crates/flux-tests/tests/lib/rmapk.rs | 2 +- crates/flux-tests/tests/lib/rset.rs | 2 +- crates/flux-tests/tests/neg/surface/rset00.rs | 2 +- crates/flux-tests/tests/pos/surface/rset00.rs | 2 +- 10 files changed, 144 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index b666890ef6..17c9725c25 100644 --- a/README.md +++ b/README.md @@ -17,5 +17,9 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). Documentation, including installation and usage guides can be found on the [website](https://flux-rs.github.io/flux). +# TODO:rset -TRACE: insert_fn_sig DefId(0:14 ~ maps00[5caf]::rmap::{impl#0}::new) fn() -> {a0:RMap. RMap[K, V][a0] | true} \ No newline at end of file +1. add `Binder` to refined_by +2. replace Param with Var in desugar +3. update field-sort +4. update param_subst (subst_param) \ No newline at end of file diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index b65536b258..878d2aaf47 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -104,7 +104,9 @@ pub fn desugar_refined_by( Ok(()) } })?; - let sr = SortResolver::with_generics(sess, sort_decls, generics); + + // CUT let sr = SortResolver::with_generics(sess, sort_decls, generics); + let sr = SortResolver::with_sort_params(sess, sort_decls, &refined_by.sort_vars); let early_bound_params: Vec<_> = refined_by .early_bound_params @@ -117,11 +119,24 @@ pub fn desugar_refined_by( .iter() .map(|param| Ok((param.name.name, sr.resolve_sort(¶m.sort)?))) .try_collect_exhaust()?; + + let generic_idx: FxHashMap = generics + .params + .iter() + .enumerate() + .map(|(i, param)| (param.name, i)) + .collect(); + let sort_params = refined_by + .sort_vars + .iter() + .map(|ident| generic_idx[&ident.name]) + .collect(); + Ok(fhir::RefinedBy::new( owner_id.def_id, - generics, early_bound_params, index_params, + sort_params, refined_by.span, )) } diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 27da70d96b..278c1f144e 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -20,7 +20,6 @@ pub mod lift; use std::{ borrow::{Borrow, Cow}, - collections::HashSet, fmt, }; @@ -62,7 +61,7 @@ pub struct GenericParam { pub kind: GenericParamKind, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum GenericParamKind { Type { default: Option }, SplTy, @@ -540,16 +539,16 @@ impl PolyFuncSort { FuncSort { inputs_and_output } } - fn mk_param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { - let params = self.params; - let args = self - .fsort - .inputs_and_output - .iter() - .map(|arg| arg.param_subst(subst)) - .collect(); - PolyFuncSort { params, fsort: FuncSort { inputs_and_output: args } } - } + // fn mk_param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { + // let params = self.params; + // let args = self + // .fsort + // .inputs_and_output + // .iter() + // .map(|arg| arg.param_subst(subst)) + // .collect(); + // PolyFuncSort { params, fsort: FuncSort { inputs_and_output: args } } + // } } #[derive(Clone)] @@ -742,12 +741,18 @@ impl Ident { /// in a definition. /// /// [early bound]: https://rustc-dev-guide.rust-lang.org/early-late-bound.html +/// +/// Sort parameters e.g. #[flux::refined_by( elems: Set )] tracks the mapping from +/// bound Var -> Generic id. e.g. if we have RMap refined_by(keys: Set) +/// then RMapIdx = forall #0. { keys: Set<#0> } +/// and sort_params = vec![0] i.e. maps Var(0) to Generic(0) + #[derive(Clone, Debug, TyEncodable, TyDecodable)] pub struct RefinedBy { pub def_id: DefId, pub span: Span, - /// Sort parameters e.g. #[flux::refined_by( { elems: Set } )] - sort_params: Vec, // TODO: Why do we need order (why do tests break with HashSet?) + // sort_params: Vec, + sort_params: Vec, /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, /// The number of early bound parameters @@ -789,11 +794,11 @@ impl Generics { pub fn with_refined_by(self, refined_by: &RefinedBy) -> Self { let mut params = vec![]; - for param in self.params { - let kind = if refined_by.is_base_generic(param.def_id.to_def_id()) { + for (idx, param) in self.params.iter().enumerate() { + let kind = if refined_by.is_base_generic(idx) { GenericParamKind::SplTy } else { - param.kind + param.kind.clone() }; params.push(GenericParam { def_id: param.def_id, kind }); } @@ -804,9 +809,9 @@ impl Generics { impl RefinedBy { pub fn new( def_id: impl Into, - generics: &rustc_middle::ty::Generics, early_bound_params: impl IntoIterator, index_params: impl IntoIterator, + sort_params: Vec, span: Span, ) -> Self { let mut sorts = early_bound_params.into_iter().collect_vec(); @@ -815,28 +820,27 @@ impl RefinedBy { .into_iter() .inspect(|(_, sort)| sorts.push(sort.clone())) .collect(); - let sort_params = Self::gather_sort_params(generics, &sorts); RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - fn gather_sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { - let mut sort_params: HashSet = Default::default(); + // fn gather_sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { + // let mut sort_params: HashSet = Default::default(); - for sort in sorts { - sort.gather_sort_params(&mut sort_params); - } + // for sort in sorts { + // sort.gather_sort_params(&mut sort_params); + // } - let mut params = vec![]; - for param in &generics.params { - let def_id = param.def_id; - if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && - sort_params.contains(&def_id) - { - params.push(def_id); - } - } - params - } + // let mut params = vec![]; + // for param in &generics.params { + // let def_id = param.def_id; + // if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && + // sort_params.contains(&def_id) + // { + // params.push(def_id); + // } + // } + // params + // } pub fn trivial(def_id: impl Into, span: Span) -> Self { RefinedBy { @@ -853,45 +857,29 @@ impl RefinedBy { self.index_params.get_index_of(&fld) } - fn param_subst(&self, sort_args: &[Sort]) -> SortParamSubst { - // TODO: check arities? - self.sort_params - .iter() - .zip(sort_args) - .map(|(def_id, sort)| (*def_id, sort.clone())) - .collect() - } - - pub fn field_sort(&self, fld: Symbol, sort_args: &[Sort]) -> Option { - let subst = self.param_subst(sort_args); - self.index_params - .get(&fld) - .map(|sort| sort.param_subst(&subst)) + pub fn field_sort(&self, fld: Symbol, args: &[Sort]) -> Option { + self.index_params.get(&fld).map(|sort| sort.subst(args)) } - pub fn early_bound_sorts(&self, sort_args: &[Sort]) -> Vec { - let subst = &self.param_subst(sort_args); + pub fn early_bound_sorts(&self, args: &[Sort]) -> Vec { self.sorts[..self.early_bound] .iter() - .map(|sort| sort.param_subst(subst)) + .map(|sort| sort.subst(args)) .collect() } - pub fn index_sorts(&self, sort_args: &[Sort]) -> Vec { - let subst = &self.param_subst(sort_args); + pub fn index_sorts(&self, args: &[Sort]) -> Vec { self.sorts[self.early_bound..] .iter() - .map(|sort| sort.param_subst(subst)) + .map(|sort| sort.subst(args)) .collect() } - fn is_base_generic(&self, def_id: DefId) -> bool { - self.sort_params.contains(&def_id) + fn is_base_generic(&self, param_idx: usize) -> bool { + self.sort_params.contains(¶m_idx) } } -type SortParamSubst = UnordMap; - impl Sort { /// Returns `true` if the sort is [`Bool`]. /// @@ -944,64 +932,71 @@ impl Sort { let args = args.iter().map(|arg| arg.subst(subst)).collect(); Sort::App(c.clone(), args) } - Sort::Func(_) => bug!("unexpected subst in (nested) func-sort"), - } - } - - /// replace all `Param(def_id)` with their respective sort in `subst` - fn param_subst(&self, subst: &SortParamSubst) -> Sort { - match self { - Sort::Int - | Sort::Bool - | Sort::Real - | Sort::Loc - | Sort::Unit - | Sort::BitVec(_) - | Sort::Wildcard - | Sort::Record(_, _) - | Sort::Var(_) - | Sort::Infer(_) => self.clone(), - Sort::Param(def_id) => { - subst - .get(def_id) - .unwrap_or_else(|| bug!("expected sort for param `{def_id:?}`")) - .clone() - } - Sort::App(c, args) => { - let args = args.iter().map(|arg| arg.param_subst(subst)).collect(); - Sort::App(c.clone(), args) - } - Sort::Func(fsort) => Sort::Func(fsort.mk_param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), - } - } - - fn gather_sort_params(&self, params: &mut HashSet) { - match self { - Sort::Int - | Sort::Bool - | Sort::Real - | Sort::Loc - | Sort::Unit - | Sort::BitVec(_) - | Sort::Var(_) - | Sort::Infer(_) - | Sort::Wildcard => {} - Sort::Param(def_id) => { - params.insert(*def_id); - } - Sort::App(_, args) => { - for arg in args { - arg.gather_sort_params(params); - } - } Sort::Func(fsort) => { - for arg in &fsort.fsort.inputs_and_output { - arg.gather_sort_params(params); + if fsort.params == 0 { + let fsort = fsort.instantiate(subst); + Sort::Func(PolyFuncSort { params: 0, fsort }) + } else { + bug!("unexpected subst in (nested) func-sort") } } - Sort::Record(_, _) => bug!("unexpected record sort"), } } + + // /// replace all `Param(def_id)` with their respective sort in `subst` + // fn param_subst(&self, subst: &SortParamSubst) -> Sort { + // match self { + // Sort::Int + // | Sort::Bool + // | Sort::Real + // | Sort::Loc + // | Sort::Unit + // | Sort::BitVec(_) + // | Sort::Wildcard + // | Sort::Record(_, _) + // | Sort::Var(_) + // | Sort::Infer(_) => self.clone(), + // Sort::Param(def_id) => { + // subst + // .get(def_id) + // .unwrap_or_else(|| bug!("expected sort for param `{def_id:?}`")) + // .clone() + // } + // Sort::App(c, args) => { + // let args = args.iter().map(|arg| arg.param_subst(subst)).collect(); + // Sort::App(c.clone(), args) + // } + // Sort::Func(fsort) => Sort::Func(fsort.mk_param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), + // } + // } + + // fn gather_sort_params(&self, params: &mut HashSet) { + // match self { + // Sort::Int + // | Sort::Bool + // | Sort::Real + // | Sort::Loc + // | Sort::Unit + // | Sort::BitVec(_) + // | Sort::Var(_) + // | Sort::Infer(_) + // | Sort::Wildcard => {} + // Sort::Param(def_id) => { + // params.insert(*def_id); + // } + // Sort::App(_, args) => { + // for arg in args { + // arg.gather_sort_params(params); + // } + // } + // Sort::Func(fsort) => { + // for arg in &fsort.fsort.inputs_and_output { + // arg.gather_sort_params(params); + // } + // } + // Sort::Record(_, _) => bug!("unexpected record sort"), + // } + // } } impl ena::unify::UnifyKey for SortVid { diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 944355db0e..5b25dcab78 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -48,6 +48,7 @@ pub TyAlias: surface::TyAlias = { => { let refined_by = surface::RefinedBy { + sort_vars: vec![], early_bound_params: early_bound_params.unwrap_or_default(), index_params: index_params.unwrap_or_default(), span: cx.map_span(refined_by_lo, refined_by_hi) @@ -63,7 +64,14 @@ pub TyAlias: surface::TyAlias = { } pub RefinedBy: surface::RefinedBy = { - > => surface::RefinedBy { + "{" > "}" => surface::RefinedBy { + sort_vars, + index_params, + early_bound_params: vec![], + span: cx.map_span(lo, hi) + }, + > => surface::RefinedBy { + sort_vars: vec![], index_params, early_bound_params: vec![], span: cx.map_span(lo, hi) diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index 9b1c440a80..46b9f57c9a 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -108,6 +108,7 @@ pub struct VariantRet { #[derive(Debug, Default)] pub struct RefinedBy { pub early_bound_params: Vec, + pub sort_vars: Vec, pub index_params: Vec, pub span: Span, } diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index 8f74fbc6ef..df91805897 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -9,7 +9,7 @@ use std::hash::Hash; /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by(vals: Map)] +#[flux::refined_by( { vals: Map } )] pub struct RMap { inner: std::collections::HashMap, } diff --git a/crates/flux-tests/tests/lib/rmapk.rs b/crates/flux-tests/tests/lib/rmapk.rs index 0e142fa457..4c38043cea 100644 --- a/crates/flux-tests/tests/lib/rmapk.rs +++ b/crates/flux-tests/tests/lib/rmapk.rs @@ -12,7 +12,7 @@ use std::hash::Hash; /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by(keys: Set, vals: Map)] +#[flux::refined_by({keys: Set, vals: Map})] pub struct RMap { inner: std::collections::HashMap, } diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 6895738128..38787baa8d 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -3,7 +3,7 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set)] +#[flux::refined_by( {elems: Set})] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/neg/surface/rset00.rs b/crates/flux-tests/tests/neg/surface/rset00.rs index 669cbee38a..39d987981b 100644 --- a/crates/flux-tests/tests/neg/surface/rset00.rs +++ b/crates/flux-tests/tests/neg/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set)] +#[flux::refined_by( { elems: Set } )] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index d85211c8a3..96961ca2a4 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by(elems: Set )] +#[flux::refined_by( { elems: Set } )] pub struct RSet { pub inner: std::collections::HashSet, } From 23c2a68d0976b4c439a0d6787a369a5dd3e41d10 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 09:07:29 -0700 Subject: [PATCH 39/44] done. --- README.md | 9 +--- crates/flux-desugar/src/desugar.rs | 1 - crates/flux-middle/src/fhir.rs | 75 ------------------------------ 3 files changed, 1 insertion(+), 84 deletions(-) diff --git a/README.md b/README.md index 17c9725c25..0d3ddccd53 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,4 @@ For an overview, take a look at the [`flux` website](https://flux-rs.github.io). # Docs Documentation, including installation and usage guides can be found on the -[website](https://flux-rs.github.io/flux). - -# TODO:rset - -1. add `Binder` to refined_by -2. replace Param with Var in desugar -3. update field-sort -4. update param_subst (subst_param) \ No newline at end of file +[website](https://flux-rs.github.io/flux). \ No newline at end of file diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 878d2aaf47..2ab2488510 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -105,7 +105,6 @@ pub fn desugar_refined_by( } })?; - // CUT let sr = SortResolver::with_generics(sess, sort_decls, generics); let sr = SortResolver::with_sort_params(sess, sort_decls, &refined_by.sort_vars); let early_bound_params: Vec<_> = refined_by diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 278c1f144e..8d603b8fce 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -751,7 +751,6 @@ impl Ident { pub struct RefinedBy { pub def_id: DefId, pub span: Span, - // sort_params: Vec, sort_params: Vec, /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, @@ -823,25 +822,6 @@ impl RefinedBy { RefinedBy { def_id: def_id.into(), sort_params, span, index_params, early_bound, sorts } } - // fn gather_sort_params(generics: &rustc_middle::ty::Generics, sorts: &Vec) -> Vec { - // let mut sort_params: HashSet = Default::default(); - - // for sort in sorts { - // sort.gather_sort_params(&mut sort_params); - // } - - // let mut params = vec![]; - // for param in &generics.params { - // let def_id = param.def_id; - // if let rustc_middle::ty::GenericParamDefKind::Type { .. } = param.kind && - // sort_params.contains(&def_id) - // { - // params.push(def_id); - // } - // } - // params - // } - pub fn trivial(def_id: impl Into, span: Span) -> Self { RefinedBy { def_id: def_id.into(), @@ -942,61 +922,6 @@ impl Sort { } } } - - // /// replace all `Param(def_id)` with their respective sort in `subst` - // fn param_subst(&self, subst: &SortParamSubst) -> Sort { - // match self { - // Sort::Int - // | Sort::Bool - // | Sort::Real - // | Sort::Loc - // | Sort::Unit - // | Sort::BitVec(_) - // | Sort::Wildcard - // | Sort::Record(_, _) - // | Sort::Var(_) - // | Sort::Infer(_) => self.clone(), - // Sort::Param(def_id) => { - // subst - // .get(def_id) - // .unwrap_or_else(|| bug!("expected sort for param `{def_id:?}`")) - // .clone() - // } - // Sort::App(c, args) => { - // let args = args.iter().map(|arg| arg.param_subst(subst)).collect(); - // Sort::App(c.clone(), args) - // } - // Sort::Func(fsort) => Sort::Func(fsort.mk_param_subst(subst)), // bug!("unexpected subst in (nested) func-sort {self:?}"), - // } - // } - - // fn gather_sort_params(&self, params: &mut HashSet) { - // match self { - // Sort::Int - // | Sort::Bool - // | Sort::Real - // | Sort::Loc - // | Sort::Unit - // | Sort::BitVec(_) - // | Sort::Var(_) - // | Sort::Infer(_) - // | Sort::Wildcard => {} - // Sort::Param(def_id) => { - // params.insert(*def_id); - // } - // Sort::App(_, args) => { - // for arg in args { - // arg.gather_sort_params(params); - // } - // } - // Sort::Func(fsort) => { - // for arg in &fsort.fsort.inputs_and_output { - // arg.gather_sort_params(params); - // } - // } - // Sort::Record(_, _) => bug!("unexpected record sort"), - // } - // } } impl ena::unify::UnifyKey for SortVid { From bea972dd56390730897697e206900c27d8183a08 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 09:09:54 -0700 Subject: [PATCH 40/44] done. --- Cargo.lock | 8 ++++---- crates/flux-fhir-analysis/src/wf/mod.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba30fe2f4d..b4e24f95e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -821,9 +821,9 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" @@ -1177,9 +1177,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.4.0", "errno", diff --git a/crates/flux-fhir-analysis/src/wf/mod.rs b/crates/flux-fhir-analysis/src/wf/mod.rs index c40ae4ad30..050f5ae50c 100644 --- a/crates/flux-fhir-analysis/src/wf/mod.rs +++ b/crates/flux-fhir-analysis/src/wf/mod.rs @@ -417,7 +417,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { if let fhir::GenericArg::Type(ty) = arg { self.check_ty_is_base(ty)?; } else { - bug!("expected type argument got `{arg:?}`") + bug!("expected type argument got `{arg:?}`"); } } } @@ -498,7 +498,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { } let snapshot = self.xi.snapshot(); - if let fhir::Res::Def(_kind, did) = &path.res /*&& !matches!(_kind, DefKind::TyParam) */ && path.args.len() > 0 { + if let fhir::Res::Def(_kind, did) = &path.res /*&& !matches!(_kind, DefKind::TyParam) */ && !path.args.is_empty() { self.check_generic_args(infcx, *did, &path.args)?; } let bindings = self.check_type_bindings(infcx, &path.bindings); From aee782b7c183998100cc87098aa139b5fa2eb3fb Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 11:09:07 -0700 Subject: [PATCH 41/44] remove explicit sort_params --- crates/flux-desugar/src/desugar.rs | 73 ++++++++++++++++--- crates/flux-syntax/src/grammar.lalrpop | 8 -- crates/flux-syntax/src/surface.rs | 1 - crates/flux-tests/tests/lib/rmap.rs | 2 +- crates/flux-tests/tests/lib/rmapk.rs | 2 +- crates/flux-tests/tests/lib/rset.rs | 2 +- crates/flux-tests/tests/neg/surface/rset00.rs | 2 +- crates/flux-tests/tests/pos/surface/rset00.rs | 2 +- 8 files changed, 66 insertions(+), 26 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index 2ab2488510..e1b7503f72 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -10,6 +10,7 @@ use flux_middle::{ }; use flux_syntax::surface; use hir::{def::DefKind, ItemKind, PrimTy}; +use itertools::Itertools; use rustc_data_structures::{ fx::{FxIndexMap, IndexEntry}, unord::UnordMap, @@ -53,9 +54,9 @@ pub fn desugar_qualifier( pub fn desugar_defn(genv: &GlobalEnv, defn: surface::FuncDef) -> Result> { if let Some(body) = defn.body { - let sort_params = &defn.sort_vars[..]; + let sort_params = defn.sort_vars.iter().map(|ident| ident.name).collect_vec(); let sort_resolver = - SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), sort_params); + SortResolver::with_sort_params(genv.sess, genv.map().sort_decls(), &sort_params); let mut binders = Binders::from_params(genv, &sort_resolver, &defn.args)?; let local_id_gen = IndexGen::new(); let cx = ExprCtxt::new(genv, FluxOwnerId::Flux(defn.name.name), &local_id_gen); @@ -76,8 +77,8 @@ pub fn func_def_to_func_decl( defn: &surface::FuncDef, ) -> Result { let params = defn.sort_vars.len(); - let sort_vars = &defn.sort_vars[..]; - let sr = SortResolver::with_sort_params(sess, sort_decls, sort_vars); + let sort_vars = defn.sort_vars.iter().map(|ident| ident.name).collect_vec(); + let sr = SortResolver::with_sort_params(sess, sort_decls, &sort_vars); let inputs: Vec = defn .args .iter() @@ -89,6 +90,57 @@ pub fn func_def_to_func_decl( Ok(fhir::FuncDecl { name: defn.name.name, sort, kind }) } +fn gather_base_sort_vars( + generics: &FxHashSet, + base_sort: &surface::BaseSort, + sort_vars: &mut FxHashSet, +) { + match base_sort { + surface::BaseSort::Ident(x) => { + if generics.contains(&x.name) { + sort_vars.insert(x.name); + } + } + surface::BaseSort::BitVec(_) => {} + surface::BaseSort::App(_, base_sorts) => { + for base_sort in base_sorts { + gather_base_sort_vars(generics, base_sort, sort_vars) + } + } + } +} +fn gather_sort_vars( + generics: &FxHashSet, + sort: &surface::Sort, + sort_vars: &mut FxHashSet, +) { + match sort { + surface::Sort::Base(base_sort) => gather_base_sort_vars(generics, base_sort, sort_vars), + surface::Sort::Func { inputs, output } => { + for base_sort in inputs { + gather_base_sort_vars(generics, base_sort, sort_vars); + } + gather_base_sort_vars(generics, output, sort_vars); + } + surface::Sort::Infer => {} + } +} + +fn gather_refined_by_sort_vars( + generics: &rustc_middle::ty::Generics, + refined_by: &surface::RefinedBy, +) -> Vec { + let generics_syms: FxHashSet = generics.params.iter().map(|param| param.name).collect(); + let mut sort_idents = FxHashSet::default(); + for refine_param in &refined_by.index_params { + gather_sort_vars(&generics_syms, &refine_param.sort, &mut sort_idents); + } + generics + .params + .iter() + .filter_map(|param| if sort_idents.contains(¶m.name) { Some(param.name) } else { None }) + .collect() +} pub fn desugar_refined_by( sess: &FluxSession, sort_decls: &fhir::SortDecls, @@ -105,7 +157,8 @@ pub fn desugar_refined_by( } })?; - let sr = SortResolver::with_sort_params(sess, sort_decls, &refined_by.sort_vars); + let sort_vars = gather_refined_by_sort_vars(generics, refined_by); + let sr = SortResolver::with_sort_params(sess, sort_decls, &sort_vars); let early_bound_params: Vec<_> = refined_by .early_bound_params @@ -125,11 +178,7 @@ pub fn desugar_refined_by( .enumerate() .map(|(i, param)| (param.name, i)) .collect(); - let sort_params = refined_by - .sort_vars - .iter() - .map(|ident| generic_idx[&ident.name]) - .collect(); + let sort_params = sort_vars.iter().map(|sym| generic_idx[&sym]).collect(); Ok(fhir::RefinedBy::new( owner_id.def_id, @@ -1366,12 +1415,12 @@ impl<'a> SortResolver<'a> { pub fn with_sort_params( sess: &'a FluxSession, sort_decls: &'a fhir::SortDecls, - sort_params: &[surface::Ident], + sort_params: &[Symbol], ) -> Self { let sort_params = sort_params .iter() .enumerate() - .map(|(i, v)| (v.name, i)) + .map(|(i, v)| (*v, i)) .collect(); Self { sess, sort_decls, generic_params: Default::default(), sort_params } } diff --git a/crates/flux-syntax/src/grammar.lalrpop b/crates/flux-syntax/src/grammar.lalrpop index 5b25dcab78..f637d6fd2e 100644 --- a/crates/flux-syntax/src/grammar.lalrpop +++ b/crates/flux-syntax/src/grammar.lalrpop @@ -48,7 +48,6 @@ pub TyAlias: surface::TyAlias = { => { let refined_by = surface::RefinedBy { - sort_vars: vec![], early_bound_params: early_bound_params.unwrap_or_default(), index_params: index_params.unwrap_or_default(), span: cx.map_span(refined_by_lo, refined_by_hi) @@ -64,14 +63,7 @@ pub TyAlias: surface::TyAlias = { } pub RefinedBy: surface::RefinedBy = { - "{" > "}" => surface::RefinedBy { - sort_vars, - index_params, - early_bound_params: vec![], - span: cx.map_span(lo, hi) - }, > => surface::RefinedBy { - sort_vars: vec![], index_params, early_bound_params: vec![], span: cx.map_span(lo, hi) diff --git a/crates/flux-syntax/src/surface.rs b/crates/flux-syntax/src/surface.rs index 46b9f57c9a..9b1c440a80 100644 --- a/crates/flux-syntax/src/surface.rs +++ b/crates/flux-syntax/src/surface.rs @@ -108,7 +108,6 @@ pub struct VariantRet { #[derive(Debug, Default)] pub struct RefinedBy { pub early_bound_params: Vec, - pub sort_vars: Vec, pub index_params: Vec, pub span: Span, } diff --git a/crates/flux-tests/tests/lib/rmap.rs b/crates/flux-tests/tests/lib/rmap.rs index df91805897..8f74fbc6ef 100644 --- a/crates/flux-tests/tests/lib/rmap.rs +++ b/crates/flux-tests/tests/lib/rmap.rs @@ -9,7 +9,7 @@ use std::hash::Hash; /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by( { vals: Map } )] +#[flux::refined_by(vals: Map)] pub struct RMap { inner: std::collections::HashMap, } diff --git a/crates/flux-tests/tests/lib/rmapk.rs b/crates/flux-tests/tests/lib/rmapk.rs index 4c38043cea..0e142fa457 100644 --- a/crates/flux-tests/tests/lib/rmapk.rs +++ b/crates/flux-tests/tests/lib/rmapk.rs @@ -12,7 +12,7 @@ use std::hash::Hash; /// define a type indexed by a map #[flux::opaque] -#[flux::refined_by({keys: Set, vals: Map})] +#[flux::refined_by(keys: Set, vals: Map)] pub struct RMap { inner: std::collections::HashMap, } diff --git a/crates/flux-tests/tests/lib/rset.rs b/crates/flux-tests/tests/lib/rset.rs index 38787baa8d..6895738128 100644 --- a/crates/flux-tests/tests/lib/rset.rs +++ b/crates/flux-tests/tests/lib/rset.rs @@ -3,7 +3,7 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by( {elems: Set})] +#[flux::refined_by(elems: Set)] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/neg/surface/rset00.rs b/crates/flux-tests/tests/neg/surface/rset00.rs index 39d987981b..669cbee38a 100644 --- a/crates/flux-tests/tests/neg/surface/rset00.rs +++ b/crates/flux-tests/tests/neg/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by( { elems: Set } )] +#[flux::refined_by(elems: Set)] pub struct RSet { pub inner: std::collections::HashSet, } diff --git a/crates/flux-tests/tests/pos/surface/rset00.rs b/crates/flux-tests/tests/pos/surface/rset00.rs index 96961ca2a4..9a5f5f89de 100644 --- a/crates/flux-tests/tests/pos/surface/rset00.rs +++ b/crates/flux-tests/tests/pos/surface/rset00.rs @@ -1,6 +1,6 @@ use std::hash::Hash; #[flux::opaque] -#[flux::refined_by( { elems: Set } )] +#[flux::refined_by( elems: Set )] pub struct RSet { pub inner: std::collections::HashSet, } From 08c5ca01f60d2216b3d134e983bcb84a0f47c4e8 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 11:14:14 -0700 Subject: [PATCH 42/44] Update crates/flux-middle/src/fhir.rs Co-authored-by: Nico Lehmann --- crates/flux-middle/src/fhir.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index c29629e89a..9095714f0d 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -539,16 +539,6 @@ impl PolyFuncSort { FuncSort { inputs_and_output } } - // fn mk_param_subst(&self, subst: &SortParamSubst) -> PolyFuncSort { - // let params = self.params; - // let args = self - // .fsort - // .inputs_and_output - // .iter() - // .map(|arg| arg.param_subst(subst)) - // .collect(); - // PolyFuncSort { params, fsort: FuncSort { inputs_and_output: args } } - // } } #[derive(Clone)] From 369ae2a33eca7899b76fb5effd7f89308e05fde5 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 11:15:01 -0700 Subject: [PATCH 43/44] Update crates/flux-middle/src/fhir.rs Co-authored-by: Nico Lehmann --- crates/flux-middle/src/fhir.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index 9095714f0d..e2911393fc 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -737,7 +737,6 @@ impl Ident { /// bound Var -> Generic id. e.g. if we have RMap refined_by(keys: Set) /// then RMapIdx = forall #0. { keys: Set<#0> } /// and sort_params = vec![0] i.e. maps Var(0) to Generic(0) - #[derive(Clone, Debug, TyEncodable, TyDecodable)] pub struct RefinedBy { pub def_id: DefId, From 6746174963b0bfaf07e79631863df04347934fb5 Mon Sep 17 00:00:00 2001 From: Ranjit Jhala Date: Thu, 2 Nov 2023 11:32:36 -0700 Subject: [PATCH 44/44] map sort-var to DefId --- crates/flux-desugar/src/desugar.rs | 7 +++---- crates/flux-middle/src/fhir.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/flux-desugar/src/desugar.rs b/crates/flux-desugar/src/desugar.rs index e1b7503f72..3f158e1847 100644 --- a/crates/flux-desugar/src/desugar.rs +++ b/crates/flux-desugar/src/desugar.rs @@ -104,7 +104,7 @@ fn gather_base_sort_vars( surface::BaseSort::BitVec(_) => {} surface::BaseSort::App(_, base_sorts) => { for base_sort in base_sorts { - gather_base_sort_vars(generics, base_sort, sort_vars) + gather_base_sort_vars(generics, base_sort, sort_vars); } } } @@ -172,11 +172,10 @@ pub fn desugar_refined_by( .map(|param| Ok((param.name.name, sr.resolve_sort(¶m.sort)?))) .try_collect_exhaust()?; - let generic_idx: FxHashMap = generics + let generic_idx: FxHashMap = generics .params .iter() - .enumerate() - .map(|(i, param)| (param.name, i)) + .map(|param| (param.name, param.def_id)) .collect(); let sort_params = sort_vars.iter().map(|sym| generic_idx[&sym]).collect(); diff --git a/crates/flux-middle/src/fhir.rs b/crates/flux-middle/src/fhir.rs index c29629e89a..5847933e47 100644 --- a/crates/flux-middle/src/fhir.rs +++ b/crates/flux-middle/src/fhir.rs @@ -746,13 +746,13 @@ impl Ident { /// Sort parameters e.g. #[flux::refined_by( elems: Set )] tracks the mapping from /// bound Var -> Generic id. e.g. if we have RMap refined_by(keys: Set) /// then RMapIdx = forall #0. { keys: Set<#0> } -/// and sort_params = vec![0] i.e. maps Var(0) to Generic(0) +/// and sort_params = vec![T] i.e. maps Var(0) to T #[derive(Clone, Debug, TyEncodable, TyDecodable)] pub struct RefinedBy { pub def_id: DefId, pub span: Span, - sort_params: Vec, + sort_params: Vec, /// Index parameters indexed by their name and in the same order they appear in the definition. index_params: FxIndexMap, /// The number of early bound parameters @@ -794,8 +794,8 @@ impl Generics { pub fn with_refined_by(self, refined_by: &RefinedBy) -> Self { let mut params = vec![]; - for (idx, param) in self.params.iter().enumerate() { - let kind = if refined_by.is_base_generic(idx) { + for param in self.params { + let kind = if refined_by.is_base_generic(param.def_id.to_def_id()) { GenericParamKind::SplTy } else { param.kind.clone() @@ -811,7 +811,7 @@ impl RefinedBy { def_id: impl Into, early_bound_params: impl IntoIterator, index_params: impl IntoIterator, - sort_params: Vec, + sort_params: Vec, span: Span, ) -> Self { let mut sorts = early_bound_params.into_iter().collect_vec(); @@ -856,8 +856,8 @@ impl RefinedBy { .collect() } - fn is_base_generic(&self, param_idx: usize) -> bool { - self.sort_params.contains(¶m_idx) + fn is_base_generic(&self, def_id: DefId) -> bool { + self.sort_params.contains(&def_id) } }