// Copyright (c) Microsoft Corporation.  All Rights Reserved.  See License.txt in the project root for license information.

namespace FSharp.Compiler.UnitTests.CodeGen.EmittedIL

open FSharp.Compiler.UnitTests
open FSharp.Test
open Xunit


module ``Mutation`` =
    // Regression test for FSHARP1.0:1206

    [<Fact>]
    let ``Mutation 01``() =
        CompilerAssert.CompileLibraryAndVerifyILWithOptions(
            [|"-g"; "--optimize-";"--realsig+"|],
            """
module Mutation01
type Test = struct
              val mutable v: int
              member t.setV v = t.v <- 0
            end
            """,
            (fun verifier -> verifier.VerifyIL [
            """
  .class sequential ansi serializable sealed nested public Test
            """
            """
    .field public int32 v
            """
            """
        .method public hidebysig instance void 
                setV<a>(!!a v) cil managed
        {
          
          .maxstack  4
          .locals init (valuetype Mutation01/Test& V_0)
          IL_0000:  ldarg.0
          IL_0001:  stloc.0
          IL_0002:  ldarg.0
          IL_0003:  ldc.i4.0
          IL_0004:  stfld      int32 Mutation01/Test::v
          IL_0009:  ret
        } 
            """
            ]))

    [<Fact>]
    let ``Mutation 02``() =
        CompilerAssert.CompileLibraryAndVerifyILWithOptions(
            [|"-g"; "--optimize-";"--realsig+"|],
            """
module Mutation02
let x = System.TimeSpan.MinValue
x.ToString()
            """,
            (fun verifier -> verifier.VerifyIL [
            """
  .method public specialname static valuetype [runtime]System.TimeSpan get_x() cil managed
  {
    
    .maxstack  8
    IL_0000:  ldsfld     valuetype [runtime]System.TimeSpan Mutation02::x@3
    IL_0005:  ret
  } 
            """
            """
  .method assembly specialname static void staticInitialization@() cil managed
  {
    
    .maxstack  3
    .locals init (valuetype [runtime]System.TimeSpan V_0)
    IL_0000:  ldsfld     valuetype [runtime]System.TimeSpan [runtime]System.TimeSpan::MinValue
    IL_0005:  stsfld     valuetype [runtime]System.TimeSpan Mutation02::x@3
    IL_000a:  call       valuetype [runtime]System.TimeSpan Mutation02::get_x()
    IL_000f:  stloc.0
    IL_0010:  ldloca.s   V_0
    IL_0012:  constrained. [runtime]System.TimeSpan
    IL_0018:  callvirt   instance string [runtime]System.Object::ToString()
    IL_001d:  pop
    IL_001e:  ret
  } 
            """
            """
  .property valuetype [runtime]System.TimeSpan
          x()
  {
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) 
    .get valuetype [runtime]System.TimeSpan Mutation02::get_x()
  } 
            """
            ]))

    [<Fact>]
    let ``Mutation 03``() =
        CompilerAssert.CompileLibraryAndVerifyILWithOptions(
            [|"-g"; "--optimize-";"--realsig+"|],
            """
module Mutation03
let x = System.DateTime.Now
x.Day
            """,
            (fun verifier -> verifier.VerifyIL [
            """
  .method public specialname static valuetype [runtime]System.DateTime get_x() cil managed
  {
    
    .maxstack  8
    IL_0000:  ldsfld     valuetype [runtime]System.DateTime Mutation03::x@3
    IL_0005:  ret
  } 
            """
            """
  .property valuetype [runtime]System.DateTime
          x()
  {
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) 
    .get valuetype [runtime]System.DateTime Mutation03::get_x()
  } 
            """
            """
  .method assembly specialname static void staticInitialization@() cil managed
  {
    
    .maxstack  3
    .locals init (valuetype [runtime]System.DateTime V_0)
    IL_0000:  call       valuetype [runtime]System.DateTime [runtime]System.DateTime::get_Now()
    IL_0005:  stsfld     valuetype [runtime]System.DateTime Mutation03::x@3
    IL_000a:  call       valuetype [runtime]System.DateTime Mutation03::get_x()
    IL_000f:  stloc.0
    IL_0010:  ldloca.s   V_0
    IL_0012:  call       instance int32 [runtime]System.DateTime::get_Day()
    IL_0017:  pop
    IL_0018:  ret
  } 
            """
            ]))

    [<Fact>]
    let ``Mutation 04``() =
        CompilerAssert.CompileLibraryAndVerifyILWithOptions(
            [|"-g"; "--optimize-";"--realsig+"|],
            """
module Mutation04
let x = System.Decimal.MaxValue
x.ToString()
            """,
            (fun verifier -> verifier.VerifyIL [
            """
  .method public specialname static valuetype [runtime]System.Decimal get_x() cil managed
  {
    
    .maxstack  8
    IL_0000:  ldsfld     valuetype [runtime]System.Decimal Mutation04::x@3
    IL_0005:  ret
  } 
            """
            """
  .property valuetype [runtime]System.Decimal
          x()
  {
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) 
    .get valuetype [runtime]System.Decimal Mutation04::get_x()
  } 
            """
            """
  .method assembly specialname static void staticInitialization@() cil managed
  {
    
    .maxstack  3
    .locals init (valuetype [runtime]System.Decimal V_0)
    IL_0000:  ldsfld     valuetype [runtime]System.Decimal [runtime]System.Decimal::MaxValue
    IL_0005:  stsfld     valuetype [runtime]System.Decimal Mutation04::x@3
    IL_000a:  call       valuetype [runtime]System.Decimal Mutation04::get_x()
    IL_000f:  stloc.0
    IL_0010:  ldloca.s   V_0
    IL_0012:  constrained. [runtime]System.Decimal
    IL_0018:  callvirt   instance string [runtime]System.Object::ToString()
    IL_001d:  pop
    IL_001e:  ret
  } 
            """
            ]))

    [<Fact>]
    let ``Mutation 05``() =
        CompilerAssert.CompileLibraryAndVerifyILWithOptions(
            [|"-g"; "--optimize-";"--realsig+"|],
            """
module Mutation05
type C() =
    [<VolatileFieldAttribute>]
    let mutable x = 1

    member this.X with get() = x and set v = x <- v


type StaticC() =
    [<VolatileFieldAttribute>]
    static let mutable x = 1

    static member X with get() = x and set v = x <- v
            """,
            (fun verifier -> verifier.VerifyIL [
            """
  .class auto ansi serializable nested public C
         extends [runtime]System.Object
  {
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) 
    .field assembly int32 x
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.VolatileFieldAttribute::.ctor() = ( 01 00 00 00 ) 
    .method public specialname rtspecialname instance void  .ctor() cil managed
    {
      
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  callvirt   instance void [runtime]System.Object::.ctor()
      IL_0006:  ldarg.0
      IL_0007:  pop
      IL_0008:  ldarg.0
      IL_0009:  ldc.i4.1
      IL_000a:  volatile.
      IL_000c:  stfld      int32 Mutation05/C::x
      IL_0011:  ret
    } 

    .method public hidebysig specialname instance int32  get_X() cil managed
    {
      
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  volatile.
      IL_0003:  ldfld      int32 Mutation05/C::x
      IL_0008:  ret
    } 

    .method public hidebysig specialname instance void  set_X(int32 v) cil managed
    {
      
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  ldarg.1
      IL_0002:  volatile.
      IL_0004:  stfld      int32 Mutation05/C::x
      IL_0009:  ret
    } 

    .property instance int32 X()
    {
      .set instance void Mutation05/C::set_X(int32)
      .get instance int32 Mutation05/C::get_X()
    } 
  } 
            """
            """
  .class auto ansi serializable nested public StaticC
         extends [runtime]System.Object
  {
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) 
    .field static assembly int32 x
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.VolatileFieldAttribute::.ctor() = ( 01 00 00 00 ) 
    .field static assembly int32 init@10
    .method public specialname rtspecialname instance void  .ctor() cil managed
    {
      
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  callvirt   instance void [runtime]System.Object::.ctor()
      IL_0006:  ldarg.0
      IL_0007:  pop
      IL_0008:  ret
    } 

    .method public specialname static int32 get_X() cil managed
    {
      
      .maxstack  8
      IL_0000:  nop
      IL_0001:  volatile.
      IL_0003:  ldsfld     int32 Mutation05/StaticC::init@10
      IL_0008:  ldc.i4.1
      IL_0009:  bge.s      IL_0014

      IL_000b:  call       void [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::FailStaticInit()
      IL_0010:  nop
      IL_0011:  nop
      IL_0012:  br.s       IL_0015

      IL_0014:  nop
      IL_0015:  volatile.
      IL_0017:  ldsfld     int32 Mutation05/StaticC::x
      IL_001c:  ret
    } 

    .method public specialname static void set_X(int32 v) cil managed
    {
      
      .maxstack  8
      IL_0000:  nop
      IL_0001:  volatile.
      IL_0003:  ldsfld     int32 Mutation05/StaticC::init@10
      IL_0008:  ldc.i4.1
      IL_0009:  bge.s      IL_0014

      IL_000b:  call       void [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::FailStaticInit()
      IL_0010:  nop
      IL_0011:  nop
      IL_0012:  br.s       IL_0015

      IL_0014:  nop
      IL_0015:  ldarg.0
      IL_0016:  volatile.
      IL_0018:  stsfld     int32 Mutation05/StaticC::x
      IL_001d:  ret
    } 

    .method private specialname rtspecialname static void  .cctor() cil managed
    {
      
      .maxstack  8
      IL_0000:  ldc.i4.0
      IL_0001:  stsfld     int32 '<StartupCode$assembly>'.$Mutation05::init@
      IL_0006:  ldsfld     int32 '<StartupCode$assembly>'.$Mutation05::init@
      IL_000b:  pop
      IL_000c:  ret
    } 

    .method assembly specialname static void staticInitialization@() cil managed
    {
      
      .maxstack  8
      IL_0000:  ldc.i4.1
      IL_0001:  volatile.
      IL_0003:  stsfld     int32 Mutation05/StaticC::x
      IL_0008:  ldc.i4.1
      IL_0009:  volatile.
      IL_000b:  stsfld     int32 Mutation05/StaticC::init@10
      IL_0010:  ret
    } 

    .property int32 X()
    {
      .set void Mutation05/StaticC::set_X(int32)
      .get int32 Mutation05/StaticC::get_X()
    } 
  } 

  .method private specialname rtspecialname static void  .cctor() cil managed
  {
    
    .maxstack  8
    IL_0000:  ldc.i4.0
    IL_0001:  stsfld     int32 '<StartupCode$assembly>'.$Mutation05::init@
    IL_0006:  ldsfld     int32 '<StartupCode$assembly>'.$Mutation05::init@
    IL_000b:  pop
    IL_000c:  ret
  } 

  .method assembly specialname static void staticInitialization@() cil managed
  {
    
    .maxstack  8
    IL_0000:  call       void Mutation05/StaticC::staticInitialization@()
    IL_0005:  ret
  } 

} 
            """
            ]))
