Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save migueldeicaza/43b28ef3ceb8db59ffc00b70eb37f309 to your computer and use it in GitHub Desktop.
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
--- /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