aboutsummaryrefslogtreecommitdiff
path: root/src/comp
diff options
context:
space:
mode:
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/typeck.rs110
1 files changed, 109 insertions, 1 deletions
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 58f723bd..4fc847af 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -26,6 +26,7 @@ type fn_ctxt = rec(@ty ret_ty,
@crate_ctxt ccx);
type arg = rec(ast.mode mode, @ty ty);
+type field = rec(ast.ident label, @ty ty);
// NB: If you change this, you'll probably want to change the corresponding
// AST structure in front/ast.rs as well.
@@ -41,6 +42,7 @@ tag sty {
ty_box(@ty);
ty_vec(@ty);
ty_tup(vec[@ty]);
+ ty_rec(vec[field]);
ty_fn(vec[arg], @ty); // TODO: effect
ty_var(int); // ephemeral type var
ty_local(ast.def_id); // type of a local var
@@ -52,6 +54,9 @@ tag type_err {
terr_mismatch;
terr_tuple_size(uint, uint);
terr_tuple_mutability;
+ terr_record_size(uint, uint);
+ terr_record_mutability;
+ terr_record_fields(ast.ident,ast.ident);
terr_arg_count;
}
@@ -78,6 +83,10 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
ret s + ast_ty_to_str(input.ty);
}
+ fn ast_field_to_str(&tup(ast.ident, @ast.ty) f) -> str {
+ ret ast_ty_to_str(f._1) + " " + f._0;
+ }
+
auto s;
alt (ty.node) {
case (ast.ty_nil) { s = "()"; }
@@ -97,6 +106,14 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
s += ")";
}
+ case (ast.ty_rec(?elems)) {
+ auto f = ast_field_to_str;
+ s = "rec(";
+ s += _str.connect(_vec.map[tup(ast.ident, @ast.ty),str]
+ (f, elems), ",");
+ s += ")";
+ }
+
case (ast.ty_fn(?inputs, ?output)) {
auto f = ast_fn_input_to_str;
s = "fn(";
@@ -154,6 +171,10 @@ fn ty_to_str(&@ty typ) -> str {
ret s + ty_to_str(input.ty);
}
+ fn field_to_str(&field f) -> str {
+ ret ty_to_str(f.ty) + " " + f.label;
+ }
+
auto s = "";
if (typ.mut == ast.mut) {
s += "mutable ";
@@ -176,6 +197,12 @@ fn ty_to_str(&@ty typ) -> str {
s = "tup(" + _str.connect(strs, ",") + ")";
}
+ case (ty_rec(?elems)) {
+ auto f = field_to_str;
+ auto strs = _vec.map[field,str](f, elems);
+ s = "rec(" + _str.connect(strs, ",") + ")";
+ }
+
case (ty_fn(?inputs, ?output)) {
auto f = fn_input_to_str;
s = "fn(" + _str.connect(_vec.map[arg,str](f, inputs),
@@ -222,6 +249,14 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty {
}
sty = ty_tup(flds);
}
+ case (ast.ty_rec(?fields)) {
+ let vec[field] flds = vec();
+ for (tup(ast.ident, @ast.ty) f in fields) {
+ append[field](flds, rec(label=f._0,
+ ty=ast_ty_to_ty(getter, f._1)));
+ }
+ sty = ty_rec(flds);
+ }
case (ast.ty_fn(?inputs, ?output)) {
auto f = bind ast_arg_to_arg(getter, _);
@@ -281,6 +316,19 @@ fn type_err_to_str(&type_err err) -> str {
case (terr_tuple_mutability) {
ret "tuple elements differ in mutability";
}
+ case (terr_record_size(?e_sz, ?a_sz)) {
+ ret "expected a record with " + _uint.to_str(e_sz, 10u) +
+ " fields but found one with " + _uint.to_str(a_sz, 10u) +
+ " fields";
+ }
+ case (terr_record_mutability) {
+ ret "record elements differ in mutability";
+ }
+ case (terr_record_fields(?e_fld, ?a_fld)) {
+ ret "expected a record with field '" + e_fld +
+ "' but found one with field '" + a_fld +
+ "'";
+ }
case (terr_arg_count) {
ret "incorrect number of function parameters";
}
@@ -445,8 +493,9 @@ fn type_is_nil(@ty t) -> bool {
fn type_is_structural(@ty t) -> bool {
alt (t.struct) {
- // FIXME: cover rec and tag when we support them.
+ // FIXME: cover tag when we support it.
case (ty_tup(_)) { ret true; }
+ case (ty_rec(_)) { ret true; }
}
ret false;
}
@@ -726,6 +775,65 @@ fn unify(&fn_ctxt fcx, @ty expected, @ty actual) -> unify_result {
}
}
+ case (ty_rec(?expected_fields)) {
+ alt (actual.struct) {
+ case (ty_rec(?actual_fields)) {
+ auto expected_len = _vec.len[field](expected_fields);
+ auto actual_len = _vec.len[field](actual_fields);
+ if (expected_len != actual_len) {
+ auto err = terr_record_size(expected_len,
+ actual_len);
+ ret ures_err(err, expected, actual);
+ }
+
+ // TODO: implement an iterator that can iterate over
+ // two arrays simultaneously.
+ let vec[field] result_fields = vec();
+ auto i = 0u;
+ while (i < expected_len) {
+ auto expected_field = expected_fields.(i);
+ auto actual_field = actual_fields.(i);
+ if (expected_field.ty.mut != actual_field.ty.mut) {
+ auto err = terr_record_mutability;
+ ret ures_err(err, expected, actual);
+ }
+
+ if (!_str.eq(expected_field.label,
+ actual_field.label)) {
+ auto err =
+ terr_record_fields(expected_field.label,
+ actual_field.label);
+ ret ures_err(err, expected, actual);
+ }
+
+ auto result = unify_step(fcx,
+ bindings,
+ expected_field.ty,
+ actual_field.ty);
+ alt (result) {
+ case (ures_ok(?rty)) {
+ append[field](result_fields,
+ rec(ty=rty with expected_field));
+ }
+ case (_) {
+ ret result;
+ }
+ }
+
+ i += 1u;
+ }
+
+ ret ures_ok(plain_ty(ty_rec(result_fields)));
+ }
+
+ // TODO: ty_var
+
+ case (_) {
+ ret ures_err(terr_mismatch, expected, actual);
+ }
+ }
+ }
+
case (ty_fn(?expected_inputs, ?expected_output)) {
alt (actual.struct) {
case (ty_fn(?actual_inputs, ?actual_output)) {