protected internal override object VisitArrayType(ArrayTypeSymbol symbol, ArrayBuilder<SymbolDescriptionPart> builder) { //See spec section 12.1 for the order of rank specificiers //e.g. int[][,][,,] is stored as // ArrayType // Rank = 1 // ElementType = ArrayType // Rank = 2 // ElementType = ArrayType // Rank = 3 // ElementType = int TypeSymbol underlyingNonArrayType = symbol.ElementType; while (underlyingNonArrayType.TypeKind == TypeKind.ArrayType) { underlyingNonArrayType = ((ArrayTypeSymbol)underlyingNonArrayType).ElementType; } VisitType(underlyingNonArrayType, builder); ArrayTypeSymbol arrayType = symbol; while (arrayType != null) { AddArrayRank(arrayType, builder); arrayType = arrayType.ElementType as ArrayTypeSymbol; } return null; }
public ArrayTypeReference(Module moduleBeingBuilt, ArrayTypeSymbol underlyingArrayType) : base(moduleBeingBuilt) { Contract.ThrowIfNull(underlyingArrayType); this.underlyingArrayType = underlyingArrayType; }
private static void AddArrayRank(ArrayTypeSymbol symbol, ArrayBuilder<SymbolDescriptionPart> builder) { AddPunctuation(SyntaxKind.OpenBracketToken, builder); for (int i = 0; i < symbol.Rank - 1; i++) { AddPunctuation(SyntaxKind.CommaToken, builder); } AddPunctuation(SyntaxKind.CloseBracketToken, builder); }
private ArrayTypeSymbol DecodeArrayType(ArrayTypeSymbol type) { TypeSymbolWithAnnotations decodedElementType = DecodeTypeInternal(type.ElementType); return(type.WithElementType(decodedElementType)); }
protected override IArrayTypeSymbol CommonCreateArrayTypeSymbol(ITypeSymbol elementType, int rank) { return(ArrayTypeSymbol.CreateCSharpArray(SourceAssembly, (TypeSymbol)elementType, rank: rank)); }
public virtual TResult VisitArrayType(ArrayTypeSymbol symbol) { return(DefaultVisit(symbol)); }
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal) { BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal); if (_methodBody == original) { _dynamicAnalysisSpans = _spansBuilder.ToImmutableAndFree(); // In the future there will be multiple analysis kinds. const int analysisKind = 0; ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, _payloadType); // Synthesize the initialization of the instrumentation payload array, using concurrency-safe code: // // var payload = PID.PayloadRootField[methodIndex]; // if (payload == null) // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndexOrIndices, ref PID.PayloadRootField[methodIndex], payloadLength); BoundStatement payloadInitialization = _methodBodyFactory.Assignment( _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))); BoundExpression mvid = _methodBodyFactory.ModuleVersionId(); BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method); BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))); BoundStatement createPayloadCall = GetCreatePayloadStatement( _dynamicAnalysisSpans, _methodBody.Syntax, _methodPayload, _createPayloadForMethodsSpanningSingleFile, _createPayloadForMethodsSpanningMultipleFiles, mvid, methodToken, payloadSlot, _methodBodyFactory, _debugDocumentProvider); BoundExpression payloadNullTest = _methodBodyFactory.Binary( BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType)); BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall); Debug.Assert(synthesizedLocal == null); synthesizedLocal = _methodPayload; ArrayBuilder <BoundStatement> prologueStatements = ArrayBuilder <BoundStatement> .GetInstance(previousPrologue == null? 3 : 4); prologueStatements.Add(payloadInitialization); prologueStatements.Add(payloadIf); if (_methodEntryInstrumentation != null) { prologueStatements.Add(_methodEntryInstrumentation); } if (previousPrologue != null) { prologueStatements.Add(previousPrologue); } return(_methodBodyFactory.StatementList(prologueStatements.ToImmutableAndFree())); } return(previousPrologue); }
internal Microsoft.Cci.IArrayTypeReference Translate(ArrayTypeSymbol symbol) { return symbol; }
private ArrayTypeSymbol DecodeArrayType(ArrayTypeSymbol type) { var decodedElementType = DecodeType(type.ElementType); return ReferenceEquals(decodedElementType, type) ? type : type.IsSZArray ? ArrayTypeSymbol.CreateSZArray(_containingAssembly, decodedElementType, type.CustomModifiers) : ArrayTypeSymbol.CreateMDArray(_containingAssembly, decodedElementType, type.Rank, type.Sizes, type.LowerBounds, type.CustomModifiers); }
/// <summary> /// Create real CIL entry point, where it calls given method. /// </summary> internal void CreateEntryPoint(MethodSymbol method, DiagnosticBag diagnostic) { // "static int Main(string[] args)" var realmethod = new SynthesizedMethodSymbol(this.ScriptType, "Main", true, false, _compilation.CoreTypes.Int32, Accessibility.Private); realmethod.SetParameters(new SynthesizedParameterSymbol(realmethod, ArrayTypeSymbol.CreateSZArray(this.Compilation.SourceAssembly, this.Compilation.CoreTypes.String), 0, RefKind.None, "args")); // var body = MethodGenerator.GenerateMethodBody(this, realmethod, (il) => { var types = this.Compilation.CoreTypes; var methods = this.Compilation.CoreMethods; var args_place = new ParamPlace(realmethod.Parameters[0]); // AddScriptReference<Script>() var AddScriptReferenceMethod = (MethodSymbol)methods.Context.AddScriptReference_TScript.Symbol.Construct(this.ScriptType); il.EmitCall(this, diagnostic, ILOpCode.Call, AddScriptReferenceMethod); // int exitcode = 0; var exitcode_loc = il.LocalSlotManager.AllocateSlot(types.Int32.Symbol, LocalSlotConstraints.None); il.EmitIntConstant(0); il.EmitLocalStore(exitcode_loc); // create Context var ctx_loc = il.LocalSlotManager.AllocateSlot(types.Context.Symbol, LocalSlotConstraints.None); if (_compilation.Options.OutputKind == OutputKind.ConsoleApplication) { // CreateConsole(mainscript, args) MethodSymbol create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateConsole"); Debug.Assert(create_method != null); Debug.Assert(create_method.ParameterCount == 2); Debug.Assert(create_method.Parameters[0].Type == types.String); Debug.Assert(create_method.Parameters[1].Type == args_place.TypeOpt); il.EmitStringConstant(EntryPointScriptName(method)); // mainscript args_place.EmitLoad(il); // args il.EmitOpCode(ILOpCode.Call, +2); il.EmitToken(create_method, null, diagnostic); } else { // CreateEmpty(args) MethodSymbol create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateEmpty"); Debug.Assert(create_method != null); Debug.Assert(create_method.ParameterCount == 1); Debug.Assert(create_method.Parameters[0].Type == args_place.TypeOpt); args_place.EmitLoad(il); // args il.EmitOpCode(ILOpCode.Call, +1); il.EmitToken(create_method, null, diagnostic); } il.EmitLocalStore(ctx_loc); // Template: // try { Main(...); } catch (ScriptDiedException) { } finally { ctx.Dispose; } il.OpenLocalScope(ScopeType.TryCatchFinally); // try { try ... } finally {} il.OpenLocalScope(ScopeType.Try); { // IL requires catches and finally block to be distinct try il.OpenLocalScope(ScopeType.TryCatchFinally); // try {} catch (ScriptDiedException) {} il.OpenLocalScope(ScopeType.Try); { // emit .call method; if (method.HasThis) { throw new NotImplementedException(); // TODO: create instance of ContainingType } // params foreach (var p in method.Parameters) { switch (p.Name) { case SpecialParameterSymbol.ContextName: // <ctx> il.EmitLocalLoad(ctx_loc); break; case SpecialParameterSymbol.LocalsName: // <ctx>.Globals il.EmitLocalLoad(ctx_loc); il.EmitCall(this, diagnostic, ILOpCode.Call, methods.Context.Globals.Getter) .Expect(p.Type); break; case SpecialParameterSymbol.ThisName: // null il.EmitNullConstant(); break; case SpecialParameterSymbol.SelfName: // default(RuntimeTypeHandle) var runtimetypehandle_loc = il.LocalSlotManager.AllocateSlot(types.RuntimeTypeHandle.Symbol, LocalSlotConstraints.None); il.EmitValueDefault(this, diagnostic, runtimetypehandle_loc); break; default: throw new ArgumentException(p.Name); } } if (il.EmitCall(this, diagnostic, ILOpCode.Call, method).SpecialType != SpecialType.System_Void) { il.EmitOpCode(ILOpCode.Pop); } } il.CloseLocalScope(); // /Try il.AdjustStack(1); // Account for exception on the stack. il.OpenLocalScope(ScopeType.Catch, Compilation.CoreTypes.ScriptDiedException.Symbol); { // exitcode = <exception>.ProcessStatus(ctx) il.EmitLocalLoad(ctx_loc); il.EmitCall(this, diagnostic, ILOpCode.Callvirt, Compilation.CoreTypes.ScriptDiedException.Symbol.LookupMember <MethodSymbol>("ProcessStatus")); il.EmitLocalStore(exitcode_loc); } il.CloseLocalScope(); // /Catch il.CloseLocalScope(); // /TryCatch } il.CloseLocalScope(); // /Try il.OpenLocalScope(ScopeType.Finally); { // ctx.Dispose il.EmitLocalLoad(ctx_loc); il.EmitOpCode(ILOpCode.Call, -1); il.EmitToken(methods.Context.Dispose.Symbol, null, diagnostic); } il.CloseLocalScope(); // /Finally il.CloseLocalScope(); // /TryCatch // return ctx.ExitCode il.EmitLocalLoad(exitcode_loc); il.EmitRet(false); }, null, diagnostic, false); SetMethodBody(realmethod, body); // this.ScriptType.EntryPointSymbol = realmethod; }
public void Test1() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, TestReferences.NetFx.v4_0_21006.mscorlib }); var modifiersModule = assemblies[0].Modules[0]; var modifiers = modifiersModule.GlobalNamespace.GetTypeMembers("Modifiers").Single(); FieldSymbol f0 = modifiers.GetMembers("F0").OfType <FieldSymbol>().Single(); Assert.Equal(1, f0.CustomModifiers.Length); var f0Mod = f0.CustomModifiers[0]; Assert.True(f0Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", f0Mod.Modifier.ToTestDisplayString()); MethodSymbol m1 = modifiers.GetMembers("F1").OfType <MethodSymbol>().Single(); ParameterSymbol p1 = m1.Parameters[0]; ParameterSymbol p2 = modifiers.GetMembers("F2").OfType <MethodSymbol>().Single().Parameters[0]; ParameterSymbol p4 = modifiers.GetMembers("F4").OfType <MethodSymbol>().Single().Parameters[0]; MethodSymbol m5 = modifiers.GetMembers("F5").OfType <MethodSymbol>().Single(); ParameterSymbol p5 = m5.Parameters[0]; ParameterSymbol p6 = modifiers.GetMembers("F6").OfType <MethodSymbol>().Single().Parameters[0]; MethodSymbol m7 = modifiers.GetMembers("F7").OfType <MethodSymbol>().Single(); Assert.Equal(0, m1.ReturnTypeCustomModifiers.Length); Assert.Equal(1, p1.CustomModifiers.Length); var p1Mod = p1.CustomModifiers[0]; Assert.True(p1Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p1Mod.Modifier.ToTestDisplayString()); Assert.Equal(2, p2.CustomModifiers.Length); foreach (var p2Mod in p2.CustomModifiers) { Assert.True(p2Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p2Mod.Modifier.ToTestDisplayString()); } Assert.Equal(SymbolKind.ErrorType, p4.Type.Kind); Assert.True(m5.ReturnsVoid); Assert.Equal(1, m5.ReturnTypeCustomModifiers.Length); var m5Mod = m5.ReturnTypeCustomModifiers[0]; Assert.True(m5Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", m5Mod.Modifier.ToTestDisplayString()); Assert.Equal(0, p5.CustomModifiers.Length); ArrayTypeSymbol p5Type = (ArrayTypeSymbol)p5.Type; Assert.Equal("System.Int32", p5Type.ElementType.ToTestDisplayString()); Assert.Equal(1, p5Type.CustomModifiers.Length); var p5TypeMod = p5Type.CustomModifiers[0]; Assert.True(p5TypeMod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p5TypeMod.Modifier.ToTestDisplayString()); Assert.Equal(0, p6.CustomModifiers.Length); PointerTypeSymbol p6Type = (PointerTypeSymbol)p6.Type; Assert.Equal("System.Int32", p6Type.PointedAtType.ToTestDisplayString()); Assert.Equal(1, p6Type.CustomModifiers.Length); var p6TypeMod = p6Type.CustomModifiers[0]; Assert.True(p6TypeMod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p6TypeMod.Modifier.ToTestDisplayString()); Assert.False(m7.ReturnsVoid); Assert.Equal(1, m7.ReturnTypeCustomModifiers.Length); var m7Mod = m7.ReturnTypeCustomModifiers[0]; Assert.True(m7Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", m7Mod.Modifier.ToTestDisplayString()); }
/// <summary> /// Determine whether there is any substitution of type parameters that will /// make two types identical. /// </summary> /// <param name="t1">LHS</param> /// <param name="t2">RHS</param> /// <param name="substitution"> /// Substitutions performed so far (or null for none). /// Keys are type parameters, values are types (possibly type parameters). /// Will be updated with new subsitutions by the callee. /// Should be ignored when false is returned. /// </param> /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns> /// <remarks> /// Derived from Dev10's BSYMMGR::UnifyTypes. /// Two types will not unify if they have different custom modifiers. /// </remarks> private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution) { if (ReferenceEquals(t1, t2)) { return(true); } else if ((object)t1 == null || (object)t2 == null) { // Can't both be null or they would have been ReferenceEquals return(false); } if (substitution != null) { t1 = substitution.SubstituteType(t1); t2 = substitution.SubstituteType(t2); } // If one of the types is a type parameter, then the substitution could make them ReferenceEquals. if (ReferenceEquals(t1, t2)) { return(true); } // We can avoid a lot of redundant checks if we ensure that we only have to check // for type parameters on the LHS if (!t1.IsTypeParameter() && t2.IsTypeParameter()) { TypeSymbol tmp = t1; t1 = t2; t2 = tmp; } // If t1 is not a type parameter, then neither is t2 Debug.Assert(t1.IsTypeParameter() || !t2.IsTypeParameter()); switch (t1.Kind) { case SymbolKind.ArrayType: { if (t2.TypeKind != t1.TypeKind) { return(false); } ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1; ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2; if (at1.Rank != at2.Rank || !at1.CustomModifiers.SequenceEqual(at2.CustomModifiers)) { return(false); } return(CanUnifyHelper(at1.ElementType, at2.ElementType, ref substitution)); } case SymbolKind.PointerType: { if (t2.TypeKind != t1.TypeKind) { return(false); } PointerTypeSymbol pt1 = (PointerTypeSymbol)t1; PointerTypeSymbol pt2 = (PointerTypeSymbol)t2; if (!pt1.CustomModifiers.SequenceEqual(pt2.CustomModifiers)) { return(false); } return(CanUnifyHelper(pt1.PointedAtType, pt2.PointedAtType, ref substitution)); } case SymbolKind.NamedType: case SymbolKind.ErrorType: { if (t2.TypeKind != t1.TypeKind) { return(false); } NamedTypeSymbol nt1 = (NamedTypeSymbol)t1; NamedTypeSymbol nt2 = (NamedTypeSymbol)t2; if (!nt1.IsGenericType) { return(!nt2.IsGenericType && nt1 == nt2); } else if (!nt2.IsGenericType) { return(false); } int arity = nt1.Arity; if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition) { return(false); } for (int i = 0; i < arity; i++) { if (!CanUnifyHelper(nt1.TypeArgumentsNoUseSiteDiagnostics[i], nt2.TypeArgumentsNoUseSiteDiagnostics[i], ref substitution)) { return(false); } } // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types return((object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution)); } case SymbolKind.TypeParameter: { // These substitutions are not allowed in C# if (t2.TypeKind == TypeKind.Pointer || t2.SpecialType == SpecialType.System_Void) { return(false); } TypeParameterSymbol tp1 = (TypeParameterSymbol)t1; // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above if (Contains(t2, tp1)) { return(false); } if (substitution == null) { substitution = new MutableTypeMap(); } // MutableTypeMap.Add will throw if the key has already been added. However, // if t1 was already in the substitution, it would have been substituted at the // start of this method and we wouldn't be here. substitution.Add(tp1, t2); return(true); } default: { return(t1 == t2); } } }
public void Test1() { var oldMsCorLib = TestMetadata.Net40.mscorlib; var newMsCorLib = TestMetadata.Net451.mscorlib; var c1 = CSharpCompilation.Create("C1", references: new[] { oldMsCorLib, TestReferences.SymbolsTests.CustomModifiers.Modifiers.netmodule }); var c1Assembly = c1.Assembly; CSharpCompilation c2 = CSharpCompilation.Create("C2", references: new MetadataReference[] { newMsCorLib, new CSharpCompilationReference(c1) }); var mscorlibAssembly = c2.GetReferencedAssemblySymbol(newMsCorLib); Assert.NotSame(mscorlibAssembly, c1.GetReferencedAssemblySymbol(oldMsCorLib)); var modifiers = c2.GlobalNamespace.GetTypeMembers("Modifiers").Single(); Assert.IsAssignableFrom <PENamedTypeSymbol>(modifiers); FieldSymbol f0 = modifiers.GetMembers("F0").OfType <FieldSymbol>().Single(); Assert.Equal(1, f0.TypeWithAnnotations.CustomModifiers.Length); var f0Mod = f0.TypeWithAnnotations.CustomModifiers[0]; Assert.True(f0Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", f0Mod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, f0Mod.Modifier.ContainingAssembly.GetSymbol()); MethodSymbol m1 = modifiers.GetMembers("F1").OfType <MethodSymbol>().Single(); ParameterSymbol p1 = m1.Parameters[0]; ParameterSymbol p2 = modifiers.GetMembers("F2").OfType <MethodSymbol>().Single().Parameters[0]; MethodSymbol m5 = modifiers.GetMembers("F5").OfType <MethodSymbol>().Single(); ParameterSymbol p5 = m5.Parameters[0]; ParameterSymbol p6 = modifiers.GetMembers("F6").OfType <MethodSymbol>().Single().Parameters[0]; MethodSymbol m7 = modifiers.GetMembers("F7").OfType <MethodSymbol>().Single(); Assert.Equal(0, m1.ReturnTypeWithAnnotations.CustomModifiers.Length); Assert.Equal(1, p1.TypeWithAnnotations.CustomModifiers.Length); var p1Mod = p1.TypeWithAnnotations.CustomModifiers[0]; Assert.True(p1Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p1Mod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, p1Mod.Modifier.ContainingAssembly.GetSymbol()); Assert.Equal(2, p2.TypeWithAnnotations.CustomModifiers.Length); foreach (var p2Mod in p2.TypeWithAnnotations.CustomModifiers) { Assert.True(p2Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p2Mod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, p2Mod.Modifier.ContainingAssembly.GetSymbol()); } Assert.True(m5.ReturnsVoid); Assert.Equal(1, m5.ReturnTypeWithAnnotations.CustomModifiers.Length); var m5Mod = m5.ReturnTypeWithAnnotations.CustomModifiers[0]; Assert.True(m5Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", m5Mod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, m5Mod.Modifier.ContainingAssembly.GetSymbol()); Assert.Equal(0, p5.TypeWithAnnotations.CustomModifiers.Length); ArrayTypeSymbol p5Type = (ArrayTypeSymbol)p5.Type; Assert.Equal("System.Int32", p5Type.ElementType.ToTestDisplayString()); Assert.Equal(1, p5Type.ElementTypeWithAnnotations.CustomModifiers.Length); var p5TypeMod = p5Type.ElementTypeWithAnnotations.CustomModifiers[0]; Assert.True(p5TypeMod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p5TypeMod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, p5TypeMod.Modifier.ContainingAssembly.GetSymbol()); Assert.Equal(0, p6.TypeWithAnnotations.CustomModifiers.Length); PointerTypeSymbol p6Type = (PointerTypeSymbol)p6.Type; Assert.Equal("System.Int32", p6Type.PointedAtType.ToTestDisplayString()); Assert.Equal(1, p6Type.PointedAtTypeWithAnnotations.CustomModifiers.Length); var p6TypeMod = p6Type.PointedAtTypeWithAnnotations.CustomModifiers[0]; Assert.True(p6TypeMod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", p6TypeMod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, p6TypeMod.Modifier.ContainingAssembly.GetSymbol()); Assert.False(m7.ReturnsVoid); Assert.Equal(1, m7.ReturnTypeWithAnnotations.CustomModifiers.Length); var m7Mod = m7.ReturnTypeWithAnnotations.CustomModifiers[0]; Assert.True(m7Mod.IsOptional); Assert.Equal("System.Runtime.CompilerServices.IsConst", m7Mod.Modifier.ToTestDisplayString()); Assert.Same(mscorlibAssembly, m7Mod.Modifier.ContainingAssembly.GetSymbol()); }
public void TestBaseTypeDynamicTransforms() { CommonTestInitialization(); // public class Base0 { } Assert.Equal(_objectType, _base0Class.BaseType()); Assert.False(_base0Class.ContainsDynamic()); // public class Base1<T> { } Assert.Equal(_objectType, _base1Class.BaseType()); Assert.False(_base1Class.ContainsDynamic()); // public class Base2<T, U> { } Assert.Equal(_objectType, _base2Class.BaseType()); Assert.False(_base2Class.ContainsDynamic()); // public class Derived<T> : Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> where T : Derived<T> { ... } Assert.False(_derivedClass.ContainsDynamic()); Assert.True(_derivedClass.BaseType().ContainsDynamic()); // Outer<dynamic> var outerClassOfDynamic = _outerClass.Construct(s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic> var t = _derivedClass.TypeParameters[0]; var arrayOfT = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(t)); var innerClassOfTArrDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfT, s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[] var memberInnerInnerOfInt = innerClassOfTArrDynamic.GetTypeMember("InnerInner").Construct(_intType); var arrayOfInnerInnerOfInt = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(memberInnerInnerOfInt)); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic> var memberComplicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfInnerInnerOfInt, s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> var memberInnerInnerOfDynamic = memberComplicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType); Assert.Equal(memberInnerInnerOfDynamic, _derivedClass.BaseType()); // public class Outer<T> : Base1<dynamic> Assert.False(_outerClass.ContainsDynamic()); Assert.True(_outerClass.BaseType().ContainsDynamic()); var base1OfDynamic = _base1Class.Construct(s_dynamicType); Assert.Equal(base1OfDynamic, _outerClass.BaseType()); // public class Inner<U, V> : Base2<dynamic, V> Assert.False(_innerClass.ContainsDynamic()); Assert.True(_innerClass.BaseType().ContainsDynamic()); var base2OfDynamicV = _base2Class.Construct(s_dynamicType, _innerClass.TypeParameters[1]); Assert.Equal(base2OfDynamicV, _innerClass.BaseType()); // public class InnerInner<W> : Base1<dynamic> { } Assert.False(_innerInnerClass.ContainsDynamic()); Assert.True(_innerInnerClass.BaseType().ContainsDynamic()); Assert.Equal(base1OfDynamic, _innerInnerClass.BaseType()); // public class Outer2<T> : Base1<dynamic> Assert.False(_outer2Class.ContainsDynamic()); Assert.True(_outer2Class.BaseType().ContainsDynamic()); Assert.Equal(base1OfDynamic, _outer2Class.BaseType()); // public class Inner2<U, V> : Base0 Assert.False(_inner2Class.ContainsDynamic()); Assert.False(_inner2Class.BaseType().ContainsDynamic()); Assert.Equal(_base0Class, _inner2Class.BaseType()); // public class InnerInner2<W> : Base0 { } Assert.False(_innerInner2Class.ContainsDynamic()); Assert.False(_innerInner2Class.BaseType().ContainsDynamic()); Assert.Equal(_base0Class, _innerInner2Class.BaseType()); // public class Inner3<U> Assert.False(_inner3Class.ContainsDynamic()); }
public void TestReturnValueParameterAndPropertyTransforms() { CommonTestInitialization(); //public static dynamic F1(dynamic x) { return x; } var f1 = _derivedClass.GetMember <MethodSymbol>("F1"); Assert.Equal(s_dynamicType, f1.ReturnType); Assert.Equal(s_dynamicType, f1.GetParameterType(0)); //public static dynamic F2(ref dynamic x) { return x; } var f2 = _derivedClass.GetMember <MethodSymbol>("F2"); Assert.Equal(s_dynamicType, f2.ReturnType); Assert.Equal(s_dynamicType, f2.GetParameterType(0)); Assert.Equal(RefKind.Ref, f2.Parameters[0].RefKind); //public static dynamic[] F3(dynamic[] x) { return x; } var f3 = _derivedClass.GetMember <MethodSymbol>("F3"); var arrayOfDynamic = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(s_dynamicType)); Assert.Equal(arrayOfDynamic, f3.ReturnType); Assert.Equal(arrayOfDynamic, f3.GetParameterType(0)); Assert.Equal(RefKind.None, f3.Parameters[0].RefKind); var derivedTypeParam = _derivedClass.TypeParameters[0]; var arrayOfDerivedTypeParam = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(derivedTypeParam)); // Outer<dynamic> var outerClassOfDynamic = _outerClass.Construct(s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic> var complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfDerivedTypeParam, s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int> var complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(_intType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[] var complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner)); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic> complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(complicatedInnerInnerArray, s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner)); var complicatedInnerInnerArrayOfArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInnerArray)); //public static Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] F4(Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] x) { return x; } var f4 = _derivedClass.GetMember <MethodSymbol>("F4"); Assert.Equal(complicatedInnerInnerArrayOfArray, f4.ReturnType); Assert.Equal(complicatedInnerInnerArrayOfArray, f4.GetParameterType(0)); Assert.Equal(RefKind.None, f4.Parameters[0].RefKind); //public static dynamic Prop1 { get { return field1; } } var prop1 = _derivedClass.GetMember <PropertySymbol>("Prop1"); Assert.Equal(s_dynamicType, prop1.Type); Assert.Equal(s_dynamicType, prop1.GetMethod.ReturnType); //public static Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] Prop2 { get { return field17; } set { field17 = value; } } var prop2 = _derivedClass.GetMember <PropertySymbol>("Prop2"); Assert.Equal(complicatedInnerInnerArrayOfArray, prop2.Type); Assert.Equal(complicatedInnerInnerArrayOfArray, prop2.GetMethod.ReturnType); Assert.Equal(SpecialType.System_Void, prop2.SetMethod.ReturnType.SpecialType); Assert.Equal(complicatedInnerInnerArrayOfArray, prop2.SetMethod.GetParameterType(0)); }
public void TestFieldDynamicTransforms() { CommonTestInitialization(); //public static dynamic field1; var field1 = _derivedClass.GetMember <FieldSymbol>("field1"); Assert.Equal(s_dynamicType, field1.Type); //public static dynamic[] field2; var field2 = _derivedClass.GetMember <FieldSymbol>("field2"); var arrayOfDynamic = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(s_dynamicType), 1); Assert.Equal(arrayOfDynamic, field2.Type); //public static dynamic[][] field3; var field3 = _derivedClass.GetMember <FieldSymbol>("field3"); var arrayOfArrayOfDynamic = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(arrayOfDynamic), 1); Assert.Equal(arrayOfArrayOfDynamic, field3.Type); //public const dynamic field4 = null; var field4 = _derivedClass.GetMember <FieldSymbol>("field4"); Assert.Equal(s_dynamicType, field4.Type); //public const dynamic[] field5 = null; var field5 = _derivedClass.GetMember <FieldSymbol>("field5"); Assert.Equal(arrayOfDynamic, field5.Type); //public const dynamic[][] field6 = null; var field6 = _derivedClass.GetMember <FieldSymbol>("field6"); Assert.Equal(arrayOfArrayOfDynamic, field6.Type); //public const dynamic[][] field7 = null; var field7 = _derivedClass.GetMember <FieldSymbol>("field7"); Assert.Equal(arrayOfArrayOfDynamic, field7.Type); //public Outer<T>.Inner<int, T>.InnerInner<Outer<dynamic>> field8 = null; var field8 = _derivedClass.GetMember <FieldSymbol>("field8"); var derivedTypeParam = _derivedClass.TypeParameters[0]; var outerOfT = _outerClass.Construct(derivedTypeParam); var innerOfIntOfTWithOuterT = outerOfT.GetTypeMember("Inner").Construct(_intType, derivedTypeParam); // Outer<dynamic> var outerClassOfDynamic = _outerClass.Construct(s_dynamicType); var complicatedInnerInner = innerOfIntOfTWithOuterT.GetTypeMember("InnerInner").Construct(outerClassOfDynamic); Assert.Equal(complicatedInnerInner, field8.Type); //public Outer<dynamic>.Inner<T, T>.InnerInner<T> field9 = null; var field9 = _derivedClass.GetMember <FieldSymbol>("field9"); var innerOfTTWithOuterOfDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(derivedTypeParam, derivedTypeParam); complicatedInnerInner = innerOfTTWithOuterOfDynamic.GetTypeMember("InnerInner").Construct(derivedTypeParam); Assert.Equal(complicatedInnerInner, field9.Type); //public Outer<Outer<dynamic>.Inner<T, dynamic>>.Inner<dynamic, T>.InnerInner<T> field10 = null; var field10 = _derivedClass.GetMember <FieldSymbol>("field10"); // Outer<dynamic>.Inner<T, dynamic> var innerOfTDynamicWithOuterOfDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(derivedTypeParam, s_dynamicType); // Outer<Outer<dynamic>.Inner<T, dynamic>> var complicatedOuter = _outerClass.Construct(innerOfTDynamicWithOuterOfDynamic); // Outer<Outer<dynamic>.Inner<T, dynamic>>.Inner<dynamic, T> var complicatedInner = complicatedOuter.GetTypeMember("Inner").Construct(s_dynamicType, derivedTypeParam); complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(derivedTypeParam); Assert.Equal(complicatedInnerInner, field10.Type); //public Outer<T>.Inner<dynamic, dynamic>.InnerInner<T> field11 = null; var field11 = _derivedClass.GetMember <FieldSymbol>("field11"); // Outer<T>.Inner<dynamic, dynamic> var innerOfDynamicDynamicWithOuterOfT = outerOfT.GetTypeMember("Inner").Construct(s_dynamicType, s_dynamicType); complicatedInnerInner = innerOfDynamicDynamicWithOuterOfT.GetTypeMember("InnerInner").Construct(derivedTypeParam); Assert.Equal(complicatedInnerInner, field11.Type); //public Outer<T>.Inner<T, T>.InnerInner<Outer<dynamic>.Inner<T, dynamic>.InnerInner<int>> field12 = null; var field12 = _derivedClass.GetMember <FieldSymbol>("field12"); // Outer<T>.Inner<T, T> var innerOfTTWithOuterOfT = outerOfT.GetTypeMember("Inner").Construct(derivedTypeParam, derivedTypeParam); // Outer<dynamic>.Inner<T, dynamic>.InnerInner<int> complicatedInnerInner = innerOfTDynamicWithOuterOfDynamic.GetTypeMember("InnerInner").Construct(_intType); complicatedInnerInner = innerOfTTWithOuterOfT.GetTypeMember("InnerInner").Construct(complicatedInnerInner); Assert.Equal(complicatedInnerInner, field12.Type); //public Outer<dynamic>.Inner<Outer<T>, T>.InnerInner<dynamic> field13 = null; var field13 = _derivedClass.GetMember <FieldSymbol>("field13"); // Outer<dynamic>.Inner<Outer<T>, T> var innerOfOuterOfTTWithOuterDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(outerOfT, derivedTypeParam); complicatedInnerInner = innerOfOuterOfTTWithOuterDynamic.GetTypeMember("InnerInner").Construct(s_dynamicType); Assert.Equal(complicatedInnerInner, field13.Type); //public Outer<dynamic>.Inner<dynamic, dynamic>.InnerInner<dynamic> field14 = null; var field14 = _derivedClass.GetMember <FieldSymbol>("field14"); // Outer<dynamic>.Inner<dynamic, dynamic> var innerOfDynamicDynamicWithOuterOfDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(s_dynamicType, s_dynamicType); complicatedInnerInner = innerOfDynamicDynamicWithOuterOfDynamic.GetTypeMember("InnerInner").Construct(s_dynamicType); Assert.Equal(complicatedInnerInner, field14.Type); //public Outer<dynamic>.Inner<Outer<dynamic>, T>.InnerInner<dynamic>[] field15 = null; var field15 = _derivedClass.GetMember <FieldSymbol>("field15"); // Outer<dynamic>.Inner<Outer<dynamic>, T> var innerOfOuterOfDynamicTWithOuterDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(outerClassOfDynamic, derivedTypeParam); // Outer<dynamic>.Inner<Outer<dynamic>, T>.InnerInner<dynamic> complicatedInnerInner = innerOfOuterOfDynamicTWithOuterDynamic.GetTypeMember("InnerInner").Construct(s_dynamicType); var complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner), 1); Assert.Equal(complicatedInnerInnerArray, field15.Type); //public Outer<dynamic>.Inner<Outer<dynamic>.Inner<T, dynamic.InnerInner<int>, dynamic[]>.InnerInner<dynamic>[][] field16 = null; var field16 = _derivedClass.GetMember <FieldSymbol>("field16"); // Outer<dynamic>.Inner<T, dynamic>.InnerInner<int> complicatedInnerInner = innerOfTDynamicWithOuterOfDynamic.GetTypeMember("InnerInner").Construct(_intType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T, dynamic>.InnerInner<int>, dynamic[]> complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(complicatedInnerInner, arrayOfDynamic); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T, dynamic>.InnerInner<int>, dynamic[]>.InnerInner<dynamic> complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType); complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner), 1); var complicatedInnerInnerArrayOfArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInnerArray), 1); Assert.Equal(complicatedInnerInnerArrayOfArray, field16.Type); //public static Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] field17 = null; var field17 = _derivedClass.GetMember <FieldSymbol>("field17"); // T[] var arrayOfDerivedTypeParam = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(derivedTypeParam), 1); // Outer<dynamic>.Inner<T[], dynamic> complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfDerivedTypeParam, s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int> complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(_intType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[] complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner), 1); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic> complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(complicatedInnerInnerArray, s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic>[][] complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInner), 1); complicatedInnerInnerArrayOfArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(complicatedInnerInnerArray), 1); Assert.Equal(complicatedInnerInnerArrayOfArray, field17.Type); //public static Outer3.Inner3<dynamic> field1 = null; field1 = _inner3Class.GetMember <FieldSymbol>("field1"); var inner3OfDynamic = _inner3Class.Construct(s_dynamicType); Assert.Equal(inner3OfDynamic, field1.Type); }
private BoundStatement InitializeFixedStatementArrayLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol arrayTemp) { // From ExpressionBinder::BindPtrToArray: // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null) // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859. // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between // the time of the cast and the assignment to the local, we're toast. TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; arrayTemp = factory.SynthesizedLocal(initializerType); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)arrayTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; // NOTE: we pin the pointer, not the array. Debug.Assert(!arrayTemp.IsPinned); Debug.Assert(localSymbol.IsPinned); //(temp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr); //(temp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayType.IsSZArray) { lengthCall = factory.ArrayLength(factory.Local(arrayTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit)); }
/// <summary> /// fixed(int* ptr = arr){ ... } == becomes ===> /// /// pinned int[] pinnedTemp = arr; // pinning managed ref /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0 /// (int*)&pinnedTemp[0]: // unsafe cast to unmanaged ptr /// 0; /// . . . /// </summary> private BoundStatement InitializeFixedStatementArrayLocal( BoundLocalDeclaration localDecl, LocalSymbol localSymbol, BoundFixedLocalCollectionInitializer fixedInitializer, SyntheticBoundNodeFactory factory, out LocalSymbol pinnedTemp) { TypeSymbol localType = localSymbol.Type; BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression); TypeSymbol initializerType = initializerExpr.Type; pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)pinnedTemp.Type; TypeSymbol arrayElementType = arrayType.ElementType; // NOTE: we pin the array, not the pointer. Debug.Assert(pinnedTemp.IsPinned); Debug.Assert(!localSymbol.IsPinned); //(pinnedTemp = array) BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr); //(pinnedTemp = array) != null BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual); BoundExpression lengthCall; if (arrayType.IsSZArray) { lengthCall = factory.ArrayLength(factory.Local(pinnedTemp)); } else { MethodSymbol lengthMethod; if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod)) { lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod); } else { lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType); } } // NOTE: dev10 comment says ">", but code actually checks "!=" //temp.Length != 0 BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0)); //((temp = array) != null && temp.Length != 0) BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck); //temp[0] BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp)); // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer. //&temp[0] BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType)); BoundExpression convertedFirstElementAddress = factory.Convert( localType, firstElementAddress, fixedInitializer.ElementPointerTypeConversion); //loc = &temp[0] BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress); //loc = null BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType)); //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null) BoundStatement localInit = factory.ExpressionStatement( new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType)); return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit)); }
/// <summary> /// Called when visiting an <see cref="ArrayTypeSymbol" />; Override this with specific /// implementation; Calling <see cref="DefaultVisit" /> if it's not overridden /// </summary> /// <param name="symbol">The visited symbol</param> /// <param name="argument">Additional argument</param> /// <returns></returns> public virtual TResult VisitArrayType(ArrayTypeSymbol symbol, TArgument argument) { return(DefaultVisit(symbol, argument)); }
/// <summary> /// Lower a foreach loop that will enumerate a multi-dimensional array. /// /// A[...] a = x; /// int q_0 = a.GetUpperBound(0), q_1 = a.GetUpperBound(1), ...; /// for (int p_0 = a.GetLowerBound(0); p_0 <= q_0; p_0 = p_0 + 1) /// for (int p_1 = a.GetLowerBound(1); p_1 <= q_1; p_1 = p_1 + 1) /// ... /// { V v = (V)a[p_0, p_1, ...]; /* body */ } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's /// implementation of IEnumerable and just indexing into its elements. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to nested for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); Debug.Assert(collectionExpression.Type.IsArray()); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type; int rank = arrayType.Rank; Debug.Assert(rank > 1); TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); // Values we'll use every iteration MethodSymbol getLowerBoundMethod = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_Array__GetLowerBound); MethodSymbol getUpperBoundMethod = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_Array__GetUpperBound); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // A[...] a LocalSymbol arrayVar = factory.SynthesizedLocal(arrayType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray); BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType); // A[...] a = /*node.Expression*/; BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl); // NOTE: dev10 initializes all of the upper bound temps before entering the loop (as opposed to // initializing each one at the corresponding level of nesting). Doing it at the same time as // the lower bound would make this code a bit simpler, but it would make it harder to compare // the roslyn and dev10 IL. // int q_0, q_1, ... LocalSymbol[] upperVar = new LocalSymbol[rank]; BoundLocal[] boundUpperVar = new BoundLocal[rank]; BoundStatement[] upperVarDecl = new BoundStatement[rank]; for (int dimension = 0; dimension < rank; dimension++) { // int q_/*dimension*/ upperVar[dimension] = factory.SynthesizedLocal( intType, syntax: forEachSyntax, kind: (SynthesizedLocalKind)((int)SynthesizedLocalKind.ForEachArrayLimit0 + dimension)); boundUpperVar[dimension] = MakeBoundLocal(forEachSyntax, upperVar[dimension], intType); ImmutableArray <BoundExpression> dimensionArgument = ImmutableArray.Create <BoundExpression>( MakeLiteral(forEachSyntax, constantValue: ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32), type: intType)); // a.GetUpperBound(/*dimension*/) BoundExpression currentDimensionUpperBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getUpperBoundMethod, dimensionArgument); // int q_/*dimension*/ = a.GetUpperBound(/*dimension*/); upperVarDecl[dimension] = MakeLocalDeclaration(forEachSyntax, upperVar[dimension], currentDimensionUpperBound); } // int p_0, p_1, ... LocalSymbol[] positionVar = new LocalSymbol[rank]; BoundLocal[] boundPositionVar = new BoundLocal[rank]; for (int dimension = 0; dimension < rank; dimension++) { positionVar[dimension] = factory.SynthesizedLocal( intType, syntax: forEachSyntax, kind: (SynthesizedLocalKind)((int)SynthesizedLocalKind.ForEachArrayIndex0 + dimension)); boundPositionVar[dimension] = MakeBoundLocal(forEachSyntax, positionVar[dimension], intType); } // V v LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; // (V)a[p_0, p_1, ...] BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: new BoundArrayAccess(forEachSyntax, expression: boundArrayVar, indices: ImmutableArray.Create <BoundExpression>((BoundExpression[])boundPositionVar), type: arrayType.ElementType), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)a[p_0, p_1, ...]; BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl); // { V v = (V)a[p_0, p_1, ...]; /* node.Body */ } BoundStatement innermostLoopBody = new BoundBlock(forEachSyntax, locals: ImmutableArray.Create <LocalSymbol>(iterationVar), statements: ImmutableArray.Create <BoundStatement>(iterationVarDecl, rewrittenBody)); // work from most-nested to least-nested // for (int p_0 = a.GetLowerBound(0); p_0 <= q_0; p_0 = p_0 + 1) // for (int p_1 = a.GetLowerBound(0); p_1 <= q_1; p_1 = p_1 + 1) // ... // { V v = (V)a[p_0, p_1, ...]; /* node.Body */ } BoundStatement forLoop = null; for (int dimension = rank - 1; dimension >= 0; dimension--) { ImmutableArray <BoundExpression> dimensionArgument = ImmutableArray.Create <BoundExpression>( MakeLiteral(forEachSyntax, constantValue: ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32), type: intType)); // a.GetLowerBound(/*dimension*/) BoundExpression currentDimensionLowerBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getLowerBoundMethod, dimensionArgument); // int p_/*dimension*/ = a.GetLowerBound(/*dimension*/); BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar[dimension], currentDimensionLowerBound); GeneratedLabelSymbol breakLabel = dimension == 0 // outermost for-loop ? node.BreakLabel // i.e. the one that break statements will jump to : new GeneratedLabelSymbol("break"); // Should not affect emitted code since unused // p_/*dimension*/ <= q_/*dimension*/ //NB: OrEqual BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThanOrEqual, left: boundPositionVar[dimension], right: boundUpperVar[dimension], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p_/*dimension*/ = p_/*dimension*/ + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar[dimension], intType); BoundStatement body; GeneratedLabelSymbol continueLabel; if (forLoop == null) { // innermost for-loop body = innermostLoopBody; continueLabel = node.ContinueLabel; //i.e. the one continue statements will actually jump to } else { body = forLoop; continueLabel = new GeneratedLabelSymbol("continue"); // Should not affect emitted code since unused } forLoop = RewriteForStatement( syntax: forEachSyntax, outerLocals: ImmutableArray.Create(positionVar[dimension]), rewrittenInitializer: positionVarDecl, rewrittenCondition: exitCondition, conditionSyntaxOpt: null, conditionSpanOpt: forEachSyntax.InKeyword.Span, rewrittenIncrement: positionIncrement, rewrittenBody: body, breakLabel: breakLabel, continueLabel: continueLabel, hasErrors: node.HasErrors); } Debug.Assert(forLoop != null); BoundStatement result = new BoundBlock( forEachSyntax, ImmutableArray.Create <LocalSymbol>(arrayVar).Concat(upperVar.AsImmutableOrNull()), ImmutableArray.Create <BoundStatement>(arrayVarDecl).Concat(upperVarDecl.AsImmutableOrNull()).Add(forLoop)); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return(result); }
private ArrayTypeSymbol DecodeArrayType(ArrayTypeSymbol type) { var decodedElementType = DecodeType(type.ElementType); return ReferenceEquals(decodedElementType, type.ElementType) ? type : type.WithElementType(decodedElementType); }
/// <summary> /// Lower a foreach loop that will enumerate a single-dimensional array. /// /// A[] a = x; /// for (int p = 0; p < a.Length; p = p + 1) { /// V v = (V)a[p]; /// // body /// } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's /// implementation of IEnumerable and just indexing into its elements. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); Debug.Assert(collectionExpression.Type.IsArray()); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type; Debug.Assert(arrayType.Rank == 1); TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // A[] a LocalSymbol arrayVar = factory.SynthesizedLocal(arrayType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray); // A[] a = /*node.Expression*/; BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl); // Reference to a. BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType); // int p LocalSymbol positionVar = factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayIndex0); // Reference to p. BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType); // int p = 0; BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar, MakeLiteral(forEachSyntax, ConstantValue.Default(SpecialType.System_Int32), intType)); // V v LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; // (V)a[p] BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: new BoundArrayAccess( syntax: forEachSyntax, expression: boundArrayVar, indices: ImmutableArray.Create <BoundExpression>(boundPositionVar), type: arrayType.ElementType), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)a[p]; BoundStatement iterationVariableDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVariableDecl); BoundStatement initializer = new BoundStatementList(forEachSyntax, statements: ImmutableArray.Create <BoundStatement>(arrayVarDecl, positionVarDecl)); // a.Length BoundExpression arrayLength = new BoundArrayLength( syntax: forEachSyntax, expression: boundArrayVar, type: intType); // p < a.Length BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThan, left: boundPositionVar, right: arrayLength, constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p = p + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType); // { V v = (V)a[p]; /* node.Body */ } BoundStatement loopBody = new BoundBlock(forEachSyntax, locals: ImmutableArray.Create <LocalSymbol>(iterationVar), statements: ImmutableArray.Create <BoundStatement>(iterationVariableDecl, rewrittenBody)); // for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) { // V v = (V)a[p]; // /*node.Body*/ // } BoundStatement result = RewriteForStatement( syntax: node.Syntax, outerLocals: ImmutableArray.Create <LocalSymbol>(arrayVar, positionVar), rewrittenInitializer: initializer, rewrittenCondition: exitCondition, conditionSyntaxOpt: null, conditionSpanOpt: forEachSyntax.InKeyword.Span, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, breakLabel: node.BreakLabel, continueLabel: node.ContinueLabel, hasErrors: node.HasErrors); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return(result); }
public override Microsoft.Cci.IReference VisitArrayType(ArrayTypeSymbol symbol, bool a) { return Translate(symbol); }
/// <summary> /// Determine whether there is any substitution of type parameters that will /// make two types identical. /// </summary> /// <param name="t1">LHS</param> /// <param name="t2">RHS</param> /// <param name="substitution"> /// Substitutions performed so far (or null for none). /// Keys are type parameters, values are types (possibly type parameters). /// Will be updated with new substitutions by the callee. /// Should be ignored when false is returned. /// </param> /// <param name="untouchables"> /// Set of type symbols that cannot be replaced by substitution. /// </param> /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns> /// <remarks> /// Derived from Dev10's BSYMMGR::UnifyTypes. /// Two types will not unify if they have different custom modifiers. /// </remarks> private static bool CanUnifyHelper(TypeWithModifiers t1, TypeWithModifiers t2, ref MutableTypeMap substitution, ImmutableHashSet <TypeParameterSymbol> untouchables) { if (t1 == t2) { return(true); } else if ((object)t1.Type == null || (object)t2.Type == null) { // Can't both be null or they would have been equal return(false); } if (substitution != null) { t1 = t1.SubstituteType(substitution); t2 = t2.SubstituteType(substitution); } // If one of the types is a type parameter, then the substitution could make them equal. if (t1 == t2) { return(true); } // We can avoid a lot of redundant checks if we ensure that we only have to check // for type parameters on the LHS if (!t1.Type.IsTypeParameter() && t2.Type.IsTypeParameter()) { TypeWithModifiers tmp = t1; t1 = t2; t2 = tmp; } // If t1 is not a type parameter, then neither is t2 Debug.Assert(t1.Type.IsTypeParameter() || !t2.Type.IsTypeParameter()); switch (t1.Type.Kind) { case SymbolKind.ArrayType: { if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers)) { return(false); } ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1.Type; ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2.Type; if (!at1.HasSameShapeAs(at2)) { return(false); } return(CanUnifyHelper(new TypeWithModifiers(at1.ElementType, at1.CustomModifiers), new TypeWithModifiers(at2.ElementType, at2.CustomModifiers), ref substitution, untouchables)); } case SymbolKind.PointerType: { if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers)) { return(false); } PointerTypeSymbol pt1 = (PointerTypeSymbol)t1.Type; PointerTypeSymbol pt2 = (PointerTypeSymbol)t2.Type; return(CanUnifyHelper(new TypeWithModifiers(pt1.PointedAtType, pt1.CustomModifiers), new TypeWithModifiers(pt2.PointedAtType, pt2.CustomModifiers), ref substitution, untouchables)); } case SymbolKind.NamedType: case SymbolKind.ErrorType: { if (t2.Type.TypeKind != t1.Type.TypeKind || !t2.CustomModifiers.SequenceEqual(t1.CustomModifiers)) { return(false); } NamedTypeSymbol nt1 = (NamedTypeSymbol)t1.Type; NamedTypeSymbol nt2 = (NamedTypeSymbol)t2.Type; if (nt1.IsTupleType) { if (!nt2.IsTupleType) { return(false); } return(CanUnifyHelper(new TypeWithModifiers(nt1.TupleUnderlyingType), new TypeWithModifiers(nt2.TupleUnderlyingType), ref substitution, untouchables)); } if (!nt1.IsGenericType) { return(!nt2.IsGenericType && nt1 == nt2); } else if (!nt2.IsGenericType) { return(false); } int arity = nt1.Arity; if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition) { return(false); } var nt1Arguments = nt1.TypeArgumentsNoUseSiteDiagnostics; var nt2Arguments = nt2.TypeArgumentsNoUseSiteDiagnostics; var nt1ArgumentsCustomModifiers = nt1.HasTypeArgumentsCustomModifiers ? nt1.TypeArgumentsCustomModifiers : default(ImmutableArray <ImmutableArray <CustomModifier> >); var nt2ArgumentsCustomModifiers = nt2.HasTypeArgumentsCustomModifiers ? nt2.TypeArgumentsCustomModifiers : default(ImmutableArray <ImmutableArray <CustomModifier> >); for (int i = 0; i < arity; i++) { if (!CanUnifyHelper(new TypeWithModifiers(nt1Arguments[i], nt1ArgumentsCustomModifiers.IsDefault ? default(ImmutableArray <CustomModifier>) : nt1ArgumentsCustomModifiers[i]), new TypeWithModifiers(nt2Arguments[i], nt2ArgumentsCustomModifiers.IsDefault ? default(ImmutableArray <CustomModifier>) : nt2ArgumentsCustomModifiers[i]), ref substitution, untouchables)) { return(false); } } // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types // TODO: Calling CanUnifyHelper for the containing type is an overkill, we simply need to go through type arguments for all containers. return((object)nt1.ContainingType == null || CanUnifyHelper(new TypeWithModifiers(nt1.ContainingType), new TypeWithModifiers(nt2.ContainingType), ref substitution, untouchables)); } case SymbolKind.TypeParameter: { // These substitutions are not allowed in C# if (t2.Type.TypeKind == TypeKind.Pointer || t2.Type.SpecialType == SpecialType.System_Void) { return(false); } TypeParameterSymbol tp1 = (TypeParameterSymbol)t1.Type; // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above if (Contains(t2.Type, tp1)) { return(false); } if (!untouchables.Contains(tp1)) { if (t1.CustomModifiers.IsDefaultOrEmpty) { AddSubstitution(ref substitution, tp1, t2); return(true); } if (t1.CustomModifiers.SequenceEqual(t2.CustomModifiers)) { AddSubstitution(ref substitution, tp1, new TypeWithModifiers(t2.Type)); return(true); } if (t1.CustomModifiers.Length < t2.CustomModifiers.Length && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers.Take(t1.CustomModifiers.Length))) { AddSubstitution(ref substitution, tp1, new TypeWithModifiers(t2.Type, ImmutableArray.Create(t2.CustomModifiers, t1.CustomModifiers.Length, t2.CustomModifiers.Length - t1.CustomModifiers.Length))); return(true); } } if (t2.Type.IsTypeParameter()) { var tp2 = (TypeParameterSymbol)t2.Type; if (!untouchables.Contains(tp2)) { if (t2.CustomModifiers.IsDefaultOrEmpty) { AddSubstitution(ref substitution, tp2, t1); return(true); } if (t2.CustomModifiers.Length < t1.CustomModifiers.Length && t2.CustomModifiers.SequenceEqual(t1.CustomModifiers.Take(t2.CustomModifiers.Length))) { AddSubstitution(ref substitution, tp2, new TypeWithModifiers(t1.Type, ImmutableArray.Create(t1.CustomModifiers, t2.CustomModifiers.Length, t1.CustomModifiers.Length - t2.CustomModifiers.Length))); return(true); } } } return(false); } default: { return(t1 == t2); } } }
/// <summary> /// Create real CIL entry point, where it calls given method. /// </summary> internal void CreateEntryPoint(MethodSymbol method, DiagnosticBag diagnostic) { // "static int Main(string[] args)" var realmethod = new SynthesizedMethodSymbol(this.ScriptType, "Main", true, false, _compilation.CoreTypes.Int32, Accessibility.Private); realmethod.SetParameters(new SynthesizedParameterSymbol(realmethod, ArrayTypeSymbol.CreateSZArray(this.Compilation.SourceAssembly, this.Compilation.CoreTypes.String), 0, RefKind.None, "args")); // var body = MethodGenerator.GenerateMethodBody(this, realmethod, (il) => { var types = this.Compilation.CoreTypes; var methods = this.Compilation.CoreMethods; var conversions = this.Compilation.Conversions; var args_place = new ParamPlace(realmethod.Parameters[0]); // int exitcode = 0; var exitcode_loc = il.LocalSlotManager.AllocateSlot(types.Int32.Symbol, LocalSlotConstraints.None); il.EmitIntConstant(0); il.EmitLocalStore(exitcode_loc); // create Context var ctx_loc = il.LocalSlotManager.AllocateSlot(types.Context.Symbol, LocalSlotConstraints.None); var ex_loc = il.LocalSlotManager.AllocateSlot(types.Exception.Symbol, LocalSlotConstraints.None); var onUnhandledException_method = types.Context.Symbol.LookupMember <MethodSymbol>("OnUnhandledException"); var cg = new CodeGenerator(il, moduleBuilder: this, diagnostics: diagnostic, optimizations: PhpOptimizationLevel.Release, emittingPdb: false, container: realmethod.ContainingType, contextPlace: new LocalPlace(ctx_loc), thisPlace: null); if (_compilation.Options.OutputKind == OutputKind.ConsoleApplication) { // CreateConsole(string mainscript, params string[] args) var create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateConsole", m => { return (m.ParameterCount == 2 && m.Parameters[0].Type == types.String && // string mainscript m.Parameters[1].Type == args_place.Type); // params string[] args }); Debug.Assert(create_method != null); il.EmitStringConstant(EntryPointScriptName(method)); // mainscript args_place.EmitLoad(il); // args il.EmitOpCode(ILOpCode.Call, +2); il.EmitToken(create_method, null, diagnostic); } else { // CreateEmpty(args) MethodSymbol create_method = types.Context.Symbol.LookupMember <MethodSymbol>("CreateEmpty"); Debug.Assert(create_method != null); Debug.Assert(create_method.ParameterCount == 1); Debug.Assert(create_method.Parameters[0].Type == args_place.Type); args_place.EmitLoad(il); // args il.EmitOpCode(ILOpCode.Call, +1); il.EmitToken(create_method, null, diagnostic); } il.EmitLocalStore(ctx_loc); // Template: // try { Main(...); } catch (ScriptDiedException) { } catch (Exception) { ... } finally { ctx.Dispose(); } il.OpenLocalScope(ScopeType.TryCatchFinally); // try { try ... } finally {} il.OpenLocalScope(ScopeType.Try); { // IL requires catches and finally block to be distinct try il.OpenLocalScope(ScopeType.TryCatchFinally); // try {} catch (ScriptDiedException) {} il.OpenLocalScope(ScopeType.Try); { // emit .call method; if (method.HasThis) { // TODO: error code for this throw new NotImplementedException("Startup method must be static."); // CONSIDER: create instance of ContainingType } // params foreach (var p in method.Parameters) { switch (p.Name) { case SpecialParameterSymbol.ContextName: // <ctx> il.EmitLocalLoad(ctx_loc); break; case SpecialParameterSymbol.LocalsName: // <ctx>.Globals il.EmitLocalLoad(ctx_loc); il.EmitCall(this, diagnostic, ILOpCode.Call, methods.Context.Globals.Getter) .Expect(p.Type); break; case SpecialParameterSymbol.ThisName: // null il.EmitNullConstant(); break; case SpecialParameterSymbol.SelfName: // default(RuntimeTypeHandle) var runtimetypehandle_loc = il.LocalSlotManager.AllocateSlot(types.RuntimeTypeHandle.Symbol, LocalSlotConstraints.None); il.EmitValueDefault(this, diagnostic, runtimetypehandle_loc); il.LocalSlotManager.FreeSlot(runtimetypehandle_loc); break; default: throw new ArgumentException($"Startup method's argument '${p.Name}' of type '{p.Type.Name}' cannot be fullfilled."); } } var rettype = il.EmitCall(this, diagnostic, ILOpCode.Call, method); if (rettype.SpecialType != SpecialType.System_Void) { cg.EmitConvert(rettype, 0, types.Int32, Semantics.ConversionKind.Explicit); il.EmitLocalStore(exitcode_loc); } } il.CloseLocalScope(); // /Try il.AdjustStack(1); // Account for exception on the stack. il.OpenLocalScope(ScopeType.Catch, types.ScriptDiedException.Symbol); { // exitcode = <exception>.ProcessStatus(ctx) il.EmitLocalLoad(ctx_loc); il.EmitCall(this, diagnostic, ILOpCode.Callvirt, types.ScriptDiedException.Symbol.LookupMember <MethodSymbol>("ProcessStatus")); il.EmitLocalStore(exitcode_loc); } il.CloseLocalScope(); // /Catch if (onUnhandledException_method != null) // only if runtime defines the method (backward compat.) { il.OpenLocalScope(ScopeType.Catch, types.Exception.Symbol); { // <ex_loc> = <stack> il.EmitLocalStore(ex_loc); // <ctx_loc>.OnUnhandledException( <ex_loc> ) : bool il.EmitLocalLoad(ctx_loc); il.EmitLocalLoad(ex_loc); il.EmitCall(this, diagnostic, ILOpCode.Callvirt, onUnhandledException_method) .Expect(SpecialType.System_Boolean); // if ( !<bool> ) // { var lbl_end = new object(); il.EmitBranch(ILOpCode.Brtrue, lbl_end); // rethrow <ex_loc>; il.EmitLocalLoad(ex_loc); il.EmitThrow(true); // } il.MarkLabel(lbl_end); } il.CloseLocalScope(); // /Catch } il.CloseLocalScope(); // /TryCatch } il.CloseLocalScope(); // /Try il.OpenLocalScope(ScopeType.Finally); { // ctx.Dispose il.EmitLocalLoad(ctx_loc); il.EmitOpCode(ILOpCode.Call, -1); il.EmitToken(methods.Context.Dispose.Symbol, null, diagnostic); } il.CloseLocalScope(); // /Finally il.CloseLocalScope(); // /TryCatch // return ctx.ExitCode il.EmitLocalLoad(exitcode_loc); il.EmitRet(false); }, null, diagnostic, false); SetMethodBody(realmethod, body); // this.ScriptType.EntryPointSymbol = realmethod; }
public ArrayBackpatcher(ArrayTypeSymbol symbol, Type type) : base(type) { this.symbol = symbol; }