Skip to content

Commit

Permalink
Fixes for RoslynDeclarationProvider and Conversion.TryFindConversion (d…
Browse files Browse the repository at this point in the history
…otnet#271)

* RoslynDeclarationProvider uses all available source codes
to build the requested type declaration.

* Conversion.TryFindConversion looks for casts defined on the toType as
well.

Co-authored-by: Dmitry Kats <ratkillerx@hotmail.com>
  • Loading branch information
2 people authored and tminka committed Aug 24, 2020
1 parent e00a83e commit 52e08cc
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 28 deletions.
41 changes: 37 additions & 4 deletions src/Compiler/Dynamic/Conversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,9 @@ public static bool TryGetConversion(Type fromType, Type toType, out Conversion i
}
}
// check for custom conversions
MemberInfo[] implicits = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
MemberInfo[] implicitsOnFromType = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
"op_Implicit");
foreach (MemberInfo member in implicits)
foreach (MemberInfo member in implicitsOnFromType)
{
MethodInfo method = (MethodInfo) member;
if (method.ReturnType == toType)
Expand All @@ -489,9 +489,25 @@ public static bool TryGetConversion(Type fromType, Type toType, out Conversion i
return true;
}
}
MemberInfo[] explicits = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
MemberInfo[] implicitsOnToType = toType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
"op_Implicit");
foreach (MemberInfo member in implicitsOnToType)
{
MethodInfo method = (MethodInfo)member;
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == fromType)
{
info.SubclassCount = 1000;
info.Converter = delegate (object value)
{
return Util.Invoke(method, null, value);
};
return true;
}
}
MemberInfo[] explicitsOnFromType = fromType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
"op_Explicit");
foreach (MemberInfo member in explicits)
foreach (MemberInfo member in explicitsOnFromType)
{
MethodInfo method = (MethodInfo) member;
if (method.ReturnType == toType)
Expand All @@ -504,6 +520,23 @@ public static bool TryGetConversion(Type fromType, Type toType, out Conversion i
return true;
}
}
MemberInfo[] explicitsOnToType = toType.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, Type.FilterName,
"op_Explicit");

foreach (MemberInfo member in explicitsOnToType)
{
MethodInfo method = (MethodInfo)member;
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == fromType)
{
info.IsExplicit = true;
info.Converter = delegate (object value)
{
return Util.Invoke(method, null, value);
};
return true;
}
}
// lastly try the IConvertible interface
if (toType.IsPrimitive)
{
Expand Down
34 changes: 21 additions & 13 deletions src/Csoft/EmbeddedResourceSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

Expand All @@ -17,17 +16,9 @@ public class EmbeddedResourceSourceProvider : ISourceProvider
{
public SourceCode TryGetSource(Type t)
{
var asm = t.Assembly;
return asm.GetManifestResourceNames().Where(s => s.EndsWith(".cs")).Select(s =>
{
var stream = asm.GetManifestResourceStream(s);
using (var reader = new StreamReader(stream))
{
return new SourceCode(s, reader.ReadToEnd());
}
}).FirstOrDefault(code =>
bool IsPrimaryFile(SourceFile sf)
{
var tree = CSharpSyntaxTree.ParseText(code.SourceText, null, code.FilePath);
var tree = CSharpSyntaxTree.ParseText(sf.SourceText, null, sf.FilePath);
var root = tree.GetRoot();
var typeDecl = root.DescendantNodes()
.OfType<NamespaceDeclarationSyntax>()
Expand All @@ -38,7 +29,24 @@ public SourceCode TryGetSource(Type t)
.Where(md => md.Identifier.ValueText.Equals(t.Name))
.FirstOrDefault();
return typeDecl != null;
});
}
var asm = t.Assembly;
SourceFile primaryFile = null;
List<SourceFile> additionalFiles = new List<SourceFile>();
foreach (var s in asm.GetManifestResourceNames().Where(s => s.EndsWith(".cs")))
{
SourceFile sf;
var stream = asm.GetManifestResourceStream(s);
using (var reader = new StreamReader(stream))
{
sf = new SourceFile(s, reader.ReadToEnd());
}
if (primaryFile == null && IsPrimaryFile(sf))
primaryFile = sf;
else
additionalFiles.Add(sf);
}
return primaryFile == null ? null : new SourceCode(primaryFile, additionalFiles.ToImmutableArray());
}
}
}
28 changes: 22 additions & 6 deletions src/Csoft/ISourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,41 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Immutable;

