From 635a3e1abaa02223bd88ec7dfc5c53951be5f34c Mon Sep 17 00:00:00 2001 From: Igor Kiselev Date: Tue, 14 Jun 2016 21:43:02 -0700 Subject: [PATCH] Variance support. --- JSIL/DefinitelyTypedAssemblyEmitter.cs | 164 +++++++++++++----- .../DefinitelyTyped/internals/JSIL.Core.d.ts | 134 ++++++++------ 2 files changed, 194 insertions(+), 104 deletions(-) diff --git a/JSIL/DefinitelyTypedAssemblyEmitter.cs b/JSIL/DefinitelyTypedAssemblyEmitter.cs index 454f7a3b7..7d56cbb8d 100644 --- a/JSIL/DefinitelyTypedAssemblyEmitter.cs +++ b/JSIL/DefinitelyTypedAssemblyEmitter.cs @@ -26,7 +26,7 @@ public class DefinitelyTypedInternalsEmitter : DefinitelyTypedBaseEmitter { } public override void EmitHeader (bool stubbed, bool iife) { - Formatter.WriteRaw("import {$private as $asmJsilCore, StaticTypePair as $StaticTypePair, TypePair as $TypePair, NullArg as $Null} from \"./JSIL.Core\""); + Formatter.WriteRaw("import {$private as $asmJsilCore, StaticType as $StaticType, Type as $Type, NullArg as $Null} from \"./JSIL.Core\""); Formatter.NewLine(); } @@ -61,7 +61,7 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.Identifier(DefinitelyTypedUtilities.GetClassName(typedef)); Formatter.OpenBrace(); EmitClassInstance(typedef); - EmitClassType(typedef); + EmitClassInOutType(typedef); EmitClassStatic(typedef); EmitClassFactory(typedef); Formatter.CloseBrace(); @@ -79,17 +79,26 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.Space(); Formatter.OpenBrace(); - Formatter.WriteRaw("private __$brand : any"); + Formatter.WriteRaw("private __$brand_"); + Formatter.Identifier(typedef.FullName); + Formatter.WriteRaw(" : any"); Formatter.Semicolon(); foreach (var genericParameter in DefinitelyTypedUtilities.BuildGenericParemetersMap(typedef.GenericParameters, null)) { Formatter.WriteRaw("private"); Formatter.Space(); - Formatter.Identifier("__$" + genericParameter + "_brand"); + Formatter.WriteRaw("__$" + genericParameter.Value + "_brand_"); + Formatter.Identifier(typedef.FullName); Formatter.Space(); Formatter.WriteRaw(":"); Formatter.Space(); - Formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInParameterName(genericParameter.Value)); + if (genericParameter.Key.IsCovariant) { + Formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterOutParameterName(genericParameter.Value)); + } else if (genericParameter.Key.IsContravariant) { + Formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInParameterName(genericParameter.Value)); + } else { + Formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(genericParameter.Value)); + } Formatter.Semicolon(); } @@ -120,10 +129,41 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.CloseBrace(); } - private void EmitClassType (TypeDefinition typedef) { + private void EmitClassInOutType (TypeDefinition typedef) { + /*In*/ + Formatter.WriteRaw("type"); + Formatter.Space(); + Formatter.WriteSelfReference(typedef, Facade.TIn); + + Formatter.Space(); + Formatter.WriteRaw("="); + Formatter.Space(); + + Formatter.WriteSelfReference(typedef, Facade.Instance); + + if (typedef.IsClass && typedef.BaseType != null) + { + Formatter.Space(); + Formatter.WriteRaw("|"); + Formatter.Space(); + Formatter.WriteTypeReference(typedef.BaseType, typedef, JavascriptFormatterHelper.ReplaceMode.In, false); + } + + var interfaces = typedef.Interfaces.Where(it => DefinitelyTypedUtilities.IsTypePublic(it) && !Translator.ShouldSkipMember(it)); + foreach (var iface in interfaces) + { + Formatter.Space(); + Formatter.WriteRaw("|"); + Formatter.Space(); + Formatter.WriteTypeReference(iface, typedef, JavascriptFormatterHelper.ReplaceMode.In, false); + } + + Formatter.Semicolon(); + + /*Out*/ Formatter.WriteRaw("type"); Formatter.Space(); - Formatter.WriteSelfReference(typedef, Facade.Type); + Formatter.WriteSelfReference(typedef, Facade.TOut); Formatter.Space(); Formatter.WriteRaw("="); @@ -135,15 +175,14 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.Space(); Formatter.WriteRaw("&"); Formatter.Space(); - Formatter.WriteTypeReference(typedef.BaseType, typedef, JavascriptFormatterHelper.ReplaceMode.Type, false); + Formatter.WriteTypeReference(typedef.BaseType, typedef, JavascriptFormatterHelper.ReplaceMode.Out, false); } - var interfaces = typedef.Interfaces.Where(it => DefinitelyTypedUtilities.IsTypePublic(it) && !Translator.ShouldSkipMember(it)); foreach (var iface in interfaces) { Formatter.Space(); Formatter.WriteRaw("&"); Formatter.Space(); - Formatter.WriteTypeReference(iface, typedef, JavascriptFormatterHelper.ReplaceMode.Type, false); + Formatter.WriteTypeReference(iface, typedef, JavascriptFormatterHelper.ReplaceMode.Out, false); } Formatter.Semicolon(); @@ -156,11 +195,13 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.Space(); Formatter.WriteRaw("extends"); Formatter.Space(); - Formatter.WriteRaw(typedef.IsAbstract && typedef.IsSealed ? "$StaticTypePair" : "$TypePair"); + Formatter.WriteRaw(typedef.IsAbstract && typedef.IsSealed ? "$StaticType" : "$Type"); Formatter.WriteRaw("<"); Formatter.WriteSelfReference(typedef, Facade.Instance); Formatter.Comma(); - Formatter.WriteSelfReference(typedef, Facade.Type); + Formatter.WriteSelfReference(typedef, Facade.TIn); + Formatter.Comma(); + Formatter.WriteSelfReference(typedef, Facade.TOut); Formatter.WriteRaw(">"); Formatter.Space(); Formatter.OpenBrace(); @@ -230,7 +271,7 @@ public override bool EmitTypeDeclarationHeader(DecompilerContext context, IAstEm Formatter.Space(); Formatter.WriteRaw(":"); Formatter.Space(); - Formatter.WriteTypeReference(field.FieldType, null, JavascriptFormatterHelper.ReplaceMode.Type); + Formatter.WriteTypeReference(field.FieldType, null, JavascriptFormatterHelper.ReplaceMode.Out); Formatter.Semicolon(); } @@ -240,7 +281,7 @@ private void EmitProperty(PropertyDefinition property) Formatter.Space(); Formatter.WriteRaw(":"); Formatter.Space(); - Formatter.WriteTypeReference(property.PropertyType, null, JavascriptFormatterHelper.ReplaceMode.Type); + Formatter.WriteTypeReference(property.PropertyType, null, JavascriptFormatterHelper.ReplaceMode.Out); Formatter.Semicolon(); } @@ -271,9 +312,9 @@ private void EmitProperty(PropertyDefinition property) Formatter.Space(); if (!method.IsConstructor) { - Formatter.WriteTypeReference(method.ReturnType, null, JavascriptFormatterHelper.ReplaceMode.Type); + Formatter.WriteTypeReference(method.ReturnType, null, JavascriptFormatterHelper.ReplaceMode.Out); } else { - Formatter.WriteSelfReference(method.DeclaringType, Facade.Type); + Formatter.WriteSelfReference(method.DeclaringType, Facade.TOut); } Formatter.Semicolon(); @@ -313,8 +354,8 @@ private void EmitProperty(PropertyDefinition property) Formatter.Space(); Formatter.OpenBracket(); Formatter.CommaSeparatedList(DefinitelyTypedUtilities.BuildGenericParemetersMap(method.GenericParameters, method.DeclaringType.GenericParameters), pair => { - Formatter.WriteRaw("$TypePair"); - Formatter.WriteGenericArgumentsIfNeed(new[] { DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value) }); + Formatter.WriteRaw("$Type"); + Formatter.WriteGenericArgumentsIfNeed(new[] { DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value) }); }); Formatter.CloseBracket(); } else { @@ -324,20 +365,24 @@ private void EmitProperty(PropertyDefinition property) Formatter.Space(); Formatter.Identifier("$Null"); } - Formatter.Comma(); - Formatter.CommaSeparatedList(method.Parameters, item => { - Formatter.Identifier(item.Name); - Formatter.Space(); - Formatter.WriteRaw(":"); - Formatter.Space(); - Formatter.WriteTypeReference(item.ParameterType, null, JavascriptFormatterHelper.ReplaceMode.Instance); - }); + if (method.Parameters.Count > 0) { + Formatter.Comma(); + + Formatter.CommaSeparatedList(method.Parameters, item => { + Formatter.Identifier(item.Name); + Formatter.Space(); + Formatter.WriteRaw(":"); + Formatter.Space(); + Formatter.WriteTypeReference(item.ParameterType, null, JavascriptFormatterHelper.ReplaceMode.Instance); + }); + } + Formatter.WriteRaw(")"); Formatter.Space(); Formatter.WriteRaw(":"); Formatter.Space(); - Formatter.WriteTypeReference(method.ReturnType, null, JavascriptFormatterHelper.ReplaceMode.Type); + Formatter.WriteTypeReference(method.ReturnType, null, JavascriptFormatterHelper.ReplaceMode.Out); Formatter.Semicolon(); } } @@ -421,15 +466,17 @@ public override void EmitHeader(bool stubbed, bool iife) public enum Facade { Instance, - Type, + TIn, + TOut, Static, Factory } static class JavascriptFormatterHelper { public enum ReplaceMode { - Type, Instance, + In, + Out } private static Dictionary _rawTypes = new Dictionary { @@ -453,9 +500,13 @@ public enum ReplaceMode { private static void TRSuffix (this JavascriptFormatter formatter, ReplaceMode replaceMode) { switch (replaceMode) { - case ReplaceMode.Type: + case ReplaceMode.In: + formatter.Dot(); + formatter.Identifier("TIn"); + break; + case ReplaceMode.Out: formatter.Dot(); - formatter.Identifier("Type"); + formatter.Identifier("TOut"); break; case ReplaceMode.Instance: formatter.Dot(); @@ -475,7 +526,9 @@ public enum ReplaceMode { formatter.WriteRaw("<"); formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.Instance); formatter.Comma(); - formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.Type); + formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.In); + formatter.Comma(); + formatter.WriteTypeReference(arrayType.ElementType, context, ReplaceMode.Out); if (!arrayType.IsVector) { formatter.Comma(); formatter.WriteRaw("\""); @@ -490,7 +543,9 @@ public enum ReplaceMode { formatter.WriteRaw("<"); formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.Instance); formatter.Comma(); - formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.Type); + formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.In); + formatter.Comma(); + formatter.WriteTypeReference(byRefType.ElementType, context, ReplaceMode.Out); formatter.WriteRaw(">"); } else if (typeReference is GenericParameter) { var gp = (GenericParameter) typeReference; @@ -506,10 +561,13 @@ public enum ReplaceMode { var name = map[gp].Value; switch (replaceMode) { - case ReplaceMode.Type: + case ReplaceMode.Instance: + formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(name)); + break; + case ReplaceMode.Out: formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterOutParameterName(name)); break; - case ReplaceMode.Instance: + case ReplaceMode.In: formatter.Identifier(DefinitelyTypedUtilities.GetGenericParameterInParameterName(name)); break; default: @@ -517,12 +575,14 @@ public enum ReplaceMode { } } else if (typeReference is GenericInstanceType) { var genericType = (GenericInstanceType) typeReference; - if (formatter.WriteTypeReference(genericType.ElementType, context, ReplaceMode.Type)) { + if (formatter.WriteTypeReference(genericType.ElementType, context, replaceMode)) /*TODO*/ { formatter.WriteRaw("<"); formatter.CommaSeparatedList(genericType.GenericArguments, genericArgument => { formatter.WriteTypeReference(genericArgument, context, ReplaceMode.Instance); formatter.Comma(); - formatter.WriteTypeReference(genericArgument, context, ReplaceMode.Type); + formatter.WriteTypeReference(genericArgument, context, ReplaceMode.In); + formatter.Comma(); + formatter.WriteTypeReference(genericArgument, context, ReplaceMode.Out); }); formatter.WriteRaw(">"); } @@ -564,11 +624,12 @@ public enum ReplaceMode { /* Hack to solve ciruclar refrence in generics. * It could be improved, by we really need generic variance support or support of: - type T = something & I + type T = something & I (see Microsoft/TypeScript#6230) */ - var fixedMode = (replaceMode == ReplaceMode.Type && context == definition) ? ReplaceMode.Instance : replaceMode; + var fixedMode = (replaceMode != ReplaceMode.Instance && context == definition) ? ReplaceMode.Instance : replaceMode; formatter.TRSuffix(fixedMode); - } else { + } + else { //TODO: We was unable to resolve assembly. Think about JSIL Proxies formatter.WriteRaw("Object"); return false; @@ -597,8 +658,12 @@ public enum ReplaceMode { formatter.Identifier("Instance"); formatter.WriteGenericArgumentsIfNeed(typeDefinition.GenericParameters, null); break; - case Facade.Type: - formatter.Identifier("Type"); + case Facade.TIn: + formatter.Identifier("TIn"); + formatter.WriteGenericArgumentsIfNeed(typeDefinition.GenericParameters, null); + break; + case Facade.TOut: + formatter.Identifier("TOut"); formatter.WriteGenericArgumentsIfNeed(typeDefinition.GenericParameters, null); break; case Facade.Static: @@ -622,8 +687,8 @@ public enum ReplaceMode { formatter.Space(); formatter.WriteRaw(":"); formatter.Space(); - formatter.WriteRaw("$TypePair"); - formatter.WriteGenericArgumentsIfNeed(new[] {DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value)}); + formatter.WriteRaw("$Type"); + formatter.WriteGenericArgumentsIfNeed(new[] { DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value)}); }); formatter.WriteRaw(")"); } @@ -631,7 +696,7 @@ public enum ReplaceMode { public static void WriteGenericArgumentsIfNeed (this JavascriptFormatter formatter, IEnumerable args, IEnumerable additionalArgsForNameCalculation) { formatter.WriteGenericArgumentsIfNeed( DefinitelyTypedUtilities.BuildGenericParemetersMap(args, additionalArgsForNameCalculation) - .SelectMany(pair => new[] {DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value)})); + .SelectMany(pair => new[] { DefinitelyTypedUtilities.GetGenericParameterInstanceParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterInParameterName(pair.Value), DefinitelyTypedUtilities.GetGenericParameterOutParameterName(pair.Value)})); } public static void WriteGenericArgumentsIfNeed (this JavascriptFormatter formatter, IEnumerable genericParameterNames) { @@ -724,12 +789,17 @@ public class GenericParemetersKeyedCollection : KeyedCollection { +export class StaticType { + private _t: T; private _in: TIn; private _out: TOut; } -export class TypePair extends StaticTypePair { +export class Type extends StaticType { $Is(input: any): boolean; $As(input: any): TOut; $Cast(input: any): TOut; - /*readonly */$TypedUndefinedInternal: TIn; - /*readonly */$TypedUndefined: TOut; + /*readonly */$UndefinedIn: TIn; + /*readonly */$UndefinedInternal: T; + /*readonly */$Undefined: TOut; } export class NullArg { @@ -23,17 +25,19 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance; - interface Static extends TypePair { - new (): Type + type TIn = Instance; + type TOut = Instance; + interface Static extends Type { + new (): TOut } type Factory = Static; } namespace String { type Instance = string; - type Type = Instance & Object.Type; - interface Static extends TypePair { - new (arg: string): Type; + type TIn = Instance | Object.TIn; + type TOut = Instance & Object.TOut; + interface Static extends Type { + new (arg: string): TOut; } type Factory = Static; } @@ -41,9 +45,10 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } @@ -51,9 +56,10 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } @@ -61,9 +67,10 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } @@ -71,9 +78,10 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } @@ -81,9 +89,10 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } @@ -91,33 +100,37 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & number; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & number; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } namespace Single { type Instance = number - type Type = Instance; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } namespace Double { type Instance = number - type Type = Instance; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance; + interface Static extends Type { + new(arg: number): TOut; } type Factory = Static; } namespace Boolean { type Instance = boolean - type Type = Instance; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance; + interface Static extends Type { + new(arg: number): TOut; } type Factory = Static; } @@ -125,46 +138,50 @@ export declare namespace $private{ class Instance { private _brand: any; } - type Type = Instance & string; - interface Static extends TypePair { - new (arg: number): Type; + type TIn = Instance; + type TOut = Instance & string; + interface Static extends Type { + new (arg: number): TOut; } type Factory = Static; } namespace Array { - class Instance { + class Instance { private _brand: any; private _TType_brand: OutTType; private _TSize_brand: TSize; } - type Type = Instance & OutTType[]; - interface Static extends TypePair, Type> { + type TIn = Instance; + type TOut = Instance & OutTType[]; + interface Static extends Type, TIn, TOut> { } interface Factory { - Of(__T: TypePair): Vector.Static + Of(__T: Type): Vector.Static //Of(TType: TypePair, TSize: TSize): Static } } namespace Vector { - class Instance { + class Instance { private _brand: any; private _TType_brand: OutTType; } - type Type = Instance & Array.Type; - interface Static extends TypePair, Type> { + type TIn = Instance | Array.TIn; + type TOut = Instance & Array.TOut; + interface Static extends Type, TIn, TOut> { } } } namespace JSIL { namespace Reference { - interface Instance { + interface Instance { get(): OutTType; - set(value: InTType): void; + set(value: TType): void; } - type Type = Instance; + type TIn = Instance; + type TOut = Instance; } namespace BoxedVariable { @@ -172,9 +189,10 @@ export declare namespace $private{ private _brand: any; private _TType_brand: TType; } - type Type = Instance & Reference.Type; + type TIn = Instance | Reference.TIn; + type TOut = Instance & Reference.TIn; interface Factory { - new (arg: TType): Type + new (arg: TType): TOut } } @@ -183,21 +201,23 @@ export declare namespace $private{ private _brand: any; private _TType_brand: TType; } - type Type = Instance & Reference.Type; + type TIn = Instance | Reference.TIn; + type TOut = Instance & Reference.TIn; interface Factory { //TODO: think how to make it static typed - new (object: Object, memberName: string): Type + new (object: Object, memberName: string): TOut } } namespace ArrayElementReference { - class Instance { + class Instance { private _brand: any; private _TType_brand: InTType; } - type Type = Instance & Reference.Type; + type TIn = Instance | Reference.TIn; + type TOut = Instance & Reference.TOut; interface Factory { - new (array: System.Vector.Instance, index: System.Int32.Instance): Type + new (array: System.Vector.Instance, index: System.Int32.Instance): TOut } } }