Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 38aaacc20a85af2361a0240ac2e7d643e086ecfa)
+++ uspace/app/sbi/src/stype.c	(revision 051bc69a7034999d45c93c61a56e515474aa78e3)
@@ -38,4 +38,5 @@
 #include <stdlib.h>
 #include <assert.h>
+#include "cspan.h"
 #include "debug.h"
 #include "intmap.h"
@@ -52,4 +53,6 @@
 
 static void stype_csi(stype_t *stype, stree_csi_t *csi);
+static void stype_ctor(stype_t *stype, stree_ctor_t *ctor);
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor);
 static void stype_fun(stype_t *stype, stree_fun_t *fun);
 static void stype_var(stype_t *stype, stree_var_t *var);
@@ -66,4 +69,5 @@
 static void stype_for(stype_t *stype, stree_for_t *for_s);
 static void stype_raise(stype_t *stype, stree_raise_t *raise_s);
+static void stype_break(stype_t *stype, stree_break_t *break_s);
 static void stype_return(stype_t *stype, stree_return_t *return_s);
 static void stype_exps(stype_t *stype, stree_exps_t *exp_s, bool_t want_value);
@@ -80,9 +84,11 @@
 static stree_expr_t *stype_convert_tdeleg(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
 static stree_expr_t *stype_convert_tfun_tdeleg(stype_t *stype,
     stree_expr_t *expr, tdata_item_t *dest);
 static stree_expr_t *stype_convert_tvref(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
-static void stype_convert_failure(stype_t *stype, tdata_item_t *src,
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
 
@@ -112,7 +118,13 @@
 	while (mbr_n != NULL) {
 		mbr = list_node_data(mbr_n, stree_modm_t *);
-		assert(mbr->mc == mc_csi);
-
-		stype_csi(stype, mbr->u.csi);
+
+		switch (mbr->mc) {
+		case mc_csi:
+			stype_csi(stype, mbr->u.csi);
+			break;
+		case mc_enum:
+			stype_enum(stype, mbr->u.enum_d);
+			break;
+		}
 
 		mbr_n = list_next(&module->members, mbr_n);
@@ -145,5 +157,7 @@
 		switch (csimbr->cc) {
 		case csimbr_csi: stype_csi(stype, csimbr->u.csi); break;
+		case csimbr_ctor: stype_ctor(stype, csimbr->u.ctor); break;
 		case csimbr_deleg: stype_deleg(stype, csimbr->u.deleg); break;
+		case csimbr_enum: stype_enum(stype, csimbr->u.enum_d); break;
 		case csimbr_fun: stype_fun(stype, csimbr->u.fun); break;
 		case csimbr_var: stype_var(stype, csimbr->u.var); break;
@@ -155,4 +169,79 @@
 
 	stype->current_csi = prev_ctx;
+}
+
+/** Type a constructor.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+static void stype_ctor(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("'.\n");
+#endif
+	if (ctor->titem == NULL)
+		stype_ctor_header(stype, ctor);
+
+	stype_ctor_body(stype, ctor);
+}
+
+/** Type constructor header.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+void stype_ctor_header(stype_t *stype, stree_ctor_t *ctor)
+{
+	stree_symbol_t *ctor_sym;
+	tdata_item_t *ctor_ti;
+	tdata_fun_t *tfun;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' header.\n");
+#endif
+	if (ctor->titem != NULL)
+		return; /* Constructor header has already been typed. */
+
+	ctor_sym = ctor_to_symbol(ctor);
+
+	/* Type function signature. */
+	stype_fun_sig(stype, ctor_sym->outer_csi, ctor->sig, &tsig);
+
+	ctor_ti = tdata_item_new(tic_tfun);
+	tfun = tdata_fun_new();
+	ctor_ti->u.tfun = tfun;
+	tfun->tsig = tsig;
+
+	ctor->titem = ctor_ti;
+}
+
+/** Type constructor body.
+ *
+ * @param stype		Static typing object
+ * @param ctor		Constructor
+ */
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' body.\n");
+#endif
+	assert(stype->proc_vr == NULL);
+
+	stype->proc_vr = stype_proc_vr_new();
+	stype->proc_vr->proc = ctor->proc;
+	list_init(&stype->proc_vr->block_vr);
+
+	stype_block(stype, ctor->proc->body);
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
 }
 
@@ -197,4 +286,33 @@
 }
 
+/** Type enum.
+ *
+ * @param stype		Static typing object
+ * @param enum_d	Enum to type
+ */
+void stype_enum(stype_t *stype, stree_enum_t *enum_d)
+{
+	tdata_item_t *titem;
+	tdata_enum_t *tenum;
+
+	(void) stype;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type enum '");
+	symbol_print_fqn(enum_to_symbol(enum_d));
+	printf("'.\n");
+#endif
+	if (enum_d->titem == NULL) {
+		titem = tdata_item_new(tic_tenum);
+		tenum = tdata_enum_new();
+		titem->u.tenum = tenum;
+		tenum->enum_d = enum_d;
+
+		enum_d->titem = titem;
+	} else {
+		titem = enum_d->titem;
+	}
+}
+
 /** Type function.
  *
@@ -457,4 +575,5 @@
 	case st_for: stype_for(stype, stat->u.for_s); break;
 	case st_raise: stype_raise(stype, stat->u.raise_s); break;
+	case st_break: stype_break(stype, stat->u.break_s); break;
 	case st_return: stype_return(stype, stat->u.return_s); break;
 	case st_exps: stype_exps(stype, stat->u.exp_s, want_value); break;
@@ -506,17 +625,31 @@
 {
 	stree_expr_t *ccond;
+	list_node_t *ifc_node;
+	stree_if_clause_t *ifc;
 
 #ifdef DEBUG_TYPE_TRACE
 	printf("Type 'if' statement.\n");
 #endif
-	/* Convert condition to boolean type. */
-	stype_expr(stype, if_s->cond);
-	ccond = stype_convert(stype, if_s->cond, stype_boolean_titem(stype));
-
-	/* Patch code with augmented expression. */
-	if_s->cond = ccond;
-
-	/* Type the @c if block */
-	stype_block(stype, if_s->if_block);
+	ifc_node = list_first(&if_s->if_clauses);
+
+	/* Walk through all if/elif clauses. */
+
+	while (ifc_node != NULL) {
+		/* Get if/elif clause */
+		ifc = list_node_data(ifc_node, stree_if_clause_t *);
+
+		/* Convert condition to boolean type. */
+		stype_expr(stype, ifc->cond);
+		ccond = stype_convert(stype, ifc->cond,
+		    stype_boolean_titem(stype));
+
+		/* Patch code with augmented expression. */
+		ifc->cond = ccond;
+
+		/* Type the @c if/elif block */
+		stype_block(stype, ifc->block);
+
+		ifc_node = list_next(&if_s->if_clauses, ifc_node);
+	}
 
 	/* Type the @c else block */
@@ -545,6 +678,11 @@
 	while_s->cond = ccond;
 
+	/* While is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
 	/* Type the body of the loop */
 	stype_block(stype, while_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
 }
 
@@ -559,5 +697,10 @@
 	printf("Type 'for' statement.\n");
 #endif
+	/* For is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
 	stype_block(stype, for_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
 }
 
@@ -573,4 +716,19 @@
 #endif
 	stype_expr(stype, raise_s->expr);
+}
+
+/** Type @c break statement */
+static void stype_break(stype_t *stype, stree_break_t *break_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'break' statement.\n");
+#endif
+	(void) break_s;
+
+	/* Check whether there is an active statement to break from. */
+	if (stype->proc_vr->bstat_cnt == 0) {
+		printf("Error: Break statement outside of while or for.\n");
+		stype_note_error(stype);
+	}
 }
 
@@ -588,5 +746,6 @@
 	printf("Type 'return' statement.\n");
 #endif
-	stype_expr(stype, return_s->expr);
+	if (return_s->expr != NULL)
+		stype_expr(stype, return_s->expr);
 
 	/* Determine the type we need to return. */
@@ -599,6 +758,22 @@
 
 		/* XXX Memoize to avoid recomputing. */
-		run_texpr(stype->program, outer_sym->outer_csi,
-		    fun->sig->rtype, &dtype);
+		if (fun->sig->rtype != NULL) {
+			run_texpr(stype->program, outer_sym->outer_csi,
+			    fun->sig->rtype, &dtype);
+
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "function returning value.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			dtype = NULL;
+
+			if (return_s->expr != NULL) {
+				printf("Error: Return with a value in "
+				    "value-less function.\n");
+				stype_note_error(stype);
+			}
+		}
 		break;
 	case sc_prop:
@@ -606,8 +781,16 @@
 		assert(prop != NULL);
 
-		if (stype->proc_vr->proc != prop->getter) {
-			printf("Error: Return statement in "
-			    "setter.\n");
-			stype_note_error(stype);
+		if (stype->proc_vr->proc == prop->getter) {
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "getter.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			if (return_s->expr == NULL) {
+				printf("Error: Return with a value in "
+				    "setter.\n");
+				stype_note_error(stype);
+			}
 		}
 
@@ -620,9 +803,11 @@
 	}
 
