Skip to content

Commit db64c20

Browse files
committed
Fixes to allow nested polymorphic calls
1 parent 78c206f commit db64c20

6 files changed

Lines changed: 339 additions & 214 deletions

File tree

src/analyze.rs

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::collections::HashMap;
1111
use std::rc::Rc;
1212

1313
use rustc_hir::lang_items::LangItem;
14-
use rustc_index::IndexVec;
1514
use rustc_middle::mir::{self, BasicBlock, Local};
1615
use rustc_middle::ty::{self as mir_ty, TyCtxt};
1716
use rustc_span::def_id::{DefId, LocalDefId};
@@ -105,14 +104,14 @@ impl<'tcx> ReplacePlacesVisitor<'tcx> {
105104
}
106105

107106
#[derive(Debug, Clone)]
108-
struct DeferredDefTy<'tcx> {
109-
cache: Rc<RefCell<HashMap<Vec<mir_ty::Ty<'tcx>>, rty::RefinedType>>>,
107+
struct DeferredDefTy {
108+
cache: Rc<RefCell<HashMap<rty::TypeArgs, rty::RefinedType>>>,
110109
}
111110

112111
#[derive(Debug, Clone)]
113-
enum DefTy<'tcx> {
112+
enum DefTy {
114113
Concrete(rty::RefinedType),
115-
Deferred(DeferredDefTy<'tcx>),
114+
Deferred(DeferredDefTy),
116115
}
117116

118117
#[derive(Clone)]
@@ -124,7 +123,7 @@ pub struct Analyzer<'tcx> {
124123
/// currently contains only local-def templates,
125124
/// but will be extended to contain externally known def's refinement types
126125
/// (at least for every defs referenced by local def bodies)
127-
defs: HashMap<DefId, DefTy<'tcx>>,
126+
defs: HashMap<DefId, DefTy>,
128127

129128
/// Resulting CHC system.
130129
system: Rc<RefCell<chc::System>>,
@@ -242,11 +241,8 @@ impl<'tcx> Analyzer<'tcx> {
242241
pub fn def_ty_with_args(
243242
&mut self,
244243
def_id: DefId,
245-
args: mir_ty::GenericArgsRef<'tcx>,
244+
rty_args: rty::TypeArgs,
246245
) -> Option<rty::RefinedType> {
247-
let type_builder = TypeBuilder::new(self.tcx, def_id);
248-
let rty_args: IndexVec<_, _> = args.types().map(|ty| type_builder.build(ty)).collect();
249-
250246
let deferred_ty = match self.defs.get(&def_id)? {
251247
DefTy::Concrete(rty) => {
252248
let mut def_ty = rty.clone();
@@ -262,28 +258,24 @@ impl<'tcx> Analyzer<'tcx> {
262258
DefTy::Deferred(deferred) => deferred,
263259
};
264260

265-
let ty_args: Vec<_> = args.types().collect();
266261
let deferred_ty_cache = Rc::clone(&deferred_ty.cache); // to cut reference to allow &mut self
267-
if let Some(rty) = deferred_ty_cache.borrow().get(&ty_args) {
262+
if let Some(rty) = deferred_ty_cache.borrow().get(&rty_args) {
268263
return Some(rty.clone());
269264
}
270-
let local_def_id = def_id.as_local()?;
271-
272-
let sig = self
273-
.tcx
274-
.fn_sig(def_id)
275-
.instantiate(self.tcx, args)
276-
.skip_binder();
277-
let expected = self
278-
.crate_analyzer()
279-
.fn_def_ty_with_sig(local_def_id.to_def_id(), sig)
280-
.unwrap();
281-
self.local_def_analyzer(local_def_id)
282-
.type_builder(type_builder.with_param_mapper(move |ty| rty_args[ty.idx].clone()))
283-
.run(&expected);
265+
266+
let type_builder = TypeBuilder::new(self.tcx, def_id).with_param_mapper({
267+
let rty_args = rty_args.clone();
268+
move |ty: rty::ParamType| rty_args[ty.idx].clone()
269+
});
270+
let mut analyzer = self.local_def_analyzer(def_id.as_local()?);
271+
analyzer.type_builder(type_builder);
272+
273+
let expected = analyzer.expected_ty();
284274
deferred_ty_cache
285275
.borrow_mut()
286-
.insert(ty_args, expected.clone());
276+
.insert(rty_args, expected.clone());
277+
278+
analyzer.run(&expected);
287279
Some(expected)
288280
}
289281

src/analyze/basic_block.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,15 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
263263
_ty,
264264
) => {
265265
let func_ty = match operand.const_fn_def() {
266-
Some((def_id, args)) => self
267-
.ctx
268-
.def_ty_with_args(def_id, args)
269-
.expect("unknown def")
270-
.ty
271-
.clone(),
266+
Some((def_id, args)) => {
267+
let rty_args: IndexVec<_, _> =
268+
args.types().map(|ty| self.type_builder.build(ty)).collect();
269+
self.ctx
270+
.def_ty_with_args(def_id, rty_args)
271+
.expect("unknown def")
272+
.ty
273+
.clone()
274+
}
272275
_ => unimplemented!(),
273276
};
274277
PlaceType::with_ty_and_term(func_ty.vacuous(), chc::Term::null())
@@ -468,12 +471,14 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
468471
let ret = rty::RefinedType::new(rty::Type::unit(), ret_formula.into());
469472
rty::FunctionType::new([param1, param2].into_iter().collect(), ret).into()
470473
}
471-
Some((def_id, args)) => self
472-
.ctx
473-
.def_ty_with_args(def_id, args)
474-
.expect("unknown def")
475-
.ty
476-
.vacuous(),
474+
Some((def_id, args)) => {
475+
let rty_args = args.types().map(|ty| self.type_builder.build(ty)).collect();
476+
self.ctx
477+
.def_ty_with_args(def_id, rty_args)
478+
.expect("unknown def")
479+
.ty
480+
.vacuous()
481+
}
477482
_ => self.operand_type(func.clone()).ty,
478483
};
479484
let expected_args: IndexVec<_, _> = args

src/analyze/crate_.rs

Lines changed: 16 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ use std::collections::HashSet;
55
use rustc_hir::def::DefKind;
66
use rustc_index::IndexVec;
77
use rustc_middle::ty::{self as mir_ty, TyCtxt};
8-
use rustc_span::def_id::DefId;
9-
use rustc_span::symbol::Ident;
8+
use rustc_span::def_id::{DefId, LocalDefId};
109

1110
use crate::analyze;
12-
use crate::annot::{self, AnnotFormula, AnnotParser, ResolverExt as _};
1311
use crate::chc;
1412
use crate::refine::{self, TypeBuilder};
1513
use crate::rty::{self, ClauseBuilderExt as _};
@@ -34,188 +32,31 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
3432
fn refine_local_defs(&mut self) {
3533
for local_def_id in self.tcx.mir_keys(()) {
3634
if self.tcx.def_kind(*local_def_id).is_fn_like() {
37-
self.refine_fn_def(local_def_id.to_def_id());
35+
self.refine_fn_def(*local_def_id);
3836
}
3937
}
4038
}
4139

42-
fn extract_require_annot<T>(
43-
&self,
44-
resolver: T,
45-
def_id: DefId,
46-
) -> Option<AnnotFormula<T::Output>>
47-
where
48-
T: annot::Resolver,
49-
{
50-
let mut require_annot = None;
51-
for attrs in self
52-
.tcx
53-
.get_attrs_by_path(def_id, &analyze::annot::requires_path())
54-
{
55-
if require_annot.is_some() {
56-
unimplemented!();
57-
}
58-
let ts = analyze::annot::extract_annot_tokens(attrs.clone());
59-
let require = AnnotParser::new(&resolver).parse_formula(ts).unwrap();
60-
require_annot = Some(require);
61-
}
62-
require_annot
63-
}
40+
#[tracing::instrument(skip(self), fields(def_id = %self.tcx.def_path_str(local_def_id)))]
41+
fn refine_fn_def(&mut self, local_def_id: LocalDefId) {
42+
let mut analyzer = self.ctx.local_def_analyzer(local_def_id);
6443

65-
fn extract_ensure_annot<T>(&self, resolver: T, def_id: DefId) -> Option<AnnotFormula<T::Output>>
66-
where
67-
T: annot::Resolver,
68-
{
69-
let mut ensure_annot = None;
70-
for attrs in self
71-
.tcx
72-
.get_attrs_by_path(def_id, &analyze::annot::ensures_path())
73-
{
74-
if ensure_annot.is_some() {
75-
unimplemented!();
76-
}
77-
let ts = analyze::annot::extract_annot_tokens(attrs.clone());
78-
let ensure = AnnotParser::new(&resolver).parse_formula(ts).unwrap();
79-
ensure_annot = Some(ensure);
44+
if analyzer.is_annotated_as_trusted() {
45+
assert!(analyzer.is_fully_annotated());
46+
self.trusted.insert(local_def_id.to_def_id());
8047
}
81-
ensure_annot
82-
}
8348

84-
fn extract_param_annots<T>(
85-
&self,
86-
resolver: T,
87-
def_id: DefId,
88-
) -> Vec<(Ident, rty::RefinedType<T::Output>)>
89-
where
90-
T: annot::Resolver,
91-
{
92-
let mut param_annots = Vec::new();
93-
for attrs in self
49+
let sig = self
9450
.tcx
95-
.get_attrs_by_path(def_id, &analyze::annot::param_path())
96-
{
97-
let ts = analyze::annot::extract_annot_tokens(attrs.clone());
98-
let (ident, ts) = analyze::annot::split_param(&ts);
99-
let param = AnnotParser::new(&resolver).parse_rty(ts).unwrap();
100-
param_annots.push((ident, param));
101-
}
102-
param_annots
103-
}
104-
105-
fn extract_ret_annot<T>(
106-
&self,
107-
resolver: T,
108-
def_id: DefId,
109-
) -> Option<rty::RefinedType<T::Output>>
110-
where
111-
T: annot::Resolver,
112-
{
113-
let mut ret_annot = None;
114-
for attrs in self
115-
.tcx
116-
.get_attrs_by_path(def_id, &analyze::annot::ret_path())
117-
{
118-
if ret_annot.is_some() {
119-
unimplemented!();
120-
}
121-
let ts = analyze::annot::extract_annot_tokens(attrs.clone());
122-
let ret = AnnotParser::new(&resolver).parse_rty(ts).unwrap();
123-
ret_annot = Some(ret);
124-
}
125-
ret_annot
126-
}
127-
128-
#[tracing::instrument(skip(self), fields(def_id = %self.tcx.def_path_str(def_id)))]
129-
fn refine_fn_def(&mut self, def_id: DefId) {
130-
let sig = self.tcx.fn_sig(def_id);
131-
let sig = sig.instantiate_identity().skip_binder();
132-
if let Some(rty) = self.fn_def_ty_with_sig(def_id, sig) {
133-
self.ctx.register_def(def_id, rty);
134-
} else {
135-
self.ctx.register_deferred_def(def_id);
136-
}
137-
}
138-
139-
pub fn fn_def_ty_with_sig(
140-
&mut self,
141-
def_id: DefId,
142-
sig: mir_ty::FnSig<'tcx>,
143-
) -> Option<rty::RefinedType> {
144-
let mut param_resolver = analyze::annot::ParamResolver::default();
145-
for (input_ident, input_ty) in self.tcx.fn_arg_names(def_id).iter().zip(sig.inputs()) {
146-
let input_ty = TypeBuilder::new(self.tcx, def_id).build(*input_ty);
147-
param_resolver.push_param(input_ident.name, input_ty.to_sort());
148-
}
149-
150-
let mut require_annot = self.extract_require_annot(&param_resolver, def_id);
151-
let mut ensure_annot = {
152-
let output_ty = TypeBuilder::new(self.tcx, def_id).build(sig.output());
153-
let resolver = annot::StackedResolver::default()
154-
.resolver(analyze::annot::ResultResolver::new(output_ty.to_sort()))
155-
.resolver((&param_resolver).map(rty::RefinedTypeVar::Free));
156-
self.extract_ensure_annot(resolver, def_id)
157-
};
158-
let param_annots = self.extract_param_annots(&param_resolver, def_id);
159-
let ret_annot = self.extract_ret_annot(&param_resolver, def_id);
160-
161-
if self
162-
.tcx
163-
.get_attrs_by_path(def_id, &analyze::annot::callable_path())
164-
.next()
165-
.is_some()
166-
{
167-
if require_annot.is_some() || ensure_annot.is_some() {
168-
unimplemented!();
169-
}
170-
171-
require_annot = Some(AnnotFormula::top());
172-
ensure_annot = Some(AnnotFormula::top());
173-
}
174-
175-
assert!(require_annot.is_none() || param_annots.is_empty());
176-
assert!(ensure_annot.is_none() || ret_annot.is_none());
177-
178-
if self
179-
.tcx
180-
.get_attrs_by_path(def_id, &analyze::annot::trusted_path())
181-
.next()
182-
.is_some()
183-
{
184-
assert!(require_annot.is_some() || !param_annots.is_empty());
185-
assert!(ensure_annot.is_some() || ret_annot.is_some());
186-
self.trusted.insert(def_id);
187-
}
188-
189-
let mut builder =
190-
TypeBuilder::new(self.tcx, def_id).for_function_template(&mut self.ctx, sig);
191-
if let Some(AnnotFormula::Formula(require)) = require_annot {
192-
let formula = require.map_var(|idx| {
193-
if idx.index() == sig.inputs().len() - 1 {
194-
rty::RefinedTypeVar::Value
195-
} else {
196-
rty::RefinedTypeVar::Free(idx)
197-
}
198-
});
199-
builder.param_refinement(formula.into());
200-
}
201-
if let Some(AnnotFormula::Formula(ensure)) = ensure_annot {
202-
builder.ret_refinement(ensure.into());
203-
}
204-
for (ident, annot_rty) in param_annots {
205-
use annot::Resolver as _;
206-
let (idx, _) = param_resolver.resolve(ident).expect("unknown param");
207-
builder.param_rty(idx, annot_rty);
208-
}
209-
if let Some(ret_rty) = ret_annot {
210-
builder.ret_rty(ret_rty);
211-
}
212-
213-
// can't generate template with type parameter...
51+
.fn_sig(local_def_id)
52+
.instantiate_identity()
53+
.skip_binder();
21454
use mir_ty::TypeVisitableExt as _;
215-
if builder.would_contain_template() && sig.has_param() {
216-
None
55+
if sig.has_param() && !analyzer.is_fully_annotated() {
56+
self.ctx.register_deferred_def(local_def_id.to_def_id());
21757
} else {
218-
Some(rty::RefinedType::unrefined(builder.build().into()))
58+
let expected = analyzer.expected_ty();
59+
self.ctx.register_def(local_def_id.to_def_id(), expected);
21960
}
22061
}
22162

0 commit comments

Comments
 (0)