+ | OPEN_PARENS tuple_elements CLOSE_PARENS opt_nullable
+ {
+ if (lang_version < LanguageVersion.V_7)
+ FeatureIsNotAvailable (GetLocation ($1), "tuples");
+
+ var a = (Tuple<TypeArguments, List<string>>) $2;
+ if (a.Item1.Count < 2) {
+ report.Error (8124, GetLocation ($1), "Tuple must contain at least two elements");
+ }
+
+ $$ = new TupleTypeExpr (a.Item1, a.Item2, GetLocation ($1));
+
+ if ($4 != null)
+ $$ = new ComposedCast ((FullNamedExpression) $$, (ComposedTypeSpecifier) $4);
+ }
+ ;
+
+tuple_elements
+ : tuple_element tuple_element_name
+ {
+ var type_args = new TypeArguments ();
+ type_args.Add ((FullNamedExpression) $1);
+
+ var names = new List<string> (2);
+ var lt = (LocatedToken) $2;
+ names.Add (lt?.Value);
+
+ $$ = Tuple.Create (type_args, names);
+ }
+ | tuple_elements COMMA tuple_element tuple_element_name
+ {
+ var a = (Tuple<TypeArguments, List<string>>) $1;
+ a.Item1.Add ((FullNamedExpression) $3);
+ var lt = (LocatedToken) $4;
+ a.Item2.Add (lt?.Value);
+ $$ = a;
+ }
+ ;
+
+tuple_element_name
+ : /* empty */
+ | IDENTIFIER
+ ;
+
+tuple_element
+ : parameter_type