Skip to content

Commit 698c640

Browse files
committed
Reject programs with unsatisfied predicate constraints
Generate appropriate constraints for calls to functions with preconditions, and reject calls where those constraints don't hold true in the prestate. ...by which I mean that it works for one test case :-)
1 parent a1bc2b1 commit 698c640

File tree

14 files changed

+309
-200
lines changed

14 files changed

+309
-200
lines changed

src/comp/front/ast.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,31 @@ tag ty_ {
355355
ty_constr(@ty, vec[@constr]);
356356
}
357357
358-
tag constr_arg_ {
358+
/*
359+
A constraint arg that's a function argument is referred to by its position
360+
rather than name. This is so we could have higher-order functions that have
361+
constraints (potentially -- right now there's no way to write that), and also
362+
so that the typestate pass doesn't have to map a function name onto its decl.
363+
So, the constr_arg type is parameterized: it's instantiated with uint for
364+
declarations, and ident for uses.
365+
*/
366+
tag constr_arg_general_[T] {
359367
carg_base;
360-
carg_ident(ident);
368+
carg_ident(T);
361369
carg_lit(@lit);
362370
}
363-
type constr_arg = spanned[constr_arg_];
364-
type constr_ = rec(path path, vec[@constr_arg] args);
365-
type constr = spanned[constr_];
371+
type constr_arg = constr_arg_general[uint];
372+
type constr_arg_use = constr_arg_general[ident];
373+
type constr_arg_general[T] = spanned[constr_arg_general_[T]];
374+
375+
// The ann field is there so that using the def_map in the type
376+
// context, we can get the def_id for the path.
377+
type constr_general[T] = rec(path path,
378+
vec[@constr_arg_general[T]] args,
379+
ann ann);
380+
381+
type constr = spanned[constr_general[uint]];
382+
type constr_use = spanned[constr_general[ident]];
366383
367384
type arg = rec(mode mode, @ty ty, ident ident, def_id id);
368385
type fn_decl = rec(vec[arg] inputs,

src/comp/front/creader.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ fn parse_constrs(@pstate st, str_def sd) -> vec[@ast::constr] {
9494
}
9595

9696
fn parse_constr(@pstate st, str_def sd) -> @ast::constr {
97+
st.tcx.sess.unimpl("Reading constraints "
98+
+ " isn't implemented");
99+
/*
97100
let vec[@ast::constr_arg] args = [];
98101
auto sp = rec(lo=0u,hi=0u); // FIXME
99102
let vec[ast::ident] ids = [];
@@ -105,6 +108,7 @@ fn parse_constr(@pstate st, str_def sd) -> @ast::constr {
105108
log_err(p1);
106109
let char ignore = next(st) as char;
107110
assert(ignore as char == '(');
111+
auto def = parse_def(st, sd);
108112
do {
109113
alt (peek(st) as char) {
110114
case ('*') {
@@ -132,7 +136,7 @@ fn parse_constr(@pstate st, str_def sd) -> @ast::constr {
132136
}
133137
} while (next(st) as char == ',');
134138
ignore = next(st) as char;
135-
ret @respan(sp, rec(path=pth, args=args));
139+
*/
136140
}
137141

138142
fn parse_ty(@pstate st, str_def sd) -> ty::t {

src/comp/front/parser.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo)
339339
auto inputs = parse_seq(token::LPAREN, token::RPAREN,
340340
some(token::COMMA), parse_fn_input_ty, p);
341341

342-
auto constrs = parse_constrs(p);
342+
auto constrs = parse_constrs([], p);
343343

344344
let @ast::ty output;
345345
auto cf = ast::return;
@@ -409,35 +409,57 @@ fn parse_ty_field(&parser p) -> ast::ty_field {
409409
ret spanned(lo, mt.ty.span.hi, rec(ident=id, mt=mt));
410410
}
411411

412-
fn parse_constr_arg(&parser p) -> @ast::constr_arg {
412+
// if i is the jth ident in args, return j
413+
// otherwise, fail
414+
fn ident_index(&parser p, &vec[ast::arg] args, &ast::ident i) -> uint {
415+
auto j = 0u;
416+
for (ast::arg a in args) {
417+
if (a.ident == i) {
418+
ret j;
419+
}
420+
j += 1u;
421+
}
422+
p.get_session().span_err(p.get_span(),
423+
"Unbound variable " + i + " in constraint arg");
424+
}
425+
426+
fn parse_constr_arg(vec[ast::arg] args, &parser p) -> @ast::constr_arg {
413427
auto sp = p.get_span();
414428
auto carg = ast::carg_base;
415429
if (p.peek() == token::BINOP(token::STAR)) {
416430
p.bump();
417431
} else {
418-
carg = ast::carg_ident(parse_value_ident(p));
432+
let ast::ident i = parse_value_ident(p);
433+
carg = ast::carg_ident(ident_index(p, args, i));
419434
}
420435
ret @rec(node=carg, span=sp);
421436
}
422437

423-
fn parse_ty_constr(&parser p) -> @ast::constr {
438+
fn parse_ty_constr(&vec[ast::arg] fn_args, &parser p) -> @ast::constr {
424439
auto lo = p.get_lo_pos();
425440
auto path = parse_path(p);
426-
auto pf = parse_constr_arg;
427-
auto args = parse_seq[@ast::constr_arg](token::LPAREN,
441+
auto pf = bind parse_constr_arg(fn_args, _);
442+
let rec(vec[@ast::constr_arg] node, span span) args =
443+
parse_seq[@ast::constr_arg](token::LPAREN,
428444
token::RPAREN,
429445
some(token::COMMA), pf, p);
430-
ret @spanned(lo, args.span.hi, rec(path=path, args=args.node));
446+
// FIXME fix the def_id
447+
ret @spanned(lo, args.span.hi,
448+
rec(path=path, args=args.node, ann=p.get_ann()));
431449
}
432450

433-
fn parse_constrs(&parser p) -> common::spanned[vec[@ast::constr]] {
451+
// Use the args list to translate each bound variable
452+
// mentioned in a constraint to an arg index.
453+
// Seems weird to do this in the parser, but I'm not sure how else to.
454+
fn parse_constrs(&vec[ast::arg] args,
455+
&parser p) -> common::spanned[vec[@ast::constr]] {
434456
auto lo = p.get_lo_pos();
435457
auto hi = p.get_hi_pos();
436458
let vec[@ast::constr] constrs = [];
437459
if (p.peek() == token::COLON) {
438460
p.bump();
439461
while (true) {
440-
auto constr = parse_ty_constr(p);
462+
auto constr = parse_ty_constr(args, p);
441463
hi = constr.span.hi;
442464
vec::push[@ast::constr](constrs, constr);
443465
if (p.peek() == token::COMMA) {
@@ -452,7 +474,7 @@ fn parse_constrs(&parser p) -> common::spanned[vec[@ast::constr]] {
452474

453475
fn parse_ty_constrs(@ast::ty t, &parser p) -> @ast::ty {
454476
if (p.peek() == token::COLON) {
455-
auto constrs = parse_constrs(p);
477+
auto constrs = parse_constrs([], p);
456478
ret @spanned(t.span.lo, constrs.span.hi,
457479
ast::ty_constr(t, constrs.node));
458480
}
@@ -1768,7 +1790,7 @@ fn parse_fn_decl(&parser p, ast::purity purity) -> ast::fn_decl {
17681790

17691791
let ty_or_bang res;
17701792

1771-
auto constrs = parse_constrs(p).node;
1793+
auto constrs = parse_constrs(inputs.node, p).node;
17721794

17731795
if (p.peek() == token::RARROW) {
17741796
p.bump();

src/comp/middle/metadata.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ mod Encode {
286286
fn enc_constr(&io::writer w, &@ctxt cx, &@ast::constr c) {
287287
w.write_str(path_to_str(c.node.path));
288288
w.write_char('(');
289+
// FIXME
290+
// w.write_str(cx.ds(c.node.id));
289291
auto comma = false;
290292
for (@constr_arg a in c.node.args) {
291293
if (comma) {
@@ -299,7 +301,7 @@ mod Encode {
299301
w.write_char('*');
300302
}
301303
case (carg_ident(?i)) {
302-
w.write_str(i);
304+
w.write_uint(i);
303305
}
304306
case (carg_lit(?l)) {
305307
w.write_str(lit_to_str(l));

src/comp/middle/resolve.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ fn resolve_names(&@env e, &@ast::crate c) {
254254
visit_arm = bind walk_arm(e, _, _, _),
255255
visit_expr = bind walk_expr(e, _, _, _),
256256
visit_ty = bind walk_ty(e, _, _, _),
257-
visit_fn = visit_fn_with_scope
257+
visit_fn = visit_fn_with_scope,
258+
visit_constr = bind walk_constr(e, _, _, _)
258259
with *visit::default_visitor());
259260
visit::visit_crate(*c, cons(scope_crate(c), @nil),
260261
visit::vtor(v));
@@ -270,6 +271,14 @@ fn resolve_names(&@env e, &@ast::crate c) {
270271
case (_) {}
271272
}
272273
}
274+
275+
fn walk_constr(@env e, &@ast::constr c, &scopes sc, &vt[scopes] v) {
276+
auto new_def = lookup_path_strict(*e, sc, c.span,
277+
c.node.path.node.idents,
278+
ns_value);
279+
e.def_map.insert(c.node.ann.id, new_def);
280+
}
281+
273282
fn walk_ty(@env e, &@ast::ty t, &scopes sc, &vt[scopes] v) {
274283
visit::visit_ty(t, sc, v);
275284
alt (t.node) {

0 commit comments

Comments
 (0)