Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for RoslynDeclarationProvider and Conversion.TryFindConversion #271

Merged
merged 2 commits into from
Aug 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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