Created
April 25, 2017 01:54
-
-
Save migueldeicaza/43b28ef3ceb8db59ffc00b70eb37f309 to your computer and use it in GitHub Desktop.
Dictionary-literal improvement to allow literals to be assigned to other Dictionary-shaped objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /dev/null 2017-04-24 21:53:22.000000000 -0400 | |
+++ README.md 2017-04-24 21:53:03.000000000 -0400 | |
@@ -0,0 +1,67 @@ | |
+Current work: | |
+ | |
+Trying to allow the existing patch for dictionary literals that allows: | |
+ | |
+ var a = ["key":"value"]; | |
+ | |
+Which creates an inferred Dictionary<string,string> above into | |
+allowing the use of Dictionary-shaped APIs like this: | |
+ | |
+ Hashtable a = ["key":"value"]; | |
+ | |
+The pipeline is in place, what we had to do is hook up a few places | |
+code to ensure that the assignment in that case propates the type. The current code hits this: | |
+ | |
+ Attempting to convert a Dictionary into System.Collections.Hashtable | |
+ Attemping to convert to System.Collections.Hashtable | |
+ | |
+And at this point, we should perform the conversion if possible. | |
+After that you get a crash, expected, because the above just blindly | |
+proceeds. | |
+ | |
+Working code: | |
+ | |
+```csharp | |
+using System; | |
+ | |
+class X { | |
+ static void Main () | |
+ { | |
+ var j = ["foo":[1.2:2.3], "bar":[1.2:3.4]]; | |
+ | |
+ var k = ["work":new Uri ("http://microsoft.com"), | |
+ "leisure":new Uri ("http://catoverflow.com")]; | |
+ | |
+ foreach (var kp in j){ | |
+ Console.WriteLine ($"k={kp.Key} v={kp.Value}"); | |
+ } | |
+ } | |
+} | |
+``` | |
+ | |
+Work in progress code: | |
+ | |
+```csharp | |
+using System; | |
+using System.Collections; | |
+ | |
+class X { | |
+ static void Main () | |
+ { | |
+ Hashtable j = ["foo":"bar"]; | |
+ var i = (Hashtable) ["foo":"bar"]; | |
+ | |
+ var k = ["work":new Uri ("http://microsoft.com"), | |
+ "leisure":new Uri ("http://catoverflow.com")]; | |
+ | |
+ foreach (var kp in j.Keys){ | |
+ Console.WriteLine ($"k={kp} v={j[kp]}"); | |
+ } | |
+ } | |
+} | |
+``` | |
+ | |
+Compile and run with: | |
+ | |
+ make && mono --debug=casts ../class/lib/net_4_x/mcs.exe b.cs && mono b.exe | |
+ | |
diff --git a/mcs/mcs/argument.cs b/mcs/mcs/argument.cs | |
index a5edeb53cf6..9ba43d34bec 100644 | |
--- a/mcs/mcs/argument.cs | |
+++ b/mcs/mcs/argument.cs | |
@@ -193,12 +193,16 @@ namespace Mono.CSharp | |
public void Resolve (ResolveContext ec) | |
{ | |
// Verify that the argument is readable | |
- if (ArgType != AType.Out) | |
+ if (ArgType != AType.Out) { | |
Expr = Expr.Resolve (ec); | |
+ if (Expr is DictionaryLiteral) { | |
+ Expr = ((DictionaryLiteral)Expr).ResolveAsDictionary (ec); | |
+ } | |
+ } | |
// Verify that the argument is writeable | |
- if (Expr != null && IsByRef) | |
- Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess); | |
+ if (Expr != null && IsByRef) | |
+ Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess); | |
if (Expr == null) | |
Expr = ErrorExpression.Instance; | |
diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs | |
index 36c5626bcc3..41b4bd23c7e 100644 | |
--- a/mcs/mcs/convert.cs | |
+++ b/mcs/mcs/convert.cs | |
@@ -347,6 +347,10 @@ namespace Mono.CSharp { | |
return TypeSpec.IsReferenceType (target_type) || target_type.Kind == MemberKind.PointerType; | |
} | |
+ if (expr_type == InternalType.DictionaryLiteralType){ | |
+ Console.WriteLine ("Should check if {0} can convert to {1}, for now, we say yes", expr_type, target_type); | |
+ return true; | |
+ } | |
// | |
// Implicit dynamic conversion | |
@@ -1369,6 +1373,10 @@ namespace Mono.CSharp { | |
TypeSpec expr_type = expr.Type; | |
Expression e; | |
+ if (expr_type == InternalType.DictionaryLiteralType){ | |
+ Console.WriteLine ("Attempting to convert a Dictionary into {0}", target_type); | |
+ } | |
+ | |
if (expr_type == target_type) { | |
if (expr_type != InternalType.NullLiteral && expr_type != InternalType.AnonymousMethod) | |
return expr; | |
diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs | |
index d2a1b7e95da..683879de7ec 100644 | |
--- a/mcs/mcs/ecore.cs | |
+++ b/mcs/mcs/ecore.cs | |
@@ -1,4 +1,4 @@ | |
-// | |
+// | |
// ecore.cs: Core of the Expression representation for the intermediate tree. | |
// | |
// Author: | |
@@ -7763,7 +7763,9 @@ namespace Mono.CSharp { | |
type = InternalType.ErrorType; | |
return false; | |
} | |
- | |
+ if (right_side.Type == InternalType.DictionaryLiteralType) { | |
+ Console.WriteLine ("We have a problem"); | |
+ } | |
eclass = ExprClass.Variable; | |
return true; | |
} | |
diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs | |
index f03be851f61..b1f988b2c8c 100644 | |
--- a/mcs/mcs/expression.cs | |
+++ b/mcs/mcs/expression.cs | |
@@ -1,4 +1,4 @@ | |
-// | |
+// | |
// expression.cs: Expression representation for the IL tree. | |
// | |
// Author: | |
@@ -1760,10 +1760,12 @@ namespace Mono.CSharp | |
} | |
var vexpr = ProbeType as VarExpr; | |
- if (vexpr != null && vexpr.InferType (rc, expr)) { | |
- probe_type_expr = vexpr.Type; | |
- rc.Report.SetPrinter (prev_recorder); | |
- return; | |
+ if (vexpr != null){ | |
+ if (vexpr.InferType (rc, expr)) { | |
+ probe_type_expr = vexpr.Type; | |
+ rc.Report.SetPrinter (prev_recorder); | |
+ return; | |
+ } | |
} | |
var expr_printer = new SessionReportPrinter (); | |
@@ -2570,6 +2572,11 @@ namespace Mono.CSharp | |
if (Initializer != null) { | |
Initializer = Initializer.Resolve (rc); | |
+ // var x = [dict:literal] is always a Dictionary | |
+ var dl = Initializer as DictionaryLiteral; | |
+ if (dl != null) | |
+ Initializer = dl.ResolveAsDictionary (rc); | |
+ | |
if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) { | |
type = var_expr.Type; | |
} | |
@@ -12526,11 +12533,11 @@ namespace Mono.CSharp | |
} | |
} | |
- public class DictionaryLiteral : Expression { | |
+ public class DictionaryLiteral : Constant { | |
List<KeyPair> KeyPairs; | |
protected TypeSpec key_type, value_type; | |
- public DictionaryLiteral (List<KeyPair> keyPairs, Location loc) | |
+ public DictionaryLiteral (List<KeyPair> keyPairs, Location loc) : base (loc) | |
{ | |
KeyPairs = keyPairs; | |
this.loc = loc; | |
@@ -12548,9 +12555,11 @@ namespace Mono.CSharp | |
Expression ResolveElement (ResolveContext rc, TypeInferenceContext tic, Expression e) | |
{ | |
e = e.Resolve (rc); | |
- if (e != null) | |
+ if (e != null){ | |
+ if (e is DictionaryLiteral) | |
+ e = ((DictionaryLiteral) e).ResolveAsDictionary (rc); | |
tic.AddCommonTypeBound (e.Type); | |
- | |
+ } | |
return e; | |
} | |
@@ -12604,6 +12613,16 @@ namespace Mono.CSharp | |
rc.Report.Error (-1, loc, "It is not possible to infer the type of the dictionary values"); | |
return null; | |
} | |
+ type = InternalType.DictionaryLiteralType; | |
+ eclass = ExprClass.Value; | |
+ return this; | |
+ } | |
+ | |
+ // | |
+ // Called when we determine that we want to use this as the default Dictionary<K,V> | |
+ // | |
+ public Expression ResolveAsDictionary (ResolveContext rc) | |
+ { | |
if (rc.Module.PredefinedTypes.Dictionary.Define ()){ | |
var dict_type = new TypeExpression (rc.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (rc, new [] { key_type, value_type }), loc); | |
var init = new List<Expression> (); | |
@@ -12620,19 +12639,57 @@ namespace Mono.CSharp | |
args.Add (new Argument (new IntConstant (rc.BuiltinTypes, init.Count, loc))); | |
return new NewInitialize (dict_type, args, new CollectionOrObjectInitializers (init, loc), loc).Resolve (rc); | |
} | |
- return this; | |
+ return null; | |
} | |
- | |
+ | |
public override Expression CreateExpressionTree (ResolveContext ec) | |
{ | |
// Not needed | |
- throw new NotImplementedException (); | |
+ throw new Exception ("not reached"); | |
} | |
public override void Emit (EmitContext ec) | |
{ | |
// Not Needed | |
+ throw new Exception ("not reached"); | |
} | |
+ | |
+ // | |
+ // Constant methods | |
+ // | |
+ | |
+ public override Constant ConvertImplicitly (TypeSpec type) | |
+ { | |
+ if (this.type == type) | |
+ return this; | |
+ | |
+ Console.WriteLine ("Attemping to convert to {0}", type); | |
+ return base.ConvertImplicitly (type); | |
+ } | |
+ | |
+ public override bool IsLiteral => true; | |
+ | |
+ public override string GetValueAsLiteral () | |
+ { | |
+ throw new NotSupportedException (); | |
+ } | |
+ | |
+ public override long GetValueAsLong () | |
+ { | |
+ throw new NotSupportedException (); | |
+ } | |
+ | |
+ public override bool IsDefaultValue => false; | |
+ public override bool IsNegative => false; | |
+ | |
+ public override object GetValue () => throw new NotImplementedException (); | |
+ | |
+ public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) | |
+ { | |
+ Console.WriteLine ("Request to convert to {0}", target_type); | |
+ return null; | |
+ } | |
+ | |
} | |
public class InterpolatedString : Expression | |
diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs | |
index 4f67eb3240f..0b437e7fc9f 100644 | |
--- a/mcs/mcs/statement.cs | |
+++ b/mcs/mcs/statement.cs | |
@@ -1,4 +1,4 @@ | |
-// | |
+// | |
// statement.cs: Statement representation for the IL tree. | |
// | |
// Authors: | |
@@ -2151,6 +2151,10 @@ namespace Mono.CSharp { | |
Initializer = Initializer.Resolve (bc); | |
if (Initializer != null) { | |
+ var dl = Initializer as DictionaryLiteral; | |
+ if (dl != null) | |
+ Initializer = dl.ResolveAsDictionary (bc); | |
+ | |
((VarExpr) type_expr).InferType (bc, Initializer); | |
type = type_expr.Type; | |
} else { | |
diff --git a/mcs/mcs/typespec.cs b/mcs/mcs/typespec.cs | |
index 696bde556c8..dd76dd6eee0 100644 | |
--- a/mcs/mcs/typespec.cs | |
+++ b/mcs/mcs/typespec.cs | |
@@ -1432,6 +1432,7 @@ namespace Mono.CSharp | |
public static readonly InternalType Namespace = new InternalType ("<namespace>"); | |
public static readonly InternalType ErrorType = new InternalType ("<error>"); | |
public static readonly InternalType VarOutType = new InternalType ("var out"); | |
+ public static readonly InternalType DictionaryLiteralType = new InternalType ("dictionary literal"); | |
readonly string name; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment