[vala] dova: Accept list, set, and map literals and tuples



commit 84b6b23be9a93fc1d17b2b8a9f5134e0f3054ccc
Author: Jürg Billeter <j bitron ch>
Date:   Sat Mar 13 20:43:56 2010 +0100

    dova: Accept list, set, and map literals and tuples

 codegen/valaccodegenerator.vala |   16 +++++
 codegen/valaccodemodule.vala    |   16 +++++
 vala/Makefile.am                |    3 +
 vala/valacodenode.vala          |    2 +-
 vala/valacodevisitor.vala       |   32 ++++++++++
 vala/valaelementaccess.vala     |   34 +++++++++++
 vala/valalistliteral.vala       |  113 ++++++++++++++++++++++++++++++++++++
 vala/valamapliteral.vala        |  120 +++++++++++++++++++++++++++++++++++++++
 vala/valaparser.vala            |   87 ++++++++++++++++++++++++++++-
 vala/valasemanticanalyzer.vala  |    4 +
 vala/valasetliteral.vala        |   97 +++++++++++++++++++++++++++++++
 vala/valatuple.vala             |   39 +++++++++++-
 12 files changed, 557 insertions(+), 6 deletions(-)
---
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index 35dff33..fd465d1 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -260,6 +260,22 @@ public class Vala.CCodeGenerator : CodeGenerator {
 		head.visit_string_literal (expr);
 	}
 
+	public override void visit_list_literal (ListLiteral expr) {
+		head.visit_list_literal (expr);
+	}
+
+	public override void visit_set_literal (SetLiteral expr) {
+		head.visit_set_literal (expr);
+	}
+
+	public override void visit_map_literal (MapLiteral expr) {
+		head.visit_map_literal (expr);
+	}
+
+	public override void visit_tuple (Tuple expr) {
+		head.visit_tuple (expr);
+	}
+
 	public override void visit_null_literal (NullLiteral expr) {
 		head.visit_null_literal (expr);
 	}
diff --git a/codegen/valaccodemodule.vala b/codegen/valaccodemodule.vala
index ebbc298..939c49f 100644
--- a/codegen/valaccodemodule.vala
+++ b/codegen/valaccodemodule.vala
@@ -239,6 +239,22 @@ public abstract class Vala.CCodeModule {
 		next.visit_string_literal (expr);
 	}
 
+	public virtual void visit_list_literal (ListLiteral expr) {
+		next.visit_list_literal (expr);
+	}
+
+	public virtual void visit_set_literal (SetLiteral expr) {
+		next.visit_set_literal (expr);
+	}
+
+	public virtual void visit_map_literal (MapLiteral expr) {
+		next.visit_map_literal (expr);
+	}
+
+	public virtual void visit_tuple (Tuple expr) {
+		next.visit_tuple (expr);
+	}
+
 	public virtual void visit_null_literal (NullLiteral expr) {
 		next.visit_null_literal (expr);
 	}
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 28a85ae..72c2b88 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -86,11 +86,13 @@ libvalacore_la_VALASOURCES = \
 	valainterfacetype.vala \
 	valainvalidtype.vala \
 	valalambdaexpression.vala \
+	valalistliteral.vala \
 	valaliteral.vala \
 	valalocalvariable.vala \
 	valalockable.vala \
 	valalockstatement.vala \
 	valaloop.vala \
+	valamapliteral.vala \
 	valamarkupreader.vala \
 	valamember.vala \
 	valamemberaccess.vala \
@@ -121,6 +123,7 @@ libvalacore_la_VALASOURCES = \
 	valascanner.vala \
 	valascope.vala \
 	valasemanticanalyzer.vala \
+	valasetliteral.vala \
 	valasignal.vala \
 	valasignaltype.vala \
 	valasizeofexpression.vala \
diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala
index d424623..8f83cfd 100644
--- a/vala/valacodenode.vala
+++ b/vala/valacodenode.vala
@@ -189,7 +189,7 @@ public abstract class Vala.CodeNode {
 	public virtual void get_used_variables (Collection<LocalVariable> collection) {
 	}
 
-	public string get_temp_name () {
+	public static string get_temp_name () {
 		return "." + (++last_temp_nr).to_string ();
 	}
 }
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index 7744674..f11a3ef 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -477,6 +477,38 @@ public abstract class Vala.CodeVisitor {
 	}
 
 	/**
+	 * Visit operation called for list literals.
+	 *
+	 * @param lit a list literal
+	 */
+	public virtual void visit_list_literal (ListLiteral lit) {
+	}
+
+	/**
+	 * Visit operation called for set literals.
+	 *
+	 * @param lit a set literal
+	 */
+	public virtual void visit_set_literal (SetLiteral lit) {
+	}
+
+	/**
+	 * Visit operation called for map literals.
+	 *
+	 * @param lit a map literal
+	 */
+	public virtual void visit_map_literal (MapLiteral lit) {
+	}
+
+	/**
+	 * Visit operation called for tuples.
+	 *
+	 * @param tuple a tuple
+	 */
+	public virtual void visit_tuple (Tuple tuple) {
+	}
+
+	/**
 	 * Visit operation called for null literals.
 	 *
 	 * @param lit a null literal
diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala
index 9cfe3c8..c96ee7a 100644
--- a/vala/valaelementaccess.vala
+++ b/vala/valaelementaccess.vala
@@ -152,6 +152,40 @@ public class Vala.ElementAccess : Expression {
 			}
 
 			value_type = analyzer.unichar_type;
+		} else if (analyzer.context.profile == Profile.DOVA && container_type == analyzer.tuple_type.data_type) {
+			if (get_indices ().size != 1) {
+				error = true;
+				Report.error (source_reference, "Element access with more than one dimension is not supported for tuples");
+				return false;
+			}
+			var index = get_indices ().get (0) as IntegerLiteral;
+			if (index == null) {
+				error = true;
+				Report.error (source_reference, "Element access with non-literal index is not supported for tuples");
+				return false;
+			}
+			int i = index.value.to_int ();
+			if (container.value_type.get_type_arguments ().size == 0) {
+				error = true;
+				Report.error (source_reference, "Element access is not supported for untyped tuples");
+				return false;
+			}
+			if (i < 0 || i >= container.value_type.get_type_arguments ().size) {
+				error = true;
+				Report.error (source_reference, "Index out of range");
+				return false;
+			}
+
+			value_type = container.value_type.get_type_arguments ().get (i);
+
+			// replace element access by call to generic get method
+			var ma = new MemberAccess (container, "get");
+			ma.add_type_argument (value_type);
+			var get_call = new MethodCall (ma);
+			get_call.add_argument (index);
+			get_call.target_type = this.target_type;
+			parent_node.replace_expression (this, get_call);
+			return get_call.check (analyzer);
 		} else if (container is MemberAccess && container.symbol_reference is Signal) {
 			index_int_type_check = false;
 
diff --git a/vala/valalistliteral.vala b/vala/valalistliteral.vala
new file mode 100644
index 0000000..9dd6a4a
--- /dev/null
+++ b/vala/valalistliteral.vala
@@ -0,0 +1,113 @@
+/* valalistliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.ListLiteral : Literal {
+	private List<Expression> expression_list = new ArrayList<Expression> ();
+
+	public DataType element_type { get; private set; }
+
+	public ListLiteral (SourceReference? source_reference = null) {
+		this.source_reference = source_reference;
+	}
+
+	public override void accept_children (CodeVisitor visitor) {
+		foreach (Expression expr in expression_list) {
+			expr.accept (visitor);
+		}
+	}
+
+	public override void accept (CodeVisitor visitor) {
+		visitor.visit_list_literal (this);
+	}
+
+	public void add_expression (Expression expr) {
+		expression_list.add (expr);
+		expr.parent_node = this;
+	}
+
+	public List<Expression> get_expressions () {
+		return expression_list;
+	}
+
+	public override bool is_pure () {
+		return false;
+	}
+
+	public override void replace_expression (Expression old_node, Expression new_node) {
+		for (int i = 0; i < expression_list.size; i++) {
+			if (expression_list[i] == old_node) {
+				expression_list[i] = new_node;
+			}
+		}
+	}
+
+	public override bool check (SemanticAnalyzer analyzer) {
+		if (checked) {
+			return !error;
+		}
+
+		checked = true;
+
+		// list literals are also allowed for constant arrays,
+		// however, they are currently handled by InitializerList
+		// therefore transform this expression if necessary
+		var array_type = target_type as ArrayType;
+		if (array_type != null && array_type.inline_allocated) {
+			var initializer = new InitializerList (source_reference);
+			initializer.target_type = target_type;
+			foreach (var expr in expression_list) {
+				initializer.append (expr);
+			}
+
+			analyzer.replaced_nodes.add (this);
+			parent_node.replace_expression (this, initializer);
+			return initializer.check (analyzer);
+		}
+
+		var list_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("List"));
+		list_type.value_owned = true;
+
+		bool fixed_element_type = false;
+		if (target_type != null && target_type.data_type == list_type.data_type && target_type.get_type_arguments ().size == 1) {
+			element_type = target_type.get_type_arguments ().get (0).copy ();
+			fixed_element_type = true;
+		}
+
+		foreach (var expr in expression_list) {
+			if (fixed_element_type) {
+				expr.target_type = element_type;
+			}
+			if (!expr.check (analyzer)) {
+				return false;
+			}
+			if (element_type == null) {
+				element_type = expr.value_type.copy ();
+			}
+		}
+
+		element_type.value_owned = true;
+		list_type.add_type_argument (element_type);
+		value_type = list_type;
+
+		return !error;
+	}
+}
diff --git a/vala/valamapliteral.vala b/vala/valamapliteral.vala
new file mode 100644
index 0000000..bf50a78
--- /dev/null
+++ b/vala/valamapliteral.vala
@@ -0,0 +1,120 @@
+/* valamapliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.MapLiteral : Literal {
+	private List<Expression> keys = new ArrayList<Expression> ();
+	private List<Expression> values = new ArrayList<Expression> ();
+
+	public DataType map_key_type { get; private set; }
+	public DataType map_value_type { get; private set; }
+
+	public MapLiteral (SourceReference? source_reference = null) {
+		this.source_reference = source_reference;
+	}
+
+	public override void accept_children (CodeVisitor visitor) {
+		for (int i = 0; i < keys.size; i++) {
+			keys[i].accept (visitor);
+			values[i].accept (visitor);
+		}
+	}
+
+	public override void accept (CodeVisitor visitor) {
+		visitor.visit_map_literal (this);
+	}
+
+	public void add_key (Expression expr) {
+		keys.add (expr);
+		expr.parent_node = this;
+	}
+
+	public void add_value (Expression expr) {
+		values.add (expr);
+		expr.parent_node = this;
+	}
+
+	public List<Expression> get_keys () {
+		return keys;
+	}
+
+	public List<Expression> get_values () {
+		return values;
+	}
+
+	public override bool is_pure () {
+		return false;
+	}
+
+	public override void replace_expression (Expression old_node, Expression new_node) {
+		for (int i = 0; i < keys.size; i++) {
+			if (keys[i] == old_node) {
+				keys[i] = new_node;
+			}
+			if (values[i] == old_node) {
+				values[i] = new_node;
+			}
+		}
+	}
+
+	public override bool check (SemanticAnalyzer analyzer) {
+		if (checked) {
+			return !error;
+		}
+
+		checked = true;
+
+		var map_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Map"));
+		map_type.value_owned = true;
+
+		bool fixed_element_type = false;
+		if (target_type != null && target_type.data_type == map_type.data_type && target_type.get_type_arguments ().size == 2) {
+			map_key_type = target_type.get_type_arguments ().get (0).copy ();
+			map_value_type = target_type.get_type_arguments ().get (1).copy ();
+			fixed_element_type = true;
+		}
+
+		for (int i = 0; i < keys.size; i++) {
+			if (fixed_element_type) {
+				keys[i].target_type = map_key_type;
+				values[i].target_type = map_value_type;
+			}
+			if (!keys[i].check (analyzer)) {
+				return false;
+			}
+			if (!values[i].check (analyzer)) {
+				return false;
+			}
+			if (map_key_type == null) {
+				map_key_type = keys[i].value_type.copy ();
+				map_value_type = values[i].value_type.copy ();
+			}
+		}
+
+		map_key_type.value_owned = true;
+		map_value_type.value_owned = true;
+		map_type.add_type_argument (map_key_type);
+		map_type.add_type_argument (map_value_type);
+		value_type = map_type;
+
+		return !error;
+	}
+}
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 2f03484..e92a4e8 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -551,11 +551,18 @@ public class Vala.Parser : CodeVisitor {
 			break;
 		case TokenType.OPEN_BRACE:
 			if (context.profile == Profile.DOVA) {
-				expr = parse_simple_name ();
+				expr = parse_set_literal ();
 			} else {
 				expr = parse_initializer ();
 			}
 			break;
+		case TokenType.OPEN_BRACKET:
+			if (context.profile == Profile.DOVA) {
+				expr = parse_list_literal ();
+			} else {
+				expr = parse_simple_name ();
+			}
+			break;
 		case TokenType.OPEN_PARENS:
 			expr = parse_tuple ();
 			break;
@@ -1526,6 +1533,32 @@ public class Vala.Parser : CodeVisitor {
 			variable_type = parse_type ();
 		}
 		do {
+			if (variable_type == null && accept (TokenType.OPEN_PARENS)) {
+				// tuple
+				var begin = get_location ();
+
+				string[] identifiers = {};
+				do {
+					identifiers += parse_identifier ();
+				} while (accept (TokenType.COMMA));
+				expect (TokenType.CLOSE_PARENS);
+
+				expect (TokenType.ASSIGN);
+				var tuple = parse_expression ();
+				var tuple_local = new LocalVariable (null, CodeNode.get_temp_name (), tuple, get_src (begin));
+				block.add_statement (new DeclarationStatement (tuple_local, tuple_local.source_reference));
+
+				for (int i = 0; i < identifiers.length; i++) {
+					var temp_access = new MemberAccess.simple (tuple_local.name, tuple_local.source_reference);
+					var ea = new ElementAccess (temp_access, tuple_local.source_reference);
+					ea.append_index (new IntegerLiteral (i.to_string ()));
+					var local = new LocalVariable (null, identifiers[i], ea, tuple_local.source_reference);
+					block.add_statement (new DeclarationStatement (local, local.source_reference));
+				}
+
+				continue;
+			}
+
 			DataType type_copy = null;
 			if (variable_type != null) {
 				type_copy = variable_type.copy ();
@@ -2312,6 +2345,58 @@ public class Vala.Parser : CodeVisitor {
 		return initializer;
 	}
 
+	ListLiteral parse_list_literal () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.OPEN_BRACKET);
+		var initializer = new ListLiteral (get_src (begin));
+		if (current () != TokenType.CLOSE_BRACKET) {
+			do {
+				var init = parse_expression ();
+				initializer.add_expression (init);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_BRACKET);
+		return initializer;
+	}
+
+	Expression parse_set_literal () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.OPEN_BRACE);
+		var set = new SetLiteral (get_src (begin));
+		bool first = true;
+		if (current () != TokenType.CLOSE_BRACE) {
+			do {
+				var expr = parse_expression ();
+				if (first && accept (TokenType.COLON)) {
+					// found colon after expression, it's a map
+					rollback (begin);
+					return parse_map_literal ();
+				}
+				first = false;
+				set.add_expression (expr);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_BRACE);
+		return set;
+	}
+
+	Expression parse_map_literal () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.OPEN_BRACE);
+		var map = new MapLiteral (get_src (begin));
+		if (current () != TokenType.CLOSE_BRACE) {
+			do {
+				var key = parse_expression ();
+				map.add_key (key);
+				expect (TokenType.COLON);
+				var value = parse_expression ();
+				map.add_value (value);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_BRACE);
+		return map;
+	}
+
 	Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
 		var begin = get_location ();
 		var access = parse_access_modifier ();
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 51b8906..bafc246 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -136,6 +136,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 	public DataType garray_type;
 	public DataType gvaluearray_type;
 	public Class gerror_type;
+	public DataType list_type;
+	public DataType tuple_type;
 
 	public int next_lambda_id = 0;
 
@@ -203,6 +205,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
 			object_type = (Class) dova_ns.scope.lookup ("Object");
 			type_type = new ObjectType ((Class) dova_ns.scope.lookup ("Type"));
+			list_type = new ObjectType ((Class) dova_ns.scope.lookup ("List"));
+			tuple_type = new ObjectType ((Class) dova_ns.scope.lookup ("Tuple"));
 		}
 
 		current_symbol = root_symbol;
diff --git a/vala/valasetliteral.vala b/vala/valasetliteral.vala
new file mode 100644
index 0000000..4f490a5
--- /dev/null
+++ b/vala/valasetliteral.vala
@@ -0,0 +1,97 @@
+/* valasetliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.SetLiteral : Literal {
+	private List<Expression> expression_list = new ArrayList<Expression> ();
+
+	public DataType element_type { get; private set; }
+
+	public SetLiteral (SourceReference? source_reference = null) {
+		this.source_reference = source_reference;
+	}
+
+	public override void accept_children (CodeVisitor visitor) {
+		foreach (Expression expr in expression_list) {
+			expr.accept (visitor);
+		}
+	}
+
+	public override void accept (CodeVisitor visitor) {
+		visitor.visit_set_literal (this);
+	}
+
+	public void add_expression (Expression expr) {
+		expression_list.add (expr);
+		expr.parent_node = this;
+	}
+
+	public List<Expression> get_expressions () {
+		return expression_list;
+	}
+
+	public override bool is_pure () {
+		return false;
+	}
+
+	public override void replace_expression (Expression old_node, Expression new_node) {
+		for (int i = 0; i < expression_list.size; i++) {
+			if (expression_list[i] == old_node) {
+				expression_list[i] = new_node;
+			}
+		}
+	}
+
+	public override bool check (SemanticAnalyzer analyzer) {
+		if (checked) {
+			return !error;
+		}
+
+		checked = true;
+
+		var set_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Set"));
+		set_type.value_owned = true;
+
+		bool fixed_element_type = false;
+		if (target_type != null && target_type.data_type == set_type.data_type && target_type.get_type_arguments ().size == 1) {
+			element_type = target_type.get_type_arguments ().get (0).copy ();
+			fixed_element_type = true;
+		}
+
+		foreach (var expr in expression_list) {
+			if (fixed_element_type) {
+				expr.target_type = element_type;
+			}
+			if (!expr.check (analyzer)) {
+				return false;
+			}
+			if (element_type == null) {
+				element_type = expr.value_type.copy ();
+			}
+		}
+
+		element_type.value_owned = true;
+		set_type.add_type_argument (element_type);
+		value_type = set_type;
+
+		return !error;
+	}
+}
diff --git a/vala/valatuple.vala b/vala/valatuple.vala
index b723d39..a842ee6 100644
--- a/vala/valatuple.vala
+++ b/vala/valatuple.vala
@@ -32,6 +32,16 @@ public class Vala.Tuple : Expression {
 		this.source_reference = source_reference;
 	}
 
+	public override void accept_children (CodeVisitor visitor) {
+		foreach (Expression expr in expression_list) {
+			expr.accept (visitor);
+		}
+	}
+
+	public override void accept (CodeVisitor visitor) {
+		visitor.visit_tuple (this);
+	}
+
 	public void add_expression (Expression expr) {
 		expression_list.add (expr);
 	}
@@ -44,6 +54,14 @@ public class Vala.Tuple : Expression {
 		return false;
 	}
 
+	public override void replace_expression (Expression old_node, Expression new_node) {
+		for (int i = 0; i < expression_list.size; i++) {
+			if (expression_list[i] == old_node) {
+				expression_list[i] = new_node;
+			}
+		}
+	}
+
 	public override bool check (SemanticAnalyzer analyzer) {
 		if (checked) {
 			return !error;
@@ -51,9 +69,22 @@ public class Vala.Tuple : Expression {
 
 		checked = true;
 
-		Report.error (source_reference, "tuples are not supported");
-		error = true;
-		return false;
+		if (analyzer.context.profile != Profile.DOVA) {
+			Report.error (source_reference, "tuples are not supported");
+			error = true;
+			return false;
+		}
+
+		value_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Tuple"));
+		value_type.value_owned = true;
+
+		foreach (var expr in expression_list) {
+			if (!expr.check (analyzer)) {
+				return false;
+			}
+			value_type.add_type_argument (expr.value_type.copy ());
+		}
+
+		return !error;
 	}
 }
-



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]