diff --git a/src/qir/ast/data/QIRRcons.java b/src/qir/ast/data/QIRRcons.java
index 7400735b53804e521632a80d454d28cefc57b87e..c01acf6862f16e24f4bc40b9ebbe2c7aa5c46152 100644
--- a/src/qir/ast/data/QIRRcons.java
+++ b/src/qir/ast/data/QIRRcons.java
@@ -45,7 +45,7 @@ public final class QIRRcons extends QIRRecord {
 
     @Override
     public final String toString() {
-        return "{ " + id + ":" + value + "; " + tail + "}";
+        return "{ " + id + ":" + value + "; " + tail + "}" + (type == null ? "" : " : " + type);
     }
 
     @Override
diff --git a/src/qir/ast/data/QIRRecord.java b/src/qir/ast/data/QIRRecord.java
index 00da67be72e030b495d78ea45ccfc0759994344d..8732c73700ef68fd57d24197631eeb1c305896b9 100644
--- a/src/qir/ast/data/QIRRecord.java
+++ b/src/qir/ast/data/QIRRecord.java
@@ -4,11 +4,14 @@ import com.oracle.truffle.api.source.SourceSection;
 
 import qir.ast.QIRNode;
 import qir.driver.IQIRVisitor;
+import qir.types.QIRType;
 
 /**
  * {@link QIRRecord} is the generic representation of a tuple in QIR.
  */
 public abstract class QIRRecord extends QIRNode {
+    public QIRType type;
+
     public QIRRecord(final SourceSection source) {
         super(source);
     }
diff --git a/src/qir/parser/Parser.frame b/src/qir/parser/Parser.frame
index 96864c46557fd5de6b98bc5b143d0fab8de56499..d66a70ae4b57f7e74c2baf26133e515c707af9a8 100644
--- a/src/qir/parser/Parser.frame
+++ b/src/qir/parser/Parser.frame
@@ -30,6 +30,8 @@ Coco/R itself) does not fall under the GNU General Public License.
 import java.math.BigInteger;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.frame.FrameDescriptor;
diff --git a/src/qir/parser/Parser.java b/src/qir/parser/Parser.java
index d30feda5d8e6ea9b8341b939786012e6371102f1..175a78cf9141f517724028100d4ac69e71ce06fc 100644
--- a/src/qir/parser/Parser.java
+++ b/src/qir/parser/Parser.java
@@ -3,6 +3,8 @@ package qir.parser;
 import java.math.BigInteger;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -271,12 +273,12 @@ public class Parser {
 			res = result; 
 			break;
 		}
-		case 34: {
+		case 25: {
 			QIRIf result = Ifexpr();
 			res = result; 
 			break;
 		}
-		case 37: {
+		case 28: {
 			QIRRecord result = Tuplecons();
 			res = result; 
 			break;
@@ -413,7 +415,7 @@ public class Parser {
 		Expect(21);
 		final Token srcToken = t;
 		Token funName = null;
-		QIRType type = new FunctionType(Arrays.asList(QIRConstantType.ANY, QIRConstantType.ANY)); 
+		QIRType type = new QIRFunctionType(Arrays.asList(QIRConstantType.ANY, QIRConstantType.ANY)); 
 		if (la.kind == 22) {
 			Get();
 			Expect(1);
@@ -432,12 +434,12 @@ public class Parser {
 
 	QIRIf  Ifexpr() {
 		QIRIf  res;
-		Expect(34);
+		Expect(25);
 		final Token srcToken = t; 
 		QIRNode cond = QIR();
-		Expect(35);
+		Expect(26);
 		QIRNode thenNode = QIR();
-		Expect(36);
+		Expect(27);
 		QIRNode elseNode = QIR();
 		res = new QIRIf(srcFromToken(srcToken), cond, thenNode, elseNode); 
 		return res;
@@ -445,26 +447,32 @@ public class Parser {
 
 	QIRRecord  Tuplecons() {
 		QIRRecord  res;
-		Expect(37);
+		Expect(28);
 		res = QIRRnil.getInstance();
 		final Token srcToken = t;
-		Token idToken; 
+		Token idToken;
+		QIRType type = QIRConstantType.ANY; 
 		if (la.kind == 1) {
 			Get();
 			idToken = t; 
-			Expect(38);
+			Expect(29);
 			QIRNode value = QIR();
 			res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); 
-			while (la.kind == 39) {
+			while (la.kind == 30) {
 				Get();
 				Expect(1);
 				idToken = t; 
-				Expect(38);
+				Expect(29);
 				value = QIR();
 				res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); 
 			}
 		}
-		Expect(40);
+		Expect(31);
+		if (la.kind == 23) {
+			Get();
+			type = RecordType();
+		}
+		res.type = type; 
 		return res;
 	}
 
@@ -476,7 +484,7 @@ public class Parser {
 		if (StartOf(1)) {
 			QIRNode value = QIR();
 			res = new QIRLcons(srcFromToken(srcToken), value, res); 
-			while (la.kind == 39) {
+			while (la.kind == 30) {
 				Get();
 				value = QIR();
 				res = new QIRLcons(srcFromToken(srcToken), value, res); 
@@ -495,7 +503,7 @@ public class Parser {
 		Expect(45);
 		Expect(24);
 		QIRNode ifEmpty = QIR();
-		Expect(36);
+		Expect(27);
 		Expect(24);
 		QIRNode handler = QIR();
 		Expect(20);
@@ -686,16 +694,45 @@ public class Parser {
 
 	QIRType  Type() {
 		QIRType  res;
-		QIRType first = ConstantType();
-		final List<QIRType> types = new ArrayList<>();
-		types.add(first);
-		QIRType type; 
-		while (la.kind == 24) {
+		res = null; 
+		if (StartOf(2)) {
+			QIRType first = ConstantType();
+			final List<QIRType> types = new ArrayList<>();
+			types.add(first);
+			QIRType type; 
+			while (la.kind == 24) {
+				Get();
+				type = ConstantType();
+				types.add(type); 
+			}
+			res = types.size() == 1 ? first : new QIRFunctionType(types); 
+		} else if (la.kind == 28) {
+			res = RecordType();
+		} else SynErr(63);
+		return res;
+	}
+
+	QIRRecordType  RecordType() {
+		QIRRecordType  res;
+		Expect(28);
+		final Map<String, QIRType> types = new HashMap<>(); 
+		if (la.kind == 1) {
 			Get();
-			type = ConstantType();
-			types.add(type); 
+			Token idToken = t; 
+			Expect(23);
+			QIRType type = Type();
+			types.put(idToken.val, type); 
+			while (la.kind == 30) {
+				Get();
+				Expect(1);
+				idToken = t; 
+				Expect(23);
+				type = Type();
+				types.put(idToken.val, type); 
+			}
 		}
-		res = types.size() == 1 ? first : new FunctionType(types); 
+		Expect(31);
+		res = new QIRRecordType(types); 
 		return res;
 	}
 
@@ -703,52 +740,52 @@ public class Parser {
 		QIRType  res;
 		res = null; 
 		switch (la.kind) {
-		case 25: {
+		case 32: {
 			Get();
 			res = QIRConstantType.ANY; 
 			break;
 		}
-		case 26: {
+		case 33: {
 			Get();
 			res = QIRConstantType.NUMBER; 
 			break;
 		}
-		case 27: {
+		case 34: {
 			Get();
 			res = QIRConstantType.BIG_NUMBER; 
 			break;
 		}
-		case 28: {
+		case 35: {
 			Get();
 			res = QIRConstantType.DOUBLE; 
 			break;
 		}
-		case 29: {
+		case 36: {
 			Get();
 			res = QIRConstantType.BOOLEAN; 
 			break;
 		}
-		case 30: {
+		case 37: {
 			Get();
 			res = QIRConstantType.STRING; 
 			break;
 		}
-		case 31: {
+		case 38: {
 			Get();
 			res = QIRConstantType.NULL; 
 			break;
 		}
-		case 32: {
+		case 39: {
 			Get();
 			res = QIRConstantType.LIST; 
 			break;
 		}
-		case 33: {
+		case 40: {
 			Get();
 			res = QIRConstantType.RECORD; 
 			break;
 		}
-		default: SynErr(63); break;
+		default: SynErr(64); break;
 		}
 		return res;
 	}
@@ -768,7 +805,8 @@ public class Parser {
 
 	private static final boolean[][] set = {
 		{_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
-		{_x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_T,_x,_x, _x,_T,_x,_T, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x}
+		{_x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_T,_x,_x, _x,_T,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_T, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x},
+		{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x}
 
 	};
 
@@ -826,22 +864,22 @@ class Errors {
 			case 22: s = "\"#\" expected"; break;
 			case 23: s = "\":\" expected"; break;
 			case 24: s = "\"->\" expected"; break;
-			case 25: s = "\"any\" expected"; break;
-			case 26: s = "\"int\" expected"; break;
-			case 27: s = "\"big_int\" expected"; break;
-			case 28: s = "\"double\" expected"; break;
-			case 29: s = "\"bool\" expected"; break;
-			case 30: s = "\"string\" expected"; break;
-			case 31: s = "\"null\" expected"; break;
-			case 32: s = "\"list\" expected"; break;
-			case 33: s = "\"record\" expected"; break;
-			case 34: s = "\"if\" expected"; break;
-			case 35: s = "\"then\" expected"; break;
-			case 36: s = "\"else\" expected"; break;
-			case 37: s = "\"{\" expected"; break;
-			case 38: s = "\"=\" expected"; break;
-			case 39: s = "\";\" expected"; break;
-			case 40: s = "\"}\" expected"; break;
+			case 25: s = "\"if\" expected"; break;
+			case 26: s = "\"then\" expected"; break;
+			case 27: s = "\"else\" expected"; break;
+			case 28: s = "\"{\" expected"; break;
+			case 29: s = "\"=\" expected"; break;
+			case 30: s = "\";\" expected"; break;
+			case 31: s = "\"}\" expected"; break;
+			case 32: s = "\"any\" expected"; break;
+			case 33: s = "\"int\" expected"; break;
+			case 34: s = "\"big_int\" expected"; break;
+			case 35: s = "\"double\" expected"; break;
+			case 36: s = "\"bool\" expected"; break;
+			case 37: s = "\"string\" expected"; break;
+			case 38: s = "\"null\" expected"; break;
+			case 39: s = "\"list\" expected"; break;
+			case 40: s = "\"record\" expected"; break;
 			case 41: s = "\"[\" expected"; break;
 			case 42: s = "\"]\" expected"; break;
 			case 43: s = "\"match\" expected"; break;
@@ -864,7 +902,8 @@ class Errors {
 			case 60: s = "??? expected"; break;
 			case 61: s = "invalid Expression"; break;
 			case 62: s = "invalid Boolean"; break;
-			case 63: s = "invalid ConstantType"; break;
+			case 63: s = "invalid Type"; break;
+			case 64: s = "invalid ConstantType"; break;
 			default: s = "error " + n; break;
 		}
 		printMsg(line, col, s);
diff --git a/src/qir/parser/Scanner.java b/src/qir/parser/Scanner.java
index 7b48bd38042324073f796df7da0a4d7685618587..26e55b7e796b39a62e6294dcdb2573d5505cc03d 100644
--- a/src/qir/parser/Scanner.java
+++ b/src/qir/parser/Scanner.java
@@ -314,18 +314,18 @@ public class Scanner {
 		start.set(66, 102); 
 		start.set(Buffer.EOF, -1);
 		literals.put("fun", new Integer(21));
-		literals.put("any", new Integer(25));
-		literals.put("int", new Integer(26));
-		literals.put("big_int", new Integer(27));
-		literals.put("double", new Integer(28));
-		literals.put("bool", new Integer(29));
-		literals.put("string", new Integer(30));
-		literals.put("null", new Integer(31));
-		literals.put("list", new Integer(32));
-		literals.put("record", new Integer(33));
-		literals.put("if", new Integer(34));
-		literals.put("then", new Integer(35));
-		literals.put("else", new Integer(36));
+		literals.put("if", new Integer(25));
+		literals.put("then", new Integer(26));
+		literals.put("else", new Integer(27));
+		literals.put("any", new Integer(32));
+		literals.put("int", new Integer(33));
+		literals.put("big_int", new Integer(34));
+		literals.put("double", new Integer(35));
+		literals.put("bool", new Integer(36));
+		literals.put("string", new Integer(37));
+		literals.put("null", new Integer(38));
+		literals.put("list", new Integer(39));
+		literals.put("record", new Integer(40));
 		literals.put("match", new Integer(43));
 		literals.put("with", new Integer(44));
 		literals.put("empty", new Integer(45));
@@ -549,11 +549,11 @@ public class Scanner {
 				case 30:
 					{t.kind = 24; break loop;}
 				case 31:
-					{t.kind = 37; break loop;}
+					{t.kind = 28; break loop;}
 				case 32:
-					{t.kind = 39; break loop;}
+					{t.kind = 30; break loop;}
 				case 33:
-					{t.kind = 40; break loop;}
+					{t.kind = 31; break loop;}
 				case 34:
 					{t.kind = 41; break loop;}
 				case 35:
@@ -734,9 +734,9 @@ public class Scanner {
 					else if (ch == '>') {AddCh(); state = 30; break;}
 					else {t.kind = 11; break loop;}
 				case 97:
-					recEnd = pos; recKind = 38;
+					recEnd = pos; recKind = 29;
 					if (ch == '=') {AddCh(); state = 17; break;}
-					else {t.kind = 38; break loop;}
+					else {t.kind = 29; break loop;}
 				case 98:
 					recEnd = pos; recKind = 8;
 					if (ch == '=') {AddCh(); state = 18; break;}
diff --git a/src/qir/parser/qir.atg b/src/qir/parser/qir.atg
index 6d7b68dd297cb2bae4a7bc99874996936611dd35..a99306738657646fb044b801158d941f95384459 100644
--- a/src/qir/parser/qir.atg
+++ b/src/qir/parser/qir.atg
@@ -153,18 +153,52 @@ identifier																	(. res = new QIRVariable(srcFromToken(t), t.val); .)
 Lambda<out QIRLambda res> =
 "fun"																		(. final Token srcToken = t;
 																			   Token funName = null;
-																			   QIRType type = new FunctionType(Arrays.asList(QIRConstantType.ANY, QIRConstantType.ANY)); .)
+																			   QIRType type = new QIRFunctionType(Arrays.asList(QIRConstantType.ANY, QIRConstantType.ANY)); .)
 [ "#" identifier															(. funName = t; .)
 ] [ ":" Type<out type> ] Variable<out QIRVariable var> "->"
 QIR<out QIRNode body>														(. res = new QIRLambda(srcFromToken(srcToken), funName == null ? null : funName.val, type, var, body, new FrameDescriptor()); .)
 .
 
-Type<out QIRType res> =
+Ifexpr<out QIRIf res> =
+"if"																		(. final Token srcToken = t; .)
+QIR<out QIRNode cond> "then" QIR<out QIRNode thenNode> "else"
+QIR<out QIRNode elseNode>													(. res = new QIRIf(srcFromToken(srcToken), cond, thenNode, elseNode); .)
+.
+
+Tuplecons<out QIRRecord res> =
+"{"																			(. res = QIRRnil.getInstance();
+																			   final Token srcToken = t;
+																			   Token idToken;
+																			   QIRType type = QIRConstantType.ANY; .)
+[
+identifier																	(. idToken = t; .)
+"=" QIR<out QIRNode value>													(. res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); .)
+{
+";" identifier																(. idToken = t; .)
+"=" QIR<out value>															(. res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); .)
+} ] "}" [ ":" RecordType<out type> ]										(. res.type = type; .)
+.
+
+Type<out QIRType res> =														(. res = null; .)
+(
 ConstantType<out QIRType first>												(. final List<QIRType> types = new ArrayList<>();
 																			   types.add(first);
 																			   QIRType type; .)
 { "->" ConstantType<out type>												(. types.add(type); .)
-}																			(. res = types.size() == 1 ? first : new FunctionType(types); .)
+}																			(. res = types.size() == 1 ? first : new QIRFunctionType(types); .)
+| RecordType<out res>
+)
+.
+
+RecordType<out QIRRecordType res> =
+"{"																			(. final Map<String, QIRType> types = new HashMap<>(); .)
+[
+identifier																	(. Token idToken = t; .)
+":" Type<out QIRType type>													(. types.put(idToken.val, type); .)
+{ ";" identifier															(. idToken = t; .)
+":" Type<out type>															(. types.put(idToken.val, type); .)
+} ]
+"}"																			(. res = new QIRRecordType(types); .)
 .
 
 ConstantType<out QIRType res> =												(. res = null; .)
@@ -181,25 +215,6 @@ ConstantType<out QIRType res> =												(. res = null; .)
 )
 .
 
-Ifexpr<out QIRIf res> =
-"if"																		(. final Token srcToken = t; .)
-QIR<out QIRNode cond> "then" QIR<out QIRNode thenNode> "else"
-QIR<out QIRNode elseNode>													(. res = new QIRIf(srcFromToken(srcToken), cond, thenNode, elseNode); .)
-.
-
-Tuplecons<out QIRRecord res> =
-"{"																			(. res = QIRRnil.getInstance();
-																			   final Token srcToken = t;
-																			   Token idToken; .)
-[
-identifier																	(. idToken = t; .)
-"=" QIR<out QIRNode value>													(. res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); .)
-{
-";" identifier																(. idToken = t; .)
-"=" QIR<out value>															(. res = new QIRRcons(srcFromToken(srcToken), idToken.val, value, res); .)
-} ] "}"
-.
-
 Listcons<out QIRList res> =
 "["																			(. res = QIRLnil.getInstance();
 																			   final Token srcToken = t; .)
diff --git a/src/qir/parser/test.qir b/src/qir/parser/test.qir
index a52991ef0ffcbbd2f8c63a56b01a84fdbd6e1028..20890fd2412c21d50065b846a63eeccb993424a6 100644
--- a/src/qir/parser/test.qir
+++ b/src/qir/parser/test.qir
@@ -1 +1 @@
-(fun : any -> any x -> x) @ [ { x = 2; y = 3 + 4 }; "toto"; (fun : int -> int x -> x + 2) ]
+(fun x -> x) @ [ { x = 2; y = 3 + 4 } : { x : int; y : int }; "toto"; (fun : int -> int x -> x + 2) ]
diff --git a/src/qir/types/FunctionType.java b/src/qir/types/QIRFunctionType.java
similarity index 80%
rename from src/qir/types/FunctionType.java
rename to src/qir/types/QIRFunctionType.java
index 677830c5e80ada6bdd1d08a09fa569b9a85c0682..d48fea9f06307a20b2cde018ab833d184172821b 100644
--- a/src/qir/types/FunctionType.java
+++ b/src/qir/types/QIRFunctionType.java
@@ -4,10 +4,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
-public final class FunctionType implements QIRType {
+public final class QIRFunctionType implements QIRType {
     private final List<QIRType> types;
 
-    public FunctionType(final List<QIRType> types) {
+    public QIRFunctionType(final List<QIRType> types) {
         this.types = types;
     }
 
diff --git a/src/qir/types/QIRRecordType.java b/src/qir/types/QIRRecordType.java
new file mode 100644
index 0000000000000000000000000000000000000000..32597a03ff19cb2aaafae8edab948b3e324f1065
--- /dev/null
+++ b/src/qir/types/QIRRecordType.java
@@ -0,0 +1,17 @@
+package qir.types;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class QIRRecordType implements QIRType {
+    private Map<String, QIRType> types;
+
+    public QIRRecordType(final Map<String, QIRType> types) {
+        this.types = types;
+    }
+
+    @Override
+    public final String toString() {
+        return "{ " + types.entrySet().stream().map(e -> e.getKey() + " : " + e.getValue()).collect(Collectors.joining(" -> ")) + " }";
+    }
+}