Skip to content

Commit

Permalink
Proper deserialization of declaration headers with attributes (micros…
Browse files Browse the repository at this point in the history
  • Loading branch information
bettinaheim committed Oct 11, 2019
1 parent e5c5c62 commit bb013f2
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 35 deletions.
6 changes: 2 additions & 4 deletions src/QsCompiler/CompilationManager/AssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using Microsoft.Quantum.QsCompiler.ReservedKeywords;
using Microsoft.Quantum.QsCompiler.Serialization;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;


Expand All @@ -39,7 +38,7 @@ public static bool LoadReferencedAssembly(Uri asm, out References.Headers header
{
if (asm == null) throw new ArgumentNullException(nameof(asm));
if (!CompilationUnitManager.TryGetFileId(asm, out var id) || !File.Exists(asm.LocalPath))
{ throw new FileNotFoundException($"the uti '{asm}' given to the assembly loader is invalid or the file does not exist"); }
{ throw new FileNotFoundException($"the uri '{asm}' given to the assembly loader is invalid or the file does not exist"); }

using (var stream = File.OpenRead(asm.LocalPath))
using (var assemblyFile = new PEReader(stream))
Expand Down Expand Up @@ -67,8 +66,7 @@ public static IEnumerable<QsNamespace> LoadSyntaxTree(Stream stream)
using (var reader = new BsonDataReader(stream))
{
reader.ReadRootValueAsArray = true;
var settings = new JsonSerializerSettings { Converters = JsonConverters.All(false), ContractResolver = new DictionaryAsArrayResolver() };
var serializer = JsonSerializer.CreateDefault(settings);
var serializer = Json.Serializer(Json.Converters(false));
return serializer.Deserialize<IEnumerable<QsNamespace>>(reader);
}
}
Expand Down
1 change: 0 additions & 1 deletion src/QsCompiler/CompilationManager/CompilationUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
Expand Down
4 changes: 1 addition & 3 deletions src/QsCompiler/Compiler/CompilationLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,7 @@ private bool SerializeSyntaxTree(MemoryStream ms)
var serialized = this.GeneratedSyntaxTree != null;
using (var writer = new BsonDataWriter(ms) { CloseOutput = false })
{
var settings = new JsonSerializerSettings
{ Converters = JsonConverters.All(false), ContractResolver = new DictionaryAsArrayResolver() };
var serializer = JsonSerializer.CreateDefault(settings);
var serializer = Json.Serializer(Json.Converters(false));
var validTree = this.GeneratedSyntaxTree?.Select(ns => FilterBySourceFile.Apply(ns, validSources));
try { serializer.Serialize(writer, validTree ?? Enumerable.Empty<QsNamespace>()); }
catch (Exception ex)
Expand Down
42 changes: 27 additions & 15 deletions src/QsCompiler/Core/DeclarationHeaders.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,32 @@ namespace Microsoft.Quantum.QsCompiler

open System
open System.Collections.Immutable
open System.IO
open System.Text
open Microsoft.Quantum.QsCompiler.DataTypes
open Microsoft.Quantum.QsCompiler.Serialization
open Microsoft.Quantum.QsCompiler.SyntaxTokens
open Microsoft.Quantum.QsCompiler.SyntaxTree
open Newtonsoft.Json


/// to be removed as soon as we ship our own binary instead of compiled C#
/// to be removed in future releases
type private DeclarationHeader =

static member internal FromJson<'T> json =
let deserialize converters =
let reader = new JsonTextReader(new StringReader(json));
(converters |> Json.Serializer).Deserialize<'T>(reader)
try true, Json.Converters false |> deserialize
with _ -> false, Json.Converters true |> deserialize

static member internal ToJson obj =
let builder = new StringBuilder()
(Json.Converters false |> Json.Serializer).Serialize(new StringWriter(builder), obj)
builder.ToString()


/// to be removed in future releases
type TypeDeclarationHeader = {
QualifiedName : QsQualifiedName
Attributes : ImmutableArray<QsDeclarationAttribute>
Expand All @@ -38,19 +56,17 @@ type TypeDeclarationHeader = {
}

static member FromJson json =
let (success, header) =
try true, JsonConvert.DeserializeObject<TypeDeclarationHeader>(json, JsonConverters.All false)
with _ -> false, JsonConvert.DeserializeObject<TypeDeclarationHeader>(json, JsonConverters.All true)
let (success, header) = DeclarationHeader.FromJson<TypeDeclarationHeader> json
let attributesAreNullOrDefault = Object.ReferenceEquals(header.Attributes, null) || header.Attributes.IsDefault
let header = if attributesAreNullOrDefault then {header with Attributes = ImmutableArray.Empty} else header // no reason to raise an error
if not (Object.ReferenceEquals(header.TypeItems, null)) then success, header
else false, {header with TypeItems = ImmutableArray.Create (header.Type |> Anonymous |> QsTupleItem) |> QsTuple}

member this.ToJson() : string =
JsonConvert.SerializeObject(this, JsonConverters.All false)
DeclarationHeader.ToJson this


/// to be removed as soon as we ship our own binary instead of compiled C#
/// to be removed in future releases
type CallableDeclarationHeader = {
Kind : QsCallableKind
QualifiedName : QsQualifiedName
Expand Down Expand Up @@ -84,9 +100,7 @@ type CallableDeclarationHeader = {
| QsTupleItem (decl : LocalVariableDeclaration<_>) -> QsTupleItem {decl with InferredInformation = info}
// we need to make sure that all fields that could possibly be null after deserializing
// due to changes of fields over time are initialized to a proper value
let (success, header) =
try true, JsonConvert.DeserializeObject<CallableDeclarationHeader>(json, JsonConverters.All false)
with _ -> false, JsonConvert.DeserializeObject<CallableDeclarationHeader>(json, JsonConverters.All true)
let (success, header) = DeclarationHeader.FromJson<CallableDeclarationHeader> json
let attributesAreNullOrDefault = Object.ReferenceEquals(header.Attributes, null) || header.Attributes.IsDefault
let header = if attributesAreNullOrDefault then {header with Attributes = ImmutableArray.Empty} else header // no reason to raise an error
let header = {header with ArgumentTuple = header.ArgumentTuple |> setInferredInfo}
Expand All @@ -95,10 +109,10 @@ type CallableDeclarationHeader = {
else success, header

member this.ToJson() : string =
JsonConvert.SerializeObject(this, JsonConverters.All false)
DeclarationHeader.ToJson this


/// to be removed as soon as we ship our own binary instead of compiled C#
/// to be removed in future releases
type SpecializationDeclarationHeader = {
Kind : QsSpecializationKind
TypeArguments : QsNullable<ImmutableArray<ResolvedType>>
Expand Down Expand Up @@ -128,9 +142,7 @@ type SpecializationDeclarationHeader = {
static member FromJson json =
// we need to make sure that all fields that could possibly be null after deserializing
// due to changes of fields over time are initialized to a proper value
let (success, header) =
try true, JsonConvert.DeserializeObject<SpecializationDeclarationHeader>(json, JsonConverters.All false)
with _ -> false, JsonConvert.DeserializeObject<SpecializationDeclarationHeader>(json, JsonConverters.All true)
let (success, header) = DeclarationHeader.FromJson<SpecializationDeclarationHeader> json
let infoIsNull = Object.ReferenceEquals(header.Information, null)
let typeArgsAreNull = Object.ReferenceEquals(header.TypeArguments, null)
let attributesAreNullOrDefault = Object.ReferenceEquals(header.Attributes, null) || header.Attributes.IsDefault
Expand All @@ -142,7 +154,7 @@ type SpecializationDeclarationHeader = {
false, {header with Information = information; TypeArguments = typeArguments }

member this.ToJson() : string =
JsonConvert.SerializeObject(this, JsonConverters.All false)
DeclarationHeader.ToJson this



29 changes: 18 additions & 11 deletions src/QsCompiler/DataStructures/Serialization.fs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,19 @@ type QsNamespaceConverter() =
serializer.Serialize(writer, (value.Name, value.Elements))


type JsonConverters =
static member All ignoreSerializationException =
type DictionaryAsArrayResolver () =
inherit DefaultContractResolver()

override this.CreateContract (objectType : Type) =
let isDictionary (t : Type) =
t = typedefof<IDictionary<_,_>> ||
(t.IsGenericType && t.GetGenericTypeDefinition() = typeof<IDictionary<_,_>>.GetGenericTypeDefinition())
if objectType.GetInterfaces().Any(new Func<_,_>(isDictionary)) then base.CreateArrayContract(objectType) :> JsonContract;
else base.CreateContract(objectType);


type Json =
static member Converters ignoreSerializationException =
[|
new NonNullableConverter<string>() :> JsonConverter
new ResolvedTypeConverter(ignoreSerializationException) :> JsonConverter
Expand All @@ -102,14 +113,10 @@ type JsonConverters =
new QsNamespaceConverter() :> JsonConverter
|]

static member Serializer converters =
let settings = new JsonSerializerSettings()
settings.Converters <- converters
settings.ContractResolver <- new DictionaryAsArrayResolver()
JsonSerializer.CreateDefault(settings)

type DictionaryAsArrayResolver () =
inherit DefaultContractResolver()

override this.CreateContract (objectType : Type) =
let isDictionary (t : Type) =
t = typedefof<IDictionary<_,_>> ||
(t.IsGenericType && t.GetGenericTypeDefinition() = typeof<IDictionary<_,_>>.GetGenericTypeDefinition())
if objectType.GetInterfaces().Any(new Func<_,_>(isDictionary)) then base.CreateArrayContract(objectType) :> JsonContract;
else base.CreateContract(objectType);

3 changes: 2 additions & 1 deletion src/QsCompiler/Transformations/BasicTransformations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public static ImmutableHashSet<NonNullable<string>> Apply(IEnumerable<QsNamespac
/// Returns a hash set containing all source files in the given namespace(s).
/// Throws an ArgumentNullException if any of the given namespaces is null.
/// </summary>
public static ImmutableHashSet<NonNullable<string>> Apply(params QsNamespace[] namespaces) => Apply(namespaces);
public static ImmutableHashSet<NonNullable<string>> Apply(params QsNamespace[] namespaces) =>
Apply((IEnumerable<QsNamespace>)namespaces);

private readonly HashSet<NonNullable<string>> SourceFiles;
private GetSourceFiles() :
Expand Down

0 comments on commit bb013f2

Please sign in to comment.