-	/* Convert to the return type. */
-	cexpr = stype_convert(stype, return_s->expr, dtype);
-
-	/* Patch code with the augmented expression. */
-	return_s->expr = cexpr;
+	if (dtype != NULL && return_s->expr != NULL) {
+		/* Convert to the return type. */
+		cexpr = stype_convert(stype, return_s->expr, dtype);
+
+		/* Patch code with the augmented expression. */
+		return_s->expr = cexpr;
+	}
 }
 
@@ -714,5 +899,6 @@
 
 	if (src == NULL) {
-		printf("Error: Conversion source is not valid.\n");
+		cspan_print(expr->cspan);
+		printf(" Error: Conversion source is not valid.\n");
 		stype_note_error(stype);
 		return expr;
@@ -738,6 +924,13 @@
 	}
 
+	if (src->tic == tic_tebase) {
+		stype_convert_failure(stype, expr, dest);
+		printf("Invalid use of reference to enum type in "
+		    "expression.\n");
+		return expr;
+	}
+
 	if (src->tic != dest->tic) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -756,4 +949,10 @@
 		expr = stype_convert_tdeleg(stype, expr, dest);
 		break;
+	case tic_tebase:
+		/* Conversion destination should never be enum-base */
+		assert(b_false);
+	case tic_tenum:
+		expr = stype_convert_tenum(stype, expr, dest);
+		break;
 	case tic_tfun:
 		assert(b_false);
