[mcs] Adds missing file
authorMarek Safar <marek.safar@gmail.com>
Fri, 30 Jun 2017 18:22:27 +0000 (20:22 +0200)
committerMarek Safar <marek.safar@gmail.com>
Fri, 30 Jun 2017 18:22:27 +0000 (20:22 +0200)
mcs/mcs/tuples.cs [new file with mode: 0644]

diff --git a/mcs/mcs/tuples.cs b/mcs/mcs/tuples.cs
new file mode 100644 (file)
index 0000000..e4f56ca
--- /dev/null
@@ -0,0 +1,503 @@
+//
+// tuples.cs: Tuples types
+//
+// Author:
+//   Marek Safar (marek.safar@gmail.com)
+//
+// Dual licensed under the terms of the MIT X11 or GNU GPL
+//
+// Copyright (C) Microsoft Corporation.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Globalization;
+
+#if STATIC
+using MetaType = IKVM.Reflection.Type;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using MetaType = System.Type;
+using System.Reflection;
+using System.Reflection.Emit;
+#endif
+
+namespace Mono.CSharp
+{
+       class TupleTypeExpr : TypeExpr
+       {
+               TypeArguments elements;
+               List<string> names;
+
+               public TupleTypeExpr (TypeArguments elements, List<string> names, Location loc)
+               {
+                       this.elements = elements;
+                       this.names = names;
+                       this.loc = loc;
+               }
+
+               public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
+               {
+                       var length = elements.Count;
+                       if (length > 7)
+                               throw new NotImplementedException ("tuples > 7");
+
+                       eclass = ExprClass.Type;
+
+                       var otype = mc.Module.PredefinedTypes.Tuples [length - 1].Resolve ();
+                       if (otype == null)
+                               return null;
+
+                       GenericTypeExpr ctype = new GenericTypeExpr (otype, elements, loc);
+                       type = ctype.ResolveAsType (mc);
+
+                       if (names != null && CheckElementNames (mc) && type != null) {
+                               type = NamedTupleSpec.MakeType (mc.Module, (InflatedTypeSpec) type, names);
+                       }
+
+                       return type;
+               }
+
+               bool CheckElementNames (IMemberContext mc)
+               {
+                       int first_name = -1;
+                       for (int i = 0; i < names.Count; ++i) {
+                               var name = names [i];
+                               if (name == null)
+                                       continue;
+
+                               if (IsReservedName (name)) {
+                                       mc.Module.Compiler.Report.Error (8126, loc, "The tuple element name `{0}' is reserved", name);
+                                       names [i] = null;
+                                       continue;
+                               }
+
+                               if (name.StartsWith ("Item", StringComparison.Ordinal)) {
+                                       var idx = name.Substring (4);
+                                       uint value;
+                                       if (uint.TryParse (idx, NumberStyles.Integer, CultureInfo.InvariantCulture, out value) && value != i + 1) {
+                                               mc.Module.Compiler.Report.Error (8125, loc, "The tuple element name `{0}' can only be used at position {1}", name, idx);
+                                               names [i] = null;
+                                               continue;
+                                       }
+                               }
+
+                               if (first_name < 0) {
+                                       first_name = i;
+                                       continue;
+                               }
+
+                               for (int ii = first_name; ii < i; ++ii) {
+                                       if (name == names [ii]) {
+                                               mc.Module.Compiler.Report.Error (8127, loc, "The tuple element name `{0}' is a duplicate", name);
+                                               names [i] = null;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       return first_name >= 0;
+               }
+
+               static bool IsReservedName (string name)
+               {
+                       switch (name) {
+                       case "CompareTo":
+                       case "Deconstruct":
+                       case "Equals":
+                       case "GetHashCode":
+                       case "Rest":
+                       case "ToString":
+                               return true;
+                       default:
+                               return false;
+                       }
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       var sb = new StringBuilder ();
+                       for (int i = 0; i < elements.Count; ++i) {
+                               sb.Append (elements.Arguments [i].GetSignatureForError ());
+
+                               if (names [i] != null) {
+                                       sb.Append (" ");
+                                       sb.Append (names [i]);
+                               }
+
+                               if (i != 0)
+                                       sb.Append (",");
+                       }
+
+                       return sb.ToString ();
+               }
+       }
+
+       public class NamedTupleSpec : TypeSpec
+       {
+               InflatedTypeSpec tuple;
+               IList<string> elements;
+
+               private NamedTupleSpec (InflatedTypeSpec tupleDefinition, IList<string> elements)
+                       : base (tupleDefinition.Kind, tupleDefinition.DeclaringType, tupleDefinition.MemberDefinition, null, tupleDefinition.Modifiers)
+               {
+                       tuple = tupleDefinition;
+                       this.elements = elements;
+
+                       state |= StateFlags.HasNamedTupleElement | StateFlags.Tuple;
+               }
+
+               public IList<string> Elements {
+                       get {
+                               return elements;
+                       }
+               }
+
+               public override TypeSpec [] TypeArguments {
+                       get {
+                               return tuple.TypeArguments;
+                       }
+               }
+
+               protected override void InitializeMemberCache (bool onlyTypes)
+               {
+                       cache = tuple.MemberCache;
+               }
+
+               public override MetaType GetMetaInfo ()
+               {
+                       return tuple.GetMetaInfo ();
+               }
+
+               public MemberSpec FindElement (IMemberContext mc, string name, Location loc)
+               {
+                       // TODO: cache it
+                       for (int i = 0; i < elements.Count; ++i) {
+                               var ename = elements [i];
+                               if (ename == null || ename != name)
+                                       continue;
+
+                               var member_name = GetElementPropertyName (i);
+                               var ms = MemberCache.FindMember (tuple, MemberFilter.Field (member_name, null), BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
+                               if (ms == null) {
+                                       mc.Module.Compiler.Report.Error (8128, loc, "Member `{0}' was not found on type '{1}'", member_name, tuple.GetSignatureForError ());
+                                       return null;
+                               }
+
+                               return ms;
+                       }
+
+                       return null;
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       //
+                       // csc reports names as well but it seems to me redundant when
+                       // they are not included in any type conversion
+                       //
+                       return tuple.GetSignatureForError ();
+               }
+
+               public string GetSignatureForErrorWithNames ()
+               {
+                       // TODO: Include names
+                       return tuple.GetSignatureForError ();
+               }
+
+               public static NamedTupleSpec MakeType (ModuleContainer module, InflatedTypeSpec tupleType, IList<string> names)
+               {
+                       // TODO: cache it
+                       return new NamedTupleSpec (tupleType, names);
+               }
+
+               public static string GetElementPropertyName (int index)
+               {
+                       return "Item" + (index + 1).ToString (CultureInfo.InvariantCulture);
+               }
+
+               public static bool CheckOverrideName (IParametersMember member, IParametersMember baseMember)
+               {
+                       var btypes = baseMember.Parameters.Types;
+                       var ttypes = member.Parameters.Types;
+                       for (int ii = 0; ii < baseMember.Parameters.Count; ++ii) {
+                               if (!CheckOverrideName (ttypes [ii], btypes [ii])) {
+                                       return false;
+                               }
+                       }
+
+                       return true;
+               }
+       
+               public static bool CheckOverrideName (TypeSpec type, TypeSpec baseType)
+               {
+                       var btype_ntuple = baseType as NamedTupleSpec;
+                       var mtype_ntupe = type as NamedTupleSpec;
+                       if (btype_ntuple == null && mtype_ntupe == null)
+                               return true;
+
+                       if (btype_ntuple != null || mtype_ntupe != null)
+                               return false;
+
+                       var b_elements = btype_ntuple.elements;
+                       var m_elements = mtype_ntupe.elements;
+                       for (int i = 0; i < b_elements.Count; ++i) {
+                               if (b_elements [i] != m_elements [i])
+                                       return false;
+                       }
+
+                       return true;
+               }
+       }
+
+       class TupleLiteralElement
+       {
+               public TupleLiteralElement (string name, Expression expr, Location loc)
+               {
+                       this.Name = name;
+                       this.Expr = expr;
+                       this.Location = loc;
+               }
+
+               public TupleLiteralElement (Expression expr)
+               {
+                       this.Expr = expr;
+                       this.Location = expr.Location;
+               }
+
+               public string Name { get; private set; }
+               public Expression Expr { get; set; }
+               public Location Location { get; private set; }
+       }
+
+       sealed class TupleLiteral : Expression
+       {
+               List<TupleLiteralElement> elements;
+
+               public TupleLiteral (List<TupleLiteralElement> elements, Location loc)
+               {
+                       this.elements = elements;
+                       this.loc = loc;
+               }
+
+               public List<TupleLiteralElement> Elements {
+                       get {
+                               return elements;
+                       }
+               }
+
+               public static bool ContainsNoTypeElement (TypeSpec type)
+               {
+                       var ta = type.TypeArguments;
+
+                       for (int i = 0; i < ta.Length; ++i) {
+                               var et = ta [i];
+                               if (InternalType.HasNoType (et))
+                                       return true;
+
+                               if (et.IsTupleType && ContainsNoTypeElement (et))
+                                       return true;
+                       }
+
+                       return false;
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8143, loc, "An expression tree cannot contain a tuple literal");
+                       return ErrorExpression.Instance;
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       var ta = new TypeArguments ();
+                       List<string> names = null;
+
+                       for (int i = 0; i < elements.Count; ++i) {
+                               var el = elements [i];
+                               var expr = el.Expr.Resolve (rc);
+                               if (expr == null) {
+                                       el.Expr = null;
+                                       ta = null;
+                                       continue;
+                               }
+
+                               if (expr.Type.Kind == MemberKind.Void) {
+                                       rc.Report.Error (8210, expr.Location, "A tuple literal cannot not contain a value of type `{0}'", expr.Type.GetSignatureForError ());
+                                       expr = null;
+                                       ta = null;
+                                       continue;
+                               }
+
+                               if (el.Name != null) {
+                                       if (names == null) {
+                                               names = new List<string> ();
+                                               for (int ii = 0; ii < i; ++ii) {
+                                                       names.Add (null);
+                                               }
+                                       }
+
+                                       names.Add (el.Name);
+                               }
+
+                               el.Expr = expr;
+
+                               if (ta != null)
+                                       ta.Add (new TypeExpression (expr.Type, expr.Location));
+                       }
+
+                       eclass = ExprClass.Value;
+
+                       if (ta == null)
+                               return null;
+
+                       var t = new TupleTypeExpr (ta, names, loc);
+                       type = t.ResolveAsType (rc) ?? InternalType.ErrorType;
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       foreach (var el in elements) {
+                               el.Expr.Emit (ec);
+                       }
+
+                       // TODO: Needs arguments check
+                       var ctor = MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly) as MethodSpec;
+
+                       ec.Emit (OpCodes.Newobj, ctor);
+               }
+
+               public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
+               {
+                       rc.Report.Error (8135, Location, "Tuple literal `{0}' cannot be converted to type `{1}'", type.GetSignatureForError (), target.GetSignatureForError ());
+               }
+       }
+
+       //
+       // Used when converting from a tuple literal or tuple instance to different tuple type
+       //
+       class TupleLiteralConversion : Expression
+       {
+               List<Expression> elements;
+               Expression source;
+
+               public TupleLiteralConversion (Expression source, TypeSpec type, List<Expression> elements, Location loc)
+               {
+                       this.source = source;
+                       this.type = type;
+                       this.elements = elements;
+                       this.loc = loc;
+
+                       eclass = source.eclass;
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8144, loc, "An expression tree cannot contain a tuple conversion");
+                       return null;
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       // Should not be reached
+                       throw new NotSupportedException ();
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (!(source is TupleLiteral)) {
+                               var assign = source as CompilerAssign;
+                               if (assign != null)
+                                       assign.EmitStatement (ec);
+                               else
+                                       source.Emit (ec);
+                       }
+                       
+                       foreach (var el in elements) {
+                               el.Emit (ec);
+                       }
+
+                       // TODO: Needs arguments check
+                       var ctor = MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly) as MethodSpec;
+
+                       ec.Emit (OpCodes.Newobj, ctor);
+               }
+       }
+
+       class TupleDeconstruct : ExpressionStatement
+       {
+               Expression source;
+               List<Expression> targetExprs;
+
+               public TupleDeconstruct (List<Expression> targetExprs, Expression source, Location loc)
+               {
+                       this.source = source;
+                       this.targetExprs = targetExprs;
+                       this.loc = loc;
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext ec)
+               {
+                       ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
+                       
+                       throw new NotImplementedException ();
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       var src = source.Resolve (rc);
+                       if (src == null)
+                               return null;
+                       
+                       if (InternalType.HasNoType (src.Type)) {
+                               rc.Report.Error (8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side");
+                               return null;
+                       }
+
+                       var tupleLiteral = src as TupleLiteral;
+                       if (tupleLiteral != null) {
+                               if (tupleLiteral.Elements.Count != targetExprs.Count) {
+                                       rc.Report.Error (8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{0}' variables",
+                                               tupleLiteral.Elements.Count.ToString (), targetExprs.Count.ToString ());
+                                       return null;
+                               }
+
+                               for (int i = 0; i < targetExprs.Count; ++i) {
+                                       targetExprs [i] = new SimpleAssign (targetExprs [i], tupleLiteral.Elements [i].Expr).Resolve (rc);
+                               }
+
+                               eclass = ExprClass.Value;
+                               type = src.Type;
+                               return this;
+                       }
+
+                       if (src.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
+                               rc.Report.Error (8133, loc, "Cannot deconstruct dynamic objects");
+                               return null;
+                       }
+
+                       throw new NotImplementedException ("Deconstruct assignment");
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       foreach (ExpressionStatement expr in targetExprs)
+                               expr.EmitStatement (ec);
+               }
+
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       foreach (var expr in targetExprs)
+                               expr.FlowAnalysis (fc);
+               }
+       }
+}
\ No newline at end of file