namespace Microsoft.ML.Probabilistic.Compiler
{
public class SourceCode
public class SourceFile
{
public string FilePath { get; }
public string SourceText { get; }

public SourceCode(string filePath, string sourceText)
public SourceFile(string filePath, string sourceText)
{
FilePath = filePath;
SourceText = sourceText;
}
}

public class SourceCode
{
/// <summary>
/// Source file that contains the primary definition.
/// </summary>
public SourceFile PrimaryFile { get; }
/// <summary>
/// Additional files that contain the definitions of some of the types referenced in the primary file.
/// Should be used to build a more complete semantic model.
/// </summary>
public ImmutableArray<SourceFile> AddtionalFiles { get; }

public SourceCode(SourceFile primaryFile, ImmutableArray<SourceFile> additionalFiles)
{
PrimaryFile = primaryFile;
AddtionalFiles = additionalFiles;
}
}

public interface ISourceProvider
{
SourceCode TryGetSource(Type t);
Expand Down
10 changes: 6 additions & 4 deletions src/Csoft/RoslynDeclarationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ public ITypeDeclaration GetTypeDeclaration(Type t, bool translate)
var source = SourceProvider.TryGetSource(t);
if (source == null)
throw new InvalidOperationException($"Cannot find source code for the type {t.Name}");
var tree = CSharpSyntaxTree.ParseText(source.SourceText, null, source.FilePath, Encoding.UTF8);
var primaryTree = CSharpSyntaxTree.ParseText(source.PrimaryFile.SourceText, null, source.PrimaryFile.FilePath, Encoding.UTF8);
var allTrees = source.AddtionalFiles.Select(f => CSharpSyntaxTree.ParseText(f.SourceText, null, f.FilePath, Encoding.UTF8)).ToList();
allTrees.Add(primaryTree);

var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var targetAssemblyName = Path.GetFileNameWithoutExtension(tree.FilePath);
var targetAssemblyName = Path.GetFileNameWithoutExtension(primaryTree.FilePath);
var asmName = t.Assembly.GetName();
var pk = asmName.GetPublicKey();
if (pk != null && pk.Length > 0)
Expand All @@ -86,8 +88,8 @@ public ITypeDeclaration GetTypeDeclaration(Type t, bool translate)
.WithPublicSign(true)
.WithCryptoPublicKey(System.Collections.Immutable.ImmutableArray.Create(pk));
}
var compilation = CSharpCompilation.Create(targetAssemblyName, new[] { tree }, references, options);
var model = compilation.GetSemanticModel(tree);
var compilation = CSharpCompilation.Create(targetAssemblyName, allTrees, references, options);
var model = compilation.GetSemanticModel(primaryTree);

var errors = compilation.GetDiagnostics().ToList();

Expand Down
35 changes: 35 additions & 0 deletions test/Tests/Dynamic/TypeInference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ public void ConversionTest()
Assert.True(Conversion.TryGetConversion(typeof (Tester), typeof (int[]), out conv));
o = conv.Converter(t);
Console.WriteLine("{0}: {1}", o.GetType(), o);
Assert.True(Conversion.TryGetConversion(typeof(int), typeof(Tester), out conv));
Assert.True(conv.IsExplicit);
Assert.True(Conversion.TryGetConversion(typeof(int[]), typeof(Tester), out conv));
Assert.True(conv.IsExplicit);
Assert.True(Conversion.TryGetConversion(typeof(ImplicitlyConvertibleToTesterDefinesCast), typeof(Tester), out conv));
Assert.False(conv.IsExplicit);
Assert.True(Conversion.TryGetConversion(typeof(ImplicitlyConvertibleToTesterCastDefinedOnTester), typeof(Tester), out conv));
Assert.False(conv.IsExplicit);

// conversion from null
Assert.False(Conversion.TryGetConversion(typeof (Nullable), typeof (int), out conv));
Expand Down Expand Up @@ -842,8 +850,35 @@ public static explicit operator int[](Tester t)
{
return t.arrayField;
}

public static explicit operator Tester(int x)
{
var tester = new Tester
{
intField = x
};
return tester;
}

public static explicit operator Tester(int[] x)
{
var tester = new Tester
{
arrayField = x
};
return tester;
}

public static implicit operator Tester(ImplicitlyConvertibleToTesterCastDefinedOnTester _) => new Tester();
}

public class ImplicitlyConvertibleToTesterDefinesCast
{
public static implicit operator Tester(ImplicitlyConvertibleToTesterDefinesCast _) => new Tester();
}

public class ImplicitlyConvertibleToTesterCastDefinedOnTester { }

/// <summary>
/// Help class of dynamically invoking methods.
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion test/Tests/MslTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ internal override void MethodOverrideModel(double[] prec)

[Fact]
[Trait("Category", "CsoftModel")]
[Trait("Category", "OpenBug")]
public void MethodInAnotherFileTest()
{
Assert.Throws<CompilationFailedException>(() =>
Expand Down

0 comments on commit 52e08cc

Please sign in to comment.