@@ -788,5 +987,5 @@
 	/* Check if both have the same tprimitive class. */
 	if (src->u.tprimitive->tpc != dest->u.tprimitive->tpc)
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 
 	return expr;
@@ -795,5 +994,6 @@
 /** Convert expression of primitive type to object type.
  *
- * This function implements autoboxing. It modified the code.
+ * This function implements autoboxing. It modifies the code by inserting
+ * the boxing operation.
  *
  * @param stype		Static typing object
@@ -828,5 +1028,5 @@
 	case tpc_string: bp_sym = bi->boxed_string; break;
 	case tpc_resource:
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -834,5 +1034,5 @@
 	/* Target type must be boxed @a src or Object */
 	if (csi_sym != bp_sym && csi_sym != bi->gf_class)
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 
 	/* Patch the code to box the primitive value */
@@ -841,4 +1041,5 @@
 	bexpr = stree_expr_new(ec_box);
 	bexpr->u.box = box;
+	bexpr->titem = dest;
 
 	/* No action needed to optionally convert boxed type to Object */
@@ -901,5 +1102,5 @@
 		} else {
 			/* No match */
-			stype_convert_failure(stype, src, dest);
+			stype_convert_failure(stype, expr, dest);
 			return expr;
 		}
@@ -916,5 +1117,5 @@
 		if (tdata_item_equal(carg, darg) != b_true) {
 			/* Diferent argument type */
-			stype_convert_failure(stype, src, dest);
+			stype_convert_failure(stype, expr, dest);
 			printf("Different argument type '");
 			tdata_item_print(carg);
@@ -931,5 +1132,5 @@
 	if (ca_n != NULL || da_n != NULL) {
 		/* Diferent number of arguments */
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		printf("Different number of arguments.\n");
 		return expr;
@@ -959,5 +1160,5 @@
 	/* Compare rank and base type. */
 	if (src->u.tarray->rank != dest->u.tarray->rank) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -966,5 +1167,5 @@
 	if (tdata_item_equal(src->u.tarray->base_ti,
 	    dest->u.tarray->base_ti) != b_true) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 	}
 
@@ -1004,5 +1205,40 @@
 	/* Both must be the same delegate. */
 	if (sdeleg->deleg != ddeleg->deleg) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Convert expression of enum type to enum type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_enum_t *senum, *denum;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert enum type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tenum);
+	assert(dest->tic == tic_tenum);
+
+	senum = src->u.tenum;
+	denum = dest->u.tenum;
+
+	/*
+	 * XXX How should enum types interact with generics?
+	 */
+
+	/* Both must be of the same enum type (with the same declaration). */
+	if (senum->enum_d != denum->enum_d) {
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1043,5 +1279,5 @@
 
 	if (!stype_fun_sig_equal(stype, ssig, dsig)) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1075,5 +1311,5 @@
 	/* Currently only allow if both types are the same. */
 	if (src->u.tvref->targ != dest->u.tvref->targ) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1085,12 +1321,13 @@
  *
  * @param stype		Static typing object
- * @param src		Original type
+ * @param expr		Original expression
  * @param dest		Destination type
  */
-static void stype_convert_failure(stype_t *stype, tdata_item_t *src,
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest)
 {
-	printf("Error: Cannot convert ");
-	tdata_item_print(src);
+	cspan_print(expr->cspan);
+	printf(" Error: Cannot convert ");
+	tdata_item_print(expr->titem);
 	printf(" to ");
 	tdata_item_print(dest);
@@ -1099,4 +1336,66 @@
 	stype_note_error(stype);
 }
+
+/** Box value.
+ *
+ * This function implements implicit boxing. It modifies the code by inserting
+ * the boxing operation.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @return		Modified expression.
+ */
+stree_expr_t *stype_box_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *src;
+	builtin_t *bi;
+	stree_symbol_t *bp_sym;
+	stree_box_t *box;
+	stree_expr_t *bexpr;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Boxing.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tprimitive);
+
+	bi = stype->program->builtin;
+
+	/* Make compiler happy. */
+	bp_sym = NULL;
+
+	switch (src->u.tprimitive->tpc) {
+	case tpc_bool: bp_sym = bi->boxed_bool; break;
+	case tpc_char: bp_sym = bi->boxed_char; break;
+	case tpc_int: bp_sym = bi->boxed_int; break;
+	case tpc_nil: assert(b_false);
+	case tpc_string: bp_sym = bi->boxed_string; break;
+	case tpc_resource:
+		cspan_print(expr->cspan);
+		printf(" Error: Cannot use ");
+		tdata_item_print(expr->titem);
+		printf(" as an object.\n");
+
+		stype_note_error(stype);
+		return expr;
+	}
+
+	/* Patch the code to box the primitive value */
+	box = stree_box_new();
+	box->arg = expr;
+	bexpr = stree_expr_new(ec_box);
+	bexpr->u.box = box;
+	bexpr->titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	bexpr->titem->u.tobject = tobject;
+
+	tobject->csi = symbol_to_csi(bp_sym);
+	assert(tobject->csi != NULL);
+
+	return bexpr;
+}
+
+
 
 /** Determine if two type signatures are equal.
@@ -1296,4 +1595,5 @@
 
 	stree_symbol_t *outer_sym;
+	stree_ctor_t *ctor;
 	stree_fun_t *fun;
 	stree_prop_t *prop;
@@ -1314,5 +1614,15 @@
 #endif
 
+	/* Make compiler happy. */
+	args = NULL;
+	varg = NULL;
+
 	switch (outer_sym->sc) {
+	case sc_ctor:
+		ctor = symbol_to_ctor(outer_sym);
+		assert(ctor != NULL);
+		args = &ctor->sig->args;
+		varg = ctor->sig->varg;
+		break;
 	case sc_fun:
 		fun = symbol_to_fun(outer_sym);
@@ -1331,5 +1641,8 @@
 			setter_arg = prop->setter_arg;
 		break;
-	default:
+	case sc_csi:
+	case sc_deleg:
+	case sc_enum:
+	case sc_var:
 		assert(b_false);
 	}
